Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhtmlelemcol.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2006-2008 Jacek Caban for CodeWeavers 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include <stdarg.h> 00020 00021 #define COBJMACROS 00022 00023 #include "windef.h" 00024 #include "winbase.h" 00025 #include "winuser.h" 00026 #include "ole2.h" 00027 00028 #include "wine/debug.h" 00029 00030 #include "mshtml_private.h" 00031 00032 WINE_DEFAULT_DEBUG_CHANNEL(mshtml); 00033 00034 typedef struct { 00035 DispatchEx dispex; 00036 const IHTMLElementCollectionVtbl *lpHTMLElementCollectionVtbl; 00037 00038 IUnknown *ref_unk; 00039 HTMLElement **elems; 00040 DWORD len; 00041 00042 LONG ref; 00043 } HTMLElementCollection; 00044 00045 #define HTMLELEMCOL(x) ((IHTMLElementCollection*) &(x)->lpHTMLElementCollectionVtbl) 00046 00047 typedef struct { 00048 HTMLElement **buf; 00049 DWORD len; 00050 DWORD size; 00051 } elem_vector_t; 00052 00053 static IHTMLElementCollection *HTMLElementCollection_Create(IUnknown *ref_unk, 00054 HTMLElement **elems, DWORD len); 00055 00056 static void elem_vector_add(elem_vector_t *buf, HTMLElement *elem) 00057 { 00058 if(buf->len == buf->size) { 00059 buf->size <<= 1; 00060 buf->buf = heap_realloc(buf->buf, buf->size*sizeof(HTMLElement**)); 00061 } 00062 00063 buf->buf[buf->len++] = elem; 00064 } 00065 00066 static void elem_vector_normalize(elem_vector_t *buf) 00067 { 00068 if(!buf->len) { 00069 heap_free(buf->buf); 00070 buf->buf = NULL; 00071 }else if(buf->size > buf->len) { 00072 buf->buf = heap_realloc(buf->buf, buf->len*sizeof(HTMLElement**)); 00073 } 00074 00075 buf->size = buf->len; 00076 } 00077 00078 static inline BOOL is_elem_node(nsIDOMNode *node) 00079 { 00080 PRUint16 type=0; 00081 00082 nsIDOMNode_GetNodeType(node, &type); 00083 00084 return type == ELEMENT_NODE || type == COMMENT_NODE; 00085 } 00086 00087 #define ELEMCOL_THIS(iface) DEFINE_THIS(HTMLElementCollection, HTMLElementCollection, iface) 00088 #define HTMLELEM_NODE_THIS(iface) DEFINE_THIS2(HTMLElement, node, iface) 00089 00090 static HRESULT WINAPI HTMLElementCollection_QueryInterface(IHTMLElementCollection *iface, 00091 REFIID riid, void **ppv) 00092 { 00093 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00094 00095 *ppv = NULL; 00096 00097 if(IsEqualGUID(&IID_IUnknown, riid)) { 00098 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 00099 *ppv = HTMLELEMCOL(This); 00100 }else if(IsEqualGUID(&IID_IHTMLElementCollection, riid)) { 00101 TRACE("(%p)->(IID_IHTMLElementCollection %p)\n", This, ppv); 00102 *ppv = HTMLELEMCOL(This); 00103 }else if(dispex_query_interface(&This->dispex, riid, ppv)) { 00104 return *ppv ? S_OK : E_NOINTERFACE; 00105 } 00106 00107 if(*ppv) { 00108 IHTMLElementCollection_AddRef(HTMLELEMCOL(This)); 00109 return S_OK; 00110 } 00111 00112 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 00113 return E_NOINTERFACE; 00114 } 00115 00116 static ULONG WINAPI HTMLElementCollection_AddRef(IHTMLElementCollection *iface) 00117 { 00118 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00119 LONG ref = InterlockedIncrement(&This->ref); 00120 00121 TRACE("(%p) ref=%d\n", This, ref); 00122 00123 return ref; 00124 } 00125 00126 static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface) 00127 { 00128 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00129 LONG ref = InterlockedDecrement(&This->ref); 00130 00131 TRACE("(%p) ref=%d\n", This, ref); 00132 00133 if(!ref) { 00134 IUnknown_Release(This->ref_unk); 00135 release_dispex(&This->dispex); 00136 heap_free(This->elems); 00137 heap_free(This); 00138 } 00139 00140 return ref; 00141 } 00142 00143 static HRESULT WINAPI HTMLElementCollection_GetTypeInfoCount(IHTMLElementCollection *iface, 00144 UINT *pctinfo) 00145 { 00146 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00147 return IDispatchEx_GetTypeInfoCount(DISPATCHEX(&This->dispex), pctinfo); 00148 } 00149 00150 static HRESULT WINAPI HTMLElementCollection_GetTypeInfo(IHTMLElementCollection *iface, 00151 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) 00152 { 00153 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00154 return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->dispex), iTInfo, lcid, ppTInfo); 00155 } 00156 00157 static HRESULT WINAPI HTMLElementCollection_GetIDsOfNames(IHTMLElementCollection *iface, 00158 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) 00159 { 00160 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00161 return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->dispex), riid, rgszNames, cNames, lcid, rgDispId); 00162 } 00163 00164 static HRESULT WINAPI HTMLElementCollection_Invoke(IHTMLElementCollection *iface, 00165 DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, 00166 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 00167 { 00168 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00169 return IDispatchEx_Invoke(DISPATCHEX(&This->dispex), dispIdMember, riid, lcid, 00170 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 00171 } 00172 00173 static HRESULT WINAPI HTMLElementCollection_toString(IHTMLElementCollection *iface, 00174 BSTR *String) 00175 { 00176 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00177 FIXME("(%p)->(%p)\n", This, String); 00178 return E_NOTIMPL; 00179 } 00180 00181 static HRESULT WINAPI HTMLElementCollection_put_length(IHTMLElementCollection *iface, 00182 LONG v) 00183 { 00184 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00185 FIXME("(%p)->(%d)\n", This, v); 00186 return E_NOTIMPL; 00187 } 00188 00189 static HRESULT WINAPI HTMLElementCollection_get_length(IHTMLElementCollection *iface, 00190 LONG *p) 00191 { 00192 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00193 00194 TRACE("(%p)->(%p)\n", This, p); 00195 00196 *p = This->len; 00197 return S_OK; 00198 } 00199 00200 static HRESULT WINAPI HTMLElementCollection_get__newEnum(IHTMLElementCollection *iface, 00201 IUnknown **p) 00202 { 00203 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00204 FIXME("(%p)->(%p)\n", This, p); 00205 return E_NOTIMPL; 00206 } 00207 00208 static BOOL is_elem_id(HTMLElement *elem, LPCWSTR name) 00209 { 00210 BSTR elem_id; 00211 HRESULT hres; 00212 00213 hres = IHTMLElement_get_id(HTMLELEM(elem), &elem_id); 00214 if(FAILED(hres)){ 00215 WARN("IHTMLElement_get_id failed: 0x%08x\n", hres); 00216 return FALSE; 00217 } 00218 00219 if(elem_id && !strcmpW(elem_id, name)) { 00220 SysFreeString(elem_id); 00221 return TRUE; 00222 } 00223 00224 SysFreeString(elem_id); 00225 return FALSE; 00226 } 00227 00228 static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name) 00229 { 00230 const PRUnichar *str; 00231 nsAString nsstr, nsname; 00232 BOOL ret = FALSE; 00233 nsresult nsres; 00234 00235 static const PRUnichar nameW[] = {'n','a','m','e',0}; 00236 00237 if(!elem->nselem) 00238 return FALSE; 00239 00240 nsAString_Init(&nsstr, NULL); 00241 nsIDOMHTMLElement_GetId(elem->nselem, &nsstr); 00242 nsAString_GetData(&nsstr, &str); 00243 if(!strcmpiW(str, name)) { 00244 nsAString_Finish(&nsstr); 00245 return TRUE; 00246 } 00247 00248 nsAString_InitDepend(&nsname, nameW); 00249 nsres = nsIDOMHTMLElement_GetAttribute(elem->nselem, &nsname, &nsstr); 00250 nsAString_Finish(&nsname); 00251 if(NS_SUCCEEDED(nsres)) { 00252 nsAString_GetData(&nsstr, &str); 00253 ret = !strcmpiW(str, name); 00254 } 00255 00256 nsAString_Finish(&nsstr); 00257 return ret; 00258 } 00259 00260 static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret) 00261 { 00262 if(idx < This->len) { 00263 *ret = (IDispatch*)This->elems[idx]; 00264 IDispatch_AddRef(*ret); 00265 } 00266 00267 return S_OK; 00268 } 00269 00270 static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface, 00271 VARIANT name, VARIANT index, IDispatch **pdisp) 00272 { 00273 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00274 HRESULT hres = S_OK; 00275 00276 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp); 00277 00278 *pdisp = NULL; 00279 00280 switch(V_VT(&name)) { 00281 case VT_I4: 00282 if(V_I4(&name) < 0) 00283 return E_INVALIDARG; 00284 hres = get_item_idx(This, V_I4(&name), pdisp); 00285 break; 00286 00287 case VT_UINT: 00288 hres = get_item_idx(This, V_UINT(&name), pdisp); 00289 break; 00290 00291 case VT_BSTR: { 00292 DWORD i; 00293 00294 if(V_VT(&index) == VT_I4) { 00295 LONG idx = V_I4(&index); 00296 00297 if(idx < 0) 00298 return E_INVALIDARG; 00299 00300 for(i=0; i<This->len; i++) { 00301 if(is_elem_name(This->elems[i], V_BSTR(&name)) && !idx--) 00302 break; 00303 } 00304 00305 if(i != This->len) { 00306 *pdisp = (IDispatch*)HTMLELEM(This->elems[i]); 00307 IDispatch_AddRef(*pdisp); 00308 } 00309 }else { 00310 elem_vector_t buf = {NULL, 0, 8}; 00311 00312 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 00313 00314 for(i=0; i<This->len; i++) { 00315 if(is_elem_name(This->elems[i], V_BSTR(&name))) 00316 elem_vector_add(&buf, This->elems[i]); 00317 } 00318 00319 if(buf.len > 1) { 00320 elem_vector_normalize(&buf); 00321 *pdisp = (IDispatch*)HTMLElementCollection_Create(This->ref_unk, buf.buf, buf.len); 00322 }else { 00323 if(buf.len == 1) { 00324 *pdisp = (IDispatch*)HTMLELEM(buf.buf[0]); 00325 IDispatch_AddRef(*pdisp); 00326 } 00327 00328 heap_free(buf.buf); 00329 } 00330 } 00331 break; 00332 } 00333 00334 default: 00335 FIXME("Unsupported name %s\n", debugstr_variant(&name)); 00336 hres = E_NOTIMPL; 00337 } 00338 00339 if(SUCCEEDED(hres)) 00340 TRACE("returning %p\n", *pdisp); 00341 return hres; 00342 } 00343 00344 static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface, 00345 VARIANT tagName, IDispatch **pdisp) 00346 { 00347 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00348 DWORD i; 00349 nsAString tag_str; 00350 const PRUnichar *tag; 00351 elem_vector_t buf = {NULL, 0, 8}; 00352 00353 if(V_VT(&tagName) != VT_BSTR) { 00354 WARN("Invalid arg\n"); 00355 return DISP_E_MEMBERNOTFOUND; 00356 } 00357 00358 TRACE("(%p)->(%s %p)\n", This, debugstr_w(V_BSTR(&tagName)), pdisp); 00359 00360 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 00361 00362 nsAString_Init(&tag_str, NULL); 00363 00364 for(i=0; i<This->len; i++) { 00365 if(!This->elems[i]->nselem) 00366 continue; 00367 00368 nsIDOMElement_GetTagName(This->elems[i]->nselem, &tag_str); 00369 nsAString_GetData(&tag_str, &tag); 00370 00371 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, tag, -1, 00372 V_BSTR(&tagName), -1) == CSTR_EQUAL) 00373 elem_vector_add(&buf, This->elems[i]); 00374 } 00375 00376 nsAString_Finish(&tag_str); 00377 elem_vector_normalize(&buf); 00378 00379 TRACE("fount %d tags\n", buf.len); 00380 00381 *pdisp = (IDispatch*)HTMLElementCollection_Create(This->ref_unk, buf.buf, buf.len); 00382 return S_OK; 00383 } 00384 00385 #define DISPID_ELEMCOL_0 MSHTML_DISPID_CUSTOM_MIN 00386 00387 static HRESULT HTMLElementCollection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid) 00388 { 00389 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00390 WCHAR *ptr; 00391 DWORD idx=0; 00392 00393 if(!*name) 00394 return DISP_E_UNKNOWNNAME; 00395 00396 for(ptr = name; *ptr && isdigitW(*ptr); ptr++) 00397 idx = idx*10 + (*ptr-'0'); 00398 00399 if(*ptr) { 00400 /* the name contains alpha characters, so search by name & id */ 00401 for(idx = 0; idx < This->len; ++idx) { 00402 if(is_elem_id(This->elems[idx], name) || 00403 is_elem_name(This->elems[idx], name)) 00404 break; 00405 } 00406 } 00407 00408 if(idx >= This->len) 00409 return DISP_E_UNKNOWNNAME; 00410 00411 *dispid = DISPID_ELEMCOL_0 + idx; 00412 TRACE("ret %x\n", *dispid); 00413 return S_OK; 00414 } 00415 00416 static HRESULT HTMLElementCollection_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, 00417 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) 00418 { 00419 HTMLElementCollection *This = ELEMCOL_THIS(iface); 00420 DWORD idx; 00421 00422 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller); 00423 00424 idx = id - DISPID_ELEMCOL_0; 00425 if(idx >= This->len) 00426 return DISP_E_UNKNOWNNAME; 00427 00428 switch(flags) { 00429 case DISPATCH_PROPERTYGET: 00430 V_VT(res) = VT_DISPATCH; 00431 V_DISPATCH(res) = (IDispatch*)HTMLELEM(This->elems[idx]); 00432 IHTMLElement_AddRef(HTMLELEM(This->elems[idx])); 00433 break; 00434 default: 00435 FIXME("unimplemented flags %x\n", flags); 00436 return E_NOTIMPL; 00437 } 00438 00439 return S_OK; 00440 } 00441 00442 #undef ELEMCOL_THIS 00443 00444 static const IHTMLElementCollectionVtbl HTMLElementCollectionVtbl = { 00445 HTMLElementCollection_QueryInterface, 00446 HTMLElementCollection_AddRef, 00447 HTMLElementCollection_Release, 00448 HTMLElementCollection_GetTypeInfoCount, 00449 HTMLElementCollection_GetTypeInfo, 00450 HTMLElementCollection_GetIDsOfNames, 00451 HTMLElementCollection_Invoke, 00452 HTMLElementCollection_toString, 00453 HTMLElementCollection_put_length, 00454 HTMLElementCollection_get_length, 00455 HTMLElementCollection_get__newEnum, 00456 HTMLElementCollection_item, 00457 HTMLElementCollection_tags 00458 }; 00459 00460 static const dispex_static_data_vtbl_t HTMLElementColection_dispex_vtbl = { 00461 NULL, 00462 HTMLElementCollection_get_dispid, 00463 HTMLElementCollection_invoke 00464 }; 00465 00466 static const tid_t HTMLElementCollection_iface_tids[] = { 00467 IHTMLElementCollection_tid, 00468 0 00469 }; 00470 static dispex_static_data_t HTMLElementCollection_dispex = { 00471 &HTMLElementColection_dispex_vtbl, 00472 DispHTMLElementCollection_tid, 00473 NULL, 00474 HTMLElementCollection_iface_tids 00475 }; 00476 00477 static void create_all_list(HTMLDocumentNode *doc, HTMLDOMNode *elem, elem_vector_t *buf) 00478 { 00479 nsIDOMNodeList *nsnode_list; 00480 nsIDOMNode *iter; 00481 PRUint32 list_len = 0, i; 00482 nsresult nsres; 00483 00484 nsres = nsIDOMNode_GetChildNodes(elem->nsnode, &nsnode_list); 00485 if(NS_FAILED(nsres)) { 00486 ERR("GetChildNodes failed: %08x\n", nsres); 00487 return; 00488 } 00489 00490 nsIDOMNodeList_GetLength(nsnode_list, &list_len); 00491 if(!list_len) 00492 return; 00493 00494 for(i=0; i<list_len; i++) { 00495 nsres = nsIDOMNodeList_Item(nsnode_list, i, &iter); 00496 if(NS_FAILED(nsres)) { 00497 ERR("Item failed: %08x\n", nsres); 00498 continue; 00499 } 00500 00501 if(is_elem_node(iter)) { 00502 HTMLDOMNode *node = get_node(doc, iter, TRUE); 00503 00504 elem_vector_add(buf, HTMLELEM_NODE_THIS(node)); 00505 create_all_list(doc, node, buf); 00506 } 00507 } 00508 } 00509 00510 IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_root) 00511 { 00512 elem_vector_t buf = {NULL, 0, 8}; 00513 00514 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement**)); 00515 00516 if(include_root) 00517 elem_vector_add(&buf, HTMLELEM_NODE_THIS(node)); 00518 create_all_list(node->doc, node, &buf); 00519 elem_vector_normalize(&buf); 00520 00521 return HTMLElementCollection_Create((IUnknown*)HTMLDOMNODE(node), buf.buf, buf.len); 00522 } 00523 00524 IHTMLElementCollection *create_collection_from_nodelist(HTMLDocumentNode *doc, IUnknown *unk, nsIDOMNodeList *nslist) 00525 { 00526 PRUint32 length = 0, i; 00527 elem_vector_t buf; 00528 00529 nsIDOMNodeList_GetLength(nslist, &length); 00530 00531 buf.len = 0; 00532 buf.size = length; 00533 if(length) { 00534 nsIDOMNode *nsnode; 00535 00536 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 00537 00538 for(i=0; i<length; i++) { 00539 nsIDOMNodeList_Item(nslist, i, &nsnode); 00540 if(is_elem_node(nsnode)) 00541 buf.buf[buf.len++] = HTMLELEM_NODE_THIS(get_node(doc, nsnode, TRUE)); 00542 nsIDOMNode_Release(nsnode); 00543 } 00544 00545 elem_vector_normalize(&buf); 00546 }else { 00547 buf.buf = NULL; 00548 } 00549 00550 return HTMLElementCollection_Create(unk, buf.buf, buf.len); 00551 } 00552 00553 IHTMLElementCollection *create_collection_from_htmlcol(HTMLDocumentNode *doc, IUnknown *unk, nsIDOMHTMLCollection *nscol) 00554 { 00555 PRUint32 length = 0, i; 00556 elem_vector_t buf; 00557 00558 nsIDOMHTMLCollection_GetLength(nscol, &length); 00559 00560 buf.len = buf.size = length; 00561 if(buf.len) { 00562 nsIDOMNode *nsnode; 00563 00564 buf.buf = heap_alloc(buf.size*sizeof(HTMLElement*)); 00565 00566 for(i=0; i<length; i++) { 00567 nsIDOMHTMLCollection_Item(nscol, i, &nsnode); 00568 buf.buf[i] = HTMLELEM_NODE_THIS(get_node(doc, nsnode, TRUE)); 00569 nsIDOMNode_Release(nsnode); 00570 } 00571 }else { 00572 buf.buf = NULL; 00573 } 00574 00575 return HTMLElementCollection_Create(unk, buf.buf, buf.len); 00576 } 00577 00578 static IHTMLElementCollection *HTMLElementCollection_Create(IUnknown *ref_unk, 00579 HTMLElement **elems, DWORD len) 00580 { 00581 HTMLElementCollection *ret = heap_alloc_zero(sizeof(HTMLElementCollection)); 00582 00583 ret->lpHTMLElementCollectionVtbl = &HTMLElementCollectionVtbl; 00584 ret->ref = 1; 00585 ret->elems = elems; 00586 ret->len = len; 00587 00588 init_dispex(&ret->dispex, (IUnknown*)HTMLELEMCOL(ret), &HTMLElementCollection_dispex); 00589 00590 IUnknown_AddRef(ref_unk); 00591 ret->ref_unk = ref_unk; 00592 00593 TRACE("ret=%p len=%d\n", ret, len); 00594 00595 return HTMLELEMCOL(ret); 00596 } Generated on Sun May 27 2012 04:24:55 for ReactOS by
1.7.6.1
|