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