Bug 1436040 - xslt processor: <?xslt-param name= value= ?> isn't recognized. r=bz a=jcristau
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 20 Feb 2018 20:55:23 +0100
changeset 463373 b72ae1a6c4a4a62c31f87cf56bc0269e2dcf3e12
parent 463372 14286e941bdfabec387a59da2b3bb07ee8e5fa90
child 463374 20d2e80aa71b8fcefbe5e72d203007909810db03
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, jcristau
bugs1436040, 1387427
milestone60.0
Bug 1436040 - xslt processor: <?xslt-param name= value= ?> isn't recognized. r=bz a=jcristau The patch for bug 1387427 made us keep the source content in an array and we don't insert it into the document anymore. The code for xslt-param and xslt-param-namespace should look in the source content array instead of the document.
dom/xml/nsXMLContentSink.cpp
dom/xslt/nsIDocumentTransformer.h
dom/xslt/tests/mochitest/mochitest.ini
dom/xslt/tests/mochitest/test_bug1436040.html
dom/xslt/xslt/txMozillaXSLTProcessor.cpp
dom/xslt/xslt/txMozillaXSLTProcessor.h
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -216,17 +216,17 @@ nsXMLContentSink::MaybePrettyPrint()
 
   mPrettyPrinting = isPrettyPrinting;
   return NS_OK;
 }
 
 static void
 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
                  nsIDocumentTransformer* aProcessor,
