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