2 * Copyright 2006-2008 Jacek Caban for CodeWeavers
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.
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.
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
28 #include "wine/debug.h"
30 #include "mshtml_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
36 const IHTMLElementCollectionVtbl *lpHTMLElementCollectionVtbl;
43 } HTMLElementCollection;
45 #define HTMLELEMCOL(x) ((IHTMLElementCollection*) &(x)->lpHTMLElementCollectionVtbl)
53 /* FIXME: Handle it better way */
54 static inline HTMLElement *elem_from_HTMLDOMNode(HTMLDOMNode *iface)
56 return CONTAINING_RECORD(iface, HTMLElement, node);
59 static IHTMLElementCollection *HTMLElementCollection_Create(IUnknown *ref_unk,
60 HTMLElement **elems, DWORD len);
62 static void elem_vector_add(elem_vector_t *buf, HTMLElement *elem)
64 if(buf->len == buf->size) {
66 buf->buf = heap_realloc(buf->buf, buf->size*sizeof(HTMLElement**));
69 buf->buf[buf->len++] = elem;
72 static void elem_vector_normalize(elem_vector_t *buf)
77 }else if(buf->size > buf->len) {
78 buf->buf = heap_realloc(buf->buf, buf->len*sizeof(HTMLElement**));
84 static inline BOOL is_elem_node(nsIDOMNode *node)
88 nsIDOMNode_GetNodeType(node, &type);
90 return type == ELEMENT_NODE || type == COMMENT_NODE;
93 #define ELEMCOL_THIS(iface) DEFINE_THIS(HTMLElementCollection, HTMLElementCollection, iface)
95 static HRESULT WINAPI HTMLElementCollection_QueryInterface(IHTMLElementCollection *iface,
96 REFIID riid, void **ppv)
98 HTMLElementCollection *This = ELEMCOL_THIS(iface);
102 if(IsEqualGUID(&IID_IUnknown, riid)) {
103 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
104 *ppv = HTMLELEMCOL(This);
105 }else if(IsEqualGUID(&IID_IHTMLElementCollection, riid)) {
106 TRACE("(%p)->(IID_IHTMLElementCollection %p)\n", This, ppv);
107 *ppv = HTMLELEMCOL(This);
108 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
109 return *ppv ? S_OK : E_NOINTERFACE;
113 IHTMLElementCollection_AddRef(HTMLELEMCOL(This));
117 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
118 return E_NOINTERFACE;
121 static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface)
123 HTMLElementCollection *This = ELEMCOL_THIS(iface);
124 LONG ref = InterlockedIncrement(&This->ref);
126 TRACE("(%p) ref=%d\n", This, ref);
131 static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface)
133 HTMLElementCollection *This = ELEMCOL_THIS(iface);
134 LONG ref = InterlockedDecrement(&This->ref);
136 TRACE("(%p) ref=%d\n", This, ref);
139 IUnknown_Release(This->ref_unk);
140 release_dispex(&This->dispex);
141 heap_free(This->elems);
148 static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface,
151 HTMLElementCollection *This = ELEMCOL_THIS(iface);
152 return IDispatchEx_GetTypeInfoCount(DISPATCHEX(&This->dispex), pctinfo);
155 static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface,
156 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
158 HTMLElementCollection *This = ELEMCOL_THIS(iface);
159 return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->dispex), iTInfo, lcid, ppTInfo);
162 static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface,
163 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
165 HTMLElementCollection *This = ELEMCOL_THIS(iface);
166 return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->dispex), riid, rgszNames, cNames, lcid, rgDispId);
169 static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface,
170 DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
171 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
173 HTMLElementCollection *This = ELEMCOL_THIS(iface);
174 return IDispatchEx_Invoke(DISPATCHEX(&This->dispex), dispIdMember, riid, lcid,
175 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
178 static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface,
181 HTMLElementCollection *This = ELEMCOL_THIS(iface);
182 FIXME("(%p)->(%p)\n", This, String);
186 static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface,
189 HTMLElementCollection *This = ELEMCOL_THIS(iface);
190 FIXME("(%p)->(%d)\n", This, v);
194 static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface,
197 HTMLElementCollection *This = ELEMCOL_THIS(iface);
199 TRACE("(%p)->(%p)\n", This, p);
205 static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface,
208 HTMLElementCollection *This = ELEMCOL_THIS(iface);
209 FIXME("(%p)->(%p)\n", This, p);
213 static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name)
218 hres = IHTMLElement_get_id(HTMLELEM(elem), &elem_id);
220 WARN("IHTMLElement_get_id failed: 0x%08x\n", hres);
224 if(elem_id && !strcmpW(elem_id, name)) {
225 SysFreeString(elem_id);
229 SysFreeString(elem_id);
233 static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name)
235 const PRUnichar *str;
236 nsAString nsstr, nsname;
240 static const PRUnichar nameW[] = {'n','a','m','e',0};
245 nsAString_Init(&nsstr, NULL);
246 nsIDOMHTMLElement_GetId(elem->nselem, &nsstr);
247 nsAString_GetData(&nsstr, &str);
248 if(!strcmpiW(str, name)) {
249 nsAString_Finish(&nsstr);
253 nsAString_InitDepend(&nsname, nameW);
254 nsres = nsIDOMHTMLElement_GetAttribute(elem->nselem, &nsname, &nsstr);
255 nsAString_Finish(&nsname);
256 if(NS_SUCCEEDED(nsres)) {
257 nsAString_GetData(&nsstr, &str);
258 ret = !strcmpiW(str, name);
261 nsAString_Finish(&nsstr);
265 static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret)
267 if(idx < This->len) {
268 *ret = (IDispatch*)This->elems[idx];
269 IDispatch_AddRef(*ret);
275 static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface,
276 VARIANT name, VARIANT index, IDispatch **pdisp)
278 HTMLElementCollection *This = ELEMCOL_THIS(iface);
281 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
285 switch(V_VT(&name)) {
289 hres = get_item_idx(This, V_I4(&name), pdisp);
293 hres = get_item_idx(This, V_UINT(&name), pdisp);
299 if(V_VT(&index) == VT_I4) {
300 LONG idx = V_I4(&index);
305 for(i=0; i<This->len; i++) {
306 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--)
311 *pdisp = (IDispatch*)HTMLELEM(This->elems[i]);
312 IDispatch_AddRef(*pdisp);
315 elem_vector_t buf = {NULL, 0, 8};
317 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
319 for(i=0; i<This->len; i++) {
320 if(is_elem_name(This->elems[i], V_BSTR(&name)))
321 elem_vector_add(&buf, This->elems[i]);
325 elem_vector_normalize(&buf);
326 *pdisp = (IDispatch*)HTMLElementCollection_Create(This->ref_unk, buf.buf, buf.len);
329 *pdisp = (IDispatch*)HTMLELEM(buf.buf[0]);
330 IDispatch_AddRef(*pdisp);
340 FIXME("Unsupported name %s\n", debugstr_variant(&name));
345 TRACE("returning %p\n", *pdisp);
349 static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface,
350 VARIANT tagName, IDispatch **pdisp)
352 HTMLElementCollection *This = ELEMCOL_THIS(iface);
355 const PRUnichar *tag;
356 elem_vector_t buf = {NULL, 0, 8};
358 if(V_VT(&tagName) != VT_BSTR) {
359 WARN("Invalid arg\n");
360 return DISP_E_MEMBERNOTFOUND;
363 TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp);
365 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
367 nsAString_Init(&tag_str, NULL);
369 for(i=0; i<This->len; i++) {
370 if(!This->elems[i]->nselem)
373 nsIDOMElement_GetTagName(This->elems[i]->nselem, &tag_str);
374 nsAString_GetData(&tag_str, &tag);
376 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1,
377 V_BSTR(&tagName), -1) == CSTR_EQUAL)
378 elem_vector_add(&buf, This->elems[i]);
381 nsAString_Finish(&tag_str);
382 elem_vector_normalize(&buf);
384 TRACE("fount %d tags\n", buf.len);
386 *pdisp = (IDispatch*)HTMLElementCollection_Create(This->ref_unk, buf.buf, buf.len);
392 static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = {
393 HTMLElementCollection_QueryInterface,
394 HTMLElementCollection_AddRef,
395 HTMLElementCollection_Release,
396 HTMLElementCollection_GetTypeInfoCount,
397 HTMLElementCollection_GetTypeInfo,
398 HTMLElementCollection_GetIDsOfNames,
399 HTMLElementCollection_Invoke,
400 HTMLElementCollection_toString,
401 HTMLElementCollection_put_length,
402 HTMLElementCollection_get_length,
403 HTMLElementCollection_get__newEnum,
404 HTMLElementCollection_item,
405 HTMLElementCollection_tags
408 static inline HTMLElementCollection *impl_from_DispatchEx(DispatchEx *iface)
410 return CONTAINING_RECORD(iface, HTMLElementCollection, dispex);
413 #define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN
415 static HRESULT HTMLElementCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
417 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
422 return DISP_E_UNKNOWNNAME;
424 for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
425 idx = idx*10 + (*ptr-'0');
428 /* the name contains alpha characters, so search by name & id */
429 for(idx = 0; idx < This->len; ++idx) {
430 if(is_elem_id(This->elems[idx], name) ||
431 is_elem_name(This->elems[idx], name))
437 return DISP_E_UNKNOWNNAME;
439 *dispid = DISPID_ELEMCOL_0 + idx;
440 TRACE("ret %x\n", *dispid);
444 static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
445 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
447 HTMLElementCollection *This = impl_from_DispatchEx(dispex);
450 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
452 idx = id - DISPID_ELEMCOL_0;
454 return DISP_E_UNKNOWNNAME;
457 case DISPATCH_PROPERTYGET:
458 V_VT(res) = VT_DISPATCH;
459 V_DISPATCH(res) = (IDispatch*)HTMLELEM(This->elems[idx]);
460 IHTMLElement_AddRef(HTMLELEM(This->elems[idx]));
463 FIXME("unimplemented flags %x\n", flags);
470 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = {
472 HTMLElementCollection_get_dispid,
473 HTMLElementCollection_invoke
476 static const tid_t HTMLElementCollection_iface_tids[] = {
477 IHTMLElementCollection_tid,
481 static dispex_static_data_t HTMLElementCollection_dispex = {
482 &HTMLElementColection_dispex_vtbl,
483 DispHTMLElementCollection_tid,
485 HTMLElementCollection_iface_tids
488 static void create_all_list(HTMLDocumentNode *doc, HTMLDOMNode *elem, elem_vector_t *buf)
490 nsIDOMNodeList *nsnode_list;
492 PRUint32 list_len = 0, i;
496 nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list);
497 if(NS_FAILED(nsres)) {
498 ERR("GetChildNodes failed: %08x\n", nsres);
502 nsIDOMNodeList_GetLength(nsnode_list, &list_len);
506 for(i=0; i<list_len; i++) {
507 nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter);
508 if(NS_FAILED(nsres)) {
509 ERR("Item failed: %08x\n", nsres);
513 if(is_elem_node(iter)) {
516 hres = get_node(doc, iter, TRUE, &node);
518 FIXME("get_node failed: %08x\n", hres);
522 elem_vector_add(buf, elem_from_HTMLDOMNode(node));
523 create_all_list(doc, node, buf);
528 IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_root)
530 elem_vector_t buf = {NULL, 0, 8};
532 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement**));
535 elem_vector_add(&buf, elem_from_HTMLDOMNode(node));
536 create_all_list(node->doc, node, &buf);
537 elem_vector_normalize(&buf);
539 return HTMLElementCollection_Create((IUnknown*)HTMLDOMNODE(node), buf.buf, buf.len);
542 IHTMLElementCollection *create_collection_from_nodelist(HTMLDocumentNode *doc, IUnknown *unk, nsIDOMNodeList *nslist)
544 PRUint32 length = 0, i;
549 nsIDOMNodeList_GetLength(nslist, &length);
556 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
558 for(i=0; i<length; i++) {
559 nsIDOMNodeList_Item(nslist, i, &nsnode);
560 if(is_elem_node(nsnode)) {
561 hres = get_node(doc, nsnode, TRUE, &node);
564 buf.buf[buf.len++] = elem_from_HTMLDOMNode(node);
566 nsIDOMNode_Release(nsnode);
569 elem_vector_normalize(&buf);
574 return HTMLElementCollection_Create(unk, buf.buf, buf.len);
577 IHTMLElementCollection *create_collection_from_htmlcol(HTMLDocumentNode *doc, IUnknown *unk, nsIDOMHTMLCollection *nscol)
579 PRUint32 length = 0, i;
584 nsIDOMHTMLCollection_GetLength(nscol, &length);
586 buf.len = buf.size = length;
590 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*));
592 for(i=0; i<length; i++) {
593 nsIDOMHTMLCollection_Item(nscol, i, &nsnode);
594 hres = get_node(doc, nsnode, TRUE, &node);
595 nsIDOMNode_Release(nsnode);
598 buf.buf[i] = elem_from_HTMLDOMNode(node);
609 return HTMLElementCollection_Create(unk, buf.buf, buf.len);
612 static IHTMLElementCollection *HTMLElementCollection_Create(IUnknown *ref_unk,
613 HTMLElement **elems, DWORD len)
615 HTMLElementCollection *ret = heap_alloc_zero(sizeof(HTMLElementCollection));
617 ret->lpHTMLElementCollectionVtbl = &HTMLElementCollectionVtbl;
622 init_dispex(&ret->dispex, (IUnknown*)HTMLELEMCOL(ret), &HTMLElementCollection_dispex);
624 IUnknown_AddRef(ref_unk);
625 ret->ref_unk = ref_unk;
627 TRACE("ret=%p len=%d\n", ret, len);
629 return HTMLELEMCOL(ret);