-                 nsIDocument* aDocument)
+                 nsINode* aSource)
 {
   nsAutoString target, data;
   aPi->GetTarget(target);
 
   // Check for namespace declarations
   if (target.EqualsLiteral("xslt-param-namespace")) {
     aPi->GetData(data);
     nsAutoString prefix, namespaceAttr;
@@ -249,18 +249,17 @@ CheckXSLTParamPI(nsIDOMProcessingInstruc
                                             namespaceAttr);
     if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
       select.SetIsVoid(true);
     }
     if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
       value.SetIsVoid(true);
     }
     if (!name.IsEmpty()) {
-      nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
-      aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
+      aProcessor->AddXSLTParam(name, namespaceAttr, select, value, aSource);
     }
   }
 }
 
 NS_IMETHODIMP
 nsXMLContentSink::DidBuildModel(bool aTerminated)
 {
   if (!mParser) {
@@ -274,31 +273,41 @@ nsXMLContentSink::DidBuildModel(bool aTe
 
   DidBuildModelImpl(aTerminated);
 
   if (mXSLTProcessor) {
     // stop observing in order to avoid crashing when replacing content
     mDocument->RemoveObserver(this);
     mIsDocumentObserver = false;
 
+    ErrorResult rv;
+    RefPtr<DocumentFragment> source = mDocument->CreateDocumentFragment();
+    for (nsIContent* child : mDocumentChildren) {
+        // XPath data model doesn't have DocumentType nodes.
+        if (child->NodeType() != nsINode::DOCUMENT_TYPE_NODE) {
+            source->AppendChild(*child, rv);
+            if (rv.Failed()) {
+                return rv.StealNSResult();
+            }
+        }
+    }
+
     // Check for xslt-param and xslt-param-namespace PIs
-    for (nsIContent* child = mDocument->GetFirstChild();
-         child;
-         child = child->GetNextSibling()) {
+    for (nsIContent* child : mDocumentChildren) {
       if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
         nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
-        CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
+        CheckXSLTParamPI(pi, mXSLTProcessor, source);
       }
       else if (child->IsElement()) {
         // Only honor PIs in the prolog
         break;
       }
     }
 
-    mXSLTProcessor->SetSourceContentModel(mDocument, mDocumentChildren);
+    mXSLTProcessor->SetSourceContentModel(source);
     // Since the processor now holds a reference to us we drop our reference
     // to it to avoid owning cycles
     mXSLTProcessor = nullptr;
   }
   else {
     // Kick off layout for non-XSLT transformed documents.
 
     // Check if we want to prettyprint
--- a/dom/xslt/nsIDocumentTransformer.h
+++ b/dom/xslt/nsIDocumentTransformer.h
@@ -6,17 +6,17 @@
 #define nsIDocumentTransformer_h__
 
 #include "nsISupports.h"
 #include "nsStringFwd.h"
 
 template<class> class nsCOMPtr;
 class nsIContent;
 class nsIDocument;
-class nsIDOMNode;
+class nsINode;
 class nsIURI;
 template<class> class nsTArray;
 
 #define NS_ITRANSFORMOBSERVER_IID \
 { 0x04b2d17c, 0xe98d, 0x45f5, \
   { 0x9a, 0x67, 0xb7, 0x01, 0x19, 0x59, 0x7d, 0xe7 } }
 
 class nsITransformObserver : public nsISupports
@@ -41,25 +41,24 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsITransfo
 class nsIDocumentTransformer : public nsISupports
 {
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENTTRANSFORMER_IID)
 
   NS_IMETHOD SetTransformObserver(nsITransformObserver* aObserver) = 0;
   NS_IMETHOD LoadStyleSheet(nsIURI* aUri, nsIDocument* aLoaderDocument) = 0;
-  NS_IMETHOD SetSourceContentModel(nsIDocument* aDocument,
-                                   const nsTArray<nsCOMPtr<nsIContent>>& aSource) = 0;
+  NS_IMETHOD SetSourceContentModel(nsINode* aSource) = 0;
   NS_IMETHOD CancelLoads() = 0;
 
   NS_IMETHOD AddXSLTParamNamespace(const nsString& aPrefix,
                                    const nsString& aNamespace) = 0;
   NS_IMETHOD AddXSLTParam(const nsString& aName,
                           const nsString& aNamespace,
                           const nsString& aValue,
                           const nsString& aSelect,
-                          nsIDOMNode* aContextNode) = 0;
+                          nsINode* aContextNode) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentTransformer,
                               NS_IDOCUMENTTRANSFORMER_IID)
 
 #endif //nsIDocumentTransformer_h__
--- a/dom/xslt/tests/mochitest/mochitest.ini
+++ b/dom/xslt/tests/mochitest/mochitest.ini
@@ -11,10 +11,11 @@
 [test_bug551654.html]
 [test_bug566629.html]
 [test_bug566629.xhtml]
 [test_bug603159.html]
 [test_bug616774.html]
 [test_bug667315.html]
 [test_bug1135764.html]
 support-files = file_bug1135764.xml file_bug1135764.xsl
+[test_bug1436040.html]
 [test_exslt_regex.html]
 [test_parameter.html]
new file mode 100644
--- /dev/null
+++ b/dom/xslt/tests/mochitest/test_bug1436040.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test for xslt-param PIs</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+  let iframe = document.createElement('iframe');
+  let src = `<?xml version="1.0"?>
+             <?xslt-param name="param" value="true"?>
+             <?xml-stylesheet type="text/xml" href="#bug"?>
+             <doc>
+               <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" id="bug">
+                 <xsl:output method="html"/>
+                 <xsl:param name="param">false</xsl:param>
+                 <xsl:template match="/">
+                   <xsl:element name="script">parent.postMessage({test: 1, result: <xsl:value-of select="$param"/>}, "*");</xsl:element> 
+                 </xsl:template>
+               </xsl:stylesheet>
+             </doc>`;
+  iframe.src = "data:text/xml," + encodeURIComponent(src);
+  self.addEventListener("message", t.step_func_done(({data: {test, result}}) => {
+    if (test == 1) {
+      assert_true(result, "The stylesheet param's value should be set by the xslt-param PI.");
+    }
+  }));
+  document.body.appendChild(iframe);
+}, "Test for xslt-param PIs");
+async_test(t => {
+  let iframe = document.createElement('iframe');
+  let src = `<?xml version="1.0"?>
+             <?xslt-param-namespace prefix="foo" namespace="foonamespace"?>
+             <?xslt-param name="param" select="//foo:default"?>
+             <?xml-stylesheet type="text/xml" href="#bug"?>
+             <doc>
+               <default xmlns="foonamespace">true</default>
+               <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" id="bug">
+                 <xsl:output method="html"/>
+                 <xsl:param name="param">false</xsl:param>
+                 <xsl:template match="/">
+                   <xsl:element name="script">parent.postMessage({test: 2, result: <xsl:value-of select="$param"/>}, "*");</xsl:element> 
+                 </xsl:template>
+               </xsl:stylesheet>
+             </doc>`;
+  iframe.src = "data:text/xml," + encodeURIComponent(src);
+  self.addEventListener("message", t.step_func_done(({data: {test, result}}) => {
+    if (test == 2) {
+      assert_true(result, "xslt-param-namespace should have set the right namespace");
+    }
+  }));
+  document.body.appendChild(iframe);
+}, "Test for xslt-param PIs");
+</script>
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -369,38 +369,26 @@ txMozillaXSLTProcessor::~txMozillaXSLTPr
 
 NS_IMETHODIMP
 txMozillaXSLTProcessor::SetTransformObserver(nsITransformObserver* aObserver)
 {
     mObserver = aObserver;
     return NS_OK;
 }
 
