Back to index

lightning-sunbird  0.9+nobinonly
IEHtmlElementCollection.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Adam Lock <adamlock@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "stdafx.h"
00039 
00040 #include "nsIDOMDocumentTraversal.h"
00041 #include "nsIDOMTreeWalker.h"
00042 #include "nsIDOMNodeFilter.h"
00043 #include "nsIDOMDocument.h"
00044 #include "nsIDOMHtmlElement.h"
00045 
00046 #include "nsString.h"
00047 
00048 #include "IEHtmlElement.h"
00049 #include "IEHtmlElementCollection.h"
00050 
00051 CIEHtmlElementCollection::CIEHtmlElementCollection()
00052 {
00053     mNodeList = NULL;
00054     mNodeListCount = 0;
00055     mNodeListCapacity = 0;
00056 }
00057 
00058 CIEHtmlElementCollection::~CIEHtmlElementCollection()
00059 {
00060     // Clean the node list
00061     if (mNodeList)
00062     {
00063         for (PRUint32 i = 0; i < mNodeListCount; i++)
00064         {
00065             IDispatch *pDisp = mNodeList[i];
00066             if (pDisp)
00067             {
00068                 pDisp->Release();
00069             }
00070         }
00071         free(mNodeList);
00072         mNodeList = NULL;
00073         mNodeListCount = 0;
00074         mNodeListCapacity = 0;
00075     }
00076 }
00077 
00078 HRESULT CIEHtmlElementCollection::FindOrCreateIEElement(nsIDOMNode* domNode, IHTMLElement** pIHtmlElement)
00079 {
00080     CComPtr<IUnknown> pNode;
00081     HRESULT hr = CIEHtmlDomNode::FindOrCreateFromDOMNode(domNode, &pNode);
00082     if (FAILED(hr))
00083         return hr;
00084     if (FAILED(pNode->QueryInterface(IID_IHTMLElement, (void**)pIHtmlElement)))
00085         return E_UNEXPECTED;
00086     return S_OK;
00087 }
00088 
00089 HRESULT CIEHtmlElementCollection::PopulateFromDOMHTMLCollection(nsIDOMHTMLCollection *pNodeList)
00090 {
00091     if (pNodeList == nsnull)
00092     {
00093         return S_OK;
00094     }
00095 
00096     // Recurse through the children of the node (and the children of that)
00097     // to populate the collection
00098 
00099     // Iterate through items in list
00100     PRUint32 length = 0;
00101     pNodeList->GetLength(&length);
00102     for (PRUint32 i = 0; i < length; i++)
00103     {
00104         // Get the next item from the list
00105         nsCOMPtr<nsIDOMNode> childNode;
00106         pNodeList->Item(i, getter_AddRefs(childNode));
00107         if (!childNode)
00108         {
00109             // Empty node (unexpected, but try and carry on anyway)
00110             NS_ASSERTION(0, "Empty node");
00111             continue;
00112         }
00113 
00114         // Skip nodes representing, text, attributes etc.
00115         PRUint16 nodeType;
00116         childNode->GetNodeType(&nodeType);
00117         if (nodeType != nsIDOMNode::ELEMENT_NODE)
00118         {
00119             continue;
00120         }
00121 
00122         // Create an equivalent IE element
00123         CComQIPtr<IHTMLElement> pHtmlElement;
00124         HRESULT hr = FindOrCreateIEElement(childNode, &pHtmlElement);
00125         if (FAILED(hr))
00126             return hr;
00127         AddNode(pHtmlElement);
00128     }
00129     return S_OK;
00130 }
00131 
00132 HRESULT CIEHtmlElementCollection::PopulateFromDOMNode(nsIDOMNode *aDOMNode, BOOL bRecurseChildren)
00133 {
00134     if (aDOMNode == nsnull)
00135     {
00136         NS_ASSERTION(0, "No dom node");
00137         return E_INVALIDARG;
00138     }
00139 
00140     PRBool hasChildNodes = PR_FALSE;
00141     aDOMNode->HasChildNodes(&hasChildNodes);
00142     if (hasChildNodes)
00143     {
00144         if (bRecurseChildren)
00145         {
00146             nsresult rv;
00147 
00148             // Search through parent nodes, looking for the DOM document
00149             nsCOMPtr<nsIDOMNode> docAsNode = aDOMNode;
00150             nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDOMNode);
00151             while (!doc) {
00152                 nsCOMPtr<nsIDOMNode> parentNode;
00153                 docAsNode->GetParentNode(getter_AddRefs(parentNode));
00154                 docAsNode = parentNode;
00155                 if (!docAsNode)
00156                 {
00157                     return E_FAIL;
00158                 }
00159                 doc = do_QueryInterface(docAsNode);
00160             }
00161 
00162             // Walk the DOM
00163             nsCOMPtr<nsIDOMDocumentTraversal> trav = do_QueryInterface(doc, &rv);
00164             NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
00165             nsCOMPtr<nsIDOMTreeWalker> walker;
00166             rv = trav->CreateTreeWalker(aDOMNode, 
00167                 nsIDOMNodeFilter::SHOW_ELEMENT,
00168                 nsnull, PR_TRUE, getter_AddRefs(walker));
00169             NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
00170 
00171             // We're not interested in the document node, so we always start
00172             // with the next one, walking through them all to make the collection
00173             nsCOMPtr<nsIDOMNode> currentNode;
00174             walker->FirstChild(getter_AddRefs(currentNode));
00175             while (currentNode)
00176             {
00177                 // Create an equivalent IE element
00178                 CComQIPtr<IHTMLElement> pHtmlElement;
00179                 HRESULT hr = FindOrCreateIEElement(currentNode, &pHtmlElement);
00180                 if (FAILED(hr))
00181                     return hr;
00182                 AddNode(pHtmlElement);
00183                 walker->NextNode(getter_AddRefs(currentNode));
00184             }
00185         }
00186         else
00187         {
00188             nsCOMPtr<nsIDOMNodeList> nodeList;
00189             aDOMNode->GetChildNodes(getter_AddRefs(nodeList));
00190             mDOMNodeList = nodeList;
00191         }
00192     }
00193     return S_OK;
00194 }
00195 
00196 
00197 HRESULT CIEHtmlElementCollection::CreateFromDOMHTMLCollection(CNode *pParentNode, nsIDOMHTMLCollection *pNodeList, CIEHtmlElementCollection **pInstance)
00198 {
00199     if (pInstance == NULL || pParentNode == NULL)
00200     {
00201         NS_ASSERTION(0, "No instance or parent node");
00202         return E_INVALIDARG;
00203     }
00204 
00205     // Get the DOM node from the parent node
00206     if (!pParentNode->mDOMNode)
00207     {
00208         NS_ASSERTION(0, "Parent has no DOM node");
00209         return E_INVALIDARG;
00210     }
00211 
00212     *pInstance = NULL;
00213 
00214     // Create a collection object
00215     CIEHtmlElementCollectionInstance *pCollection = NULL;
00216     CIEHtmlElementCollectionInstance::CreateInstance(&pCollection);
00217     if (pCollection == NULL)
00218     {
00219         NS_ASSERTION(0, "Could not create collection");
00220         return E_OUTOFMEMORY;
00221     }
00222 
00223     // Initialise and populate the collection
00224     pCollection->SetParent(pParentNode);
00225     pCollection->PopulateFromDOMHTMLCollection(pNodeList);
00226 
00227     *pInstance = pCollection;
00228 
00229     return S_OK;
00230 }
00231 
00232 HRESULT CIEHtmlElementCollection::CreateFromParentNode(CNode *pParentNode, BOOL bRecurseChildren, CIEHtmlElementCollection **pInstance)
00233 {
00234     if (pInstance == NULL || pParentNode == NULL)
00235     {
00236         NS_ASSERTION(0, "No instance or parent node");
00237         return E_INVALIDARG;
00238     }
00239 
00240     // Get the DOM node from the parent node
00241     if (!pParentNode->mDOMNode)
00242     {
00243         NS_ASSERTION(0, "Parent has no DOM node");
00244         return E_INVALIDARG;
00245     }
00246 
00247     *pInstance = NULL;
00248 
00249     // Create a collection object
00250     CIEHtmlElementCollectionInstance *pCollection = NULL;
00251     CIEHtmlElementCollectionInstance::CreateInstance(&pCollection);
00252     if (pCollection == NULL)
00253     {
00254         NS_ASSERTION(0, "Could not create collection");
00255         return E_OUTOFMEMORY;
00256     }
00257 
00258     // Initialise and populate the collection
00259     pCollection->SetParent(pParentNode);
00260     pCollection->PopulateFromDOMNode(pParentNode->mDOMNode, bRecurseChildren);
00261 
00262     *pInstance = pCollection;
00263 
00264     return S_OK;
00265 }
00266 
00267 
00268 HRESULT CIEHtmlElementCollection::AddNode(IDispatch *pNode)
00269 {
00270     if (pNode == NULL)
00271     {
00272         NS_ASSERTION(0, "No node");
00273         return E_INVALIDARG;
00274     }
00275 
00276     const PRUint32 c_NodeListResizeBy = 100;
00277 
00278     if (mNodeList == NULL)
00279     {
00280         mNodeListCapacity = c_NodeListResizeBy;
00281         mNodeList = (IDispatch **) malloc(sizeof(IDispatch *) * mNodeListCapacity);
00282         mNodeListCount = 0;
00283     }
00284     else if (mNodeListCount == mNodeListCapacity)
00285     {
00286         mNodeListCapacity += c_NodeListResizeBy;
00287         mNodeList = (IDispatch **) realloc(mNodeList, sizeof(IDispatch *) * mNodeListCapacity);
00288     }
00289 
00290     if (mNodeList == NULL)
00291     {
00292         NS_ASSERTION(0, "Could not realloc node list");
00293         return E_OUTOFMEMORY;
00294     }
00295 
00296     pNode->AddRef();
00297     mNodeList[mNodeListCount++] = pNode;
00298 
00299     return S_OK;
00300 }
00301 
00302 
00304 // IHTMLElementCollection methods
00305 
00306 
00307 HRESULT STDMETHODCALLTYPE CIEHtmlElementCollection::toString(BSTR __RPC_FAR *String)
00308 {
00309     if (String == NULL)
00310     {
00311         return E_INVALIDARG;
00312     }
00313     *String = SysAllocString(OLESTR("ElementCollection"));
00314     return S_OK;
00315 }
00316 
00317 
00318 HRESULT STDMETHODCALLTYPE CIEHtmlElementCollection::put_length(long v)
00319 {
00320     // What is the point of this method?
00321     return S_OK;
00322 }
00323 
00324 
00325 HRESULT STDMETHODCALLTYPE CIEHtmlElementCollection::get_length(long __RPC_FAR *p)
00326 {
00327     if (p == NULL)
00328     {
00329         return E_INVALIDARG;
00330     }
00331     
00332     // Return the size of the collection
00333     if (mDOMNodeList)
00334     {
00335         // Count the number of elements in the list
00336         PRUint32 elementCount = 0;
00337         PRUint32 length = 0;
00338         mDOMNodeList->GetLength(&length);
00339         for (PRUint32 i = 0; i < length; i++)
00340         {
00341             // Get the next item from the list
00342             nsCOMPtr<nsIDOMNode> childNode;
00343             mDOMNodeList->Item(i, getter_AddRefs(childNode));
00344             if (!childNode)
00345             {
00346                 // Empty node (unexpected, but try and carry on anyway)
00347                 NS_ASSERTION(0, "Empty node");
00348                 continue;
00349             }
00350 
00351             // Only count elements
00352             PRUint16 nodeType;
00353             childNode->GetNodeType(&nodeType);
00354             if (nodeType == nsIDOMNode::ELEMENT_NODE)
00355             {
00356                 elementCount++;
00357             }
00358         }
00359         *p = elementCount;
00360     }
00361     else
00362     {
00363         *p = mNodeListCount;
00364     }
00365     return S_OK;
00366 }
00367 
00368 typedef CComObject<CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > > CComEnumVARIANT;
00369 
00370 HRESULT STDMETHODCALLTYPE CIEHtmlElementCollection::get__newEnum(IUnknown __RPC_FAR *__RPC_FAR *p)
00371 {
00372     TRACE_METHOD(CIEHtmlElementCollection::get__newEnum);
00373 
00374     if (p == NULL)
00375     {
00376         return E_INVALIDARG;
00377     }
00378 
00379     *p = NULL;
00380 
00381     // Create a new IEnumVARIANT object
00382     CComEnumVARIANT *pEnumVARIANT = NULL;
00383     CComEnumVARIANT::CreateInstance(&pEnumVARIANT);
00384     if (pEnumVARIANT == NULL)
00385     {
00386         NS_ASSERTION(0, "Could not creat Enum");
00387         return E_OUTOFMEMORY;
00388     }
00389 
00390     int nObject = 0;
00391     long nObjects = 0;
00392     get_length(&nObjects);
00393 
00394     // Create an array of VARIANTs
00395     VARIANT *avObjects = new VARIANT[nObjects];
00396     if (avObjects == NULL)
00397     {
00398         NS_ASSERTION(0, "Could not create variant array");
00399         return E_OUTOFMEMORY;
00400     }
00401 
00402     if (mDOMNodeList)
00403     {
00404         // Fill the variant array with elements from the DOM node list
00405         PRUint32 length = 0;
00406         mDOMNodeList->GetLength(&length);
00407         for (PRUint32 i = 0; i < length; i++)
00408         {
00409             // Get the next item from the list
00410             nsCOMPtr<nsIDOMNode> childNode;
00411             mDOMNodeList->Item(i, getter_AddRefs(childNode));
00412             if (!childNode)
00413             {
00414                 // Empty node (unexpected, but try and carry on anyway)
00415                 NS_ASSERTION(0, "Could not get node");
00416                 continue;
00417             }
00418 
00419             // Skip nodes representing, text, attributes etc.
00420             PRUint16 nodeType;
00421             childNode->GetNodeType(&nodeType);
00422             if (nodeType != nsIDOMNode::ELEMENT_NODE)
00423             {
00424                 continue;
00425             }
00426 
00427             // Store the element in the array
00428             CComQIPtr<IHTMLElement> pHtmlElement;
00429             HRESULT hr = FindOrCreateIEElement(childNode, &pHtmlElement);
00430             if (FAILED(hr))
00431                 return hr;
00432             VARIANT *pVariant = &avObjects[nObject++];
00433             VariantInit(pVariant);
00434             pVariant->vt = VT_DISPATCH;
00435             pHtmlElement->QueryInterface(IID_IDispatch, (void **) &pVariant->pdispVal);
00436         }
00437     }
00438     else
00439     {
00440         // Copy the contents of the collection to the array
00441         for (nObject = 0; nObject < nObjects; nObject++)
00442         {
00443             VARIANT *pVariant = &avObjects[nObject];
00444             IDispatch *pDispObject = mNodeList[nObject];
00445             VariantInit(pVariant);
00446             pVariant->vt = VT_DISPATCH;
00447             pVariant->pdispVal = pDispObject;
00448             pDispObject->AddRef();
00449         }
00450     }
00451 
00452     // Copy the variants to the enumeration object
00453     pEnumVARIANT->Init(&avObjects[0], &avObjects[nObjects], NULL, AtlFlagCopy);
00454 
00455     // Cleanup the array
00456     for (nObject = 0; nObject < nObjects; nObject++)
00457     {
00458         VARIANT *pVariant = &avObjects[nObject];
00459         VariantClear(pVariant);
00460     }
00461     delete []avObjects;
00462 
00463     return pEnumVARIANT->QueryInterface(IID_IUnknown, (void**) p);
00464 }
00465 
00466 
00467 HRESULT STDMETHODCALLTYPE CIEHtmlElementCollection::item(VARIANT name, VARIANT index, IDispatch __RPC_FAR *__RPC_FAR *pdisp)
00468 {
00469     TRACE_METHOD(CIEHtmlElementCollection::item);
00470 
00471     if (pdisp == NULL)
00472     {
00473         return E_INVALIDARG;
00474     }
00475     
00476     *pdisp = NULL;
00477 
00478     // Parameter name is either a string or a number
00479 
00480     PRBool searchForName = PR_FALSE;
00481     nsAutoString nameToSearch;
00482     PRInt32 idxForSearch = 0;
00483 
00484     if (name.vt == VT_BSTR && name.bstrVal && wcslen(name.bstrVal) > 0)
00485     {
00486         nameToSearch.Assign(name.bstrVal);
00487         searchForName = PR_TRUE;
00488     }
00489     else switch (name.vt)
00490     {
00491     case VT_UI1:
00492     case VT_UI2:
00493     case VT_UI4:
00494     case VT_I1:
00495     case VT_I2:
00496     case VT_I1 | VT_BYREF:
00497     case VT_I2 | VT_BYREF:
00498         // Coerce the variant into a long
00499         if (FAILED(VariantChangeType(&name, &name, 0, VT_I4)))
00500         {
00501             return E_INVALIDARG;
00502         }
00503         // Fall through
00504     case VT_I4:
00505         idxForSearch = name.lVal;
00506         if (idxForSearch < 0)
00507             return E_INVALIDARG;
00508         break;
00509     default:
00510         // Unknown arg.
00511         // As per documentation, no attempt to be lenient with crappy clients
00512         // for the time being.
00513         return E_INVALIDARG;
00514     }
00515 
00516     CIEHtmlElementCollectionInstance* pCollection = NULL;
00517 
00518     if (mDOMNodeList)
00519     {
00520         CComQIPtr<IHTMLElement> pHtmlElement;
00521         // Search for the Nth element in the list
00522         PRUint32 elementCount = 0;
00523         PRUint32 length = 0;
00524         mDOMNodeList->GetLength(&length);
00525         for (PRUint32 i = 0; i < length; i++)
00526         {
00527             // Get the next item from the list
00528             nsCOMPtr<nsIDOMNode> childNode;
00529             mDOMNodeList->Item(i, getter_AddRefs(childNode));
00530             if (!childNode)
00531             {
00532                 // Empty node (unexpected, but try and carry on anyway)
00533                 NS_ASSERTION(0, "Could not get node");
00534                 continue;
00535             }
00536 
00537             // Skip nodes representing, text, attributes etc.
00538             nsCOMPtr<nsIDOMElement> nodeAsElement = do_QueryInterface(childNode);
00539             if (!nodeAsElement)
00540             {
00541                 continue;
00542             }
00543 
00544             // Have we found the element we need?
00545             PRBool grabThisNode = PR_FALSE;
00546             if (searchForName)
00547             {
00548                 nsCOMPtr<nsIDOMHTMLElement> nodeAsHtmlElement = do_QueryInterface(childNode);
00549                 if (nodeAsHtmlElement)
00550                 {
00551                     NS_NAMED_LITERAL_STRING(nameAttr, "name");
00552                     nsAutoString nodeName;
00553                     nsAutoString nodeId;
00554                     nodeAsHtmlElement->GetAttribute(nameAttr, nodeName);
00555                     nodeAsHtmlElement->GetId(nodeId);
00556                     if (nodeName.Equals(nameToSearch) || nodeId.Equals(nameToSearch))
00557                     {
00558                         grabThisNode = PR_TRUE;
00559                     }
00560                 }
00561             }
00562             else if (elementCount == idxForSearch)
00563             {
00564                 grabThisNode = PR_TRUE;
00565             }
00566 
00567             if (grabThisNode)
00568             {
00569                 if (pHtmlElement)
00570                 {
00571                     if (pCollection == NULL)
00572                         CIEHtmlElementCollectionInstance::CreateInstance(&pCollection);
00573                     // Add existing to collection
00574                     pCollection->AddNode(pHtmlElement);
00575                 }
00576                 // Create new element:
00577                 HRESULT hr = FindOrCreateIEElement(childNode, &pHtmlElement);
00578                 if (FAILED(hr))
00579                     return hr; 
00580                 ((CIEHtmlElement*)pHtmlElement.p)->SetParent(mParent);
00581                 }
00582             elementCount++;
00583         }
00584         // Return the element or collection :
00585         if (pCollection != NULL)
00586         {
00587             // Add last created element to collection
00588             pCollection->AddNode(pHtmlElement);
00589             pCollection->QueryInterface(IID_IDispatch, (void **) pdisp);
00590         }
00591         else if (pHtmlElement != NULL)
00592             pHtmlElement->QueryInterface(IID_IDispatch, (void **) pdisp);
00593     }
00594     else
00595     {
00596         if (searchForName)
00597         {
00598             CComPtr<IHTMLElement> element = NULL;
00599             for (PRUint32 i = 0; i < mNodeListCount; i++)
00600             {
00601                 CComQIPtr<IHTMLElement> currElement = mNodeList[i];
00602                 if (currElement.p)
00603                 {
00604                     CComVariant elementName;
00605                     CComBSTR elementId;
00606                     currElement->get_id(&elementId);
00607                     currElement->getAttribute(L"name", 0, &elementName);
00608                     if ((elementId && wcscmp(elementId, name.bstrVal) == 0) ||
00609                         (elementName.vt == VT_BSTR && elementName.bstrVal &&
00610                         wcscmp(elementName.bstrVal, name.bstrVal) == 0))
00611                     {
00612                         if (element != NULL)
00613                         {
00614                             if (!pCollection)
00615                                 CIEHtmlElementCollectionInstance::CreateInstance(&pCollection);
00616                             pCollection->AddNode(element);
00617                         }
00618                         element = currElement;
00619                     }
00620                 }
00621             }
00622             // Return the element or collection :
00623             if (pCollection != NULL)
00624             {
00625                 pCollection->AddNode(element);
00626                 pCollection->QueryInterface(IID_IDispatch, (void **) pdisp);
00627             }
00628             else if (element != NULL)
00629                 element->QueryInterface(IID_IDispatch, (void **) pdisp);
00630         }
00631         else
00632         {
00633             // Test for stupid values
00634             if (idxForSearch >= mNodeListCount)
00635             {
00636                 return E_INVALIDARG;
00637             }
00638 
00639             *pdisp = NULL;
00640             IDispatch *pNode = mNodeList[idxForSearch];
00641             if (pNode == NULL)
00642             {
00643                 NS_ASSERTION(0, "No node");
00644                 return E_UNEXPECTED;
00645             }
00646             pNode->QueryInterface(IID_IDispatch, (void **) pdisp);
00647         }
00648     }
00649 
00650     // Note: As per docs S_OK is fine even if no node is returned
00651     return S_OK;
00652 }
00653 
00654 HRESULT STDMETHODCALLTYPE CIEHtmlElementCollection::tags(VARIANT tagName, IDispatch __RPC_FAR *__RPC_FAR *pdisp)
00655 {
00656     if (pdisp == NULL || tagName.vt != VT_BSTR)
00657     {
00658         return E_INVALIDARG;
00659     }
00660     
00661     *pdisp = NULL;
00662 
00663     CIEHtmlElementCollectionInstance* pCollection = NULL;
00664     CIEHtmlElementCollectionInstance::CreateInstance(&pCollection);
00665     if (mNodeList)
00666     {
00667         for (PRUint32 i = 0; i < mNodeListCount; i++)
00668         {
00669             CComQIPtr<IHTMLElement> element = mNodeList[i];
00670             if (element.p)
00671             {
00672                 CComBSTR elementTagName;
00673                 element->get_tagName(&elementTagName);
00674                 if (elementTagName && _wcsicmp(elementTagName, tagName.bstrVal) == 0)
00675                     pCollection->AddNode(element);
00676             }
00677         }
00678         pCollection->QueryInterface(IID_IDispatch, (void**)pdisp);
00679         return S_OK;
00680     }
00681     else if (mDOMNodeList)
00682     {
00683         PRUint32 length = 0;
00684         mDOMNodeList->GetLength(&length);
00685         for (PRUint32 i = 0; i < length; i++)
00686         {
00687             // Get the next item from the list
00688             nsCOMPtr<nsIDOMNode> childNode;
00689             mDOMNodeList->Item(i, getter_AddRefs(childNode));
00690             if (!childNode)
00691             {
00692                 // Empty node (unexpected, but try and carry on anyway)
00693                 NS_ASSERTION(0, "Could not get node");
00694                 continue;
00695             }
00696 
00697             // Skip nodes representing, text, attributes etc.
00698             nsCOMPtr<nsIDOMElement> nodeAsElement = do_QueryInterface(childNode);
00699             if (!nodeAsElement)
00700             {
00701                 continue;
00702             }
00703     
00704             nsCOMPtr<nsIDOMHTMLElement> nodeAsHtmlElement = do_QueryInterface(childNode);
00705             if (nodeAsHtmlElement)
00706             {
00707                 nsAutoString elementTagName;
00708                 nodeAsHtmlElement->GetTagName(elementTagName);
00709                 if (_wcsicmp(elementTagName.get(), OLE2CW(tagName.bstrVal)) == 0)
00710                 {
00711                     CComQIPtr<IHTMLElement> pHtmlElement;
00712                     HRESULT hr = FindOrCreateIEElement(childNode, &pHtmlElement);
00713                     if (FAILED(hr))
00714                         return hr;
00715                     //Add to collection :
00716                     pCollection->AddNode(pHtmlElement);
00717                 }
00718             }
00719         }
00720         pCollection->QueryInterface(IID_IDispatch, (void**)pdisp);
00721         return S_OK;
00722     }
00723     return E_UNEXPECTED;
00724 }
00725