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