-nsresult
-txMozillaXSLTProcessor::SetSourceContentModel(nsIDocument* aDocument,
-                                              const nsTArray<nsCOMPtr<nsIContent>>& aSource)
+NS_IMETHODIMP
+txMozillaXSLTProcessor::SetSourceContentModel(nsINode* aSource)
 {
-    mSource = aDocument->CreateDocumentFragment();
+    mSource = aSource;
 
     if (NS_FAILED(mTransformResult)) {
         notifyError();
         return NS_OK;
     }
 
-    ErrorResult rv;
-    for (nsIContent* child : aSource) {
-        // XPath data model doesn't have DocumentType nodes.
-        if (child->NodeType() != nsINode::DOCUMENT_TYPE_NODE) {
-            mSource->AppendChild(*child, rv);
-            if (rv.Failed()) {
-                return rv.StealNSResult();
-            }
-        }
-    }
-
     if (mStylesheet) {
         return DoTransform();
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -488,17 +476,17 @@ private:
 };
 
 
 NS_IMETHODIMP
 txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName,
                                      const nsString& aNamespace,
                                      const nsString& aSelect,
                                      const nsString& aValue,
-                                     nsIDOMNode* aContext)
+                                     nsINode* aContext)
 {
     nsresult rv = NS_OK;
 
     if (aSelect.IsVoid() == aValue.IsVoid()) {
         // Ignore if neither or both are specified
         return NS_ERROR_FAILURE;
     }
 
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.h
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.h
@@ -15,17 +15,16 @@
 #include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/XSLTProcessorBinding.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 class nsINode;
-class nsIDOMNode;
 class nsIURI;
 class txStylesheet;
 class txResultRecycler;
 class txIGlobalParameter;
 
 namespace mozilla {
 namespace dom {
 
@@ -55,26 +54,25 @@ public:
     // nsISupports interface
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(txMozillaXSLTProcessor,
                                                            nsIDocumentTransformer)
 
     // nsIDocumentTransformer interface
     NS_IMETHOD SetTransformObserver(nsITransformObserver* aObserver) override;
     NS_IMETHOD LoadStyleSheet(nsIURI* aUri, nsIDocument* aLoaderDocument) override;
-    NS_IMETHOD SetSourceContentModel(nsIDocument* aDocument,
-                                     const nsTArray<nsCOMPtr<nsIContent>>& aSource) override;
+    NS_IMETHOD SetSourceContentModel(nsINode* aSource) override;
     NS_IMETHOD CancelLoads() override {return NS_OK;}
     NS_IMETHOD AddXSLTParamNamespace(const nsString& aPrefix,
                                      const nsString& aNamespace) override;
     NS_IMETHOD AddXSLTParam(const nsString& aName,
                             const nsString& aNamespace,
                             const nsString& aSelect,
                             const nsString& aValue,
-                            nsIDOMNode* aContext) override;
+                            nsINode* aContext) override;
 
     // nsIMutationObserver interface
     NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
     NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED