Bug 1264270 - Parser should output attributes in source order, not reversed; r=hsivonen,bgrins
authorAryeh Gregor <ayg@aryeh.name>
Sun, 01 May 2016 15:15:26 +0300
changeset 295622 45cde9858aa0dd06f18de23e517b11e334d9d410
parent 295621 922be574731fabc93c41ab50ca7861958df57a29
child 295623 b0899873114542f7a46f13c8b438d301c1dfda3a
push id19015
push usercbook@mozilla.com
push dateMon, 02 May 2016 09:39:23 +0000
treeherderfx-team@2080375bc69d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen, bgrins
bugs1264270
milestone49.0a1
Bug 1264270 - Parser should output attributes in source order, not reversed; r=hsivonen,bgrins
devtools/client/inspector/markup/markup.js
devtools/client/inspector/markup/test/browser_markup_html_edit_03.js
devtools/client/shared/test/browser_outputparser.js
devtools/client/webconsole/test/browser_webconsole_output_dom_elements_01.js
devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
devtools/client/webconsole/test/browser_webconsole_output_dom_elements_04.js
devtools/server/actors/inspector.js
devtools/server/tests/mochitest/test_inspector-search.html
dom/base/nsAttrAndChildArray.cpp
dom/base/nsContentUtils.cpp
dom/base/nsHTMLContentSerializer.cpp
dom/base/test/test_bug422403-2.xhtml
dom/base/test/test_bug424359-2.html
dom/base/test/test_bug744830.html
dom/base/test/test_htmlcopyencoder.html
dom/base/test/test_htmlcopyencoder.xhtml
parser/html/nsHtml5TreeOperation.cpp
parser/xml/test/unit/results.js
testing/web-platform/meta/dom/collections/domstringmap-supported-property-names.html.ini
testing/web-platform/meta/dom/collections/namednodemap-supported-property-names.html.ini
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -3191,19 +3191,17 @@ function parseAttributeValues(attr, doc)
       attributes.push({ name, value });
     } catch (e) {
       // This may throw exceptions on bad input.
       // Prevents InvalidCharacterError - "String contains an invalid
       // character".
     }
   }
 
