Reactos
at master 827 lines 24 kB view raw
1/* 2 * Copyright 2006-2008 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 "mshtml_private.h" 20 21typedef struct { 22 DispatchEx dispex; 23 IHTMLElementCollection IHTMLElementCollection_iface; 24 25 HTMLElement **elems; 26 DWORD len; 27 28 LONG ref; 29} HTMLElementCollection; 30 31typedef struct { 32 IEnumVARIANT IEnumVARIANT_iface; 33 34 LONG ref; 35 36 ULONG iter; 37 HTMLElementCollection *col; 38} HTMLElementCollectionEnum; 39 40typedef struct { 41 HTMLElement **buf; 42 DWORD len; 43 DWORD size; 44} elem_vector_t; 45 46/* FIXME: Handle it better way */ 47static inline HTMLElement *elem_from_HTMLDOMNode(HTMLDOMNode *iface) 48{ 49 return CONTAINING_RECORD(iface, HTMLElement, node); 50} 51 52static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len); 53 54static void elem_vector_add(elem_vector_t *buf, HTMLElement *elem) 55{ 56 if(buf->len == buf->size) { 57 buf->size <<= 1; 58 buf->buf = heap_realloc(buf->buf, buf->size*sizeof(HTMLElement*)); 59 } 60 61 buf->buf[buf->len++] = elem; 62} 63 64static void elem_vector_normalize(elem_vector_t *buf) 65{ 66 if(!buf->len) { 67 heap_free(buf->buf); 68 buf->buf = NULL; 69 }else if(buf->size > buf->len) { 70 buf->buf = heap_realloc(buf->buf, buf->len*sizeof(HTMLElement*)); 71 } 72 73 buf->size = buf->len; 74} 75 76static inline BOOL is_elem_node(nsIDOMNode *node) 77{ 78 UINT16 type=0; 79 80 nsIDOMNode_GetNodeType(node, &type); 81 82 return type == ELEMENT_NODE || type == COMMENT_NODE; 83} 84 85static inline HTMLElementCollectionEnum *impl_from_IEnumVARIANT(IEnumVARIANT *iface) 86{ 87 return CONTAINING_RECORD(iface, HTMLElementCollectionEnum, IEnumVARIANT_iface); 88} 89 90static HRESULT WINAPI HTMLElementCollectionEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) 91{ 92 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface); 93 94 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); 95 96 if(IsEqualGUID(riid, &IID_IUnknown)) { 97 *ppv = &This->IEnumVARIANT_iface; 98 }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) { 99 *ppv = &This->IEnumVARIANT_iface; 100 }else { 101 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid)); 102 *ppv = NULL; 103 return E_NOINTERFACE; 104 } 105 106 IUnknown_AddRef((IUnknown*)*ppv); 107 return S_OK; 108} 109 110static ULONG WINAPI HTMLElementCollectionEnum_AddRef(IEnumVARIANT *iface) 111{ 112 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface); 113 LONG ref = InterlockedIncrement(&This->ref); 114 115 TRACE("(%p) ref=%d\n", This, ref); 116 117 return ref; 118} 119 120static ULONG WINAPI HTMLElementCollectionEnum_Release(IEnumVARIANT *iface) 121{ 122 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface); 123 LONG ref = InterlockedDecrement(&This->ref); 124 125 TRACE("(%p) ref=%d\n", This, ref); 126 127 if(!ref) { 128 IHTMLElementCollection_Release(&This->col->IHTMLElementCollection_iface); 129 heap_free(This); 130 } 131 132 return ref; 133} 134 135static HRESULT WINAPI HTMLElementCollectionEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) 136{ 137 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface); 138 ULONG fetched = 0; 139 140 TRACE("(%p)->(%d %p %p)\n", This, celt, rgVar, pCeltFetched); 141 142 while(This->iter+fetched < This->col->len && fetched < celt) { 143 V_VT(rgVar+fetched) = VT_DISPATCH; 144 V_DISPATCH(rgVar+fetched) = (IDispatch*)&This->col->elems[This->iter+fetched]->IHTMLElement_iface; 145 IDispatch_AddRef(V_DISPATCH(rgVar+fetched)); 146 fetched++; 147 } 148 149 This->iter += fetched; 150 if(pCeltFetched) 151 *pCeltFetched = fetched; 152 return fetched == celt ? S_OK : S_FALSE; 153} 154 155static HRESULT WINAPI HTMLElementCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt) 156{ 157 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface); 158 159 TRACE("(%p)->(%d)\n", This, celt); 160 161 if(This->iter + celt > This->col->len) { 162 This->iter = This->col->len; 163 return S_FALSE; 164 } 165 166 This->iter += celt; 167 return S_OK; 168} 169 170static HRESULT WINAPI HTMLElementCollectionEnum_Reset(IEnumVARIANT *iface) 171{ 172 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface); 173 174 TRACE("(%p)->()\n", This); 175 176 This->iter = 0; 177 return S_OK; 178} 179 180static HRESULT WINAPI HTMLElementCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum) 181{ 182 HTMLElementCollectionEnum *This = impl_from_IEnumVARIANT(iface); 183 FIXME("(%p)->(%p)\n", This, ppEnum); 184 return E_NOTIMPL; 185} 186 187static const IEnumVARIANTVtbl HTMLElementCollectionEnumVtbl = { 188 HTMLElementCollectionEnum_QueryInterface, 189 HTMLElementCollectionEnum_AddRef, 190 HTMLElementCollectionEnum_Release, 191 HTMLElementCollectionEnum_Next, 192 HTMLElementCollectionEnum_Skip, 193 HTMLElementCollectionEnum_Reset, 194 HTMLElementCollectionEnum_Clone 195}; 196 197static inline HTMLElementCollection *impl_from_IHTMLElementCollection(IHTMLElementCollection *iface) 198{ 199 return CONTAINING_RECORD(iface, HTMLElementCollection, IHTMLElementCollection_iface); 200} 201 202static HRESULT WINAPI HTMLElementCollection_QueryInterface(IHTMLElementCollection *iface, 203 REFIID riid, void **ppv) 204{ 205 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 206 207 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); 208 209 if(IsEqualGUID(&IID_IUnknown, riid)) { 210 *ppv = &This->IHTMLElementCollection_iface; 211 }else if(IsEqualGUID(&IID_IHTMLElementCollection, riid)) { 212 *ppv = &This->IHTMLElementCollection_iface; 213 }else if(dispex_query_interface(&This->dispex, riid, ppv)) { 214 return *ppv ? S_OK : E_NOINTERFACE; 215 }else { 216 *ppv = NULL; 217 FIXME("Unsupported iface %s\n", debugstr_mshtml_guid(riid)); 218 return E_NOINTERFACE; 219 } 220 221 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface); 222 return S_OK; 223} 224 225static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface) 226{ 227 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 228 LONG ref = InterlockedIncrement(&This->ref); 229 230 TRACE("(%p) ref=%d\n", This, ref); 231 232 return ref; 233} 234 235static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface) 236{ 237 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 238 LONG ref = InterlockedDecrement(&This->ref); 239 240 TRACE("(%p) ref=%d\n", This, ref); 241 242 if(!ref) { 243 unsigned i; 244 245 for(i=0; i < This->len; i++) 246 node_release(&This->elems[i]->node); 247 heap_free(This->elems); 248 249 release_dispex(&This->dispex); 250 heap_free(This); 251 } 252 253 return ref; 254} 255 256static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface, 257 UINT *pctinfo) 258{ 259 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 260 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); 261} 262 263static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface, 264 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 265{ 266 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 267 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); 268} 269 270static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface, 271 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) 272{ 273 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 274 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, 275 lcid, rgDispId); 276} 277 278static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface, 279 DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, 280 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 281{ 282 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 283 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, 284 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 285} 286 287static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface, 288 BSTR *String) 289{ 290 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 291 FIXME("(%p)->(%p)\n", This, String); 292 return E_NOTIMPL; 293} 294 295static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface, 296 LONG v) 297{ 298 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 299 FIXME("(%p)->(%d)\n", This, v); 300 return E_NOTIMPL; 301} 302 303static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface, 304 LONG *p) 305{ 306 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 307 308 TRACE("(%p)->(%p)\n", This, p); 309 310 *p = This->len; 311 return S_OK; 312} 313 314static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface, 315 IUnknown **p) 316{ 317 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 318 HTMLElementCollectionEnum *ret; 319 320 TRACE("(%p)->(%p)\n", This, p); 321 322 ret = heap_alloc(sizeof(*ret)); 323 if(!ret) 324 return E_OUTOFMEMORY; 325 326 ret->IEnumVARIANT_iface.lpVtbl = &HTMLElementCollectionEnumVtbl; 327 ret->ref = 1; 328 ret->iter = 0; 329 330 IHTMLElementCollection_AddRef(&This->IHTMLElementCollection_iface); 331 ret->col = This; 332 333 *p = (IUnknown*)&ret->IEnumVARIANT_iface; 334 return S_OK; 335} 336 337static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name) 338{ 339 BSTR elem_id; 340 HRESULT hres; 341 342 hres = IHTMLElement_get_id(&elem->IHTMLElement_iface, &elem_id); 343 if(FAILED(hres)){ 344 WARN("IHTMLElement_get_id failed: 0x%08x\n", hres); 345 return FALSE; 346 } 347 348 if(elem_id && !strcmpW(elem_id, name)) { 349 SysFreeString(elem_id); 350 return TRUE; 351 } 352 353 SysFreeString(elem_id); 354 return FALSE; 355} 356 357static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name) 358{ 359 const PRUnichar *str; 360 nsAString nsstr; 361 BOOL ret = FALSE; 362 nsresult nsres; 363 364 static const PRUnichar nameW[] = {'n','a','m','e',0}; 365 366 if(!elem->nselem) 367 return FALSE; 368 369 nsAString_Init(&nsstr, NULL); 370 nsIDOMHTMLElement_GetId(elem->nselem, &nsstr); 371 nsAString_GetData(&nsstr, &str); 372 if(!strcmpiW(str, name)) { 373 nsAString_Finish(&nsstr); 374 return TRUE; 375 } 376 377 nsres = get_elem_attr_value(elem->nselem, nameW, &nsstr, &str); 378 if(NS_SUCCEEDED(nsres)) { 379 ret = !strcmpiW(str, name); 380 nsAString_Finish(&nsstr); 381 } 382 383 return ret; 384} 385 386static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret) 387{ 388 if(idx < This->len) { 389 *ret = (IDispatch*)This->elems[idx]; 390 IDispatch_AddRef(*ret); 391 } 392 393 return S_OK; 394} 395 396static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface, 397 VARIANT name, VARIANT index, IDispatch **pdisp) 398{ 399 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 400 HRESULT hres = S_OK; 401 402 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp); 403 404 *pdisp = NULL; 405 406 switch(V_VT(&name)) { 407 case VT_I4: 408 case VT_INT: 409 if(V_I4(&name) < 0) 410 return E_INVALIDARG; 411 hres = get_item_idx(This, V_I4(&name), pdisp); 412 break; 413 414 case VT_UI4: 415 case VT_UINT: 416 hres = get_item_idx(This, V_UINT(&name), pdisp); 417 break; 418 419 case VT_BSTR: { 420 DWORD i; 421 422 if(V_VT(&index) == VT_I4) { 423 LONG idx = V_I4(&index); 424 425 if(idx < 0) 426 return E_INVALIDARG; 427 428 for(i=0; i<This->len; i++) { 429 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--) 430 break; 431 } 432 433 if(i != This->len) { 434 *pdisp = (IDispatch*)&This->elems[i]->IHTMLElement_iface; 435 IDispatch_AddRef(*pdisp); 436 } 437 }else { 438 elem_vector_t buf = {NULL, 0, 8}; 439 440 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 441 442 for(i=0; i<This->len; i++) { 443 if(is_elem_name(This->elems[i], V_BSTR(&name))) { 444 node_addref(&This->elems[i]->node); 445 elem_vector_add(&buf, This->elems[i]); 446 } 447 } 448 449 if(buf.len > 1) { 450 elem_vector_normalize(&buf); 451 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len); 452 }else { 453 if(buf.len == 1) { 454 /* Already AddRef-ed */ 455 *pdisp = (IDispatch*)&buf.buf[0]->IHTMLElement_iface; 456 } 457 458 heap_free(buf.buf); 459 } 460 } 461 break; 462 } 463 464 default: 465 FIXME("Unsupported name %s\n", debugstr_variant(&name)); 466 hres = E_NOTIMPL; 467 } 468 469 if(SUCCEEDED(hres)) 470 TRACE("returning %p\n", *pdisp); 471 return hres; 472} 473 474static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface, 475 VARIANT tagName, IDispatch **pdisp) 476{ 477 HTMLElementCollection *This = impl_from_IHTMLElementCollection(iface); 478 DWORD i; 479 nsAString tag_str; 480 const PRUnichar *tag; 481 elem_vector_t buf = {NULL, 0, 8}; 482 483 if(V_VT(&tagName) != VT_BSTR) { 484 WARN("Invalid arg\n"); 485 return DISP_E_MEMBERNOTFOUND; 486 } 487 488 TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp); 489 490 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 491 492 nsAString_Init(&tag_str, NULL); 493 494 for(i=0; i<This->len; i++) { 495 if(!This->elems[i]->nselem) 496 continue; 497 498 nsIDOMHTMLElement_GetTagName(This->elems[i]->nselem, &tag_str); 499 nsAString_GetData(&tag_str, &tag); 500 501 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1, 502 V_BSTR(&tagName), -1) == CSTR_EQUAL) { 503 node_addref(&This->elems[i]->node); 504 elem_vector_add(&buf, This->elems[i]); 505 } 506 } 507 508 nsAString_Finish(&tag_str); 509 elem_vector_normalize(&buf); 510 511 TRACE("fount %d tags\n", buf.len); 512 513 *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len); 514 return S_OK; 515} 516 517static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = { 518 HTMLElementCollection_QueryInterface, 519 HTMLElementCollection_AddRef, 520 HTMLElementCollection_Release, 521 HTMLElementCollection_GetTypeInfoCount, 522 HTMLElementCollection_GetTypeInfo, 523 HTMLElementCollection_GetIDsOfNames, 524 HTMLElementCollection_Invoke, 525 HTMLElementCollection_toString, 526 HTMLElementCollection_put_length, 527 HTMLElementCollection_get_length, 528 HTMLElementCollection_get__newEnum, 529 HTMLElementCollection_item, 530 HTMLElementCollection_tags 531}; 532 533static inline HTMLElementCollection *impl_from_DispatchEx(DispatchEx *iface) 534{ 535 return CONTAINING_RECORD(iface, HTMLElementCollection, dispex); 536} 537 538#define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN 539 540static HRESULT HTMLElementCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid) 541{ 542 HTMLElementCollection *This = impl_from_DispatchEx(dispex); 543 WCHAR *ptr; 544 DWORD idx=0; 545 546 if(!*name) 547 return DISP_E_UNKNOWNNAME; 548 549 for(ptr = name; *ptr && isdigitW(*ptr); ptr++) 550 idx = idx*10 + (*ptr-'0'); 551 552 if(*ptr) { 553 /* the name contains alpha characters, so search by name & id */ 554 for(idx = 0; idx < This->len; ++idx) { 555 if(is_elem_id(This->elems[idx], name) || 556 is_elem_name(This->elems[idx], name)) 557 break; 558 } 559 } 560 561 if(idx >= This->len) 562 return DISP_E_UNKNOWNNAME; 563 564 *dispid = DISPID_ELEMCOL_0 + idx; 565 TRACE("ret %x\n", *dispid); 566 return S_OK; 567} 568 569static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, 570 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) 571{ 572 HTMLElementCollection *This = impl_from_DispatchEx(dispex); 573 DWORD idx; 574 575 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller); 576 577 idx = id - DISPID_ELEMCOL_0; 578 if(idx >= This->len) 579 return DISP_E_UNKNOWNNAME; 580 581 switch(flags) { 582 case DISPATCH_PROPERTYGET: 583 V_VT(res) = VT_DISPATCH; 584 V_DISPATCH(res) = (IDispatch*)&This->elems[idx]->IHTMLElement_iface; 585 IHTMLElement_AddRef(&This->elems[idx]->IHTMLElement_iface); 586 break; 587 default: 588 FIXME("unimplemented flags %x\n", flags); 589 return E_NOTIMPL; 590 } 591 592 return S_OK; 593} 594 595static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = { 596 NULL, 597 HTMLElementCollection_get_dispid, 598 HTMLElementCollection_invoke, 599 NULL 600}; 601 602static const tid_t HTMLElementCollection_iface_tids[] = { 603 IHTMLElementCollection_tid, 604 0 605}; 606 607static dispex_static_data_t HTMLElementCollection_dispex = { 608 &HTMLElementColection_dispex_vtbl, 609 DispHTMLElementCollection_tid, 610 NULL, 611 HTMLElementCollection_iface_tids 612}; 613 614static void create_all_list(HTMLDocumentNode *doc, HTMLDOMNode *elem, elem_vector_t *buf) 615{ 616 nsIDOMNodeList *nsnode_list; 617 nsIDOMNode *iter; 618 UINT32 list_len = 0, i; 619 nsresult nsres; 620 HRESULT hres; 621 622 nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list); 623 if(NS_FAILED(nsres)) { 624 ERR("GetChildNodes failed: %08x\n", nsres); 625 return; 626 } 627 628 nsIDOMNodeList_GetLength(nsnode_list, &list_len); 629 if(!list_len) 630 return; 631 632 for(i=0; i<list_len; i++) { 633 nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter); 634 if(NS_FAILED(nsres)) { 635 ERR("Item failed: %08x\n", nsres); 636 continue; 637 } 638 639 if(is_elem_node(iter)) { 640 HTMLDOMNode *node; 641 642 hres = get_node(doc, iter, TRUE, &node); 643 if(FAILED(hres)) { 644 FIXME("get_node failed: %08x\n", hres); 645 continue; 646 } 647 648 elem_vector_add(buf, elem_from_HTMLDOMNode(node)); 649 create_all_list(doc, node, buf); 650 } 651 } 652} 653 654IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_root) 655{ 656 elem_vector_t buf = {NULL, 0, 8}; 657 658 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 659 660 if(include_root) { 661 node_addref(node); 662 elem_vector_add(&buf, elem_from_HTMLDOMNode(node)); 663 } 664 create_all_list(node->doc, node, &buf); 665 elem_vector_normalize(&buf); 666 667 return HTMLElementCollection_Create(buf.buf, buf.len); 668} 669 670IHTMLElementCollection *create_collection_from_nodelist(HTMLDocumentNode *doc, nsIDOMNodeList *nslist) 671{ 672 UINT32 length = 0, i; 673 HTMLDOMNode *node; 674 elem_vector_t buf; 675 HRESULT hres; 676 677 nsIDOMNodeList_GetLength(nslist, &length); 678 679 buf.len = 0; 680 buf.size = length; 681 if(length) { 682 nsIDOMNode *nsnode; 683 684 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 685 686 for(i=0; i<length; i++) { 687 nsIDOMNodeList_Item(nslist, i, &nsnode); 688 if(is_elem_node(nsnode)) { 689 hres = get_node(doc, nsnode, TRUE, &node); 690 if(FAILED(hres)) 691 continue; 692 buf.buf[buf.len++] = elem_from_HTMLDOMNode(node); 693 } 694 nsIDOMNode_Release(nsnode); 695 } 696 697 elem_vector_normalize(&buf); 698 }else { 699 buf.buf = NULL; 700 } 701 702 return HTMLElementCollection_Create(buf.buf, buf.len); 703} 704 705IHTMLElementCollection *create_collection_from_htmlcol(HTMLDocumentNode *doc, nsIDOMHTMLCollection *nscol) 706{ 707 UINT32 length = 0, i; 708 elem_vector_t buf; 709 HTMLDOMNode *node; 710 HRESULT hres = S_OK; 711 712 nsIDOMHTMLCollection_GetLength(nscol, &length); 713 714 buf.len = buf.size = length; 715 if(buf.len) { 716 nsIDOMNode *nsnode; 717 718 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 719 720 for(i=0; i<length; i++) { 721 nsIDOMHTMLCollection_Item(nscol, i, &nsnode); 722 hres = get_node(doc, nsnode, TRUE, &node); 723 nsIDOMNode_Release(nsnode); 724 if(FAILED(hres)) 725 break; 726 buf.buf[i] = elem_from_HTMLDOMNode(node); 727 } 728 }else { 729 buf.buf = NULL; 730 } 731 732 if(FAILED(hres)) { 733 heap_free(buf.buf); 734 return NULL; 735 } 736 737 return HTMLElementCollection_Create(buf.buf, buf.len); 738} 739 740HRESULT get_elem_source_index(HTMLElement *elem, LONG *ret) 741{ 742 elem_vector_t buf = {NULL, 0, 8}; 743 nsIDOMNode *parent_node, *iter; 744 UINT16 parent_type; 745 HTMLDOMNode *node; 746 int i; 747 nsresult nsres; 748 HRESULT hres; 749 750 iter = elem->node.nsnode; 751 nsIDOMNode_AddRef(iter); 752 753 /* Find document or document fragment parent. */ 754 while(1) { 755 nsres = nsIDOMNode_GetParentNode(iter, &parent_node); 756 nsIDOMNode_Release(iter); 757 assert(nsres == NS_OK); 758 if(!parent_node) 759 break; 760 761 nsres = nsIDOMNode_GetNodeType(parent_node, &parent_type); 762 assert(nsres == NS_OK); 763 764 if(parent_type != ELEMENT_NODE) { 765 if(parent_type != DOCUMENT_NODE && parent_type != DOCUMENT_FRAGMENT_NODE) 766 FIXME("Unexpected parent_type %d\n", parent_type); 767 break; 768 } 769 770 iter = parent_node; 771 } 772 773 if(!parent_node) { 774 *ret = -1; 775 return S_OK; 776 } 777 778 hres = get_node(elem->node.doc, parent_node, TRUE, &node); 779 nsIDOMNode_Release(parent_node); 780 if(FAILED(hres)) 781 return hres; 782 783 784 /* Create all children collection and find the element in it. 785 * This could be optimized if we ever find the reason. */ 786 buf.buf = heap_alloc(buf.size*sizeof(*buf.buf)); 787 if(!buf.buf) { 788 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface); 789 return E_OUTOFMEMORY; 790 } 791 792 create_all_list(elem->node.doc, node, &buf); 793 794 for(i=0; i < buf.len; i++) { 795 if(buf.buf[i] == elem) 796 break; 797 } 798 IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface); 799 heap_free(buf.buf); 800 if(i == buf.len) { 801 FIXME("The element is not in parent's child list?\n"); 802 return E_UNEXPECTED; 803 } 804 805 *ret = i; 806 return S_OK; 807} 808 809static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len) 810{ 811 HTMLElementCollection *ret = heap_alloc_zero(sizeof(HTMLElementCollection)); 812 813 if (!ret) 814 return NULL; 815 816 ret->IHTMLElementCollection_iface.lpVtbl = &HTMLElementCollectionVtbl; 817 ret->ref = 1; 818 ret->elems = elems; 819 ret->len = len; 820 821 init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLElementCollection_iface, 822 &HTMLElementCollection_dispex); 823 824 TRACE("ret=%p len=%d\n", ret, len); 825 826 return &ret->IHTMLElementCollection_iface; 827}