LCOV - code coverage report
Current view: directory - content/xslt/src/xpath - nsXPathResult.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 186 57 30.6 %
Date: 2012-06-02 Functions: 31 12 38.7 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is TransforMiiX XSLT processor code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Peter Van der Beken <peterv@propagandism.org>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsXPathResult.h"
      40                 : #include "txExprResult.h"
      41                 : #include "txNodeSet.h"
      42                 : #include "nsDOMError.h"
      43                 : #include "mozilla/dom/Element.h"
      44                 : #include "nsIAttribute.h"
      45                 : #include "nsDOMClassInfoID.h"
      46                 : #include "nsIDOMNode.h"
      47                 : #include "nsIDOMDocument.h"
      48                 : #include "nsDOMString.h"
      49                 : #include "txXPathTreeWalker.h"
      50                 : #include "nsCycleCollectionParticipant.h"
      51                 : 
      52                 : using namespace mozilla::dom;
      53                 : 
      54              42 : nsXPathResult::nsXPathResult() : mDocument(nsnull),
      55                 :                                  mCurrentPos(0),
      56                 :                                  mResultType(ANY_TYPE),
      57                 :                                  mInvalidIteratorState(true),
      58                 :                                  mBooleanResult(false),
      59              42 :                                  mNumberResult(0)
      60                 : {
      61              42 : }
      62                 : 
      63               0 : nsXPathResult::nsXPathResult(const nsXPathResult &aResult)
      64                 :     : mResult(aResult.mResult),
      65                 :       mResultNodes(aResult.mResultNodes),
      66                 :       mDocument(aResult.mDocument),
      67                 :       mCurrentPos(0),
      68                 :       mResultType(aResult.mResultType),
      69                 :       mContextNode(aResult.mContextNode),
      70               0 :       mInvalidIteratorState(aResult.mInvalidIteratorState)
      71                 : {
      72               0 :     if (mDocument) {
      73               0 :         mDocument->AddMutationObserver(this);
      74                 :     }
      75               0 : }
      76                 : 
      77              84 : nsXPathResult::~nsXPathResult()
      78                 : {
      79              42 :     RemoveObserver();
      80              42 : }
      81                 : 
      82            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXPathResult)
      83              26 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXPathResult)
      84                 :     {
      85              26 :         tmp->RemoveObserver();
      86                 :     }
      87              26 :     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
      88              26 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      89              26 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXPathResult)
      90              26 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
      91              26 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mResultNodes)
      92              26 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      93                 : 
      94             278 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPathResult)
      95             320 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPathResult)
      96                 : 
      97                 : DOMCI_DATA(XPathResult, nsXPathResult)
      98                 : 
      99             770 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXPathResult)
     100             420 :     NS_INTERFACE_MAP_ENTRY(nsIDOMXPathResult)
     101             378 :     NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     102             378 :     NS_INTERFACE_MAP_ENTRY(nsIXPathResult)
     103             336 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMXPathResult)
     104             210 :     NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XPathResult)
     105             168 : NS_INTERFACE_MAP_END
     106                 : 
     107                 : void
     108              68 : nsXPathResult::RemoveObserver()
     109                 : {
     110              68 :     if (mDocument) {
     111               0 :         mDocument->RemoveMutationObserver(this);
     112                 :     }
     113              68 : }
     114                 : 
     115                 : NS_IMETHODIMP
     116               0 : nsXPathResult::GetResultType(PRUint16 *aResultType)
     117                 : {
     118               0 :     *aResultType = mResultType;
     119                 : 
     120               0 :     return NS_OK;
     121                 : }
     122                 : 
     123                 : NS_IMETHODIMP
     124               0 : nsXPathResult::GetNumberValue(double *aNumberValue)
     125                 : {
     126               0 :     if (mResultType != NUMBER_TYPE) {
     127               0 :         return NS_ERROR_DOM_TYPE_ERR;
     128                 :     }
     129                 : 
     130               0 :     *aNumberValue = mNumberResult;
     131                 : 
     132               0 :     return NS_OK;
     133                 : }
     134                 : 
     135                 : NS_IMETHODIMP
     136               0 : nsXPathResult::GetStringValue(nsAString &aStringValue)
     137                 : {
     138               0 :     if (mResultType != STRING_TYPE) {
     139               0 :         return NS_ERROR_DOM_TYPE_ERR;
     140                 :     }
     141                 : 
     142               0 :     aStringValue = mStringResult;
     143                 : 
     144               0 :     return NS_OK;
     145                 : }
     146                 : 
     147                 : NS_IMETHODIMP
     148               0 : nsXPathResult::GetBooleanValue(bool *aBooleanValue)
     149                 : {
     150               0 :     if (mResultType != BOOLEAN_TYPE) {
     151               0 :         return NS_ERROR_DOM_TYPE_ERR;
     152                 :     }
     153                 : 
     154               0 :     *aBooleanValue = mBooleanResult;
     155                 : 
     156               0 :     return NS_OK;
     157                 : }
     158                 : 
     159                 : NS_IMETHODIMP
     160              42 : nsXPathResult::GetSingleNodeValue(nsIDOMNode **aSingleNodeValue)
     161                 : {
     162              42 :     if (!isNode()) {
     163               0 :         return NS_ERROR_DOM_TYPE_ERR;
     164                 :     }
     165                 : 
     166              42 :     if (mResultNodes.Count() > 0) {
     167              42 :         NS_ADDREF(*aSingleNodeValue = mResultNodes[0]);
     168                 :     }
     169                 :     else {
     170               0 :         *aSingleNodeValue = nsnull;
     171                 :     }
     172                 : 
     173              42 :     return NS_OK;
     174                 : }
     175                 : 
     176                 : NS_IMETHODIMP
     177               0 : nsXPathResult::GetInvalidIteratorState(bool *aInvalidIteratorState)
     178                 : {
     179               0 :     *aInvalidIteratorState = isIterator() && mInvalidIteratorState;
     180                 : 
     181               0 :     return NS_OK;
     182                 : }
     183                 : 
     184                 : NS_IMETHODIMP
     185               0 : nsXPathResult::GetSnapshotLength(PRUint32 *aSnapshotLength)
     186                 : {
     187               0 :     if (!isSnapshot()) {
     188               0 :         return NS_ERROR_DOM_TYPE_ERR;
     189                 :     }
     190                 : 
     191               0 :     *aSnapshotLength = (PRUint32)mResultNodes.Count();
     192                 : 
     193               0 :     return NS_OK;
     194                 : }
     195                 : 
     196                 : NS_IMETHODIMP
     197               0 : nsXPathResult::IterateNext(nsIDOMNode **aResult)
     198                 : {
     199               0 :     if (!isIterator()) {
     200               0 :         return NS_ERROR_DOM_TYPE_ERR;
     201                 :     }
     202                 : 
     203               0 :     if (mDocument) {
     204               0 :         mDocument->FlushPendingNotifications(Flush_Content);
     205                 :     }
     206                 : 
     207               0 :     if (mInvalidIteratorState) {
     208               0 :         return NS_ERROR_DOM_INVALID_STATE_ERR;
     209                 :     }
     210                 : 
     211               0 :     if (mCurrentPos < (PRUint32)mResultNodes.Count()) {
     212               0 :         NS_ADDREF(*aResult = mResultNodes[mCurrentPos++]);
     213                 :     }
     214                 :     else {
     215               0 :         *aResult = nsnull;
     216                 :     }
     217                 : 
     218               0 :     return NS_OK;
     219                 : }
     220                 : 
     221                 : NS_IMETHODIMP
     222               0 : nsXPathResult::SnapshotItem(PRUint32 aIndex, nsIDOMNode **aResult)
     223                 : {
     224               0 :     if (!isSnapshot()) {
     225               0 :         return NS_ERROR_DOM_TYPE_ERR;
     226                 :     }
     227                 : 
     228               0 :     NS_IF_ADDREF(*aResult = mResultNodes.SafeObjectAt(aIndex));
     229                 : 
     230               0 :     return NS_OK;
     231                 : }
     232                 : 
     233                 : void
     234               0 : nsXPathResult::NodeWillBeDestroyed(const nsINode* aNode)
     235                 : {
     236               0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     237                 :     // Set to null to avoid unregistring unnecessarily
     238               0 :     mDocument = nsnull;
     239               0 :     Invalidate(aNode->IsNodeOfType(nsINode::eCONTENT) ?
     240               0 :                static_cast<const nsIContent*>(aNode) : nsnull);
     241               0 : }
     242                 : 
     243                 : void
     244               0 : nsXPathResult::CharacterDataChanged(nsIDocument* aDocument,
     245                 :                                     nsIContent *aContent,
     246                 :                                     CharacterDataChangeInfo* aInfo)
     247                 : {
     248               0 :     Invalidate(aContent);
     249               0 : }
     250                 : 
     251                 : void
     252               0 : nsXPathResult::AttributeChanged(nsIDocument* aDocument,
     253                 :                                 Element* aElement,
     254                 :                                 PRInt32 aNameSpaceID,
     255                 :                                 nsIAtom* aAttribute,
     256                 :                                 PRInt32 aModType)
     257                 : {
     258               0 :     Invalidate(aElement);
     259               0 : }
     260                 : 
     261                 : void
     262               0 : nsXPathResult::ContentAppended(nsIDocument* aDocument,
     263                 :                                nsIContent* aContainer,
     264                 :                                nsIContent* aFirstNewContent,
     265                 :                                PRInt32 aNewIndexInContainer)
     266                 : {
     267               0 :     Invalidate(aContainer);
     268               0 : }
     269                 : 
     270                 : void
     271               0 : nsXPathResult::ContentInserted(nsIDocument* aDocument,
     272                 :                                nsIContent* aContainer,
     273                 :                                nsIContent* aChild,
     274                 :                                PRInt32 aIndexInContainer)
     275                 : {
     276               0 :     Invalidate(aContainer);
     277               0 : }
     278                 : 
     279                 : void
     280               0 : nsXPathResult::ContentRemoved(nsIDocument* aDocument,
     281                 :                               nsIContent* aContainer,
     282                 :                               nsIContent* aChild,
     283                 :                               PRInt32 aIndexInContainer,
     284                 :                               nsIContent* aPreviousSibling)
     285                 : {
     286               0 :     Invalidate(aContainer);
     287               0 : }
     288                 : 
     289                 : nsresult
     290              42 : nsXPathResult::SetExprResult(txAExprResult* aExprResult, PRUint16 aResultType,
     291                 :                              nsINode* aContextNode)
     292                 : {
     293             126 :     if ((isSnapshot(aResultType) || isIterator(aResultType) ||
     294              42 :          isNode(aResultType)) &&
     295              42 :         aExprResult->getResultType() != txAExprResult::NODESET) {
     296                 :         // The DOM spec doesn't really say what should happen when reusing an
     297                 :         // XPathResult and an error is thrown. Let's not touch the XPathResult
     298                 :         // in that case.
     299               0 :         return NS_ERROR_DOM_TYPE_ERR;
     300                 :     }
     301                 : 
     302              42 :     mResultType = aResultType;
     303              42 :     mContextNode = do_GetWeakReference(aContextNode);
     304                 : 
     305              42 :     if (mDocument) {
     306               0 :         mDocument->RemoveMutationObserver(this);
     307               0 :         mDocument = nsnull;
     308                 :     }
     309                 :  
     310              42 :     mResultNodes.Clear();
     311                 : 
     312                 :     // XXX This will keep the recycler alive, should we clear it?
     313              42 :     mResult = aExprResult;
     314              42 :     mBooleanResult = mResult->booleanValue();
     315              42 :     mNumberResult = mResult->numberValue();
     316              42 :     mResult->stringValue(mStringResult);
     317                 : 
     318              42 :     if (aExprResult && aExprResult->getResultType() == txAExprResult::NODESET) {
     319              42 :         txNodeSet *nodeSet = static_cast<txNodeSet*>(aExprResult);
     320              84 :         nsCOMPtr<nsIDOMNode> node;
     321              42 :         PRInt32 i, count = nodeSet->size();
     322              84 :         for (i = 0; i < count; ++i) {
     323              42 :             txXPathNativeNode::getNode(nodeSet->get(i), getter_AddRefs(node));
     324              42 :             if (node) {
     325              42 :                 mResultNodes.AppendObject(node);
     326                 :             }
     327                 :         }
     328                 : 
     329              42 :         if (count > 0) {
     330              42 :             mResult = nsnull;
     331                 :         }
     332                 :     }
     333                 : 
     334              42 :     if (!isIterator()) {
     335              42 :         return NS_OK;
     336                 :     }
     337                 : 
     338               0 :     mInvalidIteratorState = false;
     339                 : 
     340               0 :     if (mResultNodes.Count() > 0) {
     341                 :         // If we support the document() function in DOM-XPath we need to
     342                 :         // observe all documents that we have resultnodes in.
     343               0 :         nsCOMPtr<nsIDOMDocument> document;
     344               0 :         mResultNodes[0]->GetOwnerDocument(getter_AddRefs(document));
     345               0 :         if (document) {
     346               0 :             mDocument = do_QueryInterface(document);
     347                 :         }
     348                 :         else {
     349               0 :             mDocument = do_QueryInterface(mResultNodes[0]);
     350                 :         }
     351                 : 
     352               0 :         NS_ASSERTION(mDocument, "We need a document!");
     353               0 :         if (mDocument) {
     354               0 :             mDocument->AddMutationObserver(this);
     355                 :         }
     356                 :     }
     357                 : 
     358               0 :     return NS_OK;
     359                 : }
     360                 : 
     361                 : void
     362               0 : nsXPathResult::Invalidate(const nsIContent* aChangeRoot)
     363                 : {
     364               0 :     nsCOMPtr<nsINode> contextNode = do_QueryReferent(mContextNode);
     365               0 :     if (contextNode && aChangeRoot && aChangeRoot->GetBindingParent()) {
     366                 :         // If context node is in anonymous content, changes to
     367                 :         // non-anonymous content need to invalidate the XPathResult. If
     368                 :         // the changes are happening in a different anonymous trees, no
     369                 :         // invalidation should happen.
     370               0 :         nsIContent* ctxBindingParent = nsnull;
     371               0 :         if (contextNode->IsNodeOfType(nsINode::eCONTENT)) {
     372                 :             ctxBindingParent =
     373               0 :                 static_cast<nsIContent*>(contextNode.get())
     374               0 :                     ->GetBindingParent();
     375               0 :         } else if (contextNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
     376                 :             nsIContent* parent =
     377               0 :               static_cast<nsIAttribute*>(contextNode.get())->GetContent();
     378               0 :             if (parent) {
     379               0 :                 ctxBindingParent = parent->GetBindingParent();
     380                 :             }
     381                 :         }
     382               0 :         if (ctxBindingParent != aChangeRoot->GetBindingParent()) {
     383                 :           return;
     384                 :         }
     385                 :     }
     386                 : 
     387               0 :     mInvalidIteratorState = true;
     388                 :     // Make sure nulling out mDocument is the last thing we do.
     389               0 :     if (mDocument) {
     390               0 :         mDocument->RemoveMutationObserver(this);
     391               0 :         mDocument = nsnull;
     392                 :     }
     393                 : }
     394                 : 
     395                 : nsresult
     396               0 : nsXPathResult::GetExprResult(txAExprResult** aExprResult)
     397                 : {
     398               0 :     if (isIterator() && mInvalidIteratorState) {
     399               0 :         return NS_ERROR_DOM_INVALID_STATE_ERR;
     400                 :     }
     401                 : 
     402               0 :     if (mResult) {
     403               0 :         NS_ADDREF(*aExprResult = mResult);
     404                 : 
     405               0 :         return NS_OK;
     406                 :     }
     407                 : 
     408               0 :     if (mResultNodes.Count() == 0) {
     409               0 :         return NS_ERROR_DOM_INVALID_STATE_ERR;
     410                 :     }
     411                 : 
     412               0 :     nsRefPtr<txNodeSet> nodeSet = new txNodeSet(nsnull);
     413               0 :     if (!nodeSet) {
     414               0 :         return NS_ERROR_OUT_OF_MEMORY;
     415                 :     }
     416                 : 
     417               0 :     PRUint32 i, count = mResultNodes.Count();
     418               0 :     for (i = 0; i < count; ++i) {
     419               0 :         nsAutoPtr<txXPathNode> node(txXPathNativeNode::createXPathNode(mResultNodes[i]));
     420               0 :         if (!node) {
     421               0 :             return NS_ERROR_OUT_OF_MEMORY;
     422                 :         }
     423                 : 
     424               0 :         nodeSet->append(*node);
     425                 :     }
     426                 : 
     427               0 :     NS_ADDREF(*aExprResult = nodeSet);
     428                 : 
     429               0 :     return NS_OK;
     430                 : }
     431                 : 
     432                 : nsresult
     433               0 : nsXPathResult::Clone(nsIXPathResult **aResult)
     434                 : {
     435               0 :     *aResult = nsnull;
     436                 : 
     437               0 :     if (isIterator() && mInvalidIteratorState) {
     438               0 :         return NS_ERROR_DOM_INVALID_STATE_ERR;
     439                 :     }
     440                 : 
     441               0 :     nsCOMPtr<nsIXPathResult> result = new nsXPathResult(*this);
     442               0 :     if (!result) {
     443               0 :         return NS_ERROR_OUT_OF_MEMORY;
     444                 :     }
     445                 : 
     446               0 :     result.swap(*aResult);
     447                 : 
     448               0 :     return NS_OK;
     449            4392 : }

Generated by: LCOV version 1.7