diff --git a/dom/webidl/XSLTProcessor.webidl b/dom/webidl/XSLTProcessor.webidl index 2215a98feae3..69b195ded7d9 100644 --- a/dom/webidl/XSLTProcessor.webidl +++ b/dom/webidl/XSLTProcessor.webidl @@ -88,13 +88,11 @@ interface XSLTProcessor { * the processor use the default-value for all parameters as specified in * the stylesheet. */ - [Throws] undefined clearParameters(); /** * Remove all parameters and stylesheets from this XSLTProcessor. */ - [Throws] undefined reset(); /** diff --git a/dom/xslt/xml/txXMLParser.cpp b/dom/xslt/xml/txXMLParser.cpp index 1d576cdbacfc..779e198fb1da 100644 --- a/dom/xslt/xml/txXMLParser.cpp +++ b/dom/xslt/xml/txXMLParser.cpp @@ -12,15 +12,16 @@ #include "nsNetUtil.h" #include "nsIURI.h" -using namespace mozilla; using namespace mozilla::dom; -Result txParseDocumentFromURI(const nsAString& aHref, - const txXPathNode& aLoader, - nsAString& aErrMsg) { +nsresult txParseDocumentFromURI(const nsAString& aHref, + const txXPathNode& aLoader, nsAString& aErrMsg, + txXPathNode** aResult) { + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nullptr; nsCOMPtr documentURI; nsresult rv = NS_NewURI(getter_AddRefs(documentURI), aHref); - NS_ENSURE_SUCCESS(rv, Err(rv)); + NS_ENSURE_SUCCESS(rv, rv); Document* loaderDocument = txXPathNativeNode::getDocument(aLoader); @@ -31,7 +32,7 @@ Result txParseDocumentFromURI(const nsAString& aHref, // Raw pointer, we want the resulting txXPathNode to hold a reference to // the document. - nsCOMPtr theDocument; + Document* theDocument = nullptr; nsAutoSyncOperation sync(loaderDocument, SyncOperationBehavior::eSuspendInput); rv = nsSyncLoadService::LoadDocument( @@ -39,14 +40,20 @@ Result txParseDocumentFromURI(const nsAString& aHref, loaderDocument->NodePrincipal(), nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT, loadGroup, loaderDocument->CookieJarSettings(), true, - loaderDocument->GetReferrerPolicy(), getter_AddRefs(theDocument)); + loaderDocument->GetReferrerPolicy(), &theDocument); if (NS_FAILED(rv)) { aErrMsg.AppendLiteral("Document load of "); aErrMsg.Append(aHref); aErrMsg.AppendLiteral(" failed."); - return Err(rv); + return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE; } - return txXPathNode(theDocument); + *aResult = txXPathNativeNode::createXPathNode(theDocument); + if (!*aResult) { + NS_RELEASE(theDocument); + return NS_ERROR_FAILURE; + } + + return NS_OK; } diff --git a/dom/xslt/xml/txXMLParser.h b/dom/xslt/xml/txXMLParser.h index ba800a7b2b39..83f22215062b 100644 --- a/dom/xslt/xml/txXMLParser.h +++ b/dom/xslt/xml/txXMLParser.h @@ -10,11 +10,6 @@ class txXPathNode; -namespace mozilla { -template -class Result; -} // namespace mozilla - /** * API to load XML files into DOM datastructures. * Parsing is either done by expat, or by expat via the syncloaderservice @@ -24,7 +19,9 @@ class Result; * Parse a document from the aHref location, with referrer URI on behalf * of the document aLoader. */ -mozilla::Result txParseDocumentFromURI( - const nsAString& aHref, const txXPathNode& aLoader, nsAString& aErrMsg); +extern "C" nsresult txParseDocumentFromURI(const nsAString& aHref, + const txXPathNode& aLoader, + nsAString& aErrMsg, + txXPathNode** aResult); #endif diff --git a/dom/xslt/xpath/XPathExpression.cpp b/dom/xslt/xpath/XPathExpression.cpp index cf226a39c540..0706763d79f2 100644 --- a/dom/xslt/xpath/XPathExpression.cpp +++ b/dom/xslt/xpath/XPathExpression.cpp @@ -23,9 +23,9 @@ namespace mozilla::dom { class EvalContextImpl : public txIEvalContext { public: - EvalContextImpl(txXPathNode&& aContextNode, uint32_t aContextPosition, + EvalContextImpl(const txXPathNode& aContextNode, uint32_t aContextPosition, uint32_t aContextSize, txResultRecycler* aRecycler) - : mContextNode(std::move(aContextNode)), + : mContextNode(aContextNode), mContextPosition(aContextPosition), mContextSize(aContextSize), mLastError(NS_OK), @@ -121,15 +121,15 @@ already_AddRefed XPathExpression::EvaluateWithContext( return nullptr; } - Maybe contextNode = - txXPathNativeNode::createXPathNode(&aContextNode); + UniquePtr contextNode( + txXPathNativeNode::createXPathNode(&aContextNode)); if (!contextNode) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - EvalContextImpl eContext(contextNode.extract(), aContextPosition, - aContextSize, mRecycler); + EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize, + mRecycler); RefPtr exprResult; aRv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); if (aRv.Failed()) { diff --git a/dom/xslt/xpath/XPathResult.cpp b/dom/xslt/xpath/XPathResult.cpp index 73dd610156f6..ba2c1b31fcd7 100644 --- a/dom/xslt/xpath/XPathResult.cpp +++ b/dom/xslt/xpath/XPathResult.cpp @@ -238,13 +238,13 @@ nsresult XPathResult::GetExprResult(txAExprResult** aExprResult) { RefPtr nodeSet = new txNodeSet(nullptr); uint32_t i, count = mResultNodes.Length(); for (i = 0; i < count; ++i) { - Maybe node( + UniquePtr node( txXPathNativeNode::createXPathNode(mResultNodes[i])); if (!node) { return NS_ERROR_OUT_OF_MEMORY; } - nodeSet->append(node.extract()); + nodeSet->append(*node); } NS_ADDREF(*aExprResult = nodeSet); diff --git a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp index 6fdd33f05531..8150d7307e5a 100644 --- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp +++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp @@ -23,8 +23,8 @@ #include #include -using namespace mozilla; using namespace mozilla::dom; +using mozilla::Maybe; txXPathTreeWalker::txXPathTreeWalker(const txXPathTreeWalker& aOther) = default; @@ -228,6 +228,24 @@ bool txXPathTreeWalker::moveToParent() { return true; } +txXPathNode::txXPathNode(const txXPathNode& aNode) + : mNode(aNode.mNode), + mRefCountRoot(aNode.mRefCountRoot), + mIndex(aNode.mIndex) { + MOZ_COUNT_CTOR(txXPathNode); + if (mRefCountRoot) { + NS_ADDREF(Root()); + } +} + +txXPathNode::~txXPathNode() { + MOZ_COUNT_DTOR(txXPathNode); + if (mRefCountRoot) { + nsINode* root = Root(); + NS_RELEASE(root); + } +} + /* static */ bool txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsAtom* aLocalName, int32_t aNSID, nsAString& aValue) { @@ -425,8 +443,8 @@ bool txXPathNodeUtils::isWhitespace(const txXPathNode& aNode) { } /* static */ -txXPathNode txXPathNodeUtils::getOwnerDocument(const txXPathNode& aNode) { - return txXPathNode(aNode.mNode->OwnerDoc()); +txXPathNode* txXPathNodeUtils::getOwnerDocument(const txXPathNode& aNode) { + return new txXPathNode(aNode.mNode->OwnerDoc()); } const char gPrintfFmt[] = "id0x%" PRIxPTR; @@ -436,8 +454,7 @@ const char gPrintfFmtAttr[] = "id0x%" PRIxPTR "-%010i"; nsresult txXPathNodeUtils::getXSLTId(const txXPathNode& aNode, const txXPathNode& aBase, nsAString& aResult) { - uintptr_t nodeid = - ((uintptr_t)aNode.mNode.get()) - ((uintptr_t)aBase.mNode.get()); + uintptr_t nodeid = ((uintptr_t)aNode.mNode) - ((uintptr_t)aBase.mNode); if (!aNode.isAttribute()) { CopyASCIItoUTF16(nsPrintfCString(gPrintfFmt, nodeid), aResult); } else { @@ -568,7 +585,16 @@ int txXPathNodeUtils::comparePosition(const txXPathNode& aNode, } /* static */ -Maybe txXPathNativeNode::createXPathNode(nsINode* aNode) { +txXPathNode* txXPathNativeNode::createXPathNode(nsIContent* aContent, + bool aKeepRootAlive) { + nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(aContent) : nullptr; + + return new txXPathNode(aContent, txXPathNode::eContent, root); +} + +/* static */ +txXPathNode* txXPathNativeNode::createXPathNode(nsINode* aNode, + bool aKeepRootAlive) { uint16_t nodeType = aNode->NodeType(); if (nodeType == nsINode::ATTRIBUTE_NODE) { auto* attr = static_cast(aNode); @@ -576,30 +602,42 @@ Maybe txXPathNativeNode::createXPathNode(nsINode* aNode) { NodeInfo* nodeInfo = attr->NodeInfo(); Element* parent = attr->GetElement(); if (!parent) { - return Nothing(); + return nullptr; } + nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(parent) : nullptr; + uint32_t i, total = parent->GetAttrCount(); for (i = 0; i < total; ++i) { const nsAttrName* name = parent->GetAttrNameAt(i); if (nodeInfo->Equals(name->LocalName(), name->NamespaceID())) { - return Some(txXPathNode(parent, i)); + return new txXPathNode(parent, i, root); } } NS_ERROR("Couldn't find the attribute in its parent!"); - return Nothing(); + return nullptr; } uint32_t index; + nsINode* root = aKeepRootAlive ? aNode : nullptr; + if (nodeType == nsINode::DOCUMENT_NODE) { index = txXPathNode::eDocument; } else { index = txXPathNode::eContent; + if (root) { + root = txXPathNode::RootOf(root); + } } - return Some(txXPathNode(aNode, index)); + return new txXPathNode(aNode, index, root); +} + +/* static */ +txXPathNode* txXPathNativeNode::createXPathNode(Document* aDocument) { + return new txXPathNode(aDocument); } /* static */ diff --git a/dom/xslt/xpath/txNodeSet.cpp b/dom/xslt/xpath/txNodeSet.cpp index a8ba2a7b29dd..9baf006906ab 100644 --- a/dom/xslt/xpath/txNodeSet.cpp +++ b/dom/xslt/xpath/txNodeSet.cpp @@ -82,12 +82,12 @@ txNodeSet::~txNodeSet() { } } -nsresult txNodeSet::add(txXPathNode&& aNode) { +nsresult txNodeSet::add(const txXPathNode& aNode) { NS_ASSERTION(mDirection == kForward, "only append(aNode) is supported on reversed nodesets"); if (isEmpty()) { - return append(std::move(aNode)); + return append(aNode); } bool dupe; @@ -113,7 +113,7 @@ nsresult txNodeSet::add(txXPathNode&& aNode) { memmove((void*)(pos + 1), pos, moveSize * sizeof(txXPathNode)); } - new (pos) txXPathNode(std::move(aNode)); + new (pos) txXPathNode(aNode); ++mEnd; return NS_OK; @@ -295,19 +295,19 @@ nsresult txNodeSet::add(const txNodeSet& aNodes, transferOp aTransfer, * order info operations will be performed. */ -nsresult txNodeSet::append(txXPathNode&& aNode) { +nsresult txNodeSet::append(const txXPathNode& aNode) { if (!ensureGrowSize(1)) { return NS_ERROR_OUT_OF_MEMORY; } if (mDirection == kForward) { - new (mEnd) txXPathNode(std::move(aNode)); + new (mEnd) txXPathNode(aNode); ++mEnd; return NS_OK; } - new (--mStart) txXPathNode(std::move(aNode)); + new (--mStart) txXPathNode(aNode); return NS_OK; } diff --git a/dom/xslt/xpath/txNodeSet.h b/dom/xslt/xpath/txNodeSet.h index 5885799923a1..8c5e805d6bcf 100644 --- a/dom/xslt/xpath/txNodeSet.h +++ b/dom/xslt/xpath/txNodeSet.h @@ -44,8 +44,7 @@ class txNodeSet : public txAExprResult { * @param aNode the txXPathNode to add to the NodeSet * @return errorcode. */ - nsresult add(const txXPathNode& aNode) { return add(txXPathNode(aNode)); } - nsresult add(txXPathNode&& aNode); + nsresult add(const txXPathNode& aNode); /** * Adds the nodes in specified NodeSet to this NodeSet. The resulting @@ -73,10 +72,7 @@ class txNodeSet : public txAExprResult { * @param aNode the Node to append to the NodeSet * @return errorcode. */ - nsresult append(const txXPathNode& aNode) { - return append(txXPathNode(aNode)); - } - nsresult append(txXPathNode&& aNode); + nsresult append(const txXPathNode& aNode); /** * Appends the nodes in the specified NodeSet to the end of this NodeSet diff --git a/dom/xslt/xpath/txXPathNode.h b/dom/xslt/xpath/txXPathNode.h index ea7d1f6220c9..8c5d6f530838 100644 --- a/dom/xslt/xpath/txXPathNode.h +++ b/dom/xslt/xpath/txXPathNode.h @@ -13,70 +13,35 @@ using txXPathNodeType = nsINode; -/** - * txXPathNode represents a node in XPath's data model (which is a bit different - * from the DOM's). While XPath 1.0 has 7 node types, we essentially deal with 3 - * kinds: a document node, any other node type that is backed by an - * implementation of nsIContent in Gecko, and attribute nodes. Because we try to - * avoid creating actual node objects for attribute nodes in Gecko's DOM, we - * store attribute nodes as a pointer to their owner element and an index into - * that element's attribute node list. So to represent the 3 kinds of node we - * need to store: - * - * - a pointer to a document (a nsIDocument as a nsINode pointer) - * - a pointer to a nsIContent object (as a nsINode pointer) - * - a pointer to a nsIContent object (a nsIContent as a nsINode pointer) and - * an index - * - * So we make txXPathNode store a |nsCOMPtr| and a uint32_t for the - * index. To be able to distinguish between the attribute nodes and other nodes - * we store a flag value for the other nodes in the index. To be able to quickly - * cast from the nsINode pointer to a nsIDocument or nsIContent pointer we - * actually use 2 different flag values (see txXPathNode::PositionType). - * - * We provide 2 fast constructors for txXPathNode, one that takes a nsIContent - * and one that takes a nsIDocument, since for those kinds of nodes we can - * simply store the pointer and the relevant flag value. For attribute nodes, or - * if you have just a nsINode pointer, then there is a helper function - * (txXPathNativeNode::createXPathNode) that either picks the right flag value - * or the correct index (for attribute nodes) when creating the txXPathNode. - */ class txXPathNode { public: - explicit txXPathNode(const txXPathNode& aNode) - : mNode(aNode.mNode), mIndex(aNode.mIndex) { - MOZ_COUNT_CTOR(txXPathNode); - } - txXPathNode(txXPathNode&& aNode) - : mNode(std::move(aNode.mNode)), mIndex(aNode.mIndex) { - MOZ_COUNT_CTOR(txXPathNode); - } - - explicit txXPathNode(mozilla::dom::Document* aDocument) - : mNode(aDocument), mIndex(eDocument) { - MOZ_COUNT_CTOR(txXPathNode); - } - explicit txXPathNode(nsIContent* aContent) - : mNode(aContent), mIndex(eContent) { - MOZ_COUNT_CTOR(txXPathNode); - } - - txXPathNode& operator=(txXPathNode&& aOther) = default; bool operator==(const txXPathNode& aNode) const; bool operator!=(const txXPathNode& aNode) const { return !(*this == aNode); } - ~txXPathNode() { MOZ_COUNT_DTOR(txXPathNode); } + ~txXPathNode(); private: + friend class txNodeSet; friend class txXPathNativeNode; friend class txXPathNodeUtils; friend class txXPathTreeWalker; - txXPathNode(nsINode* aNode, uint32_t aIndex) : mNode(aNode), mIndex(aIndex) { + txXPathNode(const txXPathNode& aNode); + + explicit txXPathNode(mozilla::dom::Document* aDocument) + : mNode(aDocument), mRefCountRoot(0), mIndex(eDocument) { MOZ_COUNT_CTOR(txXPathNode); } + txXPathNode(nsINode* aNode, uint32_t aIndex, nsINode* aRoot) + : mNode(aNode), mRefCountRoot(aRoot ? 1 : 0), mIndex(aIndex) { + MOZ_COUNT_CTOR(txXPathNode); + if (aRoot) { + NS_ADDREF(aRoot); + } + } static nsINode* RootOf(nsINode* aNode) { return aNode->SubtreeRoot(); } nsINode* Root() const { return RootOf(mNode); } + nsINode* GetRootToAddRef() const { return mRefCountRoot ? Root() : nullptr; } bool isDocument() const { return mIndex == eDocument; } bool isContent() const { return mIndex == eContent; } @@ -84,20 +49,18 @@ class txXPathNode { nsIContent* Content() const { NS_ASSERTION(isContent() || isAttribute(), "wrong type"); - return static_cast(mNode.get()); + return static_cast(mNode); } mozilla::dom::Document* Document() const { NS_ASSERTION(isDocument(), "wrong type"); - return static_cast(mNode.get()); + return static_cast(mNode); } - enum PositionType : uint32_t { - eDocument = UINT32_MAX, - eContent = eDocument - 1 - }; + enum PositionType { eDocument = (1 << 30), eContent = eDocument - 1 }; - nsCOMPtr mNode; - uint32_t mIndex; + nsINode* mNode; + uint32_t mRefCountRoot : 1; + uint32_t mIndex : 31; }; class txNamespaceManager { diff --git a/dom/xslt/xpath/txXPathTreeWalker.h b/dom/xslt/xpath/txXPathTreeWalker.h index e6bc14ae9984..6b74b1e18d8f 100644 --- a/dom/xslt/xpath/txXPathTreeWalker.h +++ b/dom/xslt/xpath/txXPathTreeWalker.h @@ -60,7 +60,7 @@ class txXPathNodeUtils { static uint16_t getNodeType(const txXPathNode& aNode); static void appendNodeValue(const txXPathNode& aNode, nsAString& aResult); static bool isWhitespace(const txXPathNode& aNode); - static txXPathNode getOwnerDocument(const txXPathNode& aNode); + static txXPathNode* getOwnerDocument(const txXPathNode& aNode); static int32_t getUniqueIdentifier(const txXPathNode& aNode); static nsresult getXSLTId(const txXPathNode& aNode, const txXPathNode& aBase, nsAString& aResult); @@ -86,10 +86,19 @@ class txXPathNodeUtils { class txXPathNativeNode { public: - static mozilla::Maybe createXPathNode(nsINode* aNode); + static txXPathNode* createXPathNode(nsINode* aNode, + bool aKeepRootAlive = false); + static txXPathNode* createXPathNode(nsIContent* aContent, + bool aKeepRootAlive = false); + static txXPathNode* createXPathNode(mozilla::dom::Document* aDocument); static nsINode* getNode(const txXPathNode& aNode); static nsIContent* getContent(const txXPathNode& aNode); static mozilla::dom::Document* getDocument(const txXPathNode& aNode); + static void addRef(const txXPathNode& aNode) { NS_ADDREF(aNode.mNode); } + static void release(const txXPathNode& aNode) { + nsINode* node = aNode.mNode; + NS_RELEASE(node); + } }; inline const txXPathNode& txXPathTreeWalker::getCurrentPosition() const { @@ -114,8 +123,21 @@ inline void txXPathTreeWalker::getNodeName(nsAString& aName) const { } inline void txXPathTreeWalker::moveTo(const txXPathTreeWalker& aWalker) { + nsINode* root = nullptr; + if (mPosition.mRefCountRoot) { + root = mPosition.Root(); + } mPosition.mIndex = aWalker.mPosition.mIndex; + mPosition.mRefCountRoot = aWalker.mPosition.mRefCountRoot; mPosition.mNode = aWalker.mPosition.mNode; + nsINode* newRoot = nullptr; + if (mPosition.mRefCountRoot) { + newRoot = mPosition.Root(); + } + if (root != newRoot) { + NS_IF_ADDREF(newRoot); + NS_IF_RELEASE(root); + } } inline bool txXPathTreeWalker::isOnNode(const txXPathNode& aNode) const { @@ -125,7 +147,12 @@ inline bool txXPathTreeWalker::isOnNode(const txXPathNode& aNode) const { /* static */ inline int32_t txXPathNodeUtils::getUniqueIdentifier(const txXPathNode& aNode) { MOZ_ASSERT(!aNode.isAttribute(), "Not implemented for attributes."); - return NS_PTR_TO_INT32(aNode.mNode.get()); + return NS_PTR_TO_INT32(aNode.mNode); +} + +/* static */ +inline void txXPathNodeUtils::release(txXPathNode* aNode) { + NS_RELEASE(aNode->mNode); } /* static */ diff --git a/dom/xslt/xslt/txEXSLTFunctions.cpp b/dom/xslt/xslt/txEXSLTFunctions.cpp index e61b47dcad03..d58ca33b5374 100644 --- a/dom/xslt/xslt/txEXSLTFunctions.cpp +++ b/dom/xslt/xslt/txEXSLTFunctions.cpp @@ -73,7 +73,11 @@ static nsresult convertRtfToNode(txIEvalContext* aContext, NS_ENSURE_SUCCESS(rv, rv); // The txResultTreeFragment will own this. - aRtf->setNode(new txXPathNode(domFragment)); + const txXPathNode* node = + txXPathNativeNode::createXPathNode(domFragment, true); + NS_ENSURE_TRUE(node, NS_ERROR_OUT_OF_MEMORY); + + aRtf->setNode(node); return NS_OK; } @@ -91,7 +95,8 @@ static nsresult createTextNode(txIEvalContext* aContext, nsString& aValue, nsresult rv = text->SetText(aValue, false); NS_ENSURE_SUCCESS(rv, rv); - *aResult = new txXPathNode(text); + *aResult = txXPathNativeNode::createXPathNode(text, true); + NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); return NS_OK; } @@ -121,10 +126,11 @@ static nsresult createAndAddToResult(nsAtom* aName, const nsAString& aValue, return error.StealNSResult(); } - Maybe xpathNode(txXPathNativeNode::createXPathNode(elem)); + UniquePtr xpathNode( + txXPathNativeNode::createXPathNode(elem, true)); NS_ENSURE_TRUE(xpathNode, NS_ERROR_OUT_OF_MEMORY); - aResultSet->append(xpathNode.extract()); + aResultSet->append(*xpathNode); return NS_OK; } @@ -699,7 +705,8 @@ nsresult txEXSLTRegExFunctionCall::evaluate(txIEvalContext* aContext, UniquePtr node; for (nsIContent* result = docFrag->GetFirstChild(); result; result = result->GetNextSibling()) { - rv = resultSet->add(txXPathNode(result)); + node = WrapUnique(txXPathNativeNode::createXPathNode(result, true)); + rv = resultSet->add(*node); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp index d05c3a70b79c..a3cfddac1c62 100644 --- a/dom/xslt/xslt/txExecutionState.cpp +++ b/dom/xslt/xslt/txExecutionState.cpp @@ -14,12 +14,14 @@ #include "txURIUtils.h" #include "txXMLParser.h" -using namespace mozilla; +using mozilla::UniquePtr; +using mozilla::Unused; +using mozilla::WrapUnique; const int32_t txExecutionState::kMaxRecursionDepth = 20000; nsresult txLoadedDocumentsHash::init(const txXPathNode& aSource) { - mSourceDocument = Some(txXPathNodeUtils::getOwnerDocument(aSource)); + mSourceDocument = WrapUnique(txXPathNodeUtils::getOwnerDocument(aSource)); nsAutoString baseURI; nsresult rv = txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI); @@ -37,12 +39,24 @@ nsresult txLoadedDocumentsHash::init(const txXPathNode& aSource) { // txMozillaXSLTProcessor::TransformToFragment) it makes more sense to return // the real root of the source tree, which is the node where the transform // started. - WithEntryHandle(baseURI, [&aSource](auto&& entry) { - entry.Insert(txLoadedDocumentEntry{txXPathNode(aSource)}); - }); + PutEntry(baseURI)->mDocument = WrapUnique( + txXPathNativeNode::createXPathNode(txXPathNativeNode::getNode(aSource))); return NS_OK; } +txLoadedDocumentsHash::~txLoadedDocumentsHash() { + if (mSourceDocument) { + nsAutoString baseURI; + nsresult rv = txXPathNodeUtils::getBaseURI(*mSourceDocument, baseURI); + if (NS_SUCCEEDED(rv)) { + txLoadedDocumentEntry* entry = GetEntry(baseURI); + if (entry) { + delete entry->mDocument.release(); + } + } + } +} + txExecutionState::txExecutionState(txStylesheet* aStylesheet, bool aDisableLoads) : mOutputHandler(nullptr), @@ -344,24 +358,27 @@ const txXPathNode* txExecutionState::retrieveDocument(const nsAString& aUri) { ("Retrieve Document %s", NS_LossyConvertUTF16toASCII(aUri).get())); // try to get already loaded document - const Variant& result = - mLoadedDocuments.LookupOrInsertWith(aUri, [&] { - // open URI - nsAutoString errMsg; - // XXX we should get the loader from the actual node - // triggering the load, but this will do for the time being - Result loadResult = txParseDocumentFromURI( - aUri, *mLoadedDocuments.mSourceDocument, errMsg); + txLoadedDocumentEntry* entry = mLoadedDocuments.PutEntry(aUri); + if (!entry) { + return nullptr; + } - if (loadResult.isErr()) { - nsresult rv = loadResult.unwrapErr(); - receiveError( - u"Couldn't load document '"_ns + aUri + u"': "_ns + errMsg, rv); - return txLoadedDocumentEntry(rv); - } - return txLoadedDocumentEntry(loadResult.unwrap()); - }); - return result.is() ? &result.as() : nullptr; + if (!entry->mDocument && !entry->LoadingFailed()) { + // open URI + nsAutoString errMsg; + // XXX we should get the loader from the actual node + // triggering the load, but this will do for the time being + entry->mLoadResult = + txParseDocumentFromURI(aUri, *mLoadedDocuments.mSourceDocument, errMsg, + getter_Transfers(entry->mDocument)); + + if (entry->LoadingFailed()) { + receiveError(u"Couldn't load document '"_ns + aUri + u"': "_ns + errMsg, + entry->mLoadResult); + } + } + + return entry->mDocument.get(); } nsresult txExecutionState::getKeyNodes(const txExpandedName& aKeyName, diff --git a/dom/xslt/xslt/txExecutionState.h b/dom/xslt/xslt/txExecutionState.h index 89f5a1e19fca..7a314cf8a4b8 100644 --- a/dom/xslt/xslt/txExecutionState.h +++ b/dom/xslt/xslt/txExecutionState.h @@ -23,18 +23,41 @@ class txAOutputHandlerFactory; class txAXMLEventHandler; class txInstruction; -using txLoadedDocumentEntry = mozilla::Variant; - -class txLoadedDocumentsHash - : public nsTHashMap { +class txLoadedDocumentEntry : public nsStringHashKey { public: - txLoadedDocumentsHash() : nsTHashMap(4) {} + explicit txLoadedDocumentEntry(KeyTypePointer aStr) + : nsStringHashKey(aStr), mLoadResult(NS_OK) {} + txLoadedDocumentEntry(txLoadedDocumentEntry&& aOther) + : nsStringHashKey(std::move(aOther)), + mDocument(std::move(aOther.mDocument)), + mLoadResult(std::move(aOther.mLoadResult)) { + NS_ERROR("We're horked."); + } + ~txLoadedDocumentEntry() { + if (mDocument) { + txXPathNodeUtils::release(mDocument.get()); + } + } + bool LoadingFailed() { + NS_ASSERTION(NS_SUCCEEDED(mLoadResult) || !mDocument, + "Load failed but we still got a document?"); + return NS_FAILED(mLoadResult); + } + + mozilla::UniquePtr mDocument; + nsresult mLoadResult; +}; + +class txLoadedDocumentsHash : public nsTHashtable { + public: + txLoadedDocumentsHash() : nsTHashtable(4) {} + ~txLoadedDocumentsHash(); [[nodiscard]] nsresult init(const txXPathNode& aSource); private: friend class txExecutionState; - mozilla::Maybe mSourceDocument; + mozilla::UniquePtr mSourceDocument; }; class txExecutionState : public txIMatchContext { diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index 067c6a4563a5..2508056d3236 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -5,7 +5,6 @@ #include "txMozillaXSLTProcessor.h" #include "nsError.h" -#include "mozilla/AutoRestore.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Document.h" #include "nsIStringBundle.h" @@ -329,11 +328,9 @@ txMozillaXSLTProcessor::AddXSLTParamNamespace(const nsString& aPrefix, class txXSLTParamContext : public txIParseContext, public txIEvalContext { public: - txXSLTParamContext(txNamespaceMap* aResolver, txXPathNode&& aContext, + txXSLTParamContext(txNamespaceMap* aResolver, const txXPathNode& aContext, txResultRecycler* aRecycler) - : mResolver(aResolver), - mContext(std::move(aContext)), - mRecycler(aRecycler) {} + : mResolver(aResolver), mContext(aContext), mRecycler(aRecycler) {} // txIParseContext int32_t resolveNamespacePrefix(nsAtom* aPrefix) override { @@ -388,7 +385,7 @@ txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName, uint16_t resultType; if (!aSelect.IsVoid()) { // Set up context - Maybe contextNode( + UniquePtr contextNode( txXPathNativeNode::createXPathNode(aContext)); NS_ENSURE_TRUE(contextNode, NS_ERROR_OUT_OF_MEMORY); @@ -396,7 +393,7 @@ txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName, mRecycler = new txResultRecycler; } - txXSLTParamContext paramContext(&mParamNamespaceMap, contextNode.extract(), + txXSLTParamContext paramContext(&mParamNamespaceMap, *contextNode, mRecycler); // Parse @@ -476,8 +473,6 @@ class nsTransformBlockerEvent : public mozilla::Runnable { } NS_IMETHOD Run() override { - MOZ_RELEASE_ASSERT(mProcessor->mState == - txMozillaXSLTProcessor::State::None); mProcessor->TransformToDoc(nullptr, false); return NS_OK; } @@ -509,13 +504,6 @@ void txMozillaXSLTProcessor::ImportStylesheet(nsINode& aStyle, return; } - if (mState != State::None) { - aRv.ThrowInvalidStateError("Invalid call."); - return; - } - mozilla::AutoRestore restore(mState); - mState = State::Compiling; - MOZ_ASSERT(!mEmbeddedStylesheetRoot); mCompileResult = NS_OK; @@ -559,21 +547,12 @@ already_AddRefed txMozillaXSLTProcessor::TransformToDocument( return nullptr; } - if (mState != State::None) { - aRv.ThrowInvalidStateError("Invalid call."); - return nullptr; - } - nsresult rv = ensureStylesheet(); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.Throw(rv); return nullptr; } - MOZ_RELEASE_ASSERT(mState == State::None); - mozilla::AutoRestore restore(mState); - mState = State::Transforming; - mSource = aSource.CloneNode(true, aRv); if (aRv.Failed()) { return nullptr; @@ -676,7 +655,8 @@ XSLTProcessRequest::SetTRRMode(nsIRequest::TRRMode aTRRMode) { nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult, bool aCreateDataDocument) { - Maybe sourceNode(txXPathNativeNode::createXPathNode(mSource)); + UniquePtr sourceNode( + txXPathNativeNode::createXPathNode(mSource)); if (!sourceNode) { return NS_ERROR_OUT_OF_MEMORY; } @@ -758,21 +738,12 @@ already_AddRefed txMozillaXSLTProcessor::TransformToFragment( return nullptr; } - if (mState != State::None) { - aRv.ThrowInvalidStateError("Invalid call."); - return nullptr; - } - nsresult rv = ensureStylesheet(); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.Throw(rv); return nullptr; } - MOZ_RELEASE_ASSERT(mState == State::None); - mozilla::AutoRestore restore(mState); - mState = State::Transforming; - nsCOMPtr source; if (aCloneSource) { source = aSource.CloneNode(true, aRv); @@ -783,7 +754,7 @@ already_AddRefed txMozillaXSLTProcessor::TransformToFragment( source = &aSource; } - Maybe sourceNode(txXPathNativeNode::createXPathNode(source)); + UniquePtr sourceNode(txXPathNativeNode::createXPathNode(source)); if (!sourceNode) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; @@ -797,7 +768,7 @@ already_AddRefed txMozillaXSLTProcessor::TransformToFragment( txToFragmentHandlerFactory handlerFactory(frag); es.mOutputHandlerFactory = &handlerFactory; - rv = es.init(sourceNode.extract(), &mVariables); + rv = es.init(*sourceNode, &mVariables); // Process root of XML source document if (NS_SUCCEEDED(rv)) { @@ -821,11 +792,6 @@ void txMozillaXSLTProcessor::SetParameter(const nsAString& aNamespaceURI, const nsAString& aLocalName, const XSLTParameterValue& aValue, ErrorResult& aError) { - if (mState != State::None) { - aError.ThrowInvalidStateError("Invalid call."); - return; - } - if (aValue.IsNode()) { if (!nsContentUtils::CanCallerAccess(&aValue.GetAsNode())) { aError.ThrowSecurityError("Caller is not allowed to access node."); @@ -914,11 +880,6 @@ void txMozillaXSLTProcessor::GetParameter( void txMozillaXSLTProcessor::RemoveParameter(const nsAString& aNamespaceURI, const nsAString& aLocalName, ErrorResult& aRv) { - if (mState != State::None) { - aRv.ThrowInvalidStateError("Invalid call."); - return; - } - int32_t nsId = kNameSpaceID_Unknown; nsresult rv = nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, nsId); @@ -932,21 +893,9 @@ void txMozillaXSLTProcessor::RemoveParameter(const nsAString& aNamespaceURI, mVariables.remove(varName); } -void txMozillaXSLTProcessor::ClearParameters(ErrorResult& aError) { - if (mState != State::None) { - aError.ThrowInvalidStateError("Invalid call."); - return; - } - - mVariables.clear(); -} - -void txMozillaXSLTProcessor::Reset(ErrorResult& aError) { - if (mState != State::None) { - aError.ThrowInvalidStateError("Invalid call."); - return; - } +void txMozillaXSLTProcessor::ClearParameters() { mVariables.clear(); } +void txMozillaXSLTProcessor::Reset() { if (mStylesheetDocument) { mStylesheetDocument->RemoveMutationObserver(this); } @@ -1106,12 +1055,6 @@ void txMozillaXSLTProcessor::notifyError() { } nsresult txMozillaXSLTProcessor::ensureStylesheet() { - if (mState != State::None) { - return NS_ERROR_FAILURE; - } - mozilla::AutoRestore restore(mState); - mState = State::Compiling; - if (mStylesheet) { return NS_OK; } @@ -1242,7 +1185,7 @@ nsresult txVariable::convert(const OwningXSLTParameterValue& aUnionValue, if (aUnionValue.IsNode()) { nsINode& node = aUnionValue.GetAsNode(); - Maybe xpathNode(txXPathNativeNode::createXPathNode(&node)); + UniquePtr xpathNode(txXPathNativeNode::createXPathNode(&node)); if (!xpathNode) { return NS_ERROR_FAILURE; } @@ -1256,13 +1199,13 @@ nsresult txVariable::convert(const OwningXSLTParameterValue& aUnionValue, const Sequence>& values = aUnionValue.GetAsNodeSequence(); for (const auto& node : values) { - Maybe xpathNode( + UniquePtr xpathNode( txXPathNativeNode::createXPathNode(node.get())); if (!xpathNode) { return NS_ERROR_FAILURE; } - nodeSet->append(xpathNode.extract()); + nodeSet->append(*xpathNode); } nodeSet.forget(aValue); return NS_OK; diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.h b/dom/xslt/xslt/txMozillaXSLTProcessor.h index 352d32c2255a..bb470d34154d 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.h +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.h @@ -92,17 +92,17 @@ class txMozillaXSLTProcessor final : public nsIDocumentTransformer, static already_AddRefed Constructor( const mozilla::dom::GlobalObject& aGlobal); - void ImportStylesheet(nsINode& aStylesheet, mozilla::ErrorResult& aRv); + void ImportStylesheet(nsINode& stylesheet, mozilla::ErrorResult& aRv); already_AddRefed TransformToFragment( - nsINode& aSource, mozilla::dom::Document& aOutput, + nsINode& aSource, mozilla::dom::Document& aDocument, mozilla::ErrorResult& aRv) { - return TransformToFragment(aSource, true, aOutput, aRv); + return TransformToFragment(aSource, true, aDocument, aRv); } already_AddRefed TransformToFragment( nsINode& aSource, bool aCloneSource, mozilla::dom::Document& aOutput, mozilla::ErrorResult& aRv); already_AddRefed TransformToDocument( - nsINode& aSource, mozilla::ErrorResult& aRv); + nsINode& source, mozilla::ErrorResult& aRv); void SetParameter(const nsAString& aNamespaceURI, const nsAString& aLocalName, const XSLTParameterValue& aValue, @@ -112,8 +112,8 @@ class txMozillaXSLTProcessor final : public nsIDocumentTransformer, mozilla::ErrorResult& aRv); void RemoveParameter(const nsAString& aNamespaceURI, const nsAString& aLocalName, mozilla::ErrorResult& aRv); - void ClearParameters(mozilla::ErrorResult& aError); - void Reset(mozilla::ErrorResult& aError); + void ClearParameters(); + void Reset(); uint32_t Flags(mozilla::dom::SystemCallerGuarantee); void SetFlags(uint32_t aFlags, mozilla::dom::SystemCallerGuarantee); @@ -136,8 +136,6 @@ class txMozillaXSLTProcessor final : public nsIDocumentTransformer, static void Shutdown(); private: - friend class nsTransformBlockerEvent; - explicit txMozillaXSLTProcessor(nsISupports* aOwner); /** * Default destructor for txMozillaXSLTProcessor @@ -164,13 +162,6 @@ class txMozillaXSLTProcessor final : public nsIDocumentTransformer, RefPtr mRecycler; uint32_t mFlags; - - enum class State { - None, - Compiling, - Transforming, - }; - State mState = State::None; }; extern nsresult TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor, diff --git a/dom/xslt/xslt/txXSLTPatterns.cpp b/dom/xslt/xslt/txXSLTPatterns.cpp index 2c78dc45026b..dc1b81e210e1 100644 --- a/dom/xslt/xslt/txXSLTPatterns.cpp +++ b/dom/xslt/xslt/txXSLTPatterns.cpp @@ -329,11 +329,12 @@ void txIdPattern::toString(nsAString& aDest) { nsresult txKeyPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext, bool& aMatched) { txExecutionState* es = (txExecutionState*)aContext->getPrivateContext(); - txXPathNode contextDoc(txXPathNodeUtils::getOwnerDocument(aNode)); + UniquePtr contextDoc(txXPathNodeUtils::getOwnerDocument(aNode)); + NS_ENSURE_TRUE(contextDoc, NS_ERROR_FAILURE); RefPtr nodes; nsresult rv = - es->getKeyNodes(mName, contextDoc, mValue, true, getter_AddRefs(nodes)); + es->getKeyNodes(mName, *contextDoc, mValue, true, getter_AddRefs(nodes)); NS_ENSURE_SUCCESS(rv, rv); aMatched = nodes->contains(aNode);