wbemprox: Support overriding the CIM to VARIANT type mapping for method parameters.
[wine] / dlls / mshtml / htmlelem.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 <assert.h>
21
22 #define COBJMACROS
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "ole2.h"
29 #include "shlwapi.h"
30
31 #include "wine/debug.h"
32
33 #include "mshtml_private.h"
34 #include "htmlevent.h"
35 #include "htmlstyle.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
38
39 static const WCHAR aW[]        = {'A',0};
40 static const WCHAR bodyW[]     = {'B','O','D','Y',0};
41 static const WCHAR embedW[]    = {'E','M','B','E','D',0};
42 static const WCHAR formW[]     = {'F','O','R','M',0};
43 static const WCHAR frameW[]    = {'F','R','A','M','E',0};
44 static const WCHAR headW[]     = {'H','E','A','D',0};
45 static const WCHAR iframeW[]   = {'I','F','R','A','M','E',0};
46 static const WCHAR imgW[]      = {'I','M','G',0};
47 static const WCHAR inputW[]    = {'I','N','P','U','T',0};
48 static const WCHAR metaW[]     = {'M','E','T','A',0};
49 static const WCHAR objectW[]   = {'O','B','J','E','C','T',0};
50 static const WCHAR optionW[]   = {'O','P','T','I','O','N',0};
51 static const WCHAR scriptW[]   = {'S','C','R','I','P','T',0};
52 static const WCHAR selectW[]   = {'S','E','L','E','C','T',0};
53 static const WCHAR styleW[]    = {'S','T','Y','L','E',0};
54 static const WCHAR tableW[]    = {'T','A','B','L','E',0};
55 static const WCHAR tdW[]       = {'T','D',0};
56 static const WCHAR textareaW[] = {'T','E','X','T','A','R','E','A',0};
57 static const WCHAR title_tagW[]= {'T','I','T','L','E',0};
58 static const WCHAR trW[]       = {'T','R',0};
59
60 typedef struct {
61     const WCHAR *name;
62     HRESULT (*constructor)(HTMLDocumentNode*,nsIDOMHTMLElement*,HTMLElement**);
63 } tag_desc_t;
64
65 static const tag_desc_t tag_descs[] = {
66     {aW,         HTMLAnchorElement_Create},
67     {bodyW,      HTMLBodyElement_Create},
68     {embedW,     HTMLEmbedElement_Create},
69     {formW,      HTMLFormElement_Create},
70     {frameW,     HTMLFrameElement_Create},
71     {headW,      HTMLHeadElement_Create},
72     {iframeW,    HTMLIFrame_Create},
73     {imgW,       HTMLImgElement_Create},
74     {inputW,     HTMLInputElement_Create},
75     {metaW,      HTMLMetaElement_Create},
76     {objectW,    HTMLObjectElement_Create},
77     {optionW,    HTMLOptionElement_Create},
78     {scriptW,    HTMLScriptElement_Create},
79     {selectW,    HTMLSelectElement_Create},
80     {styleW,     HTMLStyleElement_Create},
81     {tableW,     HTMLTable_Create},
82     {tdW,        HTMLTableCell_Create},
83     {textareaW,  HTMLTextAreaElement_Create},
84     {title_tagW, HTMLTitleElement_Create},
85     {trW,        HTMLTableRow_Create}
86 };
87
88 static const tag_desc_t *get_tag_desc(const WCHAR *tag_name)
89 {
90     DWORD min=0, max=sizeof(tag_descs)/sizeof(*tag_descs)-1, i;
91     int r;
92
93     while(min <= max) {
94         i = (min+max)/2;
95         r = strcmpW(tag_name, tag_descs[i].name);
96         if(!r)
97             return tag_descs+i;
98
99         if(r < 0)
100             max = i-1;
101         else
102             min = i+1;
103     }
104
105     return NULL;
106 }
107
108 HRESULT replace_node_by_html(nsIDOMHTMLDocument *nsdoc, nsIDOMNode *nsnode, const WCHAR *html)
109 {
110     nsIDOMDocumentFragment *nsfragment;
111     nsIDOMNode *nsparent;
112     nsIDOMRange *range;
113     nsAString html_str;
114     nsresult nsres;
115     HRESULT hres = S_OK;
116
117     nsres = nsIDOMHTMLDocument_CreateRange(nsdoc, &range);
118     if(NS_FAILED(nsres)) {
119         ERR("CreateRange failed: %08x\n", nsres);
120         return E_FAIL;
121     }
122
123     nsAString_InitDepend(&html_str, html);
124     nsIDOMRange_CreateContextualFragment(range, &html_str, &nsfragment);
125     nsIDOMRange_Release(range);
126     nsAString_Finish(&html_str);
127     if(NS_FAILED(nsres)) {
128         ERR("CreateContextualFragment failed: %08x\n", nsres);
129         return E_FAIL;
130     }
131
132     nsres = nsIDOMNode_GetParentNode(nsnode, &nsparent);
133     if(NS_SUCCEEDED(nsres) && nsparent) {
134         nsIDOMNode *nstmp;
135
136         nsres = nsIDOMNode_ReplaceChild(nsparent, (nsIDOMNode*)nsfragment, nsnode, &nstmp);
137         nsIDOMNode_Release(nsparent);
138         if(NS_FAILED(nsres)) {
139             ERR("ReplaceChild failed: %08x\n", nsres);
140             hres = E_FAIL;
141         }else if(nstmp) {
142             nsIDOMNode_Release(nstmp);
143         }
144     }else {
145         ERR("GetParentNode failed: %08x\n", nsres);
146         hres = E_FAIL;
147     }
148
149     nsIDOMDocumentFragment_Release(nsfragment);
150     return hres;
151 }
152
153 typedef struct
154 {
155     DispatchEx dispex;
156     IHTMLFiltersCollection IHTMLFiltersCollection_iface;
157
158     LONG ref;
159 } HTMLFiltersCollection;
160
161 static inline HTMLFiltersCollection *impl_from_IHTMLFiltersCollection(IHTMLFiltersCollection *iface)
162 {
163     return CONTAINING_RECORD(iface, HTMLFiltersCollection, IHTMLFiltersCollection_iface);
164 }
165
166 static IHTMLFiltersCollection *HTMLFiltersCollection_Create(void);
167
168 static inline HTMLElement *impl_from_IHTMLElement(IHTMLElement *iface)
169 {
170     return CONTAINING_RECORD(iface, HTMLElement, IHTMLElement_iface);
171 }
172
173 HRESULT create_nselem(HTMLDocumentNode *doc, const WCHAR *tag, nsIDOMHTMLElement **ret)
174 {
175     nsIDOMElement *nselem;
176     nsAString tag_str;
177     nsresult nsres;
178
179     if(!doc->nsdoc) {
180         WARN("NULL nsdoc\n");
181         return E_UNEXPECTED;
182     }
183
184     nsAString_InitDepend(&tag_str, tag);
185     nsres = nsIDOMHTMLDocument_CreateElement(doc->nsdoc, &tag_str, &nselem);
186     nsAString_Finish(&tag_str);
187     if(NS_FAILED(nsres)) {
188         ERR("CreateElement failed: %08x\n", nsres);
189         return E_FAIL;
190     }
191
192     nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMHTMLElement, (void**)ret);
193     nsIDOMElement_Release(nselem);
194     if(NS_FAILED(nsres)) {
195         ERR("Could not get nsIDOMHTMLElement iface: %08x\n", nsres);
196         return E_FAIL;
197     }
198
199     return S_OK;
200 }
201
202 HRESULT create_element(HTMLDocumentNode *doc, const WCHAR *tag, HTMLElement **ret)
203 {
204     nsIDOMHTMLElement *nselem;
205     HRESULT hres;
206
207     /* Use owner doc if called on document fragment */
208     if(!doc->nsdoc)
209         doc = doc->node.doc;
210
211     hres = create_nselem(doc, tag, &nselem);
212     if(FAILED(hres))
213         return hres;
214
215     hres = HTMLElement_Create(doc, (nsIDOMNode*)nselem, TRUE, ret);
216     nsIDOMHTMLElement_Release(nselem);
217     return hres;
218 }
219
220 static HRESULT WINAPI HTMLElement_QueryInterface(IHTMLElement *iface,
221                                                  REFIID riid, void **ppv)
222 {
223     HTMLElement *This = impl_from_IHTMLElement(iface);
224
225     return IHTMLDOMNode_QueryInterface(&This->node.IHTMLDOMNode_iface, riid, ppv);
226 }
227
228 static ULONG WINAPI HTMLElement_AddRef(IHTMLElement *iface)
229 {
230     HTMLElement *This = impl_from_IHTMLElement(iface);
231
232     return IHTMLDOMNode_AddRef(&This->node.IHTMLDOMNode_iface);
233 }
234
235 static ULONG WINAPI HTMLElement_Release(IHTMLElement *iface)
236 {
237     HTMLElement *This = impl_from_IHTMLElement(iface);
238
239     return IHTMLDOMNode_Release(&This->node.IHTMLDOMNode_iface);
240 }
241
242 static HRESULT WINAPI HTMLElement_GetTypeInfoCount(IHTMLElement *iface, UINT *pctinfo)
243 {
244     HTMLElement *This = impl_from_IHTMLElement(iface);
245     return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
246 }
247
248 static HRESULT WINAPI HTMLElement_GetTypeInfo(IHTMLElement *iface, UINT iTInfo,
249                                               LCID lcid, ITypeInfo **ppTInfo)
250 {
251     HTMLElement *This = impl_from_IHTMLElement(iface);
252     return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
253 }
254
255 static HRESULT WINAPI HTMLElement_GetIDsOfNames(IHTMLElement *iface, REFIID riid,
256                                                 LPOLESTR *rgszNames, UINT cNames,
257                                                 LCID lcid, DISPID *rgDispId)
258 {
259     HTMLElement *This = impl_from_IHTMLElement(iface);
260     return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface, riid, rgszNames, cNames,
261             lcid, rgDispId);
262 }
263
264 static HRESULT WINAPI HTMLElement_Invoke(IHTMLElement *iface, DISPID dispIdMember,
265                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
266                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
267 {
268     HTMLElement *This = impl_from_IHTMLElement(iface);
269     return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
270             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
271 }
272
273 static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttributeName,
274                                                VARIANT AttributeValue, LONG lFlags)
275 {
276     HTMLElement *This = impl_from_IHTMLElement(iface);
277     HRESULT hres;
278     DISPID dispid, dispidNamed = DISPID_PROPERTYPUT;
279     DISPPARAMS dispParams;
280     EXCEPINFO excep;
281
282     TRACE("(%p)->(%s %s %08x)\n", This, debugstr_w(strAttributeName), debugstr_variant(&AttributeValue), lFlags);
283
284     hres = IDispatchEx_GetDispID(&This->node.dispex.IDispatchEx_iface, strAttributeName,
285             fdexNameCaseInsensitive | fdexNameEnsure, &dispid);
286     if(FAILED(hres))
287         return hres;
288
289     dispParams.cArgs = 1;
290     dispParams.cNamedArgs = 1;
291     dispParams.rgdispidNamedArgs = &dispidNamed;
292     dispParams.rgvarg = &AttributeValue;
293
294     hres = IDispatchEx_InvokeEx(&This->node.dispex.IDispatchEx_iface, dispid,
295             LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &dispParams, NULL, &excep, NULL);
296     return hres;
297 }
298
299 static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttributeName,
300                                                LONG lFlags, VARIANT *AttributeValue)
301 {
302     HTMLElement *This = impl_from_IHTMLElement(iface);
303     DISPID dispid;
304     HRESULT hres;
305     DISPPARAMS dispParams = {NULL, NULL, 0, 0};
306     EXCEPINFO excep;
307
308     TRACE("(%p)->(%s %08x %p)\n", This, debugstr_w(strAttributeName), lFlags, AttributeValue);
309
310     hres = IDispatchEx_GetDispID(&This->node.dispex.IDispatchEx_iface, strAttributeName,
311             fdexNameCaseInsensitive, &dispid);
312     if(hres == DISP_E_UNKNOWNNAME) {
313         V_VT(AttributeValue) = VT_NULL;
314         return S_OK;
315     }
316
317     if(FAILED(hres)) {
318         V_VT(AttributeValue) = VT_NULL;
319         return hres;
320     }
321
322     hres = IDispatchEx_InvokeEx(&This->node.dispex.IDispatchEx_iface, dispid, LOCALE_SYSTEM_DEFAULT,
323             DISPATCH_PROPERTYGET, &dispParams, AttributeValue, &excep, NULL);
324
325     return hres;
326 }
327
328 static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strAttributeName,
329                                                   LONG lFlags, VARIANT_BOOL *pfSuccess)
330 {
331     HTMLElement *This = impl_from_IHTMLElement(iface);
332
333     TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(strAttributeName), lFlags, pfSuccess);
334
335     return remove_prop(&This->node.dispex, strAttributeName, pfSuccess);
336 }
337
338 static HRESULT WINAPI HTMLElement_put_className(IHTMLElement *iface, BSTR v)
339 {
340     HTMLElement *This = impl_from_IHTMLElement(iface);
341     nsAString classname_str;
342     nsresult nsres;
343
344     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
345
346     if(!This->nselem) {
347         FIXME("NULL nselem\n");
348         return E_NOTIMPL;
349     }
350
351     nsAString_InitDepend(&classname_str, v);
352     nsres = nsIDOMHTMLElement_SetClassName(This->nselem, &classname_str);
353     nsAString_Finish(&classname_str);
354     if(NS_FAILED(nsres))
355         ERR("SetClassName failed: %08x\n", nsres);
356
357     return S_OK;
358 }
359
360 static HRESULT WINAPI HTMLElement_get_className(IHTMLElement *iface, BSTR *p)
361 {
362     HTMLElement *This = impl_from_IHTMLElement(iface);
363     nsAString class_str;
364     nsresult nsres;
365
366     TRACE("(%p)->(%p)\n", This, p);
367
368     if(!This->nselem) {
369         FIXME("NULL nselem\n");
370         return E_NOTIMPL;
371     }
372
373     nsAString_Init(&class_str, NULL);
374     nsres = nsIDOMHTMLElement_GetClassName(This->nselem, &class_str);
375     return return_nsstr(nsres, &class_str, p);
376 }
377
378 static HRESULT WINAPI HTMLElement_put_id(IHTMLElement *iface, BSTR v)
379 {
380     HTMLElement *This = impl_from_IHTMLElement(iface);
381     nsAString id_str;
382     nsresult nsres;
383
384     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
385
386     if(!This->nselem) {
387         FIXME("nselem == NULL\n");
388         return S_OK;
389     }
390
391     nsAString_InitDepend(&id_str, v);
392     nsres = nsIDOMHTMLElement_SetId(This->nselem, &id_str);
393     nsAString_Finish(&id_str);
394     if(NS_FAILED(nsres))
395         ERR("SetId failed: %08x\n", nsres);
396
397     return S_OK;
398 }
399
400 static HRESULT WINAPI HTMLElement_get_id(IHTMLElement *iface, BSTR *p)
401 {
402     HTMLElement *This = impl_from_IHTMLElement(iface);
403     nsAString id_str;
404     nsresult nsres;
405
406     TRACE("(%p)->(%p)\n", This, p);
407
408     if(!This->nselem) {
409         *p = NULL;
410         return S_OK;
411     }
412
413     nsAString_Init(&id_str, NULL);
414     nsres = nsIDOMHTMLElement_GetId(This->nselem, &id_str);
415     return return_nsstr(nsres, &id_str, p);
416 }
417
418 static HRESULT WINAPI HTMLElement_get_tagName(IHTMLElement *iface, BSTR *p)
419 {
420     HTMLElement *This = impl_from_IHTMLElement(iface);
421     nsAString tag_str;
422     nsresult nsres;
423
424     TRACE("(%p)->(%p)\n", This, p);
425
426     if(!This->nselem) {
427         static const WCHAR comment_tagW[] = {'!',0};
428
429         WARN("NULL nselem, assuming comment\n");
430
431         *p = SysAllocString(comment_tagW);
432         return *p ? S_OK : E_OUTOFMEMORY;
433     }
434
435     nsAString_Init(&tag_str, NULL);
436     nsres = nsIDOMHTMLElement_GetTagName(This->nselem, &tag_str);
437     return return_nsstr(nsres, &tag_str, p);
438 }
439
440 static HRESULT WINAPI HTMLElement_get_parentElement(IHTMLElement *iface, IHTMLElement **p)
441 {
442     HTMLElement *This = impl_from_IHTMLElement(iface);
443     IHTMLDOMNode *node;
444     HRESULT hres;
445
446     TRACE("(%p)->(%p)\n", This, p);
447
448     hres = IHTMLDOMNode_get_parentNode(&This->node.IHTMLDOMNode_iface, &node);
449     if(FAILED(hres))
450         return hres;
451
452     hres = IHTMLDOMNode_QueryInterface(node, &IID_IHTMLElement, (void**)p);
453     IHTMLDOMNode_Release(node);
454     if(FAILED(hres))
455         *p = NULL;
456
457     return S_OK;
458 }
459
460 static HRESULT WINAPI HTMLElement_get_style(IHTMLElement *iface, IHTMLStyle **p)
461 {
462     HTMLElement *This = impl_from_IHTMLElement(iface);
463
464     TRACE("(%p)->(%p)\n", This, p);
465
466     if(!This->style) {
467         HRESULT hres;
468
469         hres = HTMLStyle_Create(This, &This->style);
470         if(FAILED(hres))
471             return hres;
472     }
473
474     *p = &This->style->IHTMLStyle_iface;
475     IHTMLStyle_AddRef(*p);
476     return S_OK;
477 }
478
479 static HRESULT WINAPI HTMLElement_put_onhelp(IHTMLElement *iface, VARIANT v)
480 {
481     HTMLElement *This = impl_from_IHTMLElement(iface);
482     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
483     return E_NOTIMPL;
484 }
485
486 static HRESULT WINAPI HTMLElement_get_onhelp(IHTMLElement *iface, VARIANT *p)
487 {
488     HTMLElement *This = impl_from_IHTMLElement(iface);
489     FIXME("(%p)->(%p)\n", This, p);
490     return E_NOTIMPL;
491 }
492
493 static HRESULT WINAPI HTMLElement_put_onclick(IHTMLElement *iface, VARIANT v)
494 {
495     HTMLElement *This = impl_from_IHTMLElement(iface);
496
497     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
498
499     return set_node_event(&This->node, EVENTID_CLICK, &v);
500 }
501
502 static HRESULT WINAPI HTMLElement_get_onclick(IHTMLElement *iface, VARIANT *p)
503 {
504     HTMLElement *This = impl_from_IHTMLElement(iface);
505
506     TRACE("(%p)->(%p)\n", This, p);
507
508     return get_node_event(&This->node, EVENTID_CLICK, p);
509 }
510
511 static HRESULT WINAPI HTMLElement_put_ondblclick(IHTMLElement *iface, VARIANT v)
512 {
513     HTMLElement *This = impl_from_IHTMLElement(iface);
514
515     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
516
517     return set_node_event(&This->node, EVENTID_DBLCLICK, &v);
518 }
519
520 static HRESULT WINAPI HTMLElement_get_ondblclick(IHTMLElement *iface, VARIANT *p)
521 {
522     HTMLElement *This = impl_from_IHTMLElement(iface);
523
524     TRACE("(%p)->(%p)\n", This, p);
525
526     return get_node_event(&This->node, EVENTID_DBLCLICK, p);
527 }
528
529 static HRESULT WINAPI HTMLElement_put_onkeydown(IHTMLElement *iface, VARIANT v)
530 {
531     HTMLElement *This = impl_from_IHTMLElement(iface);
532
533     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
534
535     return set_node_event(&This->node, EVENTID_KEYDOWN, &v);
536 }
537
538 static HRESULT WINAPI HTMLElement_get_onkeydown(IHTMLElement *iface, VARIANT *p)
539 {
540     HTMLElement *This = impl_from_IHTMLElement(iface);
541
542     TRACE("(%p)->(%p)\n", This, p);
543
544     return get_node_event(&This->node, EVENTID_KEYDOWN, p);
545 }
546
547 static HRESULT WINAPI HTMLElement_put_onkeyup(IHTMLElement *iface, VARIANT v)
548 {
549     HTMLElement *This = impl_from_IHTMLElement(iface);
550
551     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
552
553     return set_node_event(&This->node, EVENTID_KEYUP, &v);
554 }
555
556 static HRESULT WINAPI HTMLElement_get_onkeyup(IHTMLElement *iface, VARIANT *p)
557 {
558     HTMLElement *This = impl_from_IHTMLElement(iface);
559     FIXME("(%p)->(%p)\n", This, p);
560     return E_NOTIMPL;
561 }
562
563 static HRESULT WINAPI HTMLElement_put_onkeypress(IHTMLElement *iface, VARIANT v)
564 {
565     HTMLElement *This = impl_from_IHTMLElement(iface);
566
567     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
568
569     return set_node_event(&This->node, EVENTID_KEYPRESS, &v);
570 }
571
572 static HRESULT WINAPI HTMLElement_get_onkeypress(IHTMLElement *iface, VARIANT *p)
573 {
574     HTMLElement *This = impl_from_IHTMLElement(iface);
575
576     TRACE("(%p)->(%p)\n", This, p);
577
578     return get_node_event(&This->node, EVENTID_KEYPRESS, p);
579 }
580
581 static HRESULT WINAPI HTMLElement_put_onmouseout(IHTMLElement *iface, VARIANT v)
582 {
583     HTMLElement *This = impl_from_IHTMLElement(iface);
584
585     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
586
587     return set_node_event(&This->node, EVENTID_MOUSEOUT, &v);
588 }
589
590 static HRESULT WINAPI HTMLElement_get_onmouseout(IHTMLElement *iface, VARIANT *p)
591 {
592     HTMLElement *This = impl_from_IHTMLElement(iface);
593
594     TRACE("(%p)->(%p)\n", This, p);
595
596     return get_node_event(&This->node, EVENTID_MOUSEOUT, p);
597 }
598
599 static HRESULT WINAPI HTMLElement_put_onmouseover(IHTMLElement *iface, VARIANT v)
600 {
601     HTMLElement *This = impl_from_IHTMLElement(iface);
602
603     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
604
605     return set_node_event(&This->node, EVENTID_MOUSEOVER, &v);
606 }
607
608 static HRESULT WINAPI HTMLElement_get_onmouseover(IHTMLElement *iface, VARIANT *p)
609 {
610     HTMLElement *This = impl_from_IHTMLElement(iface);
611
612     TRACE("(%p)->(%p)\n", This, p);
613
614     return get_node_event(&This->node, EVENTID_MOUSEOVER, p);
615 }
616
617 static HRESULT WINAPI HTMLElement_put_onmousemove(IHTMLElement *iface, VARIANT v)
618 {
619     HTMLElement *This = impl_from_IHTMLElement(iface);
620
621     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
622
623     return set_node_event(&This->node, EVENTID_MOUSEMOVE, &v);
624 }
625
626 static HRESULT WINAPI HTMLElement_get_onmousemove(IHTMLElement *iface, VARIANT *p)
627 {
628     HTMLElement *This = impl_from_IHTMLElement(iface);
629
630     TRACE("(%p)->(%p)\n", This, p);
631
632     return get_node_event(&This->node, EVENTID_MOUSEMOVE, p);
633 }
634
635 static HRESULT WINAPI HTMLElement_put_onmousedown(IHTMLElement *iface, VARIANT v)
636 {
637     HTMLElement *This = impl_from_IHTMLElement(iface);
638
639     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
640
641     return set_node_event(&This->node, EVENTID_MOUSEDOWN, &v);
642 }
643
644 static HRESULT WINAPI HTMLElement_get_onmousedown(IHTMLElement *iface, VARIANT *p)
645 {
646     HTMLElement *This = impl_from_IHTMLElement(iface);
647
648     TRACE("(%p)->(%p)\n", This, p);
649
650     return get_node_event(&This->node, EVENTID_MOUSEDOWN, p);
651 }
652
653 static HRESULT WINAPI HTMLElement_put_onmouseup(IHTMLElement *iface, VARIANT v)
654 {
655     HTMLElement *This = impl_from_IHTMLElement(iface);
656
657     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
658
659     return set_node_event(&This->node, EVENTID_MOUSEUP, &v);
660 }
661
662 static HRESULT WINAPI HTMLElement_get_onmouseup(IHTMLElement *iface, VARIANT *p)
663 {
664     HTMLElement *This = impl_from_IHTMLElement(iface);
665
666     TRACE("(%p)->(%p)\n", This, p);
667
668     return get_node_event(&This->node, EVENTID_MOUSEUP, p);
669 }
670
671 static HRESULT WINAPI HTMLElement_get_document(IHTMLElement *iface, IDispatch **p)
672 {
673     HTMLElement *This = impl_from_IHTMLElement(iface);
674
675     TRACE("(%p)->(%p)\n", This, p);
676
677     if(!p)
678         return E_POINTER;
679
680     if(This->node.vtbl->get_document)
681         return This->node.vtbl->get_document(&This->node, p);
682
683     *p = (IDispatch*)&This->node.doc->basedoc.IHTMLDocument2_iface;
684     IDispatch_AddRef(*p);
685     return S_OK;
686 }
687
688 static const WCHAR titleW[] = {'t','i','t','l','e',0};
689
690 static HRESULT WINAPI HTMLElement_put_title(IHTMLElement *iface, BSTR v)
691 {
692     HTMLElement *This = impl_from_IHTMLElement(iface);
693     nsAString title_str;
694     nsresult nsres;
695
696     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
697
698     if(!This->nselem) {
699         VARIANT *var;
700         HRESULT hres;
701
702         hres = dispex_get_dprop_ref(&This->node.dispex, titleW, TRUE, &var);
703         if(FAILED(hres))
704             return hres;
705
706         VariantClear(var);
707         V_VT(var) = VT_BSTR;
708         V_BSTR(var) = v ? SysAllocString(v) : NULL;
709         return S_OK;
710     }
711
712     nsAString_InitDepend(&title_str, v);
713     nsres = nsIDOMHTMLElement_SetTitle(This->nselem, &title_str);
714     nsAString_Finish(&title_str);
715     if(NS_FAILED(nsres))
716         ERR("SetTitle failed: %08x\n", nsres);
717
718     return S_OK;
719 }
720
721 static HRESULT WINAPI HTMLElement_get_title(IHTMLElement *iface, BSTR *p)
722 {
723     HTMLElement *This = impl_from_IHTMLElement(iface);
724     nsAString title_str;
725     nsresult nsres;
726
727     TRACE("(%p)->(%p)\n", This, p);
728
729     if(!This->nselem) {
730         VARIANT *var;
731         HRESULT hres;
732
733         hres = dispex_get_dprop_ref(&This->node.dispex, titleW, FALSE, &var);
734         if(hres == DISP_E_UNKNOWNNAME) {
735             *p = NULL;
736         }else if(V_VT(var) != VT_BSTR) {
737             FIXME("title = %s\n", debugstr_variant(var));
738             return E_FAIL;
739         }else {
740             *p = V_BSTR(var) ? SysAllocString(V_BSTR(var)) : NULL;
741         }
742
743         return S_OK;
744     }
745
746     nsAString_Init(&title_str, NULL);
747     nsres = nsIDOMHTMLElement_GetTitle(This->nselem, &title_str);
748     return return_nsstr(nsres, &title_str, p);
749 }
750
751 static HRESULT WINAPI HTMLElement_put_language(IHTMLElement *iface, BSTR v)
752 {
753     HTMLElement *This = impl_from_IHTMLElement(iface);
754     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
755     return E_NOTIMPL;
756 }
757
758 static HRESULT WINAPI HTMLElement_get_language(IHTMLElement *iface, BSTR *p)
759 {
760     HTMLElement *This = impl_from_IHTMLElement(iface);
761     FIXME("(%p)->(%p)\n", This, p);
762     return E_NOTIMPL;
763 }
764
765 static HRESULT WINAPI HTMLElement_put_onselectstart(IHTMLElement *iface, VARIANT v)
766 {
767     HTMLElement *This = impl_from_IHTMLElement(iface);
768
769     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
770
771     return set_node_event(&This->node, EVENTID_SELECTSTART, &v);
772 }
773
774 static HRESULT WINAPI HTMLElement_get_onselectstart(IHTMLElement *iface, VARIANT *p)
775 {
776     HTMLElement *This = impl_from_IHTMLElement(iface);
777
778     TRACE("(%p)->(%p)\n", This, p);
779
780     return get_node_event(&This->node, EVENTID_SELECTSTART, p);
781 }
782
783 static HRESULT WINAPI HTMLElement_scrollIntoView(IHTMLElement *iface, VARIANT varargStart)
784 {
785     HTMLElement *This = impl_from_IHTMLElement(iface);
786     FIXME("(%p)->(%s)\n", This, debugstr_variant(&varargStart));
787     return E_NOTIMPL;
788 }
789
790 static HRESULT WINAPI HTMLElement_contains(IHTMLElement *iface, IHTMLElement *pChild,
791                                            VARIANT_BOOL *pfResult)
792 {
793     HTMLElement *This = impl_from_IHTMLElement(iface);
794     HTMLElement *child;
795     cpp_bool result;
796     nsresult nsres;
797
798     TRACE("(%p)->(%p %p)\n", This, pChild, pfResult);
799
800     child = unsafe_impl_from_IHTMLElement(pChild);
801     if(!child) {
802         ERR("not our element\n");
803         return E_FAIL;
804     }
805
806     nsres = nsIDOMNode_Contains(This->node.nsnode, child->node.nsnode, &result);
807     if(NS_FAILED(nsres)) {
808         ERR("failed\n");
809         return E_FAIL;
810     }
811
812     *pfResult = result ? VARIANT_TRUE : VARIANT_FALSE;
813     return S_OK;
814 }
815
816 static HRESULT WINAPI HTMLElement_get_sourceIndex(IHTMLElement *iface, LONG *p)
817 {
818     HTMLElement *This = impl_from_IHTMLElement(iface);
819     FIXME("(%p)->(%p)\n", This, p);
820     return E_NOTIMPL;
821 }
822
823 static HRESULT WINAPI HTMLElement_get_recordNumber(IHTMLElement *iface, VARIANT *p)
824 {
825     HTMLElement *This = impl_from_IHTMLElement(iface);
826     FIXME("(%p)->(%p)\n", This, p);
827     return E_NOTIMPL;
828 }
829
830 static HRESULT WINAPI HTMLElement_put_lang(IHTMLElement *iface, BSTR v)
831 {
832     HTMLElement *This = impl_from_IHTMLElement(iface);
833     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
834     return E_NOTIMPL;
835 }
836
837 static HRESULT WINAPI HTMLElement_get_lang(IHTMLElement *iface, BSTR *p)
838 {
839     HTMLElement *This = impl_from_IHTMLElement(iface);
840     FIXME("(%p)->(%p)\n", This, p);
841     return E_NOTIMPL;
842 }
843
844 static HRESULT WINAPI HTMLElement_get_offsetLeft(IHTMLElement *iface, LONG *p)
845 {
846     HTMLElement *This = impl_from_IHTMLElement(iface);
847     PRInt32 off_left = 0;
848     nsresult nsres;
849
850     TRACE("(%p)->(%p)\n", This, p);
851
852     nsres = nsIDOMHTMLElement_GetOffsetLeft(This->nselem, &off_left);
853     if(NS_FAILED(nsres)) {
854         ERR("GetOffsetLeft failed: %08x\n", nsres);
855         return E_FAIL;
856     }
857
858     *p = off_left;
859     return S_OK;
860 }
861
862 static HRESULT WINAPI HTMLElement_get_offsetTop(IHTMLElement *iface, LONG *p)
863 {
864     HTMLElement *This = impl_from_IHTMLElement(iface);
865     PRInt32 top = 0;
866     nsresult nsres;
867
868     TRACE("(%p)->(%p)\n", This, p);
869
870     nsres = nsIDOMHTMLElement_GetOffsetTop(This->nselem, &top);
871     if(NS_FAILED(nsres)) {
872         ERR("GetOffsetTop failed: %08x\n", nsres);
873         return E_FAIL;
874     }
875
876     *p = top;
877     return S_OK;
878 }
879
880 static HRESULT WINAPI HTMLElement_get_offsetWidth(IHTMLElement *iface, LONG *p)
881 {
882     HTMLElement *This = impl_from_IHTMLElement(iface);
883     PRInt32 offset = 0;
884     nsresult nsres;
885
886     TRACE("(%p)->(%p)\n", This, p);
887
888     nsres = nsIDOMHTMLElement_GetOffsetWidth(This->nselem, &offset);
889     if(NS_FAILED(nsres)) {
890         ERR("GetOffsetWidth failed: %08x\n", nsres);
891         return E_FAIL;
892     }
893
894     *p = offset;
895     return S_OK;
896 }
897
898 static HRESULT WINAPI HTMLElement_get_offsetHeight(IHTMLElement *iface, LONG *p)
899 {
900     HTMLElement *This = impl_from_IHTMLElement(iface);
901     PRInt32 offset = 0;
902     nsresult nsres;
903
904     TRACE("(%p)->(%p)\n", This, p);
905
906     nsres = nsIDOMHTMLElement_GetOffsetHeight(This->nselem, &offset);
907     if(NS_FAILED(nsres)) {
908         ERR("GetOffsetHeight failed: %08x\n", nsres);
909         return E_FAIL;
910     }
911
912     *p = offset;
913     return S_OK;
914 }
915
916 static HRESULT WINAPI HTMLElement_get_offsetParent(IHTMLElement *iface, IHTMLElement **p)
917 {
918     HTMLElement *This = impl_from_IHTMLElement(iface);
919     nsIDOMElement *nsparent;
920     nsresult nsres;
921     HRESULT hres;
922
923     TRACE("(%p)->(%p)\n", This, p);
924
925     nsres = nsIDOMHTMLElement_GetOffsetParent(This->nselem, &nsparent);
926     if(NS_FAILED(nsres)) {
927         ERR("GetOffsetParent failed: %08x\n", nsres);
928         return E_FAIL;
929     }
930
931     if(nsparent) {
932         HTMLDOMNode *node;
933
934         hres = get_node(This->node.doc, (nsIDOMNode*)nsparent, TRUE, &node);
935         nsIDOMElement_Release(nsparent);
936         if(FAILED(hres))
937             return hres;
938
939         hres = IHTMLDOMNode_QueryInterface(&node->IHTMLDOMNode_iface, &IID_IHTMLElement, (void**)p);
940         node_release(node);
941     }else {
942         *p = NULL;
943         hres = S_OK;
944     }
945
946     return hres;
947 }
948
949 static HRESULT WINAPI HTMLElement_put_innerHTML(IHTMLElement *iface, BSTR v)
950 {
951     HTMLElement *This = impl_from_IHTMLElement(iface);
952     nsAString html_str;
953     nsresult nsres;
954
955     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
956
957     if(!This->nselem) {
958         FIXME("NULL nselem\n");
959         return E_NOTIMPL;
960     }
961
962     nsAString_InitDepend(&html_str, v);
963     nsres = nsIDOMHTMLElement_SetInnerHTML(This->nselem, &html_str);
964     nsAString_Finish(&html_str);
965     if(NS_FAILED(nsres)) {
966         FIXME("SetInnerHtml failed %08x\n", nsres);
967         return E_FAIL;
968     }
969
970     return S_OK;
971 }
972
973 static HRESULT WINAPI HTMLElement_get_innerHTML(IHTMLElement *iface, BSTR *p)
974 {
975     HTMLElement *This = impl_from_IHTMLElement(iface);
976     nsAString html_str;
977     nsresult nsres;
978
979     TRACE("(%p)->(%p)\n", This, p);
980
981     if(!This->nselem) {
982         FIXME("NULL nselem\n");
983         return E_NOTIMPL;
984     }
985
986     nsAString_Init(&html_str, NULL);
987     nsres = nsIDOMHTMLElement_GetInnerHTML(This->nselem, &html_str);
988     return return_nsstr(nsres, &html_str, p);
989 }
990
991 static HRESULT WINAPI HTMLElement_put_innerText(IHTMLElement *iface, BSTR v)
992 {
993     HTMLElement *This = impl_from_IHTMLElement(iface);
994     nsIDOMNode *nschild, *tmp;
995     nsIDOMText *text_node;
996     nsAString text_str;
997     nsresult nsres;
998
999     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
1000
1001     while(1) {
1002         nsres = nsIDOMHTMLElement_GetLastChild(This->nselem, &nschild);
1003         if(NS_FAILED(nsres)) {
1004             ERR("GetLastChild failed: %08x\n", nsres);
1005             return E_FAIL;
1006         }
1007         if(!nschild)
1008             break;
1009
1010         nsres = nsIDOMHTMLElement_RemoveChild(This->nselem, nschild, &tmp);
1011         nsIDOMNode_Release(nschild);
1012         if(NS_FAILED(nsres)) {
1013             ERR("RemoveChild failed: %08x\n", nsres);
1014             return E_FAIL;
1015         }
1016         nsIDOMNode_Release(tmp);
1017     }
1018
1019     nsAString_InitDepend(&text_str, v);
1020     nsres = nsIDOMHTMLDocument_CreateTextNode(This->node.doc->nsdoc, &text_str, &text_node);
1021     nsAString_Finish(&text_str);
1022     if(NS_FAILED(nsres)) {
1023         ERR("CreateTextNode failed: %08x\n", nsres);
1024         return E_FAIL;
1025     }
1026
1027     nsres = nsIDOMHTMLElement_AppendChild(This->nselem, (nsIDOMNode*)text_node, &tmp);
1028     if(NS_FAILED(nsres)) {
1029         ERR("AppendChild failed: %08x\n", nsres);
1030         return E_FAIL;
1031     }
1032
1033     nsIDOMNode_Release(tmp);
1034     return S_OK;
1035 }
1036
1037 static HRESULT WINAPI HTMLElement_get_innerText(IHTMLElement *iface, BSTR *p)
1038 {
1039     HTMLElement *This = impl_from_IHTMLElement(iface);
1040
1041     TRACE("(%p)->(%p)\n", This, p);
1042
1043     return get_node_text(&This->node, p);
1044 }
1045
1046 static HRESULT WINAPI HTMLElement_put_outerHTML(IHTMLElement *iface, BSTR v)
1047 {
1048     HTMLElement *This = impl_from_IHTMLElement(iface);
1049
1050     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
1051
1052     return replace_node_by_html(This->node.doc->nsdoc, This->node.nsnode, v);
1053 }
1054
1055 static HRESULT WINAPI HTMLElement_get_outerHTML(IHTMLElement *iface, BSTR *p)
1056 {
1057     HTMLElement *This = impl_from_IHTMLElement(iface);
1058     nsAString html_str;
1059     HRESULT hres;
1060
1061     WARN("(%p)->(%p) semi-stub\n", This, p);
1062
1063     nsAString_Init(&html_str, NULL);
1064     hres = nsnode_to_nsstring(This->node.nsnode, &html_str);
1065     if(SUCCEEDED(hres)) {
1066         const PRUnichar *html;
1067
1068         nsAString_GetData(&html_str, &html);
1069         *p = SysAllocString(html);
1070         if(!*p)
1071             hres = E_OUTOFMEMORY;
1072     }
1073
1074     nsAString_Finish(&html_str);
1075
1076     TRACE("ret %s\n", debugstr_w(*p));
1077     return hres;
1078 }
1079
1080 static HRESULT WINAPI HTMLElement_put_outerText(IHTMLElement *iface, BSTR v)
1081 {
1082     HTMLElement *This = impl_from_IHTMLElement(iface);
1083     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
1084     return E_NOTIMPL;
1085 }
1086
1087 static HRESULT WINAPI HTMLElement_get_outerText(IHTMLElement *iface, BSTR *p)
1088 {
1089     HTMLElement *This = impl_from_IHTMLElement(iface);
1090     FIXME("(%p)->(%p)\n", This, p);
1091     return E_NOTIMPL;
1092 }
1093
1094 static HRESULT HTMLElement_InsertAdjacentNode(HTMLElement *This, BSTR where, nsIDOMNode *nsnode)
1095 {
1096     static const WCHAR wszBeforeBegin[] = {'b','e','f','o','r','e','B','e','g','i','n',0};
1097     static const WCHAR wszAfterBegin[] = {'a','f','t','e','r','B','e','g','i','n',0};
1098     static const WCHAR wszBeforeEnd[] = {'b','e','f','o','r','e','E','n','d',0};
1099     static const WCHAR wszAfterEnd[] = {'a','f','t','e','r','E','n','d',0};
1100     nsresult nsres;
1101
1102     if (!strcmpiW(where, wszBeforeBegin))
1103     {
1104         nsIDOMNode *unused;
1105         nsIDOMNode *parent;
1106         nsres = nsIDOMNode_GetParentNode(This->node.nsnode, &parent);
1107         if (!parent) return E_INVALIDARG;
1108         nsres = nsIDOMNode_InsertBefore(parent, nsnode, This->node.nsnode, &unused);
1109         if (unused) nsIDOMNode_Release(unused);
1110         nsIDOMNode_Release(parent);
1111     }
1112     else if (!strcmpiW(where, wszAfterBegin))
1113     {
1114         nsIDOMNode *unused;
1115         nsIDOMNode *first_child;
1116         nsIDOMNode_GetFirstChild(This->node.nsnode, &first_child);
1117         nsres = nsIDOMNode_InsertBefore(This->node.nsnode, nsnode, first_child, &unused);
1118         if (unused) nsIDOMNode_Release(unused);
1119         if (first_child) nsIDOMNode_Release(first_child);
1120     }
1121     else if (!strcmpiW(where, wszBeforeEnd))
1122     {
1123         nsIDOMNode *unused;
1124         nsres = nsIDOMNode_AppendChild(This->node.nsnode, nsnode, &unused);
1125         if (unused) nsIDOMNode_Release(unused);
1126     }
1127     else if (!strcmpiW(where, wszAfterEnd))
1128     {
1129         nsIDOMNode *unused;
1130         nsIDOMNode *next_sibling;
1131         nsIDOMNode *parent;
1132         nsIDOMNode_GetParentNode(This->node.nsnode, &parent);
1133         if (!parent) return E_INVALIDARG;
1134
1135         nsIDOMNode_GetNextSibling(This->node.nsnode, &next_sibling);
1136         if (next_sibling)
1137         {
1138             nsres = nsIDOMNode_InsertBefore(parent, nsnode, next_sibling, &unused);
1139             nsIDOMNode_Release(next_sibling);
1140         }
1141         else
1142             nsres = nsIDOMNode_AppendChild(parent, nsnode, &unused);
1143         nsIDOMNode_Release(parent);
1144         if (unused) nsIDOMNode_Release(unused);
1145     }
1146     else
1147     {
1148         ERR("invalid where: %s\n", debugstr_w(where));
1149         return E_INVALIDARG;
1150     }
1151
1152     if (NS_FAILED(nsres))
1153         return E_FAIL;
1154     else
1155         return S_OK;
1156 }
1157
1158 static HRESULT WINAPI HTMLElement_insertAdjacentHTML(IHTMLElement *iface, BSTR where,
1159                                                      BSTR html)
1160 {
1161     HTMLElement *This = impl_from_IHTMLElement(iface);
1162     nsIDOMRange *range;
1163     nsIDOMNode *nsnode;
1164     nsAString ns_html;
1165     nsresult nsres;
1166     HRESULT hr;
1167
1168     TRACE("(%p)->(%s %s)\n", This, debugstr_w(where), debugstr_w(html));
1169
1170     if(!This->node.doc->nsdoc) {
1171         WARN("NULL nsdoc\n");
1172         return E_UNEXPECTED;
1173     }
1174
1175     nsres = nsIDOMHTMLDocument_CreateRange(This->node.doc->nsdoc, &range);
1176     if(NS_FAILED(nsres))
1177     {
1178         ERR("CreateRange failed: %08x\n", nsres);
1179         return E_FAIL;
1180     }
1181
1182     nsIDOMRange_SetStartBefore(range, This->node.nsnode);
1183
1184     nsAString_InitDepend(&ns_html, html);
1185     nsres = nsIDOMRange_CreateContextualFragment(range, &ns_html, (nsIDOMDocumentFragment **)&nsnode);
1186     nsAString_Finish(&ns_html);
1187     nsIDOMRange_Release(range);
1188
1189     if(NS_FAILED(nsres) || !nsnode)
1190     {
1191         ERR("CreateTextNode failed: %08x\n", nsres);
1192         return E_FAIL;
1193     }
1194
1195     hr = HTMLElement_InsertAdjacentNode(This, where, nsnode);
1196     nsIDOMNode_Release(nsnode);
1197
1198     return hr;
1199 }
1200
1201 static HRESULT WINAPI HTMLElement_insertAdjacentText(IHTMLElement *iface, BSTR where,
1202                                                      BSTR text)
1203 {
1204     HTMLElement *This = impl_from_IHTMLElement(iface);
1205     nsIDOMNode *nsnode;
1206     nsAString ns_text;
1207     nsresult nsres;
1208     HRESULT hr;
1209
1210     TRACE("(%p)->(%s %s)\n", This, debugstr_w(where), debugstr_w(text));
1211
1212     if(!This->node.doc->nsdoc) {
1213         WARN("NULL nsdoc\n");
1214         return E_UNEXPECTED;
1215     }
1216
1217
1218     nsAString_InitDepend(&ns_text, text);
1219     nsres = nsIDOMHTMLDocument_CreateTextNode(This->node.doc->nsdoc, &ns_text, (nsIDOMText **)&nsnode);
1220     nsAString_Finish(&ns_text);
1221
1222     if(NS_FAILED(nsres) || !nsnode)
1223     {
1224         ERR("CreateTextNode failed: %08x\n", nsres);
1225         return E_FAIL;
1226     }
1227
1228     hr = HTMLElement_InsertAdjacentNode(This, where, nsnode);
1229     nsIDOMNode_Release(nsnode);
1230
1231     return hr;
1232 }
1233
1234 static HRESULT WINAPI HTMLElement_get_parentTextEdit(IHTMLElement *iface, IHTMLElement **p)
1235 {
1236     HTMLElement *This = impl_from_IHTMLElement(iface);
1237     FIXME("(%p)->(%p)\n", This, p);
1238     return E_NOTIMPL;
1239 }
1240
1241 static HRESULT WINAPI HTMLElement_get_isTextEdit(IHTMLElement *iface, VARIANT_BOOL *p)
1242 {
1243     HTMLElement *This = impl_from_IHTMLElement(iface);
1244     FIXME("(%p)->(%p)\n", This, p);
1245     return E_NOTIMPL;
1246 }
1247
1248 static HRESULT WINAPI HTMLElement_click(IHTMLElement *iface)
1249 {
1250     HTMLElement *This = impl_from_IHTMLElement(iface);
1251
1252     TRACE("(%p)\n", This);
1253
1254     return call_fire_event(&This->node, EVENTID_CLICK);
1255 }
1256
1257 static HRESULT WINAPI HTMLElement_get_filters(IHTMLElement *iface,
1258                                               IHTMLFiltersCollection **p)
1259 {
1260     HTMLElement *This = impl_from_IHTMLElement(iface);
1261     TRACE("(%p)->(%p)\n", This, p);
1262
1263     if(!p)
1264         return E_POINTER;
1265
1266     *p = HTMLFiltersCollection_Create();
1267
1268     return S_OK;
1269 }
1270
1271 static HRESULT WINAPI HTMLElement_put_ondragstart(IHTMLElement *iface, VARIANT v)
1272 {
1273     HTMLElement *This = impl_from_IHTMLElement(iface);
1274     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1275     return E_NOTIMPL;
1276 }
1277
1278 static HRESULT WINAPI HTMLElement_get_ondragstart(IHTMLElement *iface, VARIANT *p)
1279 {
1280     HTMLElement *This = impl_from_IHTMLElement(iface);
1281     FIXME("(%p)->(%p)\n", This, p);
1282     return E_NOTIMPL;
1283 }
1284
1285 static HRESULT WINAPI HTMLElement_toString(IHTMLElement *iface, BSTR *String)
1286 {
1287     HTMLElement *This = impl_from_IHTMLElement(iface);
1288     FIXME("(%p)->(%p)\n", This, String);
1289     return E_NOTIMPL;
1290 }
1291
1292 static HRESULT WINAPI HTMLElement_put_onbeforeupdate(IHTMLElement *iface, VARIANT v)
1293 {
1294     HTMLElement *This = impl_from_IHTMLElement(iface);
1295     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1296     return E_NOTIMPL;
1297 }
1298
1299 static HRESULT WINAPI HTMLElement_get_onbeforeupdate(IHTMLElement *iface, VARIANT *p)
1300 {
1301     HTMLElement *This = impl_from_IHTMLElement(iface);
1302     FIXME("(%p)->(%p)\n", This, p);
1303     return E_NOTIMPL;
1304 }
1305
1306 static HRESULT WINAPI HTMLElement_put_onafterupdate(IHTMLElement *iface, VARIANT v)
1307 {
1308     HTMLElement *This = impl_from_IHTMLElement(iface);
1309     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1310     return E_NOTIMPL;
1311 }
1312
1313 static HRESULT WINAPI HTMLElement_get_onafterupdate(IHTMLElement *iface, VARIANT *p)
1314 {
1315     HTMLElement *This = impl_from_IHTMLElement(iface);
1316     FIXME("(%p)->(%p)\n", This, p);
1317     return E_NOTIMPL;
1318 }
1319
1320 static HRESULT WINAPI HTMLElement_put_onerrorupdate(IHTMLElement *iface, VARIANT v)
1321 {
1322     HTMLElement *This = impl_from_IHTMLElement(iface);
1323     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1324     return E_NOTIMPL;
1325 }
1326
1327 static HRESULT WINAPI HTMLElement_get_onerrorupdate(IHTMLElement *iface, VARIANT *p)
1328 {
1329     HTMLElement *This = impl_from_IHTMLElement(iface);
1330     FIXME("(%p)->(%p)\n", This, p);
1331     return E_NOTIMPL;
1332 }
1333
1334 static HRESULT WINAPI HTMLElement_put_onrowexit(IHTMLElement *iface, VARIANT v)
1335 {
1336     HTMLElement *This = impl_from_IHTMLElement(iface);
1337     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1338     return E_NOTIMPL;
1339 }
1340
1341 static HRESULT WINAPI HTMLElement_get_onrowexit(IHTMLElement *iface, VARIANT *p)
1342 {
1343     HTMLElement *This = impl_from_IHTMLElement(iface);
1344     FIXME("(%p)->(%p)\n", This, p);
1345     return E_NOTIMPL;
1346 }
1347
1348 static HRESULT WINAPI HTMLElement_put_onrowenter(IHTMLElement *iface, VARIANT v)
1349 {
1350     HTMLElement *This = impl_from_IHTMLElement(iface);
1351     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1352     return E_NOTIMPL;
1353 }
1354
1355 static HRESULT WINAPI HTMLElement_get_onrowenter(IHTMLElement *iface, VARIANT *p)
1356 {
1357     HTMLElement *This = impl_from_IHTMLElement(iface);
1358     FIXME("(%p)->(%p)\n", This, p);
1359     return E_NOTIMPL;
1360 }
1361
1362 static HRESULT WINAPI HTMLElement_put_ondatasetchanged(IHTMLElement *iface, VARIANT v)
1363 {
1364     HTMLElement *This = impl_from_IHTMLElement(iface);
1365     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1366     return E_NOTIMPL;
1367 }
1368
1369 static HRESULT WINAPI HTMLElement_get_ondatasetchanged(IHTMLElement *iface, VARIANT *p)
1370 {
1371     HTMLElement *This = impl_from_IHTMLElement(iface);
1372     FIXME("(%p)->(%p)\n", This, p);
1373     return E_NOTIMPL;
1374 }
1375
1376 static HRESULT WINAPI HTMLElement_put_ondataavailable(IHTMLElement *iface, VARIANT v)
1377 {
1378     HTMLElement *This = impl_from_IHTMLElement(iface);
1379
1380     FIXME("(%p)->(%s) semi-stub\n", This, debugstr_variant(&v));
1381
1382     return set_node_event(&This->node, EVENTID_DATAAVAILABLE, &v);
1383 }
1384
1385 static HRESULT WINAPI HTMLElement_get_ondataavailable(IHTMLElement *iface, VARIANT *p)
1386 {
1387     HTMLElement *This = impl_from_IHTMLElement(iface);
1388
1389     TRACE("(%p)->(%p)\n", This, p);
1390
1391     return get_node_event(&This->node, EVENTID_DATAAVAILABLE, p);
1392 }
1393
1394 static HRESULT WINAPI HTMLElement_put_ondatasetcomplete(IHTMLElement *iface, VARIANT v)
1395 {
1396     HTMLElement *This = impl_from_IHTMLElement(iface);
1397     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1398     return E_NOTIMPL;
1399 }
1400
1401 static HRESULT WINAPI HTMLElement_get_ondatasetcomplete(IHTMLElement *iface, VARIANT *p)
1402 {
1403     HTMLElement *This = impl_from_IHTMLElement(iface);
1404     FIXME("(%p)->(%p)\n", This, p);
1405     return E_NOTIMPL;
1406 }
1407
1408 static HRESULT WINAPI HTMLElement_put_onfilterchange(IHTMLElement *iface, VARIANT v)
1409 {
1410     HTMLElement *This = impl_from_IHTMLElement(iface);
1411     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
1412     return E_NOTIMPL;
1413 }
1414
1415 static HRESULT WINAPI HTMLElement_get_onfilterchange(IHTMLElement *iface, VARIANT *p)
1416 {
1417     HTMLElement *This = impl_from_IHTMLElement(iface);
1418     FIXME("(%p)->(%p)\n", This, p);
1419     return E_NOTIMPL;
1420 }
1421
1422 static HRESULT WINAPI HTMLElement_get_children(IHTMLElement *iface, IDispatch **p)
1423 {
1424     HTMLElement *This = impl_from_IHTMLElement(iface);
1425     nsIDOMNodeList *nsnode_list;
1426     nsresult nsres;
1427
1428     TRACE("(%p)->(%p)\n", This, p);
1429
1430     nsres = nsIDOMNode_GetChildNodes(This->node.nsnode, &nsnode_list);
1431     if(NS_FAILED(nsres)) {
1432         ERR("GetChildNodes failed: %08x\n", nsres);
1433         return E_FAIL;
1434     }
1435
1436     *p = (IDispatch*)create_collection_from_nodelist(This->node.doc, nsnode_list);
1437
1438     nsIDOMNodeList_Release(nsnode_list);
1439     return S_OK;
1440 }
1441
1442 static HRESULT WINAPI HTMLElement_get_all(IHTMLElement *iface, IDispatch **p)
1443 {
1444     HTMLElement *This = impl_from_IHTMLElement(iface);
1445
1446     TRACE("(%p)->(%p)\n", This, p);
1447
1448     *p = (IDispatch*)create_all_collection(&This->node, FALSE);
1449     return S_OK;
1450 }
1451
1452 static const IHTMLElementVtbl HTMLElementVtbl = {
1453     HTMLElement_QueryInterface,
1454     HTMLElement_AddRef,
1455     HTMLElement_Release,
1456     HTMLElement_GetTypeInfoCount,
1457     HTMLElement_GetTypeInfo,
1458     HTMLElement_GetIDsOfNames,
1459     HTMLElement_Invoke,
1460     HTMLElement_setAttribute,
1461     HTMLElement_getAttribute,
1462     HTMLElement_removeAttribute,
1463     HTMLElement_put_className,
1464     HTMLElement_get_className,
1465     HTMLElement_put_id,
1466     HTMLElement_get_id,
1467     HTMLElement_get_tagName,
1468     HTMLElement_get_parentElement,
1469     HTMLElement_get_style,
1470     HTMLElement_put_onhelp,
1471     HTMLElement_get_onhelp,
1472     HTMLElement_put_onclick,
1473     HTMLElement_get_onclick,
1474     HTMLElement_put_ondblclick,
1475     HTMLElement_get_ondblclick,
1476     HTMLElement_put_onkeydown,
1477     HTMLElement_get_onkeydown,
1478     HTMLElement_put_onkeyup,
1479     HTMLElement_get_onkeyup,
1480     HTMLElement_put_onkeypress,
1481     HTMLElement_get_onkeypress,
1482     HTMLElement_put_onmouseout,
1483     HTMLElement_get_onmouseout,
1484     HTMLElement_put_onmouseover,
1485     HTMLElement_get_onmouseover,
1486     HTMLElement_put_onmousemove,
1487     HTMLElement_get_onmousemove,
1488     HTMLElement_put_onmousedown,
1489     HTMLElement_get_onmousedown,
1490     HTMLElement_put_onmouseup,
1491     HTMLElement_get_onmouseup,
1492     HTMLElement_get_document,
1493     HTMLElement_put_title,
1494     HTMLElement_get_title,
1495     HTMLElement_put_language,
1496     HTMLElement_get_language,
1497     HTMLElement_put_onselectstart,
1498     HTMLElement_get_onselectstart,
1499     HTMLElement_scrollIntoView,
1500     HTMLElement_contains,
1501     HTMLElement_get_sourceIndex,
1502     HTMLElement_get_recordNumber,
1503     HTMLElement_put_lang,
1504     HTMLElement_get_lang,
1505     HTMLElement_get_offsetLeft,
1506     HTMLElement_get_offsetTop,
1507     HTMLElement_get_offsetWidth,
1508     HTMLElement_get_offsetHeight,
1509     HTMLElement_get_offsetParent,
1510     HTMLElement_put_innerHTML,
1511     HTMLElement_get_innerHTML,
1512     HTMLElement_put_innerText,
1513     HTMLElement_get_innerText,
1514     HTMLElement_put_outerHTML,
1515     HTMLElement_get_outerHTML,
1516     HTMLElement_put_outerText,
1517     HTMLElement_get_outerText,
1518     HTMLElement_insertAdjacentHTML,
1519     HTMLElement_insertAdjacentText,
1520     HTMLElement_get_parentTextEdit,
1521     HTMLElement_get_isTextEdit,
1522     HTMLElement_click,
1523     HTMLElement_get_filters,
1524     HTMLElement_put_ondragstart,
1525     HTMLElement_get_ondragstart,
1526     HTMLElement_toString,
1527     HTMLElement_put_onbeforeupdate,
1528     HTMLElement_get_onbeforeupdate,
1529     HTMLElement_put_onafterupdate,
1530     HTMLElement_get_onafterupdate,
1531     HTMLElement_put_onerrorupdate,
1532     HTMLElement_get_onerrorupdate,
1533     HTMLElement_put_onrowexit,
1534     HTMLElement_get_onrowexit,
1535     HTMLElement_put_onrowenter,
1536     HTMLElement_get_onrowenter,
1537     HTMLElement_put_ondatasetchanged,
1538     HTMLElement_get_ondatasetchanged,
1539     HTMLElement_put_ondataavailable,
1540     HTMLElement_get_ondataavailable,
1541     HTMLElement_put_ondatasetcomplete,
1542     HTMLElement_get_ondatasetcomplete,
1543     HTMLElement_put_onfilterchange,
1544     HTMLElement_get_onfilterchange,
1545     HTMLElement_get_children,
1546     HTMLElement_get_all
1547 };
1548
1549 HTMLElement *unsafe_impl_from_IHTMLElement(IHTMLElement *iface)
1550 {
1551     return iface->lpVtbl == &HTMLElementVtbl ? impl_from_IHTMLElement(iface) : NULL;
1552 }
1553
1554 static inline HTMLElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
1555 {
1556     return CONTAINING_RECORD(iface, HTMLElement, node);
1557 }
1558
1559 HRESULT HTMLElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
1560 {
1561     HTMLElement *This = impl_from_HTMLDOMNode(iface);
1562
1563     *ppv =  NULL;
1564
1565     if(IsEqualGUID(&IID_IUnknown, riid)) {
1566         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1567         *ppv = &This->IHTMLElement_iface;
1568     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1569         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1570         *ppv = &This->IHTMLElement_iface;
1571     }else if(IsEqualGUID(&IID_IHTMLElement, riid)) {
1572         TRACE("(%p)->(IID_IHTMLElement %p)\n", This, ppv);
1573         *ppv = &This->IHTMLElement_iface;
1574     }else if(IsEqualGUID(&IID_IHTMLElement2, riid)) {
1575         TRACE("(%p)->(IID_IHTMLElement2 %p)\n", This, ppv);
1576         *ppv = &This->IHTMLElement2_iface;
1577     }else if(IsEqualGUID(&IID_IHTMLElement3, riid)) {
1578         TRACE("(%p)->(IID_IHTMLElement3 %p)\n", This, ppv);
1579         *ppv = &This->IHTMLElement3_iface;
1580     }else if(IsEqualGUID(&IID_IHTMLElement4, riid)) {
1581         TRACE("(%p)->(IID_IHTMLElement4 %p)\n", This, ppv);
1582         *ppv = &This->IHTMLElement4_iface;
1583     }else if(IsEqualGUID(&IID_IConnectionPointContainer, riid)) {
1584         TRACE("(%p)->(IID_IConnectionPointContainer %p)\n", This, ppv);
1585         *ppv = &This->cp_container.IConnectionPointContainer_iface;
1586     }
1587
1588     if(*ppv) {
1589         IHTMLElement_AddRef(&This->IHTMLElement_iface);
1590         return S_OK;
1591     }
1592
1593     return HTMLDOMNode_QI(&This->node, riid, ppv);
1594 }
1595
1596 void HTMLElement_destructor(HTMLDOMNode *iface)
1597 {
1598     HTMLElement *This = impl_from_HTMLDOMNode(iface);
1599
1600     ConnectionPointContainer_Destroy(&This->cp_container);
1601
1602     if(This->style) {
1603         This->style->elem = NULL;
1604         IHTMLStyle_Release(&This->style->IHTMLStyle_iface);
1605     }
1606     if(This->runtime_style) {
1607         This->runtime_style->elem = NULL;
1608         IHTMLStyle_Release(&This->runtime_style->IHTMLStyle_iface);
1609     }
1610     if(This->attrs) {
1611         HTMLDOMAttribute *attr;
1612
1613         LIST_FOR_EACH_ENTRY(attr, &This->attrs->attrs, HTMLDOMAttribute, entry)
1614             attr->elem = NULL;
1615
1616         This->attrs->elem = NULL;
1617         IHTMLAttributeCollection_Release(&This->attrs->IHTMLAttributeCollection_iface);
1618     }
1619
1620     heap_free(This->filter);
1621
1622     HTMLDOMNode_destructor(&This->node);
1623 }
1624
1625 HRESULT HTMLElement_clone(HTMLDOMNode *iface, nsIDOMNode *nsnode, HTMLDOMNode **ret)
1626 {
1627     HTMLElement *This = impl_from_HTMLDOMNode(iface);
1628     HTMLElement *new_elem;
1629     HRESULT hres;
1630
1631     hres = HTMLElement_Create(This->node.doc, nsnode, FALSE, &new_elem);
1632     if(FAILED(hres))
1633         return hres;
1634
1635     if(This->filter) {
1636         new_elem->filter = heap_strdupW(This->filter);
1637         if(!new_elem->filter) {
1638             IHTMLElement_Release(&This->IHTMLElement_iface);
1639             return E_OUTOFMEMORY;
1640         }
1641     }
1642
1643     *ret = &new_elem->node;
1644     return S_OK;
1645 }
1646
1647 HRESULT HTMLElement_handle_event(HTMLDOMNode *iface, DWORD eid, nsIDOMEvent *event, BOOL *prevent_default)
1648 {
1649     HTMLElement *This = impl_from_HTMLDOMNode(iface);
1650
1651     switch(eid) {
1652     case EVENTID_KEYDOWN: {
1653         nsIDOMKeyEvent *key_event;
1654         nsresult nsres;
1655
1656         nsres = nsIDOMEvent_QueryInterface(event, &IID_nsIDOMKeyEvent, (void**)&key_event);
1657         if(NS_SUCCEEDED(nsres)) {
1658             PRUint32 code = 0;
1659
1660             nsIDOMKeyEvent_GetKeyCode(key_event, &code);
1661
1662             switch(code) {
1663             case VK_F1: /* DOM_VK_F1 */
1664                 TRACE("F1 pressed\n");
1665                 fire_event(This->node.doc, EVENTID_HELP, TRUE, This->node.nsnode, NULL);
1666                 *prevent_default = TRUE;
1667             }
1668
1669             nsIDOMKeyEvent_Release(key_event);
1670         }
1671     }
1672     }
1673
1674     return S_OK;
1675 }
1676
1677 static const NodeImplVtbl HTMLElementImplVtbl = {
1678     HTMLElement_QI,
1679     HTMLElement_destructor,
1680     HTMLElement_clone,
1681     HTMLElement_handle_event,
1682     HTMLElement_get_attr_col
1683 };
1684
1685 static inline HTMLElement *impl_from_DispatchEx(DispatchEx *iface)
1686 {
1687     return CONTAINING_RECORD(iface, HTMLElement, node.dispex);
1688 }
1689
1690 static HRESULT HTMLElement_get_dispid(DispatchEx *dispex, BSTR name,
1691         DWORD grfdex, DISPID *pid)
1692 {
1693     HTMLElement *This = impl_from_DispatchEx(dispex);
1694
1695     if(This->node.vtbl->get_dispid)
1696         return This->node.vtbl->get_dispid(&This->node, name, grfdex, pid);
1697
1698     return DISP_E_UNKNOWNNAME;
1699 }
1700
1701 static HRESULT HTMLElement_invoke(DispatchEx *dispex, DISPID id, LCID lcid,
1702         WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei,
1703         IServiceProvider *caller)
1704 {
1705     HTMLElement *This = impl_from_DispatchEx(dispex);
1706
1707     if(This->node.vtbl->invoke)
1708         return This->node.vtbl->invoke(&This->node, id, lcid, flags,
1709                 params, res, ei, caller);
1710
1711     ERR("(%p): element has no invoke method\n", This);
1712     return E_NOTIMPL;
1713 }
1714
1715 static HRESULT HTMLElement_populate_props(DispatchEx *dispex)
1716 {
1717     HTMLElement *This = impl_from_DispatchEx(dispex);
1718     nsIDOMNamedNodeMap *attrs;
1719     nsIDOMNode *node;
1720     nsAString nsstr;
1721     const PRUnichar *str;
1722     BSTR name;
1723     VARIANT value;
1724     unsigned i;
1725     PRUint32 len;
1726     DISPID id;
1727     nsresult nsres;
1728     HRESULT hres;
1729
1730     if(!This->nselem)
1731         return S_FALSE;
1732
1733     nsres = nsIDOMHTMLElement_GetAttributes(This->nselem, &attrs);
1734     if(NS_FAILED(nsres))
1735         return E_FAIL;
1736
1737     nsres = nsIDOMNamedNodeMap_GetLength(attrs, &len);
1738     if(NS_FAILED(nsres)) {
1739         nsIDOMNamedNodeMap_Release(attrs);
1740         return E_FAIL;
1741     }
1742
1743     nsAString_Init(&nsstr, NULL);
1744     for(i=0; i<len; i++) {
1745         nsres = nsIDOMNamedNodeMap_Item(attrs, i, &node);
1746         if(NS_FAILED(nsres))
1747             continue;
1748
1749         nsres = nsIDOMNode_GetNodeName(node, &nsstr);
1750         if(NS_FAILED(nsres)) {
1751             nsIDOMNode_Release(node);
1752             continue;
1753         }
1754
1755         nsAString_GetData(&nsstr, &str);
1756         name = SysAllocString(str);
1757         if(!name) {
1758             nsIDOMNode_Release(node);
1759             continue;
1760         }
1761
1762         hres = IDispatchEx_GetDispID(&dispex->IDispatchEx_iface, name, fdexNameCaseInsensitive, &id);
1763         if(hres != DISP_E_UNKNOWNNAME) {
1764             nsIDOMNode_Release(node);
1765             SysFreeString(name);
1766             continue;
1767         }
1768
1769         nsres = nsIDOMNode_GetNodeValue(node, &nsstr);
1770         nsIDOMNode_Release(node);
1771         if(NS_FAILED(nsres)) {
1772             SysFreeString(name);
1773             continue;
1774         }
1775
1776         nsAString_GetData(&nsstr, &str);
1777         V_VT(&value) = VT_BSTR;
1778         if(*str) {
1779             V_BSTR(&value) = SysAllocString(str);
1780             if(!V_BSTR(&value)) {
1781                 SysFreeString(name);
1782                 continue;
1783             }
1784         } else
1785             V_BSTR(&value) = NULL;
1786
1787         IHTMLElement_setAttribute(&This->IHTMLElement_iface, name, value, 0);
1788         SysFreeString(name);
1789         VariantClear(&value);
1790     }
1791     nsAString_Finish(&nsstr);
1792
1793     nsIDOMNamedNodeMap_Release(attrs);
1794     return S_OK;
1795 }
1796
1797 static const tid_t HTMLElement_iface_tids[] = {
1798     HTMLELEMENT_TIDS,
1799     0
1800 };
1801
1802 static dispex_static_data_vtbl_t HTMLElement_dispex_vtbl = {
1803     NULL,
1804     HTMLElement_get_dispid,
1805     HTMLElement_invoke,
1806     HTMLElement_populate_props
1807 };
1808
1809 static dispex_static_data_t HTMLElement_dispex = {
1810     &HTMLElement_dispex_vtbl,
1811     DispHTMLUnknownElement_tid,
1812     NULL,
1813     HTMLElement_iface_tids
1814 };
1815
1816 void HTMLElement_Init(HTMLElement *This, HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, dispex_static_data_t *dispex_data)
1817 {
1818     This->IHTMLElement_iface.lpVtbl = &HTMLElementVtbl;
1819
1820     HTMLElement2_Init(This);
1821     HTMLElement3_Init(This);
1822
1823     if(dispex_data && !dispex_data->vtbl)
1824         dispex_data->vtbl = &HTMLElement_dispex_vtbl;
1825     init_dispex(&This->node.dispex, (IUnknown*)&This->IHTMLElement_iface,
1826             dispex_data ? dispex_data : &HTMLElement_dispex);
1827
1828     if(nselem) {
1829         HTMLDOMNode_Init(doc, &This->node, (nsIDOMNode*)nselem);
1830
1831         /* No AddRef, share reference with HTMLDOMNode */
1832         assert((nsIDOMNode*)nselem == This->node.nsnode);
1833         This->nselem = nselem;
1834     }
1835
1836     ConnectionPointContainer_Init(&This->cp_container, (IUnknown*)&This->IHTMLElement_iface);
1837 }
1838
1839 HRESULT HTMLElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, BOOL use_generic, HTMLElement **ret)
1840 {
1841     nsIDOMHTMLElement *nselem;
1842     nsAString class_name_str;
1843     const PRUnichar *class_name;
1844     const tag_desc_t *tag;
1845     HTMLElement *elem;
1846     nsresult nsres;
1847     HRESULT hres;
1848
1849     nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMHTMLElement, (void**)&nselem);
1850     if(NS_FAILED(nsres))
1851         return E_FAIL;
1852
1853     nsAString_Init(&class_name_str, NULL);
1854     nsIDOMHTMLElement_GetTagName(nselem, &class_name_str);
1855
1856     nsAString_GetData(&class_name_str, &class_name);
1857
1858     tag = get_tag_desc(class_name);
1859     if(tag) {
1860         hres = tag->constructor(doc, nselem, &elem);
1861     }else if(use_generic) {
1862         hres = HTMLGenericElement_Create(doc, nselem, &elem);
1863     }else {
1864         elem = heap_alloc_zero(sizeof(HTMLElement));
1865         if(elem) {
1866             HTMLElement_Init(elem, doc, nselem, &HTMLElement_dispex);
1867             elem->node.vtbl = &HTMLElementImplVtbl;
1868             hres = S_OK;
1869         }else {
1870             hres = E_OUTOFMEMORY;
1871         }
1872     }
1873
1874     TRACE("%s ret %p\n", debugstr_w(class_name), elem);
1875
1876     nsIDOMHTMLElement_Release(nselem);
1877     nsAString_Finish(&class_name_str);
1878     if(FAILED(hres))
1879         return hres;
1880
1881     *ret = elem;
1882     return S_OK;
1883 }
1884
1885 HRESULT get_elem(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **ret)
1886 {
1887     HTMLDOMNode *node;
1888     HRESULT hres;
1889
1890     hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node);
1891     if(FAILED(hres))
1892         return hres;
1893
1894     *ret = impl_from_HTMLDOMNode(node);
1895     return S_OK;
1896 }
1897
1898 /* interface IHTMLFiltersCollection */
1899 static HRESULT WINAPI HTMLFiltersCollection_QueryInterface(IHTMLFiltersCollection *iface, REFIID riid, void **ppv)
1900 {
1901     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1902
1903     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppv );
1904
1905     if(IsEqualGUID(&IID_IUnknown, riid)) {
1906         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1907         *ppv = &This->IHTMLFiltersCollection_iface;
1908     }else if(IsEqualGUID(&IID_IHTMLFiltersCollection, riid)) {
1909         TRACE("(%p)->(IID_IHTMLFiltersCollection %p)\n", This, ppv);
1910         *ppv = &This->IHTMLFiltersCollection_iface;
1911     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
1912         return *ppv ? S_OK : E_NOINTERFACE;
1913     }
1914
1915     if(*ppv) {
1916         IUnknown_AddRef((IUnknown*)*ppv);
1917         return S_OK;
1918     }
1919
1920     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1921     return E_NOINTERFACE;
1922 }
1923
1924 static ULONG WINAPI HTMLFiltersCollection_AddRef(IHTMLFiltersCollection *iface)
1925 {
1926     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1927     LONG ref = InterlockedIncrement(&This->ref);
1928
1929     TRACE("(%p) ref=%d\n", This, ref);
1930
1931     return ref;
1932 }
1933
1934 static ULONG WINAPI HTMLFiltersCollection_Release(IHTMLFiltersCollection *iface)
1935 {
1936     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1937     LONG ref = InterlockedDecrement(&This->ref);
1938
1939     TRACE("(%p) ref=%d\n", This, ref);
1940
1941     if(!ref)
1942     {
1943         heap_free(This);
1944     }
1945
1946     return ref;
1947 }
1948
1949 static HRESULT WINAPI HTMLFiltersCollection_GetTypeInfoCount(IHTMLFiltersCollection *iface, UINT *pctinfo)
1950 {
1951     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1952     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1953 }
1954
1955 static HRESULT WINAPI HTMLFiltersCollection_GetTypeInfo(IHTMLFiltersCollection *iface,
1956                                     UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1957 {
1958     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1959     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1960 }
1961
1962 static HRESULT WINAPI HTMLFiltersCollection_GetIDsOfNames(IHTMLFiltersCollection *iface,
1963                                     REFIID riid, LPOLESTR *rgszNames, UINT cNames,
1964                                     LCID lcid, DISPID *rgDispId)
1965 {
1966     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1967     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
1968             lcid, rgDispId);
1969 }
1970
1971 static HRESULT WINAPI HTMLFiltersCollection_Invoke(IHTMLFiltersCollection *iface, DISPID dispIdMember, REFIID riid,
1972                                     LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
1973                                     EXCEPINFO *pExcepInfo, UINT *puArgErr)
1974 {
1975     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1976     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
1977             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1978 }
1979
1980 static HRESULT WINAPI HTMLFiltersCollection_get_length(IHTMLFiltersCollection *iface, LONG *p)
1981 {
1982     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1983
1984     if(!p)
1985         return E_POINTER;
1986
1987     FIXME("(%p)->(%p) Always returning 0\n", This, p);
1988     *p = 0;
1989
1990     return S_OK;
1991 }
1992
1993 static HRESULT WINAPI HTMLFiltersCollection_get__newEnum(IHTMLFiltersCollection *iface, IUnknown **p)
1994 {
1995     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
1996     FIXME("(%p)->(%p)\n", This, p);
1997     return E_NOTIMPL;
1998 }
1999
2000 static HRESULT WINAPI HTMLFiltersCollection_item(IHTMLFiltersCollection *iface, VARIANT *pvarIndex, VARIANT *pvarResult)
2001 {
2002     HTMLFiltersCollection *This = impl_from_IHTMLFiltersCollection(iface);
2003     FIXME("(%p)->(%p, %p)\n", This, pvarIndex, pvarResult);
2004     return E_NOTIMPL;
2005 }
2006
2007 static const IHTMLFiltersCollectionVtbl HTMLFiltersCollectionVtbl = {
2008     HTMLFiltersCollection_QueryInterface,
2009     HTMLFiltersCollection_AddRef,
2010     HTMLFiltersCollection_Release,
2011     HTMLFiltersCollection_GetTypeInfoCount,
2012     HTMLFiltersCollection_GetTypeInfo,
2013     HTMLFiltersCollection_GetIDsOfNames,
2014     HTMLFiltersCollection_Invoke,
2015     HTMLFiltersCollection_get_length,
2016     HTMLFiltersCollection_get__newEnum,
2017     HTMLFiltersCollection_item
2018 };
2019
2020 static HRESULT HTMLFiltersCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
2021 {
2022     WCHAR *ptr;
2023     int idx = 0;
2024
2025     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
2026         idx = idx*10 + (*ptr-'0');
2027     if(*ptr)
2028         return DISP_E_UNKNOWNNAME;
2029
2030     *dispid = MSHTML_DISPID_CUSTOM_MIN + idx;
2031     TRACE("ret %x\n", *dispid);
2032     return S_OK;
2033 }
2034
2035 static HRESULT HTMLFiltersCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
2036         VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
2037 {
2038     TRACE("(%p)->(%x %x %x %p %p %p)\n", dispex, id, lcid, flags, params, res, ei);
2039
2040     V_VT(res) = VT_DISPATCH;
2041     V_DISPATCH(res) = NULL;
2042
2043     FIXME("always returning NULL\n");
2044
2045     return S_OK;
2046 }
2047
2048 static const dispex_static_data_vtbl_t HTMLFiltersCollection_dispex_vtbl = {
2049     NULL,
2050     HTMLFiltersCollection_get_dispid,
2051     HTMLFiltersCollection_invoke,
2052     NULL
2053 };
2054
2055 static const tid_t HTMLFiltersCollection_iface_tids[] = {
2056     IHTMLFiltersCollection_tid,
2057     0
2058 };
2059 static dispex_static_data_t HTMLFiltersCollection_dispex = {
2060     &HTMLFiltersCollection_dispex_vtbl,
2061     IHTMLFiltersCollection_tid,
2062     NULL,
2063     HTMLFiltersCollection_iface_tids
2064 };
2065
2066 static IHTMLFiltersCollection *HTMLFiltersCollection_Create(void)
2067 {
2068     HTMLFiltersCollection *ret = heap_alloc(sizeof(HTMLFiltersCollection));
2069
2070     ret->IHTMLFiltersCollection_iface.lpVtbl = &HTMLFiltersCollectionVtbl;
2071     ret->ref = 1;
2072
2073     init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLFiltersCollection_iface,
2074             &HTMLFiltersCollection_dispex);
2075
2076     return &ret->IHTMLFiltersCollection_iface;
2077 }
2078
2079 /* interface IHTMLAttributeCollection */
2080 static inline HTMLAttributeCollection *impl_from_IHTMLAttributeCollection(IHTMLAttributeCollection *iface)
2081 {
2082     return CONTAINING_RECORD(iface, HTMLAttributeCollection, IHTMLAttributeCollection_iface);
2083 }
2084
2085 static HRESULT WINAPI HTMLAttributeCollection_QueryInterface(IHTMLAttributeCollection *iface, REFIID riid, void **ppv)
2086 {
2087     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2088
2089     *ppv = NULL;
2090
2091     if(IsEqualGUID(&IID_IUnknown, riid)) {
2092         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
2093         *ppv = &This->IHTMLAttributeCollection_iface;
2094     }else if(IsEqualGUID(&IID_IHTMLAttributeCollection, riid)) {
2095         TRACE("(%p)->(IID_IHTMLAttributeCollection %p)\n", This, ppv);
2096         *ppv = &This->IHTMLAttributeCollection_iface;
2097     }else if(IsEqualGUID(&IID_IHTMLAttributeCollection2, riid)) {
2098         TRACE("(%p)->(IID_IHTMLAttributeCollection2 %p)\n", This, ppv);
2099         *ppv = &This->IHTMLAttributeCollection2_iface;
2100     }else if(IsEqualGUID(&IID_IHTMLAttributeCollection3, riid)) {
2101         TRACE("(%p)->(IID_IHTMLAttributeCollection3 %p)\n", This, ppv);
2102         *ppv = &This->IHTMLAttributeCollection3_iface;
2103     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
2104         return *ppv ? S_OK : E_NOINTERFACE;
2105     }
2106
2107     if(*ppv) {
2108         IUnknown_AddRef((IUnknown*)*ppv);
2109         return S_OK;
2110     }
2111
2112     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
2113     return E_NOINTERFACE;
2114 }
2115
2116 static ULONG WINAPI HTMLAttributeCollection_AddRef(IHTMLAttributeCollection *iface)
2117 {
2118     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2119     LONG ref = InterlockedIncrement(&This->ref);
2120
2121     TRACE("(%p) ref=%d\n", This, ref);
2122
2123     return ref;
2124 }
2125
2126 static ULONG WINAPI HTMLAttributeCollection_Release(IHTMLAttributeCollection *iface)
2127 {
2128     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2129     LONG ref = InterlockedDecrement(&This->ref);
2130
2131     TRACE("(%p) ref=%d\n", This, ref);
2132
2133     if(!ref) {
2134         while(!list_empty(&This->attrs)) {
2135             HTMLDOMAttribute *attr = LIST_ENTRY(list_head(&This->attrs), HTMLDOMAttribute, entry);
2136
2137             list_remove(&attr->entry);
2138             attr->elem = NULL;
2139             IHTMLDOMAttribute_Release(&attr->IHTMLDOMAttribute_iface);
2140         }
2141
2142         heap_free(This);
2143     }
2144
2145     return ref;
2146 }
2147
2148 static HRESULT WINAPI HTMLAttributeCollection_GetTypeInfoCount(IHTMLAttributeCollection *iface, UINT *pctinfo)
2149 {
2150     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2151     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2152 }
2153
2154 static HRESULT WINAPI HTMLAttributeCollection_GetTypeInfo(IHTMLAttributeCollection *iface, UINT iTInfo,
2155         LCID lcid, ITypeInfo **ppTInfo)
2156 {
2157     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2158     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
2159 }
2160
2161 static HRESULT WINAPI HTMLAttributeCollection_GetIDsOfNames(IHTMLAttributeCollection *iface, REFIID riid,
2162         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2163 {
2164     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2165     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
2166             lcid, rgDispId);
2167 }
2168
2169 static HRESULT WINAPI HTMLAttributeCollection_Invoke(IHTMLAttributeCollection *iface, DISPID dispIdMember,
2170         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
2171         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2172 {
2173     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2174     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
2175             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2176 }
2177
2178 static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, DISPID *dispid)
2179 {
2180     IDispatchEx *dispex = &This->elem->node.dispex.IDispatchEx_iface;
2181     DISPID id = DISPID_STARTENUM;
2182     LONG len = -1;
2183     HRESULT hres;
2184
2185     FIXME("filter non-enumerable attributes out\n");
2186
2187     while(1) {
2188         hres = IDispatchEx_GetNextDispID(dispex, fdexEnumAll, id, &id);
2189         if(FAILED(hres))
2190             return hres;
2191         else if(hres == S_FALSE)
2192             break;
2193
2194         len++;
2195         if(len == *idx)
2196             break;
2197     }
2198
2199     if(dispid) {
2200         *dispid = id;
2201         return *idx==len ? S_OK : DISP_E_UNKNOWNNAME;
2202     }
2203
2204     *idx = len+1;
2205     return S_OK;
2206 }
2207
2208 static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BSTR name, DISPID *id)
2209 {
2210     HRESULT hres;
2211
2212     if(name[0]>='0' && name[0]<='9') {
2213         WCHAR *end_ptr;
2214         LONG idx;
2215
2216         idx = strtoulW(name, &end_ptr, 10);
2217         if(!*end_ptr) {
2218             hres = get_attr_dispid_by_idx(This, &idx, id);
2219             if(SUCCEEDED(hres))
2220                 return hres;
2221         }
2222     }
2223
2224     if(!This->elem) {
2225         WARN("NULL elem\n");
2226         return E_UNEXPECTED;
2227     }
2228
2229     hres = IDispatchEx_GetDispID(&This->elem->node.dispex.IDispatchEx_iface,
2230             name, fdexNameCaseInsensitive, id);
2231     return hres;
2232 }
2233
2234 static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr)
2235 {
2236     HTMLDOMAttribute *iter;
2237     LONG pos = 0;
2238     HRESULT hres;
2239
2240     *attr = NULL;
2241     LIST_FOR_EACH_ENTRY(iter, &This->attrs, HTMLDOMAttribute, entry) {
2242         if(iter->dispid == id) {
2243             *attr = iter;
2244             break;
2245         }
2246         pos++;
2247     }
2248
2249     if(!*attr) {
2250         if(!This->elem) {
2251             WARN("NULL elem\n");
2252             return E_UNEXPECTED;
2253         }
2254
2255         pos++;
2256         hres = HTMLDOMAttribute_Create(This->elem, id, attr);
2257         if(FAILED(hres))
2258             return hres;
2259     }
2260
2261     IHTMLDOMAttribute_AddRef(&(*attr)->IHTMLDOMAttribute_iface);
2262     if(list_pos)
2263         *list_pos = pos;
2264     return S_OK;
2265 }
2266
2267 static HRESULT WINAPI HTMLAttributeCollection_get_length(IHTMLAttributeCollection *iface, LONG *p)
2268 {
2269     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2270     HRESULT hres;
2271
2272     TRACE("(%p)->(%p)\n", This, p);
2273
2274     *p = -1;
2275     hres = get_attr_dispid_by_idx(This, p, NULL);
2276     return hres;
2277 }
2278
2279 static HRESULT WINAPI HTMLAttributeCollection__newEnum(IHTMLAttributeCollection *iface, IUnknown **p)
2280 {
2281     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2282     FIXME("(%p)->(%p)\n", This, p);
2283     return E_NOTIMPL;
2284 }
2285
2286 static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *iface, VARIANT *name, IDispatch **ppItem)
2287 {
2288     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface);
2289     HTMLDOMAttribute *attr;
2290     DISPID id;
2291     HRESULT hres;
2292
2293     TRACE("(%p)->(%s %p)\n", This, debugstr_variant(name), ppItem);
2294
2295     switch(V_VT(name)) {
2296     case VT_I4:
2297         hres = get_attr_dispid_by_idx(This, &V_I4(name), &id);
2298         break;
2299     case VT_BSTR:
2300         hres = get_attr_dispid_by_name(This, V_BSTR(name), &id);
2301         break;
2302     default:
2303         FIXME("unsupported name %s\n", debugstr_variant(name));
2304         hres = E_NOTIMPL;
2305     }
2306     if(hres == DISP_E_UNKNOWNNAME)
2307         return E_INVALIDARG;
2308     if(FAILED(hres))
2309         return hres;
2310
2311     hres = get_domattr(This, id, NULL, &attr);
2312     if(FAILED(hres))
2313         return hres;
2314
2315     *ppItem = (IDispatch*)&attr->IHTMLDOMAttribute_iface;
2316     return S_OK;
2317 }
2318
2319 static const IHTMLAttributeCollectionVtbl HTMLAttributeCollectionVtbl = {
2320     HTMLAttributeCollection_QueryInterface,
2321     HTMLAttributeCollection_AddRef,
2322     HTMLAttributeCollection_Release,
2323     HTMLAttributeCollection_GetTypeInfoCount,
2324     HTMLAttributeCollection_GetTypeInfo,
2325     HTMLAttributeCollection_GetIDsOfNames,
2326     HTMLAttributeCollection_Invoke,
2327     HTMLAttributeCollection_get_length,
2328     HTMLAttributeCollection__newEnum,
2329     HTMLAttributeCollection_item
2330 };
2331
2332 static inline HTMLAttributeCollection *impl_from_IHTMLAttributeCollection2(IHTMLAttributeCollection2 *iface)
2333 {
2334     return CONTAINING_RECORD(iface, HTMLAttributeCollection, IHTMLAttributeCollection2_iface);
2335 }
2336
2337 static HRESULT WINAPI HTMLAttributeCollection2_QueryInterface(IHTMLAttributeCollection2 *iface, REFIID riid, void **ppv)
2338 {
2339     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2340     return IHTMLAttributeCollection_QueryInterface(&This->IHTMLAttributeCollection_iface, riid, ppv);
2341 }
2342
2343 static ULONG WINAPI HTMLAttributeCollection2_AddRef(IHTMLAttributeCollection2 *iface)
2344 {
2345     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2346     return IHTMLAttributeCollection_AddRef(&This->IHTMLAttributeCollection_iface);
2347 }
2348
2349 static ULONG WINAPI HTMLAttributeCollection2_Release(IHTMLAttributeCollection2 *iface)
2350 {
2351     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2352     return IHTMLAttributeCollection_Release(&This->IHTMLAttributeCollection_iface);
2353 }
2354
2355 static HRESULT WINAPI HTMLAttributeCollection2_GetTypeInfoCount(IHTMLAttributeCollection2 *iface, UINT *pctinfo)
2356 {
2357     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2358     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2359 }
2360
2361 static HRESULT WINAPI HTMLAttributeCollection2_GetTypeInfo(IHTMLAttributeCollection2 *iface, UINT iTInfo,
2362         LCID lcid, ITypeInfo **ppTInfo)
2363 {
2364     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2365     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
2366 }
2367
2368 static HRESULT WINAPI HTMLAttributeCollection2_GetIDsOfNames(IHTMLAttributeCollection2 *iface, REFIID riid,
2369         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2370 {
2371     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2372     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
2373             lcid, rgDispId);
2374 }
2375
2376 static HRESULT WINAPI HTMLAttributeCollection2_Invoke(IHTMLAttributeCollection2 *iface, DISPID dispIdMember,
2377         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
2378         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2379 {
2380     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2381     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
2382             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2383 }
2384
2385 static HRESULT WINAPI HTMLAttributeCollection2_getNamedItem(IHTMLAttributeCollection2 *iface, BSTR bstrName,
2386         IHTMLDOMAttribute **newretNode)
2387 {
2388     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2389     HTMLDOMAttribute *attr;
2390     DISPID id;
2391     HRESULT hres;
2392
2393     TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrName), newretNode);
2394
2395     hres = get_attr_dispid_by_name(This, bstrName, &id);
2396     if(hres == DISP_E_UNKNOWNNAME) {
2397         *newretNode = NULL;
2398         return S_OK;
2399     } else if(FAILED(hres)) {
2400         return hres;
2401     }
2402
2403     hres = get_domattr(This, id, NULL, &attr);
2404     if(FAILED(hres))
2405         return hres;
2406
2407     *newretNode = &attr->IHTMLDOMAttribute_iface;
2408     return S_OK;
2409 }
2410
2411 static HRESULT WINAPI HTMLAttributeCollection2_setNamedItem(IHTMLAttributeCollection2 *iface,
2412         IHTMLDOMAttribute *ppNode, IHTMLDOMAttribute **newretNode)
2413 {
2414     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2415     FIXME("(%p)->(%p %p)\n", This, ppNode, newretNode);
2416     return E_NOTIMPL;
2417 }
2418
2419 static HRESULT WINAPI HTMLAttributeCollection2_removeNamedItem(IHTMLAttributeCollection2 *iface,
2420         BSTR bstrName, IHTMLDOMAttribute **newretNode)
2421 {
2422     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface);
2423     FIXME("(%p)->(%s %p)\n", This, debugstr_w(bstrName), newretNode);
2424     return E_NOTIMPL;
2425 }
2426
2427 static const IHTMLAttributeCollection2Vtbl HTMLAttributeCollection2Vtbl = {
2428     HTMLAttributeCollection2_QueryInterface,
2429     HTMLAttributeCollection2_AddRef,
2430     HTMLAttributeCollection2_Release,
2431     HTMLAttributeCollection2_GetTypeInfoCount,
2432     HTMLAttributeCollection2_GetTypeInfo,
2433     HTMLAttributeCollection2_GetIDsOfNames,
2434     HTMLAttributeCollection2_Invoke,
2435     HTMLAttributeCollection2_getNamedItem,
2436     HTMLAttributeCollection2_setNamedItem,
2437     HTMLAttributeCollection2_removeNamedItem
2438 };
2439
2440 static inline HTMLAttributeCollection *impl_from_IHTMLAttributeCollection3(IHTMLAttributeCollection3 *iface)
2441 {
2442     return CONTAINING_RECORD(iface, HTMLAttributeCollection, IHTMLAttributeCollection3_iface);
2443 }
2444
2445 static HRESULT WINAPI HTMLAttributeCollection3_QueryInterface(IHTMLAttributeCollection3 *iface, REFIID riid, void **ppv)
2446 {
2447     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2448     return IHTMLAttributeCollection_QueryInterface(&This->IHTMLAttributeCollection_iface, riid, ppv);
2449 }
2450
2451 static ULONG WINAPI HTMLAttributeCollection3_AddRef(IHTMLAttributeCollection3 *iface)
2452 {
2453     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2454     return IHTMLAttributeCollection_AddRef(&This->IHTMLAttributeCollection_iface);
2455 }
2456
2457 static ULONG WINAPI HTMLAttributeCollection3_Release(IHTMLAttributeCollection3 *iface)
2458 {
2459     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2460     return IHTMLAttributeCollection_Release(&This->IHTMLAttributeCollection_iface);
2461 }
2462
2463 static HRESULT WINAPI HTMLAttributeCollection3_GetTypeInfoCount(IHTMLAttributeCollection3 *iface, UINT *pctinfo)
2464 {
2465     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2466     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2467 }
2468
2469 static HRESULT WINAPI HTMLAttributeCollection3_GetTypeInfo(IHTMLAttributeCollection3 *iface, UINT iTInfo,
2470         LCID lcid, ITypeInfo **ppTInfo)
2471 {
2472     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2473     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
2474 }
2475
2476 static HRESULT WINAPI HTMLAttributeCollection3_GetIDsOfNames(IHTMLAttributeCollection3 *iface, REFIID riid,
2477         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2478 {
2479     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2480     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
2481             lcid, rgDispId);
2482 }
2483
2484 static HRESULT WINAPI HTMLAttributeCollection3_Invoke(IHTMLAttributeCollection3 *iface, DISPID dispIdMember,
2485         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
2486         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2487 {
2488     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2489     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
2490             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2491 }
2492
2493 static HRESULT WINAPI HTMLAttributeCollection3_getNamedItem(IHTMLAttributeCollection3 *iface, BSTR bstrName,
2494         IHTMLDOMAttribute **ppNodeOut)
2495 {
2496     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2497     return IHTMLAttributeCollection2_getNamedItem(&This->IHTMLAttributeCollection2_iface, bstrName, ppNodeOut);
2498 }
2499
2500 static HRESULT WINAPI HTMLAttributeCollection3_setNamedItem(IHTMLAttributeCollection3 *iface,
2501         IHTMLDOMAttribute *pNodeIn, IHTMLDOMAttribute **ppNodeOut)
2502 {
2503     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2504     FIXME("(%p)->(%p %p)\n", This, pNodeIn, ppNodeOut);
2505     return E_NOTIMPL;
2506 }
2507
2508 static HRESULT WINAPI HTMLAttributeCollection3_removeNamedItem(IHTMLAttributeCollection3 *iface,
2509         BSTR bstrName, IHTMLDOMAttribute **ppNodeOut)
2510 {
2511     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2512     FIXME("(%p)->(%s %p)\n", This, debugstr_w(bstrName), ppNodeOut);
2513     return E_NOTIMPL;
2514 }
2515
2516 static HRESULT WINAPI HTMLAttributeCollection3_item(IHTMLAttributeCollection3 *iface, LONG index, IHTMLDOMAttribute **ppNodeOut)
2517 {
2518     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2519     HTMLDOMAttribute *attr;
2520     DISPID id;
2521     HRESULT hres;
2522
2523     TRACE("(%p)->(%d %p)\n", This, index, ppNodeOut);
2524
2525     hres = get_attr_dispid_by_idx(This, &index, &id);
2526     if(hres == DISP_E_UNKNOWNNAME)
2527         return E_INVALIDARG;
2528     if(FAILED(hres))
2529         return hres;
2530
2531     hres = get_domattr(This, id, NULL, &attr);
2532     if(FAILED(hres))
2533         return hres;
2534
2535     *ppNodeOut = &attr->IHTMLDOMAttribute_iface;
2536     return S_OK;
2537 }
2538
2539 static HRESULT WINAPI HTMLAttributeCollection3_get_length(IHTMLAttributeCollection3 *iface, LONG *p)
2540 {
2541     HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface);
2542     return IHTMLAttributeCollection_get_length(&This->IHTMLAttributeCollection_iface, p);
2543 }
2544
2545 static const IHTMLAttributeCollection3Vtbl HTMLAttributeCollection3Vtbl = {
2546     HTMLAttributeCollection3_QueryInterface,
2547     HTMLAttributeCollection3_AddRef,
2548     HTMLAttributeCollection3_Release,
2549     HTMLAttributeCollection3_GetTypeInfoCount,
2550     HTMLAttributeCollection3_GetTypeInfo,
2551     HTMLAttributeCollection3_GetIDsOfNames,
2552     HTMLAttributeCollection3_Invoke,
2553     HTMLAttributeCollection3_getNamedItem,
2554     HTMLAttributeCollection3_setNamedItem,
2555     HTMLAttributeCollection3_removeNamedItem,
2556     HTMLAttributeCollection3_item,
2557     HTMLAttributeCollection3_get_length
2558 };
2559
2560 static inline HTMLAttributeCollection *HTMLAttributeCollection_from_DispatchEx(DispatchEx *iface)
2561 {
2562     return CONTAINING_RECORD(iface, HTMLAttributeCollection, dispex);
2563 }
2564
2565 static HRESULT HTMLAttributeCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
2566 {
2567     HTMLAttributeCollection *This = HTMLAttributeCollection_from_DispatchEx(dispex);
2568     HTMLDOMAttribute *attr;
2569     LONG pos;
2570     HRESULT hres;
2571
2572     TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(name), flags, dispid);
2573
2574     hres = get_attr_dispid_by_name(This, name, dispid);
2575     if(FAILED(hres))
2576         return hres;
2577
2578     hres = get_domattr(This, *dispid, &pos, &attr);
2579     if(FAILED(hres))
2580         return hres;
2581     IHTMLDOMAttribute_Release(&attr->IHTMLDOMAttribute_iface);
2582
2583     *dispid = MSHTML_DISPID_CUSTOM_MIN+pos;
2584     return S_OK;
2585 }
2586
2587 static HRESULT HTMLAttributeCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid,
2588         WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
2589 {
2590     HTMLAttributeCollection *This = HTMLAttributeCollection_from_DispatchEx(dispex);
2591
2592     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
2593
2594     switch(flags) {
2595     case DISPATCH_PROPERTYGET: {
2596         HTMLDOMAttribute *iter;
2597
2598         id = id-MSHTML_DISPID_CUSTOM_MIN+1;
2599
2600         LIST_FOR_EACH_ENTRY(iter, &This->attrs, HTMLDOMAttribute, entry) {
2601             if(!(--id))
2602                 break;
2603         }
2604         if(id)
2605             return E_INVALIDARG;
2606
2607         IHTMLDOMAttribute_AddRef(&iter->IHTMLDOMAttribute_iface);
2608         V_VT(res) = VT_DISPATCH;
2609         V_DISPATCH(res) = (IDispatch*)&iter->IHTMLDOMAttribute_iface;
2610         return S_OK;
2611     }
2612
2613     default:
2614         FIXME("unimplemented flags %x\n", flags);
2615         return E_NOTIMPL;
2616     }
2617 }
2618
2619 static const dispex_static_data_vtbl_t HTMLAttributeCollection_dispex_vtbl = {
2620     NULL,
2621     HTMLAttributeCollection_get_dispid,
2622     HTMLAttributeCollection_invoke,
2623     NULL
2624 };
2625
2626 static const tid_t HTMLAttributeCollection_iface_tids[] = {
2627     IHTMLAttributeCollection_tid,
2628     IHTMLAttributeCollection2_tid,
2629     IHTMLAttributeCollection3_tid,
2630     0
2631 };
2632
2633 static dispex_static_data_t HTMLAttributeCollection_dispex = {
2634     &HTMLAttributeCollection_dispex_vtbl,
2635     DispHTMLAttributeCollection_tid,
2636     NULL,
2637     HTMLAttributeCollection_iface_tids
2638 };
2639
2640 HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **ac)
2641 {
2642     HTMLElement *This = impl_from_HTMLDOMNode(iface);
2643
2644     if(This->attrs) {
2645         IHTMLAttributeCollection_AddRef(&This->attrs->IHTMLAttributeCollection_iface);
2646         *ac = This->attrs;
2647         return S_OK;
2648     }
2649
2650     This->attrs = heap_alloc_zero(sizeof(HTMLAttributeCollection));
2651     if(!This->attrs)
2652         return E_OUTOFMEMORY;
2653
2654     This->attrs->IHTMLAttributeCollection_iface.lpVtbl = &HTMLAttributeCollectionVtbl;
2655     This->attrs->IHTMLAttributeCollection2_iface.lpVtbl = &HTMLAttributeCollection2Vtbl;
2656     This->attrs->IHTMLAttributeCollection3_iface.lpVtbl = &HTMLAttributeCollection3Vtbl;
2657     This->attrs->ref = 2;
2658
2659     This->attrs->elem = This;
2660     list_init(&This->attrs->attrs);
2661     init_dispex(&This->attrs->dispex, (IUnknown*)&This->attrs->IHTMLAttributeCollection_iface,
2662             &HTMLAttributeCollection_dispex);
2663
2664     *ac = This->attrs;
2665     return S_OK;
2666 }