-  // Attributes return from DOMParser in reverse order from how they are
-  // entered.
-  return attributes.reverse();
+  return attributes;
 }
 
 /**
  * Apply a 'flashed' background and foreground color to elements. Intended
  * to be used with flashElementOff as a way of drawing attention to an element.
  *
  * @param  {Node} backgroundElt
  *         The element to set the highlighted background color on.
--- a/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js
+++ b/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js
@@ -163,17 +163,17 @@ function* testDocumentElement(inspector,
      1, "no extra <body>s have been added");
   is((yield testActor.getProperty("body", "textContent")),
      "Hello", "document.body.textContent has been updated");
 }
 
 function* testDocumentElement2(inspector, testActor) {
   let currentDocElementOuterHMTL = yield testActor.eval(
     "content.document.documentElement.outerHMTL");
-  let docElementHTML = "<html class=\"updated\" id=\"somethingelse\"><head>" +
+  let docElementHTML = "<html id=\"somethingelse\" class=\"updated\"><head>" +
                        "<title>Updated again from document element</title>" +
                        "<script>window.foo=\"bar\";</script></head><body>" +
                        "<p>Hello again</p></body></html>";
   let docElementFront = yield inspector.markup.walker.documentElement();
 
   let onReselected = inspector.markup.once("reselectedonremoved");
   inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML,
     currentDocElementOuterHMTL);
--- a/devtools/client/shared/test/browser_outputparser.js
+++ b/devtools/client/shared/test/browser_outputparser.js
@@ -46,18 +46,18 @@ function makeColorTest(name, value, segm
     expected: ""
   };
 
   for (let segment of segments) {
     if (typeof (segment) === "string") {
       result.expected += segment;
     } else {
       result.expected += "<span data-color=\"" + segment.name + "\">" +
-        "<span style=\"background-color:" + segment.name +
-        "\" class=\"" + COLOR_TEST_CLASS + "\"></span><span>" +
+        "<span class=\"" + COLOR_TEST_CLASS + "\" style=\"background-color:" +
+        segment.name + "\"></span><span>" +
         segment.name + "</span></span>";
     }
   }
 
   result.desc = "Testing " + name + ": " + value;
 
   return result;
 }
@@ -236,18 +236,18 @@ function testParseURL(doc, parser) {
     });
 
     let target = doc.querySelector("div");
     target.appendChild(frag);
 
     let expectedTrailer = test.expectedTrailer || test.trailer;
 
     let expected = test.leader +
-        "<a href=\"something.jpg\" class=\"test-urlclass\" " +
-        "target=\"_blank\">something.jpg</a>" +
+        "<a target=\"_blank\" class=\"test-urlclass\" " +
+        "href=\"something.jpg\">something.jpg</a>" +
         expectedTrailer;
 
     is(target.innerHTML, expected, test.desc);
 
     target.innerHTML = "";
   }
 }
 
--- a/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_01.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_01.js
@@ -14,26 +14,26 @@ thisTestLeaksUncaughtRejectionsAndShould
 // Test the webconsole output for various types of DOM Nodes.
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/test-console-output-dom-elements.html";
 
 var inputTests = [
   {
     input: "testBodyNode()",
-    output: '<body id="body-id" class="body-class">',
+    output: '<body class="body-class" id="body-id">',
     printOutput: "[object HTMLBodyElement]",
     inspectable: true,
     noClick: true,
     inspectorIcon: true
   },
 
   {
     input: "testDocumentElement()",
-    output: '<html lang="en-US" dir="ltr">',
+    output: '<html dir="ltr" lang="en-US">',
     printOutput: "[object HTMLHtmlElement]",
     inspectable: true,
     noClick: true,
     inspectorIcon: true
   },
 
   {
     input: "testDocument()",
@@ -70,17 +70,17 @@ var inputTests = [
     printOutput: "[object HTMLParagraphElement]",
     inspectable: true,
     noClick: true,
     inspectorIcon: true
   },
 
   {
     input: "testLotsOfAttributes()",
-    output: '<p n="" m="" l="" k="" j="" i="" h="" g="" f="" e="" d="" c="" b="" a="" id="lots-of-attributes">',
+    output: '<p id="lots-of-attributes" a="" b="" c="" d="" e="" f="" g="" h="" i="" j="" k="" l="" m="" n="">',
     printOutput: "[object HTMLParagraphElement]",
     inspectable: true,
     noClick: true,
     inspectorIcon: true
   },
 
   {
     input: "testDocumentFragment()",
--- a/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
@@ -18,17 +18,17 @@ const TEST_DATA = [
     // inspector-updated event
     input: "testNode()",
     output: '<p some-attribute="some-value">',
     tagName: "P",
     attrs: [{name: "some-attribute", value: "some-value"}]
   },
   {
     input: "testBodyNode()",
-    output: '<body id="body-id" class="body-class">',
+    output: '<body class="body-class" id="body-id">',
     tagName: "BODY",
     attrs: [
       {
         name: "class", value: "body-class"
       },
       {
         name: "id", value: "body-id"
       }
@@ -37,17 +37,17 @@ const TEST_DATA = [
   {
     input: "testNodeInIframe()",
     output: "<p>",
     tagName: "P",
     attrs: []
   },
   {
     input: "testDocumentElement()",
-    output: '<html lang="en-US" dir="ltr">',
+    output: '<html dir="ltr" lang="en-US">',
     tagName: "HTML",
     attrs: [
       {
         name: "dir",
         value: "ltr"
       },
       {
         name: "lang",
--- a/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_04.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_04.js
@@ -16,25 +16,25 @@ const TEST_DATA = [
     // The first test shouldn't be returning the body element as this is the
     // default selected node, so re-selecting it won't fire the
     // inspector-updated event
     input: "testNode()",
     output: '<p some-attribute="some-value">'
   },
   {
     input: "testBodyNode()",
-    output: '<body id="body-id" class="body-class">'
+    output: '<body class="body-class" id="body-id">'
   },
   {
     input: "testNodeInIframe()",
     output: "<p>"
   },
   {
     input: "testDocumentElement()",
-    output: '<html lang="en-US" dir="ltr">'
+    output: '<html dir="ltr" lang="en-US">'
   }
 ];
 
 const PREF = "devtools.webconsole.persistlog";
 
 function test() {
   Services.prefs.setBoolPref(PREF, true);
   registerCleanupFunction(() => Services.prefs.clearUserPref(PREF));
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -432,20 +432,17 @@ var NodeActor = exports.NodeActor = prot
     return false;
   },
 
   writeAttrs: function () {
     if (!this.rawNode.attributes) {
       return undefined;
     }
 
-    // The NamedNodeMap implementation in Firefox (returned by
-    // node.attributes) gives attributes in the reverse order compared
-    // to the source file when iterated. So reverse the list here.
-    return [...this.rawNode.attributes].reverse().map(attr => {
+    return [...this.rawNode.attributes].map(attr => {
       return {namespace: attr.namespace, name: attr.name, value: attr.value };
     });
   },
 
   writePseudoClassLocks: function () {
     if (this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
       return undefined;
     }
--- a/devtools/server/tests/mochitest/test_inspector-search.html
+++ b/devtools/server/tests/mochitest/test_inspector-search.html
@@ -151,17 +151,17 @@ window.onload = function() {
         {node: inspectee.querySelectorAll("h2")[1], type: "selector"},
         {node: inspectee.querySelectorAll("h2")[2], type: "selector"},
       ]
     },
     {
       desc: "Search with multiple matches in a single tag expecting a single result",
       search: "💩",
       expected: [
-        {node: inspectee.getElementById("💩"), type: "attributeName"}
+        {node: inspectee.getElementById("💩"), type: "attributeValue"}
       ]
     },
     {
       desc: "Search that has tag and text results",
       search: "h1",
       expected: [
         {node: inspectee.querySelector("h1"), type: "tag"},
         {node: inspectee.querySelector("h1 + p").childNodes[0], type: "text"},
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -376,22 +376,22 @@ nsAttrAndChildArray::GetAttr(const nsASt
 }
 
 const nsAttrValue*
 nsAttrAndChildArray::AttrAt(uint32_t aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
                "out-of-bounds access in nsAttrAndChildArray");
 
-  uint32_t mapped = MappedAttrCount();
-  if (aPos < mapped) {
-    return mImpl->mMappedAttrs->AttrAt(aPos);
+  uint32_t nonmapped = NonMappedAttrCount();
+  if (aPos < nonmapped) {
+    return &ATTRS(mImpl)[aPos].mValue;
   }
 
-  return &ATTRS(mImpl)[aPos - mapped].mValue;
+  return mImpl->mMappedAttrs->AttrAt(aPos - nonmapped);
 }
 
 nsresult
 nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
 {
   uint32_t i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
@@ -449,81 +449,79 @@ nsAttrAndChildArray::SetAndSwapAttr(mozi
 }
 
 
 nsresult
 nsAttrAndChildArray::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue)
 {
   NS_ASSERTION(aPos < AttrCount(), "out-of-bounds");
 
-  uint32_t mapped = MappedAttrCount();
-  if (aPos < mapped) {
-    if (mapped == 1) {
-      // We're removing the last mapped attribute.  Can't swap in this
-      // case; have to copy.
-      aValue.SetTo(*mImpl->mMappedAttrs->AttrAt(0));
-      NS_RELEASE(mImpl->mMappedAttrs);
+  uint32_t nonmapped = NonMappedAttrCount();
+  if (aPos < nonmapped) {
+    ATTRS(mImpl)[aPos].mValue.SwapValueWith(aValue);
+    ATTRS(mImpl)[aPos].~InternalAttr();
 
-      return NS_OK;
-    }
+    uint32_t slotCount = AttrSlotCount();
+    memmove(&ATTRS(mImpl)[aPos],
+            &ATTRS(mImpl)[aPos + 1],
+            (slotCount - aPos - 1) * sizeof(InternalAttr));
+    memset(&ATTRS(mImpl)[slotCount - 1], 0, sizeof(InternalAttr));
 
-    RefPtr<nsMappedAttributes> mapped =
-      GetModifiableMapped(nullptr, nullptr, false);
-
-    mapped->RemoveAttrAt(aPos, aValue);
-
-    return MakeMappedUnique(mapped);
+    return NS_OK;
   }
 
-  aPos -= mapped;
-  ATTRS(mImpl)[aPos].mValue.SwapValueWith(aValue);
-  ATTRS(mImpl)[aPos].~InternalAttr();
+  if (MappedAttrCount() == 1) {
+    // We're removing the last mapped attribute.  Can't swap in this
+    // case; have to copy.
+    aValue.SetTo(*mImpl->mMappedAttrs->AttrAt(0));
+    NS_RELEASE(mImpl->mMappedAttrs);
 
-  uint32_t slotCount = AttrSlotCount();
-  memmove(&ATTRS(mImpl)[aPos],
-          &ATTRS(mImpl)[aPos + 1],
-          (slotCount - aPos - 1) * sizeof(InternalAttr));
-  memset(&ATTRS(mImpl)[slotCount - 1], 0, sizeof(InternalAttr));
+    return NS_OK;
+  }
 
-  return NS_OK;
+  RefPtr<nsMappedAttributes> mapped =
+    GetModifiableMapped(nullptr, nullptr, false);
+
+  mapped->RemoveAttrAt(aPos - nonmapped, aValue);
+
+  return MakeMappedUnique(mapped);
 }
 
 const nsAttrName*
 nsAttrAndChildArray::AttrNameAt(uint32_t aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
                "out-of-bounds access in nsAttrAndChildArray");
 
-  uint32_t mapped = MappedAttrCount();
-  if (aPos < mapped) {
-    return mImpl->mMappedAttrs->NameAt(aPos);
+  uint32_t nonmapped = NonMappedAttrCount();
+  if (aPos < nonmapped) {
+    return &ATTRS(mImpl)[aPos].mName;
   }
 
-  return &ATTRS(mImpl)[aPos - mapped].mName;
+  return mImpl->mMappedAttrs->NameAt(aPos - nonmapped);
 }
 
 const nsAttrName*
 nsAttrAndChildArray::GetSafeAttrNameAt(uint32_t aPos) const
 {
-  uint32_t mapped = MappedAttrCount();
-  if (aPos < mapped) {
-    return mImpl->mMappedAttrs->NameAt(aPos);
+  uint32_t nonmapped = NonMappedAttrCount();
+  if (aPos < nonmapped) {
+    void** pos = mImpl->mBuffer + aPos * ATTRSIZE;
+    if (!*pos) {
+      return nullptr;
+    }
+
+    return &reinterpret_cast<InternalAttr*>(pos)->mName;
   }
 
-  aPos -= mapped;
-  if (aPos >= AttrSlotCount()) {
+  if (aPos >= AttrCount()) {
     return nullptr;
   }
 
-  void** pos = mImpl->mBuffer + aPos * ATTRSIZE;
-  if (!*pos) {
-    return nullptr;
-  }
-
-  return &reinterpret_cast<InternalAttr*>(pos)->mName;
+  return mImpl->mMappedAttrs->NameAt(aPos - nonmapped);
 }
 
 const nsAttrName*
 nsAttrAndChildArray::GetExistingAttrNameFromQName(const nsAString& aName) const
 {
   uint32_t i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     if (ATTRS(mImpl)[i].mName.QualifiedNameEquals(aName)) {
@@ -540,35 +538,34 @@ nsAttrAndChildArray::GetExistingAttrName
 
 int32_t
 nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) const
 {
   int32_t idx;
   if (mImpl && mImpl->mMappedAttrs && aNamespaceID == kNameSpaceID_None) {
     idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName);
     if (idx >= 0) {
-      return idx;
+      return NonMappedAttrCount() + idx;
     }
   }
 
   uint32_t i;
-  uint32_t mapped = MappedAttrCount();
   uint32_t slotCount = AttrSlotCount();
   if (aNamespaceID == kNameSpaceID_None) {
     // This should be the common case so lets make an optimized loop
     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
       if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
-        return i + mapped;
+        return i;
       }
     }
   }
   else {
     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
       if (ATTRS(mImpl)[i].mName.Equals(aLocalName, aNamespaceID)) {
-        return i + mapped;
+        return i;
       }
     }
   }
 
   return -1;
 }
 
 nsresult
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8554,18 +8554,17 @@ StartElement(Element* aContent, StringBu
   if (aContent->IsHTMLElement() || aContent->IsSVGElement() ||
       aContent->IsMathMLElement()) {
     aBuilder.Append(localName);
   } else {
     aBuilder.Append(aContent->NodeName());
   }
 
   int32_t count = aContent->GetAttrCount();
-  for (int32_t i = count; i > 0;) {
-    --i;
+  for (int32_t i = 0; i < count; i++) {
     const nsAttrName* name = aContent->GetAttrNameAt(i);
     int32_t attNs = name->NamespaceID();
     nsIAtom* attName = name->LocalName();
 
     // Filter out any attribute starting with [-|_]moz
     nsDependentAtomString attrNameStr(attName);
     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
--- a/dom/base/nsHTMLContentSerializer.cpp
+++ b/dom/base/nsHTMLContentSerializer.cpp
@@ -77,18 +77,17 @@ nsHTMLContentSerializer::SerializeHTMLAt
   int32_t count = aContent->GetAttrCount();
   if (!count)
     return true;
 
   nsresult rv;
   nsAutoString valueStr;
   NS_NAMED_LITERAL_STRING(_mozStr, "_moz");
 
-  for (int32_t index = count; index > 0;) {
-    --index;
+  for (int32_t index = 0; index < count; index++) {
     const nsAttrName* name = aContent->GetAttrNameAt(index);
     int32_t namespaceID = name->NamespaceID();
     nsIAtom* attrName = name->LocalName();
 
     // Filter out any attribute starting with [-|_]moz
     nsDependentAtomString attrNameStr(attrName);
     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
--- a/dom/base/test/test_bug422403-2.xhtml
+++ b/dom/base/test/test_bug422403-2.xhtml
@@ -219,42 +219,42 @@ function testHtmlSerializer_1 () {
   out = encoder.encodeToString();
   expected = '<select xmlns="http://www.w3.org/1999/xhtml" id="shortattr5" multiple="multiple"><option selected="selected">aaa</option></select>';
   is(out, expected, "test short attr #5");
 
   node = document.getElementById('shortattr6');
   encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
   encoder.setNode(node);
   out = encoder.encodeToString();
-  expected = '<hr xmlns="http://www.w3.org/1999/xhtml" noshade="noshade" id="shortattr6" />';
+  expected = '<hr xmlns="http://www.w3.org/1999/xhtml" id="shortattr6" noshade="noshade" />';
   is(out, expected, "test short attr #6");
 
   node = document.getElementById('shortattr7');
   encoder.init(document, "application/xhtml+xml",de.OutputSelectionOnly | de.OutputRaw);
   encoder.setNode(node);
   out = encoder.encodeToString();
   expected = '<div xmlns="http://www.w3.org/1999/xhtml" id="shortattr7"><foo:bar xmlns:foo="http://mozilla.org/ns/any" checked="" value="" disabled="" ismap="" readonly=""/></div>';
   is(out, expected, "test short attr #7");
 
   // test on _moz and -moz attr
   node = document.getElementById('mozattr');
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
   encoder.setNode(node);
   out = encoder.encodeToString();
-  expected = '<div __moz_b="b" id="mozattr"> lorem ipsum</div>';
+  expected = '<div id="mozattr" __moz_b="b"> lorem ipsum</div>';
   is(out, expected, "test -moz/_moz attr");
 
   node.setAttribute('_moz_c','barc');
   node.setAttribute('_-moz_d','bard');
   node.setAttribute('__moz_e','bare');
 
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
   encoder.setNode(node);
   out = encoder.encodeToString();
-  expected = '<div __moz_e="bare" _-moz_d="bard" __moz_b="b" id="mozattr"> lorem ipsum</div>';
+  expected = '<div id="mozattr" __moz_b="b" _-moz_d="bard" __moz_e="bare"> lorem ipsum</div>';
   is(out, expected, "test -moz/_moz attr #2");
 
   SimpleTest.finish();
 }
 
 
 SimpleTest.waitForExplicitFinish();
 
@@ -279,17 +279,17 @@ addLoadEvent(testHtmlSerializer_1);
 
 <!-- test for some short attr -->
 <div id="shortattr" xmlns:foo="http://mozilla.org/ns/any">
    <input id="shortattr1" checked="" value="" disabled="" ismap="" readonly="" foo:checked="" foo:disabled=""/>
    <ol id="shortattr2" compact=""><li></li></ol>
    <object id="shortattr3" declare="" />
    <script id="shortattr4" defer="" />
    <select id="shortattr5" multiple=""><option selected="">aaa</option></select>
-   <hr noshade="" id="shortattr6"/>
+   <hr id="shortattr6" noshade=""/>
    <div id="shortattr7"><foo:bar checked="" value="" disabled="" ismap="" readonly="" /></div>
    <div id="mozattr" _moz_a="a" __moz_b="b"> lorem ipsum</div>
 </div>
 
 </div>
 </body>
 </html>
 
--- a/dom/base/test/test_bug424359-2.html
+++ b/dom/base/test/test_bug424359-2.html
@@ -169,17 +169,17 @@ function testHtmlSerializer_1 () {
 
   // selection start at the third child of the ol, and end after the element ol + ol start at the value 5
   range.setStart(node, 3);
   range.setEnd(node.parentNode, 2);
   node.setAttribute("start","5");
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
   encoder.setSelection(select);
   out = encoder.encodeToString();
-  expected = '<ol start="5" id="aList"><li>sit amet, <strong>consectetuer</strong> </li>\n  <li>adipiscing elit</li>\n  <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n  <li>aptent taciti</li>\n</ol>';
+  expected = '<ol id="aList" start="5"><li>sit amet, <strong>consectetuer</strong> </li>\n  <li>adipiscing elit</li>\n  <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n  <li>aptent taciti</li>\n</ol>';
   is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol + ol start at the value 5");
 
 
   // selection contains only some child of the ol
   node.removeAttribute("start");
   range.setStart(node, 3);
   range.setEnd(node, 5);
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
@@ -267,17 +267,17 @@ function testHtmlSerializer_1 () {
 
   node.setAttribute('_moz_c','barc');
   node.setAttribute('_-moz_d','bard');
   node.setAttribute('__moz_e','bare');
 
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly | de.OutputRaw);
   encoder.setNode(node);
   out = encoder.encodeToString();
-  expected = '<div __moz_e="bare" _-moz_d="bard" id="mozattr" __moz_b="b"> lorem ipsum</div>';
+  expected = '<div id="mozattr" __moz_b="b" _-moz_d="bard" __moz_e="bare"> lorem ipsum</div>';
   is(out, expected, "test -moz/_moz attr #2");
 
   SimpleTest.finish();
 }
 
 
 SimpleTest.waitForExplicitFinish();
 
@@ -312,9 +312,9 @@ addLoadEvent(testHtmlSerializer_1);
    <div id="shortattr7"><foo checked="" value="" disabled="" ismap="" readonly=""></div>
    <div id="mozattr" _moz_a="a" __moz_b="b"> lorem ipsum</div>
 </div>
 
 
 
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/dom/base/test/test_bug744830.html
+++ b/dom/base/test/test_bug744830.html
@@ -49,29 +49,29 @@ https://bugzilla.mozilla.org/show_bug.cg
   t.appendChild(document.createElementNS("http://www.example.org", "example"));
   t.firstChild.textContent = "<foo>";
   is(t.innerHTML, "<example>&lt;foo&gt;</example>");
 
   t.firstChild.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:lang", "us-en");
   is(t.innerHTML, '<example xml:lang="us-en">&lt;foo&gt;</example>');
 
   t.firstChild.setAttributeNS("http://www.w3.org/1999/xlink", "href", "foo");
-  is(t.innerHTML, '<example xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
+  is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo">&lt;foo&gt;</example>');
 
   t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "http://foo");
-  is(t.innerHTML, '<example xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
+  is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo">&lt;foo&gt;</example>');
 
   t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:bar", "http://bar");
-  is(t.innerHTML, '<example xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
+  is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo" xmlns:bar="http://bar">&lt;foo&gt;</example>');
   
   t.firstChild.setAttributeNS("http://www.helloworldns.org", "hello:world", "!");
-  is(t.innerHTML, '<example hello:world="!" xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
+  is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo" xmlns:bar="http://bar" hello:world="!">&lt;foo&gt;</example>');
 
   t.firstChild.setAttribute("foo", '-"&\xA0-');
-  is(t.innerHTML, '<example foo="-&quot;&amp;&nbsp;-" hello:world="!" xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
+  is(t.innerHTML, '<example xml:lang="us-en" xlink:href="foo" xmlns="http://foo" xmlns:bar="http://bar" hello:world="!" foo="-&quot;&amp;&nbsp;-">&lt;foo&gt;</example>');
 
   t.innerHTML = null;
   t.appendChild(document.createElement("div"));
   t.firstChild.appendChild(document.implementation
                                    .createDocument(null, null, null)
                                    .createCDATASection("foo"));
   is(t.innerHTML, '<div>foo</div>');
 
--- a/dom/base/test/test_htmlcopyencoder.html
+++ b/dom/base/test/test_htmlcopyencoder.html
@@ -113,17 +113,17 @@ function testHtmlCopyEncoder () {
 
   // selection start at the third child of the ol, and end after the element ol + ol start at the value 5
   range.setStart(node, 3);
   range.setEnd(node.parentNode, 2);
   node.setAttribute("start","5");
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
   encoder.setSelection(select);
   out = encoder.encodeToString();
-  expected = '<ol start=\"5\" id=\"aList\"><li value=\"6\">sit amet, <strong>consectetuer</strong> </li>\n  <li>adipiscing elit</li>\n  <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n  <li>aptent taciti</li>\n</ol>';
+  expected = '<ol id=\"aList\" start=\"5\"><li value=\"6\">sit amet, <strong>consectetuer</strong> </li>\n  <li>adipiscing elit</li>\n  <li>Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class</li>\n  <li>aptent taciti</li>\n</ol>';
   is(out, expected, "test list selection with range: selection start at the third child of the ol, and end after the element ol + ol start at the value 5");
 
   // selection contains only some child of the ol
   node.removeAttribute("start");
   range.setStart(node, 3);
   range.setEnd(node, 5);
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
   encoder.setSelection(select);
--- a/dom/base/test/test_htmlcopyencoder.xhtml
+++ b/dom/base/test/test_htmlcopyencoder.xhtml
@@ -33,21 +33,17 @@ function testHtmlCopyEncoder () {
   encoder.setContainerNode(node);
   out = encoder.encodeToString();
   expected = 'This is a <em>draggable</em> <br>bit of text.';
   is(out, expected, "test container node ");
 
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
   encoder.setNode(node);
   out = encoder.encodeToString();
-  // the attributes are in the reverse order because the XHTML parser parse in the
-  // right order but the html serializer serializes in the reverse order
-  // (because the html parser stores the attribute in the reverse order,
-  // see bug 213347 for reason).
-  expected = "<div ondragstart=\"doDragStartSelection(event)\" id=\"draggable\">This is a <em>draggable</em> <br>bit of text.</div>";
+  expected = "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> <br>bit of text.</div>";
   is(out, expected, "test node");
 
   var select = window.getSelection();
   select.selectAllChildren(node);
   
   encoder.init(document, "text/html", de.OutputLFLineBreak | de.OutputSelectionOnly);
   encoder.setSelection(select);
   out = encoder.encodeToString();
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -405,18 +405,17 @@ nsHtml5TreeOperation::CreateElement(int3
     }
   }
 
   if (!aAttributes) {
     return newContent;
   }
 
   int32_t len = aAttributes->getLength();
-  for (int32_t i = len; i > 0;) {
-    --i;
+  for (int32_t i = 0; i < len; i++) {
     // prefix doesn't need regetting. it is always null or a static atom
     // local name is never null
     nsCOMPtr<nsIAtom> localName =
       Reget(aAttributes->getLocalNameNoBoundsCheck(i));
     nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
     int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
 
     if (aNs == kNameSpaceID_XHTML &&
--- a/parser/xml/test/unit/results.js
+++ b/parser/xml/test/unit/results.js
@@ -34,17 +34,17 @@ var vectors = [
     "sanitized": "<html><head></head><body></body></html>"
   },
   {
     "data": "<a style=\"-o-link:'javascript:alert(1)';-o-link-source:current\">X</a>",
     "sanitized": "<html><head></head><body><a>X</a></body></html>"
   },
   {
     "data": "<video poster=javascript:alert(1)//></video>",
-    "sanitized": "<html><head></head><body><video controls=\"controls\" poster=\"javascript:alert(1)//\"></video></body></html>"
+    "sanitized": "<html><head></head><body><video poster=\"javascript:alert(1)//\" controls=\"controls\"></video></body></html>"
   },
   {
     "data": "<svg xmlns=\"http://www.w3.org/2000/svg\"><g onload=\"javascript:alert(1)\"></g></svg>",
     "sanitized": "<html><head></head><body></body></html>"
   },
   {
     "data": "<body onscroll=alert(1)><br><br><br><br><br><br>...<br><br><br><br><input autofocus>",
     "sanitized": "<html><head></head><body><br><br><br><br><br><br>...<br><br><br><br></body></html>"
deleted file mode 100644
--- a/testing/web-platform/meta/dom/collections/domstringmap-supported-property-names.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[domstringmap-supported-property-names.html]
-  type: testharness
-  [Object.getOwnPropertyNames on DOMStringMap, multiple data attributes]
-    expected: FAIL
-
--- a/testing/web-platform/meta/dom/collections/namednodemap-supported-property-names.html.ini
+++ b/testing/web-platform/meta/dom/collections/namednodemap-supported-property-names.html.ini
@@ -1,11 +1,8 @@
 [namednodemap-supported-property-names.html]
   type: testharness
-  [Object.getOwnPropertyNames on NamedNodeMap]
-    expected: FAIL
-
   [Object.getOwnPropertyNames on NamedNodeMap of input]
     expected: FAIL
 
   [Object.getOwnPropertyNames on NamedNodeMap after attribute removal]
     expected: FAIL