include: Define more wuapi interfaces to avoid undefined forward declarations.
[wine] / dlls / mshtml / htmlbody.c
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20 #include <stdio.h>
21
22 #define COBJMACROS
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "ole2.h"
28
29 #include "wine/debug.h"
30
31 #include "mshtml_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34
35 typedef struct {
36     HTMLTextContainer textcont;
37
38     IHTMLBodyElement IHTMLBodyElement_iface;
39
40     ConnectionPoint cp_propnotif;
41
42     nsIDOMHTMLBodyElement *nsbody;
43 } HTMLBodyElement;
44
45 static const WCHAR aquaW[] = {'a','q','u','a',0};
46 static const WCHAR blackW[] = {'b','l','a','c','k',0};
47 static const WCHAR blueW[] = {'b','l','u','e',0};
48 static const WCHAR fuchsiaW[] = {'f','u','s','h','s','i','a',0};
49 static const WCHAR grayW[] = {'g','r','a','y',0};
50 static const WCHAR greenW[] = {'g','r','e','e','n',0};
51 static const WCHAR limeW[] = {'l','i','m','e',0};
52 static const WCHAR maroonW[] = {'m','a','r','o','o','n',0};
53 static const WCHAR navyW[] = {'n','a','v','y',0};
54 static const WCHAR oliveW[] = {'o','l','i','v','e',0};
55 static const WCHAR purpleW[] = {'p','u','r','p','l','e',0};
56 static const WCHAR redW[] = {'r','e','d',0};
57 static const WCHAR silverW[] = {'s','i','l','v','e','r',0};
58 static const WCHAR tealW[] = {'t','e','a','l',0};
59 static const WCHAR whiteW[] = {'w','h','i','t','e',0};
60 static const WCHAR yellowW[] = {'y','e','l','l','o','w',0};
61
62 static const struct {
63     LPCWSTR keyword;
64     DWORD rgb;
65 } keyword_table[] = {
66     {aquaW,     0x00ffff},
67     {blackW,    0x000000},
68     {blueW,     0x0000ff},
69     {fuchsiaW,  0xff00ff},
70     {grayW,     0x808080},
71     {greenW,    0x008000},
72     {limeW,     0x00ff00},
73     {maroonW,   0x800000},
74     {navyW,     0x000080},
75     {oliveW,    0x808000},
76     {purpleW,   0x800080},
77     {redW,      0xff0000},
78     {silverW,   0xc0c0c0},
79     {tealW,     0x008080},
80     {whiteW,    0xffffff},
81     {yellowW,   0xffff00}
82 };
83
84 static int comp_value(const WCHAR *ptr, int dpc)
85 {
86     int ret = 0;
87     WCHAR ch;
88
89     if(dpc > 2)
90         dpc = 2;
91
92     while(dpc--) {
93         if(!*ptr)
94             ret *= 16;
95         else if(isdigitW(ch = *ptr++))
96             ret = ret*16 + (ch-'0');
97         else if('a' <= ch && ch <= 'f')
98             ret = ret*16 + (ch-'a') + 10;
99         else if('A' <= ch && ch <= 'F')
100             ret = ret*16 + (ch-'A') + 10;
101         else
102             ret *= 16;
103     }
104
105     return ret;
106 }
107
108 /* Based on Gecko NS_LooseHexToRGB */
109 static int loose_hex_to_rgb(const WCHAR *hex)
110 {
111     int len, dpc;
112
113     len = strlenW(hex);
114     if(*hex == '#') {
115         hex++;
116         len--;
117     }
118     if(len <= 3)
119         return 0;
120
121     dpc = min(len/3 + (len%3 ? 1 : 0), 4);
122     return (comp_value(hex, dpc) << 16)
123         | (comp_value(hex+dpc, dpc) << 8)
124         | comp_value(hex+2*dpc, dpc);
125 }
126
127 static HRESULT nscolor_to_str(LPCWSTR color, BSTR *ret)
128 {
129     int i, rgb = -1;
130
131     static const WCHAR formatW[] = {'#','%','0','2','x','%','0','2','x','%','0','2','x',0};
132
133     if(!color || !*color) {
134         *ret = NULL;
135         return S_OK;
136     }
137
138     if(*color != '#') {
139         for(i=0; i < sizeof(keyword_table)/sizeof(keyword_table[0]); i++) {
140             if(!strcmpiW(color, keyword_table[i].keyword))
141                 rgb = keyword_table[i].rgb;
142         }
143     }
144     if(rgb == -1)
145         rgb = loose_hex_to_rgb(color);
146
147     *ret = SysAllocStringLen(NULL, 7);
148     if(!*ret)
149         return E_OUTOFMEMORY;
150
151     sprintfW(*ret, formatW, rgb>>16, (rgb>>8)&0xff, rgb&0xff);
152
153     TRACE("%s -> %s\n", debugstr_w(color), debugstr_w(*ret));
154     return S_OK;
155 }
156
157 static BOOL variant_to_nscolor(const VARIANT *v, nsAString *nsstr)
158 {
159     switch(V_VT(v)) {
160     case VT_BSTR:
161         nsAString_Init(nsstr, V_BSTR(v));
162         return TRUE;
163
164     case VT_I4: {
165         PRUnichar buf[10];
166         static const WCHAR formatW[] = {'#','%','x',0};
167
168         wsprintfW(buf, formatW, V_I4(v));
169         nsAString_Init(nsstr, buf);
170         return TRUE;
171     }
172
173     default:
174         FIXME("invalid vt=%d\n", V_VT(v));
175     }
176
177     return FALSE;
178
179 }
180
181 static void nscolor_to_variant(const nsAString *nsstr, VARIANT *p)
182 {
183     const PRUnichar *color;
184
185     nsAString_GetData(nsstr, &color);
186
187     if(*color == '#') {
188         V_VT(p) = VT_I4;
189         V_I4(p) = strtolW(color+1, NULL, 16);
190     }else {
191         V_VT(p) = VT_BSTR;
192         V_BSTR(p) = SysAllocString(color);
193     }
194 }
195
196 static inline HTMLBodyElement *impl_from_IHTMLBodyElement(IHTMLBodyElement *iface)
197 {
198     return CONTAINING_RECORD(iface, HTMLBodyElement, IHTMLBodyElement_iface);
199 }
200
201 static HRESULT WINAPI HTMLBodyElement_QueryInterface(IHTMLBodyElement *iface,
202                                                      REFIID riid, void **ppv)
203 {
204     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
205
206     return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(&This->textcont.element.node), riid, ppv);
207 }
208
209 static ULONG WINAPI HTMLBodyElement_AddRef(IHTMLBodyElement *iface)
210 {
211     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
212
213     return IHTMLDOMNode_AddRef(HTMLDOMNODE(&This->textcont.element.node));
214 }
215
216 static ULONG WINAPI HTMLBodyElement_Release(IHTMLBodyElement *iface)
217 {
218     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
219
220     return IHTMLDOMNode_Release(HTMLDOMNODE(&This->textcont.element.node));
221 }
222
223 static HRESULT WINAPI HTMLBodyElement_GetTypeInfoCount(IHTMLBodyElement *iface, UINT *pctinfo)
224 {
225     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
226     return IDispatchEx_GetTypeInfoCount(DISPATCHEX(&This->textcont.element.node.dispex), pctinfo);
227 }
228
229 static HRESULT WINAPI HTMLBodyElement_GetTypeInfo(IHTMLBodyElement *iface, UINT iTInfo,
230                                               LCID lcid, ITypeInfo **ppTInfo)
231 {
232     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
233     return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->textcont.element.node.dispex), iTInfo, lcid, ppTInfo);
234 }
235
236 static HRESULT WINAPI HTMLBodyElement_GetIDsOfNames(IHTMLBodyElement *iface, REFIID riid,
237                                                 LPOLESTR *rgszNames, UINT cNames,
238                                                 LCID lcid, DISPID *rgDispId)
239 {
240     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
241     return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->textcont.element.node.dispex), riid, rgszNames, cNames, lcid, rgDispId);
242 }
243
244 static HRESULT WINAPI HTMLBodyElement_Invoke(IHTMLBodyElement *iface, DISPID dispIdMember,
245                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
246                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
247 {
248     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
249     return IDispatchEx_Invoke(DISPATCHEX(&This->textcont.element.node.dispex), dispIdMember, riid, lcid,
250             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
251 }
252
253 static HRESULT WINAPI HTMLBodyElement_put_background(IHTMLBodyElement *iface, BSTR v)
254 {
255     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
256     nsAString nsstr;
257     nsresult nsres;
258
259     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
260
261     nsAString_InitDepend(&nsstr, v);
262     nsres = nsIDOMHTMLBodyElement_SetBackground(This->nsbody, &nsstr);
263     nsAString_Finish(&nsstr);
264     if(NS_FAILED(nsres))
265         return E_FAIL;
266
267     return S_OK;
268 }
269
270 static HRESULT WINAPI HTMLBodyElement_get_background(IHTMLBodyElement *iface, BSTR *p)
271 {
272     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
273     nsAString background_str;
274     nsresult nsres;
275
276     TRACE("(%p)->(%p)\n", This, p);
277
278     nsAString_Init(&background_str, NULL);
279
280     nsres = nsIDOMHTMLBodyElement_GetBackground(This->nsbody, &background_str);
281     if(NS_SUCCEEDED(nsres)) {
282         const PRUnichar *background;
283         nsAString_GetData(&background_str, &background);
284         *p = *background ? SysAllocString(background) : NULL;
285     }else {
286         ERR("GetBackground failed: %08x\n", nsres);
287         *p = NULL;
288     }
289
290     nsAString_Finish(&background_str);
291
292     TRACE("*p = %s\n", debugstr_w(*p));
293     return S_OK;
294 }
295
296 static HRESULT WINAPI HTMLBodyElement_put_bgProperties(IHTMLBodyElement *iface, BSTR v)
297 {
298     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
299     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
300     return E_NOTIMPL;
301 }
302
303 static HRESULT WINAPI HTMLBodyElement_get_bgProperties(IHTMLBodyElement *iface, BSTR *p)
304 {
305     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
306     FIXME("(%p)->(%p)\n", This, p);
307     return E_NOTIMPL;
308 }
309
310 static HRESULT WINAPI HTMLBodyElement_put_leftMargin(IHTMLBodyElement *iface, VARIANT v)
311 {
312     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
313     FIXME("(%p)->()\n", This);
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI HTMLBodyElement_get_leftMargin(IHTMLBodyElement *iface, VARIANT *p)
318 {
319     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
320     FIXME("(%p)->(%p)\n", This, p);
321     return E_NOTIMPL;
322 }
323
324 static HRESULT WINAPI HTMLBodyElement_put_topMargin(IHTMLBodyElement *iface, VARIANT v)
325 {
326     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
327     FIXME("(%p)->()\n", This);
328     return E_NOTIMPL;
329 }
330
331 static HRESULT WINAPI HTMLBodyElement_get_topMargin(IHTMLBodyElement *iface, VARIANT *p)
332 {
333     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
334     FIXME("(%p)->(%p)\n", This, p);
335     return E_NOTIMPL;
336 }
337
338 static HRESULT WINAPI HTMLBodyElement_put_rightMargin(IHTMLBodyElement *iface, VARIANT v)
339 {
340     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
341     FIXME("(%p)->()\n", This);
342     return E_NOTIMPL;
343 }
344
345 static HRESULT WINAPI HTMLBodyElement_get_rightMargin(IHTMLBodyElement *iface, VARIANT *p)
346 {
347     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
348     FIXME("(%p)->(%p)\n", This, p);
349     return E_NOTIMPL;
350 }
351
352 static HRESULT WINAPI HTMLBodyElement_put_bottomMargin(IHTMLBodyElement *iface, VARIANT v)
353 {
354     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
355     FIXME("(%p)->()\n", This);
356     return E_NOTIMPL;
357 }
358
359 static HRESULT WINAPI HTMLBodyElement_get_bottomMargin(IHTMLBodyElement *iface, VARIANT *p)
360 {
361     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
362     FIXME("(%p)->(%p)\n", This, p);
363     return E_NOTIMPL;
364 }
365
366 static HRESULT WINAPI HTMLBodyElement_put_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL v)
367 {
368     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
369     FIXME("(%p)->(%x)\n", This, v);
370     return E_NOTIMPL;
371 }
372
373 static HRESULT WINAPI HTMLBodyElement_get_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL *p)
374 {
375     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
376     FIXME("(%p)->(%p)\n", This, p);
377     return E_NOTIMPL;
378 }
379
380 static HRESULT WINAPI HTMLBodyElement_put_bgColor(IHTMLBodyElement *iface, VARIANT v)
381 {
382     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
383     nsAString strColor;
384     nsresult nsres;
385
386     TRACE("(%p)->()\n", This);
387
388     if(!variant_to_nscolor(&v, &strColor))
389         return S_OK;
390
391     nsres = nsIDOMHTMLBodyElement_SetBgColor(This->nsbody, &strColor);
392     nsAString_Finish(&strColor);
393     if(NS_FAILED(nsres))
394         ERR("SetBgColor failed: %08x\n", nsres);
395
396     return S_OK;
397 }
398
399 static HRESULT WINAPI HTMLBodyElement_get_bgColor(IHTMLBodyElement *iface, VARIANT *p)
400 {
401     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
402     nsAString strColor;
403     nsresult nsres;
404     HRESULT hres;
405
406     TRACE("(%p)->(%p)\n", This, p);
407
408     nsAString_Init(&strColor, NULL);
409     nsres = nsIDOMHTMLBodyElement_GetBgColor(This->nsbody, &strColor);
410     if(NS_SUCCEEDED(nsres)) {
411         const PRUnichar *color;
412
413         nsAString_GetData(&strColor, &color);
414         V_VT(p) = VT_BSTR;
415         hres = nscolor_to_str(color, &V_BSTR(p));
416     }else {
417         ERR("SetBgColor failed: %08x\n", nsres);
418         hres = E_FAIL;
419     }
420
421     nsAString_Finish(&strColor);
422     return hres;
423 }
424
425 static HRESULT WINAPI HTMLBodyElement_put_text(IHTMLBodyElement *iface, VARIANT v)
426 {
427     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
428     nsAString text;
429     nsresult nsres;
430
431     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
432
433     if(!variant_to_nscolor(&v, &text))
434         return S_OK;
435
436     nsres = nsIDOMHTMLBodyElement_SetText(This->nsbody, &text);
437     nsAString_Finish(&text);
438     if(NS_FAILED(nsres)) {
439         ERR("SetText failed: %08x\n", nsres);
440         return E_FAIL;
441     }
442
443     return S_OK;
444 }
445
446 static HRESULT WINAPI HTMLBodyElement_get_text(IHTMLBodyElement *iface, VARIANT *p)
447 {
448     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
449     nsAString text;
450     nsresult nsres;
451     HRESULT hres;
452
453     TRACE("(%p)->(%p)\n", This, p);
454
455     nsAString_Init(&text, NULL);
456     nsres = nsIDOMHTMLBodyElement_GetText(This->nsbody, &text);
457     if(NS_SUCCEEDED(nsres)) {
458         const PRUnichar *color;
459
460         nsAString_GetData(&text, &color);
461         V_VT(p) = VT_BSTR;
462         hres = nscolor_to_str(color, &V_BSTR(p));
463     }else {
464         ERR("GetText failed: %08x\n", nsres);
465         hres = E_FAIL;
466     }
467
468     nsAString_Finish(&text);
469
470     return hres;
471 }
472
473 static HRESULT WINAPI HTMLBodyElement_put_link(IHTMLBodyElement *iface, VARIANT v)
474 {
475     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
476     nsAString link_str;
477     nsresult nsres;
478
479     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
480
481     if(!variant_to_nscolor(&v, &link_str))
482         return S_OK;
483
484     nsres = nsIDOMHTMLBodyElement_SetLink(This->nsbody, &link_str);
485     nsAString_Finish(&link_str);
486     if(NS_FAILED(nsres))
487         ERR("SetLink failed: %08x\n", nsres);
488
489     return S_OK;
490 }
491
492 static HRESULT WINAPI HTMLBodyElement_get_link(IHTMLBodyElement *iface, VARIANT *p)
493 {
494     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
495     nsAString link_str;
496     nsresult nsres;
497
498     TRACE("(%p)->(%p)\n", This, p);
499
500     nsAString_Init(&link_str, NULL);
501     nsres = nsIDOMHTMLBodyElement_GetLink(This->nsbody, &link_str);
502     if(NS_FAILED(nsres))
503         ERR("GetLink failed: %08x\n", nsres);
504
505     nscolor_to_variant(&link_str, p);
506     nsAString_Finish(&link_str);
507
508     return S_OK;
509 }
510
511 static HRESULT WINAPI HTMLBodyElement_put_vLink(IHTMLBodyElement *iface, VARIANT v)
512 {
513     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
514     nsAString vlink_str;
515     nsresult nsres;
516
517     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
518
519     if(!variant_to_nscolor(&v, &vlink_str))
520         return S_OK;
521
522     nsres = nsIDOMHTMLBodyElement_SetVLink(This->nsbody, &vlink_str);
523     nsAString_Finish(&vlink_str);
524     if(NS_FAILED(nsres))
525         ERR("SetLink failed: %08x\n", nsres);
526
527     return S_OK;
528 }
529
530 static HRESULT WINAPI HTMLBodyElement_get_vLink(IHTMLBodyElement *iface, VARIANT *p)
531 {
532     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
533     nsAString vlink_str;
534     nsresult nsres;
535
536     TRACE("(%p)->(%p)\n", This, p);
537
538     nsAString_Init(&vlink_str, NULL);
539     nsres = nsIDOMHTMLBodyElement_GetVLink(This->nsbody, &vlink_str);
540     if(NS_FAILED(nsres))
541         ERR("GetLink failed: %08x\n", nsres);
542
543     nscolor_to_variant(&vlink_str, p);
544     nsAString_Finish(&vlink_str);
545
546     return S_OK;
547 }
548
549 static HRESULT WINAPI HTMLBodyElement_put_aLink(IHTMLBodyElement *iface, VARIANT v)
550 {
551     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
552     nsAString alink_str;
553     nsresult nsres;
554
555     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
556
557     if(!variant_to_nscolor(&v, &alink_str))
558         return S_OK;
559
560     nsres = nsIDOMHTMLBodyElement_SetALink(This->nsbody, &alink_str);
561     nsAString_Finish(&alink_str);
562     if(NS_FAILED(nsres))
563         ERR("SetALink failed: %08x\n", nsres);
564
565     return S_OK;
566 }
567
568 static HRESULT WINAPI HTMLBodyElement_get_aLink(IHTMLBodyElement *iface, VARIANT *p)
569 {
570     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
571     nsAString alink_str;
572     nsresult nsres;
573
574     TRACE("(%p)->(%p)\n", This, p);
575
576     nsAString_Init(&alink_str, NULL);
577     nsres = nsIDOMHTMLBodyElement_GetALink(This->nsbody, &alink_str);
578     if(NS_FAILED(nsres))
579         ERR("GetALink failed: %08x\n", nsres);
580
581     nscolor_to_variant(&alink_str, p);
582     nsAString_Finish(&alink_str);
583
584     return S_OK;
585 }
586
587 static HRESULT WINAPI HTMLBodyElement_put_onload(IHTMLBodyElement *iface, VARIANT v)
588 {
589     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
590     FIXME("(%p)->()\n", This);
591     return E_NOTIMPL;
592 }
593
594 static HRESULT WINAPI HTMLBodyElement_get_onload(IHTMLBodyElement *iface, VARIANT *p)
595 {
596     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
597     FIXME("(%p)->(%p)\n", This, p);
598     return E_NOTIMPL;
599 }
600
601 static HRESULT WINAPI HTMLBodyElement_put_onunload(IHTMLBodyElement *iface, VARIANT v)
602 {
603     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
604     FIXME("(%p)->()\n", This);
605     return E_NOTIMPL;
606 }
607
608 static HRESULT WINAPI HTMLBodyElement_get_onunload(IHTMLBodyElement *iface, VARIANT *p)
609 {
610     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
611     FIXME("(%p)->(%p)\n", This, p);
612     return E_NOTIMPL;
613 }
614
615 static HRESULT WINAPI HTMLBodyElement_put_scroll(IHTMLBodyElement *iface, BSTR v)
616 {
617     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
618     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
619     return E_NOTIMPL;
620 }
621
622 static HRESULT WINAPI HTMLBodyElement_get_scroll(IHTMLBodyElement *iface, BSTR *p)
623 {
624     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
625     FIXME("(%p)->(%p)\n", This, p);
626     return E_NOTIMPL;
627 }
628
629 static HRESULT WINAPI HTMLBodyElement_put_onselect(IHTMLBodyElement *iface, VARIANT v)
630 {
631     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
632     FIXME("(%p)->()\n", This);
633     return E_NOTIMPL;
634 }
635
636 static HRESULT WINAPI HTMLBodyElement_get_onselect(IHTMLBodyElement *iface, VARIANT *p)
637 {
638     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
639     FIXME("(%p)->(%p)\n", This, p);
640     return E_NOTIMPL;
641 }
642
643 static HRESULT WINAPI HTMLBodyElement_put_onbeforeunload(IHTMLBodyElement *iface, VARIANT v)
644 {
645     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
646     FIXME("(%p)->()\n", This);
647     return E_NOTIMPL;
648 }
649
650 static HRESULT WINAPI HTMLBodyElement_get_onbeforeunload(IHTMLBodyElement *iface, VARIANT *p)
651 {
652     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
653     FIXME("(%p)->(%p)\n", This, p);
654     return E_NOTIMPL;
655 }
656
657 static HRESULT WINAPI HTMLBodyElement_createTextRange(IHTMLBodyElement *iface, IHTMLTxtRange **range)
658 {
659     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
660     nsIDOMDocumentRange *nsdocrange;
661     nsIDOMRange *nsrange = NULL;
662     nsresult nsres;
663     HRESULT hres;
664
665     TRACE("(%p)->(%p)\n", This, range);
666
667     if(!This->textcont.element.node.doc->nsdoc) {
668         WARN("No nsdoc\n");
669         return E_UNEXPECTED;
670     }
671
672     nsres = nsIDOMDocument_QueryInterface(This->textcont.element.node.doc->nsdoc, &IID_nsIDOMDocumentRange,
673             (void**)&nsdocrange);
674     if(NS_FAILED(nsres)) {
675         ERR("Could not get nsIDOMDocumentRabge iface: %08x\n", nsres);
676         return E_FAIL;
677     }
678
679     nsres = nsIDOMDocumentRange_CreateRange(nsdocrange, &nsrange);
680     if(NS_SUCCEEDED(nsres)) {
681         nsres = nsIDOMRange_SelectNodeContents(nsrange, This->textcont.element.node.nsnode);
682         if(NS_FAILED(nsres))
683             ERR("SelectNodeContents failed: %08x\n", nsres);
684     }else {
685         ERR("CreateRange failed: %08x\n", nsres);
686     }
687
688     nsIDOMDocumentRange_Release(nsdocrange);
689
690     hres = HTMLTxtRange_Create(This->textcont.element.node.doc->basedoc.doc_node, nsrange, range);
691
692     nsIDOMRange_Release(nsrange);
693     return hres;
694 }
695
696 static const IHTMLBodyElementVtbl HTMLBodyElementVtbl = {
697     HTMLBodyElement_QueryInterface,
698     HTMLBodyElement_AddRef,
699     HTMLBodyElement_Release,
700     HTMLBodyElement_GetTypeInfoCount,
701     HTMLBodyElement_GetTypeInfo,
702     HTMLBodyElement_GetIDsOfNames,
703     HTMLBodyElement_Invoke,
704     HTMLBodyElement_put_background,
705     HTMLBodyElement_get_background,
706     HTMLBodyElement_put_bgProperties,
707     HTMLBodyElement_get_bgProperties,
708     HTMLBodyElement_put_leftMargin,
709     HTMLBodyElement_get_leftMargin,
710     HTMLBodyElement_put_topMargin,
711     HTMLBodyElement_get_topMargin,
712     HTMLBodyElement_put_rightMargin,
713     HTMLBodyElement_get_rightMargin,
714     HTMLBodyElement_put_bottomMargin,
715     HTMLBodyElement_get_bottomMargin,
716     HTMLBodyElement_put_noWrap,
717     HTMLBodyElement_get_noWrap,
718     HTMLBodyElement_put_bgColor,
719     HTMLBodyElement_get_bgColor,
720     HTMLBodyElement_put_text,
721     HTMLBodyElement_get_text,
722     HTMLBodyElement_put_link,
723     HTMLBodyElement_get_link,
724     HTMLBodyElement_put_vLink,
725     HTMLBodyElement_get_vLink,
726     HTMLBodyElement_put_aLink,
727     HTMLBodyElement_get_aLink,
728     HTMLBodyElement_put_onload,
729     HTMLBodyElement_get_onload,
730     HTMLBodyElement_put_onunload,
731     HTMLBodyElement_get_onunload,
732     HTMLBodyElement_put_scroll,
733     HTMLBodyElement_get_scroll,
734     HTMLBodyElement_put_onselect,
735     HTMLBodyElement_get_onselect,
736     HTMLBodyElement_put_onbeforeunload,
737     HTMLBodyElement_get_onbeforeunload,
738     HTMLBodyElement_createTextRange
739 };
740
741 #define HTMLBODY_NODE_THIS(iface) DEFINE_THIS2(HTMLBodyElement, textcont.element.node, iface)
742
743 static HRESULT HTMLBodyElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
744 {
745     HTMLBodyElement *This = HTMLBODY_NODE_THIS(iface);
746
747     *ppv = NULL;
748
749     if(IsEqualGUID(&IID_IUnknown, riid)) {
750         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
751         *ppv = &This->IHTMLBodyElement_iface;
752     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
753         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
754         *ppv = &This->IHTMLBodyElement_iface;
755     }else if(IsEqualGUID(&IID_IHTMLBodyElement, riid)) {
756         TRACE("(%p)->(IID_IHTMLBodyElement %p)\n", This, ppv);
757         *ppv = &This->IHTMLBodyElement_iface;
758     }else if(IsEqualGUID(&IID_IHTMLTextContainer, riid)) {
759         TRACE("(%p)->(IID_IHTMLTextContainer %p)\n", &This->textcont, ppv);
760         *ppv = HTMLTEXTCONT(&This->textcont);
761     }
762
763     if(*ppv) {
764         IUnknown_AddRef((IUnknown*)*ppv);
765         return S_OK;
766     }
767
768     return HTMLElement_QI(&This->textcont.element.node, riid, ppv);
769 }
770
771 static void HTMLBodyElement_destructor(HTMLDOMNode *iface)
772 {
773     HTMLBodyElement *This = HTMLBODY_NODE_THIS(iface);
774
775     nsIDOMHTMLBodyElement_Release(This->nsbody);
776
777     HTMLElement_destructor(&This->textcont.element.node);
778 }
779
780 static event_target_t **HTMLBodyElement_get_event_target(HTMLDOMNode *iface)
781 {
782     HTMLBodyElement *This = HTMLBODY_NODE_THIS(iface);
783
784     return This->textcont.element.node.doc
785         ? &This->textcont.element.node.doc->body_event_target
786         : &This->textcont.element.node.event_target;
787 }
788
789 #undef HTMLBODY_NODE_THIS
790
791 static const NodeImplVtbl HTMLBodyElementImplVtbl = {
792     HTMLBodyElement_QI,
793     HTMLBodyElement_destructor,
794     HTMLElement_clone,
795     HTMLBodyElement_get_event_target
796 };
797
798 static const tid_t HTMLBodyElement_iface_tids[] = {
799     IHTMLBodyElement_tid,
800     IHTMLBodyElement2_tid,
801     HTMLELEMENT_TIDS,
802     IHTMLTextContainer_tid,
803     IHTMLUniqueName_tid,
804     0
805 };
806
807 static dispex_static_data_t HTMLBodyElement_dispex = {
808     NULL,
809     DispHTMLBody_tid,
810     NULL,
811     HTMLBodyElement_iface_tids
812 };
813
814 HRESULT HTMLBodyElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, HTMLElement **elem)
815 {
816     HTMLBodyElement *ret;
817     nsresult nsres;
818
819     ret = heap_alloc_zero(sizeof(HTMLBodyElement));
820     if(!ret)
821         return E_OUTOFMEMORY;
822
823     ret->IHTMLBodyElement_iface.lpVtbl = &HTMLBodyElementVtbl;
824     ret->textcont.element.node.vtbl = &HTMLBodyElementImplVtbl;
825
826     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLBodyElement, (void**)&ret->nsbody);
827     if(NS_FAILED(nsres)) {
828         ERR("Could not get nsDOMHTMLBodyElement: %08x\n", nsres);
829         heap_free(ret);
830         return E_OUTOFMEMORY;
831     }
832
833     HTMLTextContainer_Init(&ret->textcont, doc, nselem, &HTMLBodyElement_dispex);
834
835     ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink, NULL);
836
837     *elem = &ret->textcont.element;
838     return S_OK;
839 }