mshtml: Added property value conversion type tests.
[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(&This->textcont.element.node.IHTMLDOMNode_iface, 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(&This->textcont.element.node.IHTMLDOMNode_iface);
214 }
215
216 static ULONG WINAPI HTMLBodyElement_Release(IHTMLBodyElement *iface)
217 {
218     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
219
220     return IHTMLDOMNode_Release(&This->textcont.element.node.IHTMLDOMNode_iface);
221 }
222
223 static HRESULT WINAPI HTMLBodyElement_GetTypeInfoCount(IHTMLBodyElement *iface, UINT *pctinfo)
224 {
225     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
226     return IDispatchEx_GetTypeInfoCount(&This->textcont.element.node.dispex.IDispatchEx_iface,
227             pctinfo);
228 }
229
230 static HRESULT WINAPI HTMLBodyElement_GetTypeInfo(IHTMLBodyElement *iface, UINT iTInfo,
231                                               LCID lcid, ITypeInfo **ppTInfo)
232 {
233     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
234     return IDispatchEx_GetTypeInfo(&This->textcont.element.node.dispex.IDispatchEx_iface, iTInfo,
235             lcid, ppTInfo);
236 }
237
238 static HRESULT WINAPI HTMLBodyElement_GetIDsOfNames(IHTMLBodyElement *iface, REFIID riid,
239                                                 LPOLESTR *rgszNames, UINT cNames,
240                                                 LCID lcid, DISPID *rgDispId)
241 {
242     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
243     return IDispatchEx_GetIDsOfNames(&This->textcont.element.node.dispex.IDispatchEx_iface, riid,
244             rgszNames, cNames, lcid, rgDispId);
245 }
246
247 static HRESULT WINAPI HTMLBodyElement_Invoke(IHTMLBodyElement *iface, DISPID dispIdMember,
248                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
249                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
250 {
251     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
252     return IDispatchEx_Invoke(&This->textcont.element.node.dispex.IDispatchEx_iface, dispIdMember,
253             riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
254 }
255
256 static HRESULT WINAPI HTMLBodyElement_put_background(IHTMLBodyElement *iface, BSTR v)
257 {
258     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
259     nsAString nsstr;
260     nsresult nsres;
261
262     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
263
264     nsAString_InitDepend(&nsstr, v);
265     nsres = nsIDOMHTMLBodyElement_SetBackground(This->nsbody, &nsstr);
266     nsAString_Finish(&nsstr);
267     if(NS_FAILED(nsres))
268         return E_FAIL;
269
270     return S_OK;
271 }
272
273 static HRESULT WINAPI HTMLBodyElement_get_background(IHTMLBodyElement *iface, BSTR *p)
274 {
275     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
276     nsAString background_str;
277     nsresult nsres;
278
279     TRACE("(%p)->(%p)\n", This, p);
280
281     nsAString_Init(&background_str, NULL);
282
283     nsres = nsIDOMHTMLBodyElement_GetBackground(This->nsbody, &background_str);
284     if(NS_SUCCEEDED(nsres)) {
285         const PRUnichar *background;
286         nsAString_GetData(&background_str, &background);
287         *p = *background ? SysAllocString(background) : NULL;
288     }else {
289         ERR("GetBackground failed: %08x\n", nsres);
290         *p = NULL;
291     }
292
293     nsAString_Finish(&background_str);
294
295     TRACE("*p = %s\n", debugstr_w(*p));
296     return S_OK;
297 }
298
299 static HRESULT WINAPI HTMLBodyElement_put_bgProperties(IHTMLBodyElement *iface, BSTR v)
300 {
301     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
302     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
303     return E_NOTIMPL;
304 }
305
306 static HRESULT WINAPI HTMLBodyElement_get_bgProperties(IHTMLBodyElement *iface, BSTR *p)
307 {
308     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
309     FIXME("(%p)->(%p)\n", This, p);
310     return E_NOTIMPL;
311 }
312
313 static HRESULT WINAPI HTMLBodyElement_put_leftMargin(IHTMLBodyElement *iface, VARIANT v)
314 {
315     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
316     FIXME("(%p)->()\n", This);
317     return E_NOTIMPL;
318 }
319
320 static HRESULT WINAPI HTMLBodyElement_get_leftMargin(IHTMLBodyElement *iface, VARIANT *p)
321 {
322     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
323     FIXME("(%p)->(%p)\n", This, p);
324     return E_NOTIMPL;
325 }
326
327 static HRESULT WINAPI HTMLBodyElement_put_topMargin(IHTMLBodyElement *iface, VARIANT v)
328 {
329     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
330     FIXME("(%p)->()\n", This);
331     return E_NOTIMPL;
332 }
333
334 static HRESULT WINAPI HTMLBodyElement_get_topMargin(IHTMLBodyElement *iface, VARIANT *p)
335 {
336     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
337     FIXME("(%p)->(%p)\n", This, p);
338     return E_NOTIMPL;
339 }
340
341 static HRESULT WINAPI HTMLBodyElement_put_rightMargin(IHTMLBodyElement *iface, VARIANT v)
342 {
343     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
344     FIXME("(%p)->()\n", This);
345     return E_NOTIMPL;
346 }
347
348 static HRESULT WINAPI HTMLBodyElement_get_rightMargin(IHTMLBodyElement *iface, VARIANT *p)
349 {
350     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
351     FIXME("(%p)->(%p)\n", This, p);
352     return E_NOTIMPL;
353 }
354
355 static HRESULT WINAPI HTMLBodyElement_put_bottomMargin(IHTMLBodyElement *iface, VARIANT v)
356 {
357     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
358     FIXME("(%p)->()\n", This);
359     return E_NOTIMPL;
360 }
361
362 static HRESULT WINAPI HTMLBodyElement_get_bottomMargin(IHTMLBodyElement *iface, VARIANT *p)
363 {
364     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
365     FIXME("(%p)->(%p)\n", This, p);
366     return E_NOTIMPL;
367 }
368
369 static HRESULT WINAPI HTMLBodyElement_put_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL v)
370 {
371     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
372     FIXME("(%p)->(%x)\n", This, v);
373     return E_NOTIMPL;
374 }
375
376 static HRESULT WINAPI HTMLBodyElement_get_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL *p)
377 {
378     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
379     FIXME("(%p)->(%p)\n", This, p);
380     return E_NOTIMPL;
381 }
382
383 static HRESULT WINAPI HTMLBodyElement_put_bgColor(IHTMLBodyElement *iface, VARIANT v)
384 {
385     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
386     nsAString strColor;
387     nsresult nsres;
388
389     TRACE("(%p)->()\n", This);
390
391     if(!variant_to_nscolor(&v, &strColor))
392         return S_OK;
393
394     nsres = nsIDOMHTMLBodyElement_SetBgColor(This->nsbody, &strColor);
395     nsAString_Finish(&strColor);
396     if(NS_FAILED(nsres))
397         ERR("SetBgColor failed: %08x\n", nsres);
398
399     return S_OK;
400 }
401
402 static HRESULT WINAPI HTMLBodyElement_get_bgColor(IHTMLBodyElement *iface, VARIANT *p)
403 {
404     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
405     nsAString strColor;
406     nsresult nsres;
407     HRESULT hres;
408
409     TRACE("(%p)->(%p)\n", This, p);
410
411     nsAString_Init(&strColor, NULL);
412     nsres = nsIDOMHTMLBodyElement_GetBgColor(This->nsbody, &strColor);
413     if(NS_SUCCEEDED(nsres)) {
414         const PRUnichar *color;
415
416         nsAString_GetData(&strColor, &color);
417         V_VT(p) = VT_BSTR;
418         hres = nscolor_to_str(color, &V_BSTR(p));
419     }else {
420         ERR("SetBgColor failed: %08x\n", nsres);
421         hres = E_FAIL;
422     }
423
424     nsAString_Finish(&strColor);
425     return hres;
426 }
427
428 static HRESULT WINAPI HTMLBodyElement_put_text(IHTMLBodyElement *iface, VARIANT v)
429 {
430     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
431     nsAString text;
432     nsresult nsres;
433
434     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
435
436     if(!variant_to_nscolor(&v, &text))
437         return S_OK;
438
439     nsres = nsIDOMHTMLBodyElement_SetText(This->nsbody, &text);
440     nsAString_Finish(&text);
441     if(NS_FAILED(nsres)) {
442         ERR("SetText failed: %08x\n", nsres);
443         return E_FAIL;
444     }
445
446     return S_OK;
447 }
448
449 static HRESULT WINAPI HTMLBodyElement_get_text(IHTMLBodyElement *iface, VARIANT *p)
450 {
451     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
452     nsAString text;
453     nsresult nsres;
454     HRESULT hres;
455
456     TRACE("(%p)->(%p)\n", This, p);
457
458     nsAString_Init(&text, NULL);
459     nsres = nsIDOMHTMLBodyElement_GetText(This->nsbody, &text);
460     if(NS_SUCCEEDED(nsres)) {
461         const PRUnichar *color;
462
463         nsAString_GetData(&text, &color);
464         V_VT(p) = VT_BSTR;
465         hres = nscolor_to_str(color, &V_BSTR(p));
466     }else {
467         ERR("GetText failed: %08x\n", nsres);
468         hres = E_FAIL;
469     }
470
471     nsAString_Finish(&text);
472
473     return hres;
474 }
475
476 static HRESULT WINAPI HTMLBodyElement_put_link(IHTMLBodyElement *iface, VARIANT v)
477 {
478     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
479     nsAString link_str;
480     nsresult nsres;
481
482     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
483
484     if(!variant_to_nscolor(&v, &link_str))
485         return S_OK;
486
487     nsres = nsIDOMHTMLBodyElement_SetLink(This->nsbody, &link_str);
488     nsAString_Finish(&link_str);
489     if(NS_FAILED(nsres))
490         ERR("SetLink failed: %08x\n", nsres);
491
492     return S_OK;
493 }
494
495 static HRESULT WINAPI HTMLBodyElement_get_link(IHTMLBodyElement *iface, VARIANT *p)
496 {
497     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
498     nsAString link_str;
499     nsresult nsres;
500
501     TRACE("(%p)->(%p)\n", This, p);
502
503     nsAString_Init(&link_str, NULL);
504     nsres = nsIDOMHTMLBodyElement_GetLink(This->nsbody, &link_str);
505     if(NS_FAILED(nsres))
506         ERR("GetLink failed: %08x\n", nsres);
507
508     nscolor_to_variant(&link_str, p);
509     nsAString_Finish(&link_str);
510
511     return S_OK;
512 }
513
514 static HRESULT WINAPI HTMLBodyElement_put_vLink(IHTMLBodyElement *iface, VARIANT v)
515 {
516     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
517     nsAString vlink_str;
518     nsresult nsres;
519
520     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
521
522     if(!variant_to_nscolor(&v, &vlink_str))
523         return S_OK;
524
525     nsres = nsIDOMHTMLBodyElement_SetVLink(This->nsbody, &vlink_str);
526     nsAString_Finish(&vlink_str);
527     if(NS_FAILED(nsres))
528         ERR("SetLink failed: %08x\n", nsres);
529
530     return S_OK;
531 }
532
533 static HRESULT WINAPI HTMLBodyElement_get_vLink(IHTMLBodyElement *iface, VARIANT *p)
534 {
535     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
536     nsAString vlink_str;
537     nsresult nsres;
538
539     TRACE("(%p)->(%p)\n", This, p);
540
541     nsAString_Init(&vlink_str, NULL);
542     nsres = nsIDOMHTMLBodyElement_GetVLink(This->nsbody, &vlink_str);
543     if(NS_FAILED(nsres))
544         ERR("GetLink failed: %08x\n", nsres);
545
546     nscolor_to_variant(&vlink_str, p);
547     nsAString_Finish(&vlink_str);
548
549     return S_OK;
550 }
551
552 static HRESULT WINAPI HTMLBodyElement_put_aLink(IHTMLBodyElement *iface, VARIANT v)
553 {
554     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
555     nsAString alink_str;
556     nsresult nsres;
557
558     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
559
560     if(!variant_to_nscolor(&v, &alink_str))
561         return S_OK;
562
563     nsres = nsIDOMHTMLBodyElement_SetALink(This->nsbody, &alink_str);
564     nsAString_Finish(&alink_str);
565     if(NS_FAILED(nsres))
566         ERR("SetALink failed: %08x\n", nsres);
567
568     return S_OK;
569 }
570
571 static HRESULT WINAPI HTMLBodyElement_get_aLink(IHTMLBodyElement *iface, VARIANT *p)
572 {
573     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
574     nsAString alink_str;
575     nsresult nsres;
576
577     TRACE("(%p)->(%p)\n", This, p);
578
579     nsAString_Init(&alink_str, NULL);
580     nsres = nsIDOMHTMLBodyElement_GetALink(This->nsbody, &alink_str);
581     if(NS_FAILED(nsres))
582         ERR("GetALink failed: %08x\n", nsres);
583
584     nscolor_to_variant(&alink_str, p);
585     nsAString_Finish(&alink_str);
586
587     return S_OK;
588 }
589
590 static HRESULT WINAPI HTMLBodyElement_put_onload(IHTMLBodyElement *iface, VARIANT v)
591 {
592     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
593     FIXME("(%p)->()\n", This);
594     return E_NOTIMPL;
595 }
596
597 static HRESULT WINAPI HTMLBodyElement_get_onload(IHTMLBodyElement *iface, VARIANT *p)
598 {
599     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
600     FIXME("(%p)->(%p)\n", This, p);
601     return E_NOTIMPL;
602 }
603
604 static HRESULT WINAPI HTMLBodyElement_put_onunload(IHTMLBodyElement *iface, VARIANT v)
605 {
606     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
607     FIXME("(%p)->()\n", This);
608     return E_NOTIMPL;
609 }
610
611 static HRESULT WINAPI HTMLBodyElement_get_onunload(IHTMLBodyElement *iface, VARIANT *p)
612 {
613     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
614     FIXME("(%p)->(%p)\n", This, p);
615     return E_NOTIMPL;
616 }
617
618 static HRESULT WINAPI HTMLBodyElement_put_scroll(IHTMLBodyElement *iface, BSTR v)
619 {
620     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
621     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
622     return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI HTMLBodyElement_get_scroll(IHTMLBodyElement *iface, BSTR *p)
626 {
627     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
628     FIXME("(%p)->(%p)\n", This, p);
629     return E_NOTIMPL;
630 }
631
632 static HRESULT WINAPI HTMLBodyElement_put_onselect(IHTMLBodyElement *iface, VARIANT v)
633 {
634     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
635     FIXME("(%p)->()\n", This);
636     return E_NOTIMPL;
637 }
638
639 static HRESULT WINAPI HTMLBodyElement_get_onselect(IHTMLBodyElement *iface, VARIANT *p)
640 {
641     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
642     FIXME("(%p)->(%p)\n", This, p);
643     return E_NOTIMPL;
644 }
645
646 static HRESULT WINAPI HTMLBodyElement_put_onbeforeunload(IHTMLBodyElement *iface, VARIANT v)
647 {
648     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
649     FIXME("(%p)->()\n", This);
650     return E_NOTIMPL;
651 }
652
653 static HRESULT WINAPI HTMLBodyElement_get_onbeforeunload(IHTMLBodyElement *iface, VARIANT *p)
654 {
655     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
656     FIXME("(%p)->(%p)\n", This, p);
657     return E_NOTIMPL;
658 }
659
660 static HRESULT WINAPI HTMLBodyElement_createTextRange(IHTMLBodyElement *iface, IHTMLTxtRange **range)
661 {
662     HTMLBodyElement *This = impl_from_IHTMLBodyElement(iface);
663     nsIDOMRange *nsrange = NULL;
664     nsresult nsres;
665     HRESULT hres;
666
667     TRACE("(%p)->(%p)\n", This, range);
668
669     if(!This->textcont.element.node.doc->nsdoc) {
670         WARN("No nsdoc\n");
671         return E_UNEXPECTED;
672     }
673
674     nsres = nsIDOMHTMLDocument_CreateRange(This->textcont.element.node.doc->nsdoc, &nsrange);
675     if(NS_SUCCEEDED(nsres)) {
676         nsres = nsIDOMRange_SelectNodeContents(nsrange, This->textcont.element.node.nsnode);
677         if(NS_FAILED(nsres))
678             ERR("SelectNodeContents failed: %08x\n", nsres);
679     }else {
680         ERR("CreateRange failed: %08x\n", nsres);
681     }
682
683     hres = HTMLTxtRange_Create(This->textcont.element.node.doc->basedoc.doc_node, nsrange, range);
684
685     nsIDOMRange_Release(nsrange);
686     return hres;
687 }
688
689 static const IHTMLBodyElementVtbl HTMLBodyElementVtbl = {
690     HTMLBodyElement_QueryInterface,
691     HTMLBodyElement_AddRef,
692     HTMLBodyElement_Release,
693     HTMLBodyElement_GetTypeInfoCount,
694     HTMLBodyElement_GetTypeInfo,
695     HTMLBodyElement_GetIDsOfNames,
696     HTMLBodyElement_Invoke,
697     HTMLBodyElement_put_background,
698     HTMLBodyElement_get_background,
699     HTMLBodyElement_put_bgProperties,
700     HTMLBodyElement_get_bgProperties,
701     HTMLBodyElement_put_leftMargin,
702     HTMLBodyElement_get_leftMargin,
703     HTMLBodyElement_put_topMargin,
704     HTMLBodyElement_get_topMargin,
705     HTMLBodyElement_put_rightMargin,
706     HTMLBodyElement_get_rightMargin,
707     HTMLBodyElement_put_bottomMargin,
708     HTMLBodyElement_get_bottomMargin,
709     HTMLBodyElement_put_noWrap,
710     HTMLBodyElement_get_noWrap,
711     HTMLBodyElement_put_bgColor,
712     HTMLBodyElement_get_bgColor,
713     HTMLBodyElement_put_text,
714     HTMLBodyElement_get_text,
715     HTMLBodyElement_put_link,
716     HTMLBodyElement_get_link,
717     HTMLBodyElement_put_vLink,
718     HTMLBodyElement_get_vLink,
719     HTMLBodyElement_put_aLink,
720     HTMLBodyElement_get_aLink,
721     HTMLBodyElement_put_onload,
722     HTMLBodyElement_get_onload,
723     HTMLBodyElement_put_onunload,
724     HTMLBodyElement_get_onunload,
725     HTMLBodyElement_put_scroll,
726     HTMLBodyElement_get_scroll,
727     HTMLBodyElement_put_onselect,
728     HTMLBodyElement_get_onselect,
729     HTMLBodyElement_put_onbeforeunload,
730     HTMLBodyElement_get_onbeforeunload,
731     HTMLBodyElement_createTextRange
732 };
733
734 static inline HTMLBodyElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
735 {
736     return CONTAINING_RECORD(iface, HTMLBodyElement, textcont.element.node);
737 }
738
739 static HRESULT HTMLBodyElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
740 {
741     HTMLBodyElement *This = impl_from_HTMLDOMNode(iface);
742
743     *ppv = NULL;
744
745     if(IsEqualGUID(&IID_IUnknown, riid)) {
746         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
747         *ppv = &This->IHTMLBodyElement_iface;
748     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
749         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
750         *ppv = &This->IHTMLBodyElement_iface;
751     }else if(IsEqualGUID(&IID_IHTMLBodyElement, riid)) {
752         TRACE("(%p)->(IID_IHTMLBodyElement %p)\n", This, ppv);
753         *ppv = &This->IHTMLBodyElement_iface;
754     }else if(IsEqualGUID(&IID_IHTMLTextContainer, riid)) {
755         TRACE("(%p)->(IID_IHTMLTextContainer %p)\n", &This->textcont, ppv);
756         *ppv = &This->textcont.IHTMLTextContainer_iface;
757     }
758
759     if(*ppv) {
760         IUnknown_AddRef((IUnknown*)*ppv);
761         return S_OK;
762     }
763
764     return HTMLElement_QI(&This->textcont.element.node, riid, ppv);
765 }
766
767 static void HTMLBodyElement_destructor(HTMLDOMNode *iface)
768 {
769     HTMLBodyElement *This = impl_from_HTMLDOMNode(iface);
770
771     nsIDOMHTMLBodyElement_Release(This->nsbody);
772
773     HTMLElement_destructor(&This->textcont.element.node);
774 }
775
776 static event_target_t **HTMLBodyElement_get_event_target(HTMLDOMNode *iface)
777 {
778     HTMLBodyElement *This = impl_from_HTMLDOMNode(iface);
779
780     return This->textcont.element.node.doc
781         ? &This->textcont.element.node.doc->body_event_target
782         : &This->textcont.element.node.event_target;
783 }
784
785 static const NodeImplVtbl HTMLBodyElementImplVtbl = {
786     HTMLBodyElement_QI,
787     HTMLBodyElement_destructor,
788     HTMLElement_clone,
789     HTMLElement_get_attr_col,
790     HTMLBodyElement_get_event_target
791 };
792
793 static const tid_t HTMLBodyElement_iface_tids[] = {
794     IHTMLBodyElement_tid,
795     IHTMLBodyElement2_tid,
796     HTMLELEMENT_TIDS,
797     IHTMLTextContainer_tid,
798     IHTMLUniqueName_tid,
799     0
800 };
801
802 static dispex_static_data_t HTMLBodyElement_dispex = {
803     NULL,
804     DispHTMLBody_tid,
805     NULL,
806     HTMLBodyElement_iface_tids
807 };
808
809 HRESULT HTMLBodyElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, HTMLElement **elem)
810 {
811     HTMLBodyElement *ret;
812     nsresult nsres;
813
814     ret = heap_alloc_zero(sizeof(HTMLBodyElement));
815     if(!ret)
816         return E_OUTOFMEMORY;
817
818     ret->IHTMLBodyElement_iface.lpVtbl = &HTMLBodyElementVtbl;
819     ret->textcont.element.node.vtbl = &HTMLBodyElementImplVtbl;
820
821     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLBodyElement, (void**)&ret->nsbody);
822     if(NS_FAILED(nsres)) {
823         ERR("Could not get nsDOMHTMLBodyElement: %08x\n", nsres);
824         heap_free(ret);
825         return E_OUTOFMEMORY;
826     }
827
828     HTMLTextContainer_Init(&ret->textcont, doc, nselem, &HTMLBodyElement_dispex);
829
830     ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink, NULL);
831
832     *elem = &ret->textcont.element;
833     return S_OK;
834 }