Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 03 Jul 2014 17:03:48 -0400
changeset 213032 06e9a27a6fcc5e665588fa4f670d141fd9bac694
parent 212958 613bc15ccf05629e0d0e7c5f7e53a44aa99ded41 (current diff)
parent 213031 90c7fc5b903427a9de972f274ca24c566e680489 (diff)
child 213062 dc28da9f9d80643688cd9266ed4a857cd1eb2dfc
child 213086 2991fb290e14db9e6b528e6d9704ada6d2097c32
child 213110 36ea984c29a5fecce1438a369ebcbb38bf59317a
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
--- a/accessible/tests/mochitest/events/test_focus_browserui.xul
+++ b/accessible/tests/mochitest/events/test_focus_browserui.xul
@@ -91,27 +91,23 @@
                                browserWindow()));
 
       // open new url, focus moves to new document
       gQueue.push(new loadURI(gButtonDocURI));
 
       // back one page in history, moves moves on input of tab document
       gQueue.push(new goBack());
 
-if (!MAC) {
       // open new tab, focus moves to urlbar
-      gQueue.push(new synthKey(tabDocument, "t", { ctrlKey: true, window: browserWindow() },
+      gQueue.push(new synthKey(tabDocument, "t", { accelKey: true, window: browserWindow() },
                                new focusChecker(urlbarInput)));
 
       // close open tab, focus goes on input of tab document
-      gQueue.push(new synthKey(tabDocument, "w", { ctrlKey: true, window: browserWindow() },
+      gQueue.push(new synthKey(tabDocument, "w", { accelKey: true, window: browserWindow() },
                                new focusChecker(inputInDocument)));
-} else {
-      todo(false, "Reenable on Mac after fixing bug 746178!");
-}
 
       gQueue.onFinish = function()
       {
         closeBrowserWindow();
       }
       gQueue.invoke();
     }
 
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -286,17 +286,17 @@ skip-if = (os == "linux" && debug) || e1
 [browser_discovery.js]
 skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome
 [browser_duplicateIDs.js]
 [browser_drag.js]
 skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 [browser_findbarClose.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (tries to grab an iframe directly from content)
 [browser_fullscreen-window-open.js]
-skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
+skip-if = e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
 [browser_gestureSupport.js]
 skip-if = e10s # Bug 863514 - no gesture support.
 [browser_getshortcutoruri.js]
 [browser_hide_removing.js]
 [browser_homeDrop.js]
 [browser_identity_UI.js]
 skip-if = e10s # Bug ?????? - this test fails for obscure reasons on non-windows builds only.
 [browser_keywordBookmarklets.js]
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -511,23 +511,23 @@ function synthesizeNativeMouseLDown(aEle
  * @param aElement The element used to determine the cursor position.
  */
 function synthesizeNativeMouseLUp(aElement) {
   let msg = isWindows ? 4 : (isMac ? 2 : 7);
   synthesizeNativeMouseEvent(aElement, msg);
 }
 
 /**
- * Fires a synthetic mouse drag event on the current about:newtab page.
+ * Fires a synthetic mouse vertical drag event on the current about:newtab page.
  * @param aElement The element used to determine the cursor position.
- * @param aOffsetX The left offset that is added to the position.
+ * @param aOffsetY The top offset that is added to the position.
  */
-function synthesizeNativeMouseDrag(aElement, aOffsetX) {
+function synthesizeNativeMouseDrag(aElement, aOffsetY) {
   let msg = isMac ? 6 : 1;
-  synthesizeNativeMouseEvent(aElement, msg, aOffsetX);
+  synthesizeNativeMouseEvent(aElement, msg, 0, aOffsetY);
 }
 
 /**
  * Fires a synthetic 'mousemove' event on the current about:newtab page.
  * @param aElement The element used to determine the cursor position.
  */
 function synthesizeNativeMouseMove(aElement) {
   let msg = isMac ? 5 : 1;
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -75,16 +75,17 @@ skip-if = e10s # Bug ?????? - test uses 
 [browser_967000_button_charEncoding.js]
 skip-if = e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s friendly.
 [browser_967000_button_feeds.js]
 skip-if = e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s friendly.
 [browser_967000_button_sync.js]
 skip-if = e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s friendly.
 [browser_967000_button_tabView.js]
 [browser_968447_bookmarks_toolbar_items_in_panel.js]
+skip-if = os == "linux" # Intemittent failures - bug 979207
 [browser_968565_insert_before_hidden_items.js]
 [browser_969427_recreate_destroyed_widget_after_reset.js]
 [browser_969661_character_encoding_navbar_disabled.js]
 [browser_970511_undo_restore_default.js]
 [browser_972267_customizationchange_events.js]
 [browser_973932_addonbar_currentset.js]
 [browser_975719_customtoolbars_behaviour.js]
 
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -132,16 +132,17 @@ support-files =
 [browser_console_filters.js]
 [browser_console_iframe_messages.js]
 [browser_console_keyboard_accessibility.js]
 [browser_console_log_inspectable_object.js]
 [browser_console_native_getters.js]
 [browser_console_navigation_marker.js]
 [browser_console_nsiconsolemessage.js]
 [browser_console_optimized_out_vars.js]
+skip-if = true # Intermittent failures - bug 1016310
 [browser_console_private_browsing.js]
 [browser_console_variables_view.js]
 [browser_console_variables_view_dom_nodes.js]
 [browser_console_variables_view_dont_sort_non_sortable_classes_properties.js]
 [browser_console_variables_view_while_debugging.js]
 [browser_console_variables_view_while_debugging_and_inspecting.js]
 [browser_eval_in_debugger_stackframe.js]
 [browser_jsterm_inspect.js]
--- a/browser/modules/test/browser.ini
+++ b/browser/modules/test/browser.ini
@@ -19,17 +19,17 @@ skip-if = os == "linux" || e10s # Interm
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour3.js]
 skip-if = os == "linux" || e10s # Linux: Bug 986760, Bug 989101; e10s: Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_availableTargets.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_detach_tab.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_annotation_size_attributes.js]
-skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
+skip-if = e10s || os == "win" # Bug 941428 - UITour.jsm not e10s friendly. Intermittent test failures on Windows (bug 1026310 & bug 1032137)
 [browser_UITour_panel_close_annotation.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_registerPageID.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_sync.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_taskbar_preview.js]
 run-if = os == "win"
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -237,17 +237,17 @@ public:
    */
   bool IsInAnonymousSubtree() const
   {
     NS_ASSERTION(!IsInNativeAnonymousSubtree() || GetBindingParent() ||
                  (!IsInDoc() &&
                   static_cast<nsIContent*>(SubtreeRoot())->IsInNativeAnonymousSubtree()),
                  "Must have binding parent when in native anonymous subtree which is in document.\n"
                  "Native anonymous subtree which is not in document must have native anonymous root.");
-    return IsInNativeAnonymousSubtree() || (!HasFlag(NODE_IS_IN_SHADOW_TREE) && GetBindingParent() != nullptr);
+    return IsInNativeAnonymousSubtree() || (!IsInShadowTree() && GetBindingParent() != nullptr);
   }
 
   /**
    * Return true iff this node is in an HTML document (in the HTML5 sense of
    * the term, i.e. not in an XHTML/XML document).
    */
   inline bool IsInHTMLDocument() const;
 
@@ -878,20 +878,20 @@ public:
    * there is a scroll frame that contains the frame being scrolled). This
    * frame is always the first continuation.
    *
    * In the case of absolutely positioned elements and floated elements, this
    * frame is the out of flow frame, not the placeholder.
    */
   nsIFrame* GetPrimaryFrame() const
   {
-    return (IsInDoc() || HasFlag(NODE_IS_IN_SHADOW_TREE)) ? mPrimaryFrame : nullptr;
+    return (IsInDoc() || IsInShadowTree()) ? mPrimaryFrame : nullptr;
   }
   void SetPrimaryFrame(nsIFrame* aFrame) {
-    MOZ_ASSERT(IsInDoc() || HasFlag(NODE_IS_IN_SHADOW_TREE), "This will end badly!");
+    MOZ_ASSERT(IsInDoc() || IsInShadowTree(), "This will end badly!");
     NS_PRECONDITION(!aFrame || !mPrimaryFrame || aFrame == mPrimaryFrame,
                     "Losing track of existing primary frame");
     mPrimaryFrame = aFrame;
   }
 
   nsresult LookupNamespaceURIInternal(const nsAString& aNamespacePrefix,
                                       nsAString& aNamespaceURI) const;
 
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -271,18 +271,18 @@ private:
 // Categories of node properties
 // 0 is global.
 #define DOM_USER_DATA         1
 #define DOM_USER_DATA_HANDLER 2
 #define SMIL_MAPPED_ATTR_ANIMVAL 3
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0x77a62cd0, 0xb34f, 0x42cb, \
-  { 0x94, 0x52, 0xae, 0xb2, 0x4d, 0x93, 0x2c, 0xb4 } }
+{ 0x3bd80589, 0xa6f4, 0x4a57, \
+  { 0xab, 0x38, 0xa0, 0x5b, 0x77, 0x4c, 0x3e, 0xa8 } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public mozilla::dom::EventTarget
 {
@@ -505,43 +505,76 @@ public:
    */
   nsINode *OwnerDocAsNode() const;
 
   /**
    * Returns true if the content has an ancestor that is a document.
    *
    * @return whether this content is in a document tree
    */
+  bool IsInUncomposedDoc() const
+  {
+    return GetBoolFlag(IsInDocument);
+  }
+
+  /**
+   * @deprecated
+   */
   bool IsInDoc() const
   {
-    return GetBoolFlag(IsInDocument);
+    return IsInUncomposedDoc();
   }
 
   /**
    * Get the document that this content is currently in, if any. This will be
    * null if the content has no ancestor that is a document.
    *
    * @return the current document
    */
+
+  nsIDocument* GetUncomposedDoc() const
+  {
+    return IsInUncomposedDoc() ? OwnerDoc() : nullptr;
+  }
+
+  /**
+   * @deprecated
+   */
   nsIDocument *GetCurrentDoc() const
   {
-    return IsInDoc() ? OwnerDoc() : nullptr;
+    return GetUncomposedDoc();
   }
 
   /**
    * This method gets the current doc of the node hosting this content
    * or the current doc of this content if it is not being hosted. This
    * method walks through ShadowRoot boundaries until it reach the host
    * that is located in the root of the "tree of trees" (see Shadow DOM
    * spec) and returns the current doc for that host.
    */
+  nsIDocument* GetComposedDoc() const
+  {
+    return IsInShadowTree() ?
+      GetComposedDocInternal() : GetUncomposedDoc();
+  }
+
+  /**
+   * @deprecated
+   */
   nsIDocument* GetCrossShadowCurrentDoc() const
   {
-    return HasFlag(NODE_IS_IN_SHADOW_TREE) ?
-      GetCrossShadowCurrentDocInternal() : GetCurrentDoc();
+    return GetComposedDoc();
+  }
+
+  /**
+   * Returns true if GetComposedDoc() would return a non-null value.
+   */
+  bool IsInComposedDoc() const
+  {
+    return IsInUncomposedDoc() || (IsInShadowTree() && GetComposedDocInternal());
   }
 
   /**
    * The values returned by this function are the ones defined for
    * nsIDOMNode.nodeType
    */
   uint16_t NodeType() const
   {
@@ -1015,16 +1048,21 @@ public:
 
   // True for native anonymous content and for XBL content if the binging
   // has chromeOnlyContent="true".
   bool ChromeOnlyAccess() const
   {
     return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_CHROME_ONLY_ACCESS);
   }
 
+  bool IsInShadowTree() const
+  {
+    return HasFlag(NODE_IS_IN_SHADOW_TREE);
+  }
+
   /**
    * Returns true if |this| node is the common ancestor of the start/end
    * nodes of a Range in a Selection or a descendant of such a common ancestor.
    * This node is definitely not selected when |false| is returned, but it may
    * or may not be selected when |true| is returned.
    */
   bool IsSelectionDescendant() const
   {
@@ -1198,17 +1236,17 @@ public:
    */
   bool Contains(const nsINode* aOther) const;
   nsresult Contains(nsIDOMNode* aOther, bool* aReturn);
 
   bool UnoptimizableCCNode() const;
 
 private:
 
-  nsIDocument* GetCrossShadowCurrentDocInternal() const;
+  nsIDocument* GetComposedDocInternal() const;
 
   nsIContent* GetNextNodeImpl(const nsINode* aRoot,
                               const bool aSkipChildren) const
   {
     // Can't use nsContentUtils::ContentIsDescendantOf here, since we
     // can't include it here.
 #ifdef DEBUG
     if (aRoot) {
@@ -1520,17 +1558,17 @@ protected:
   bool HandlingClick() const { return GetBoolFlag(NodeHandlingClick); }
   void SetHandlingClick() { SetBoolFlag(NodeHandlingClick); }
   void ClearHandlingClick() { ClearBoolFlag(NodeHandlingClick); }
 
   void SetSubtreeRootPointer(nsINode* aSubtreeRoot)
   {
     NS_ASSERTION(aSubtreeRoot, "aSubtreeRoot can never be null!");
     NS_ASSERTION(!(IsNodeOfType(eCONTENT) && IsInDoc()) &&
-                 !HasFlag(NODE_IS_IN_SHADOW_TREE), "Shouldn't be here!");
+                 !IsInShadowTree(), "Shouldn't be here!");
     mSubtreeRoot = aSubtreeRoot;
   }
 
   void ClearSubtreeRootPointer()
   {
     mSubtreeRoot = nullptr;
   }
 
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -746,17 +746,17 @@ Element::GetClientRects()
 
 
 //----------------------------------------------------------------------
 
 void
 Element::AddToIdTable(nsIAtom* aId)
 {
   NS_ASSERTION(HasID(), "Node doesn't have an ID?");
-  if (HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  if (IsInShadowTree()) {
     ShadowRoot* containingShadow = GetContainingShadow();
     containingShadow->AddToIdTable(this, aId);
   } else {
     nsIDocument* doc = GetCurrentDoc();
     if (doc && (!IsInAnonymousSubtree() || doc->IsXUL())) {
       doc->AddToIdTable(this, aId);
     }
   }
@@ -765,17 +765,17 @@ Element::AddToIdTable(nsIAtom* aId)
 void
 Element::RemoveFromIdTable()
 {
   if (!HasID()) {
     return;
   }
 
   nsIAtom* id = DoGetID();
-  if (HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  if (IsInShadowTree()) {
     ShadowRoot* containingShadow = GetContainingShadow();
     // Check for containingShadow because it may have
     // been deleted during unlinking.
     if (containingShadow) {
       containingShadow->RemoveFromIdTable(this, id);
     }
   } else {
     nsIDocument* doc = GetCurrentDoc();
@@ -1227,17 +1227,17 @@ Element::BindToTree(nsIDocument* aDocume
                "non-native anonymous parent!");
   if (aParent) {
     if (aParent->IsInNativeAnonymousSubtree()) {
       SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
     }
     if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
       SetFlags(NODE_CHROME_ONLY_ACCESS);
     }
-    if (aParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+    if (aParent->IsInShadowTree()) {
       ClearSubtreeRootPointer();
       SetFlags(NODE_IS_IN_SHADOW_TREE);
     }
     ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
     if (parentContainingShadow) {
       DOMSlots()->mContainingShadow = parentContainingShadow;
     }
   }
@@ -1286,17 +1286,17 @@ Element::BindToTree(nsIDocument* aDocume
     }
 
     // Unset this flag since we now really are in a document.
     UnsetFlags(NODE_FORCE_XBL_BINDINGS |
                // And clear the lazy frame construction bits.
                NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
                // And the restyle bits
                ELEMENT_ALL_RESTYLE_FLAGS);
-  } else if (!HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  } else if (!IsInShadowTree()) {
     // If we're not in the doc and not in a shadow tree,
     // update our subtree pointer.
     SetSubtreeRootPointer(aParent->SubtreeRoot());
   }
 
   // Propagate scoped style sheet tracking bit.
   if (mParent->IsContent()) {
     nsIContent* parent;
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -166,17 +166,17 @@ nsIContent::GetFlattenedTreeParent() con
   }
 
   if (!parent) {
     parent = GetParent();
   }
 
   // Shadow roots never shows up in the flattened tree. Return the host
   // instead.
-  if (parent && parent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  if (parent && parent->IsInShadowTree()) {
     ShadowRoot* parentShadowRoot = ShadowRoot::FromNode(parent);
     if (parentShadowRoot) {
       return parentShadowRoot->GetHost();
     }
   }
 
   return parent;
 }
--- a/content/base/src/ShadowRoot.cpp
+++ b/content/base/src/ShadowRoot.cpp
@@ -107,17 +107,17 @@ JSObject*
 ShadowRoot::WrapObject(JSContext* aCx)
 {
   return mozilla::dom::ShadowRootBinding::Wrap(aCx, this);
 }
 
 ShadowRoot*
 ShadowRoot::FromNode(nsINode* aNode)
 {
-  if (aNode->HasFlag(NODE_IS_IN_SHADOW_TREE) && !aNode->GetParentNode()) {
+  if (aNode->IsInShadowTree() && !aNode->GetParentNode()) {
     MOZ_ASSERT(aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
                "ShadowRoot is a document fragment.");
     return static_cast<ShadowRoot*>(aNode);
   }
 
   return nullptr;
 }
 
--- a/content/base/src/nsCSPContext.cpp
+++ b/content/base/src/nsCSPContext.cpp
@@ -179,17 +179,17 @@ nsCSPContext::ShouldLoad(nsContentPolicy
         *outDecision = nsIContentPolicy::REJECT_SERVER;
       }
 
       // Do not send a report or notify observers if this is a preload - the
       // decision may be wrong due to the inability to get the nonce, and will
       // incorrectly fail the unit tests.
       if (!isPreload) {
         this->AsyncReportViolation(aContentLocation,
-                                   aRequestOrigin,
+                                   mSelfURI,
                                    violatedDirective,
                                    p,             /* policy index        */
                                    EmptyString(), /* no observer subject */
                                    EmptyString(), /* no source file      */
                                    EmptyString(), /* no script sample    */
                                    0);            /* no line number      */
       }
     }
@@ -436,17 +436,17 @@ nsCSPContext::GetAllowsHash(const nsAStr
     PR_BEGIN_MACRO                                                             \
     if (!mPolicies[p]->allows(nsIContentPolicy::TYPE_ ## contentPolicyType,    \
                               keyword, nonceOrHash))                           \
     {                                                                          \
       nsAutoString violatedDirective;                                          \
       mPolicies[p]->getDirectiveStringForContentType(                          \
                         nsIContentPolicy::TYPE_ ## contentPolicyType,          \
                         violatedDirective);                                    \
-      this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
+      this->AsyncReportViolation(selfISupports, mSelfURI, violatedDirective, p, \
                                  NS_LITERAL_STRING(observerTopic),             \
                                  aSourceFile, aScriptSample, aLineNum);        \
     }                                                                          \
     PR_END_MACRO;                                                              \
     break
 
 /**
  * For each policy, log any violation on the Error Console and send a report
@@ -687,50 +687,51 @@ nsCSPContext::SendReports(nsISupports* a
   if (!aScriptSample.IsEmpty()) {
     csp_report.AppendASCII(", \"script-sample\": \"");
     csp_report.Append(aScriptSample);
     csp_report.AppendASCII("\"");
   }
 
   // line-number
   if (aLineNum != 0) {
-    csp_report.AppendASCII(", \"script-sample\": \"");
+    csp_report.AppendASCII(", \"line-number\": \"");
     csp_report.AppendInt(aLineNum);
     csp_report.AppendASCII("\"");
   }
 
   csp_report.AppendASCII("}}\n\n");
 
   // ---------- Assembled, now send it to all the report URIs ----------- //
 
   nsTArray<nsString> reportURIs;
   mPolicies[aViolatedPolicyIndex]->getReportURIs(reportURIs);
 
   nsCOMPtr<nsIURI> reportURI;
   nsCOMPtr<nsIChannel> reportChannel;
 
   for (uint32_t r = 0; r < reportURIs.Length(); r++) {
+    nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]);
     // try to create a new uri from every report-uri string
     rv = NS_NewURI(getter_AddRefs(reportURI), reportURIs[r]);
     if (NS_FAILED(rv)) {
       const char16_t* params[] = { reportURIs[r].get() };
       CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
-                     reportURIs[r].get()));
+                     reportURICstring.get()));
       CSP_LogLocalizedStr(NS_LITERAL_STRING("triedToSendReport").get(),
                           params, ArrayLength(params),
                           aSourceFile, aScriptSample, aLineNum, 0,
                           nsIScriptError::errorFlag, "CSP", mInnerWindowID);
       continue; // don't return yet, there may be more URIs
     }
 
     // try to create a new channel for every report-uri
     rv = NS_NewChannel(getter_AddRefs(reportChannel), reportURI);
     if (NS_FAILED(rv)) {
       CSPCONTEXTLOG(("Could not create new channel for report URI %s",
-                     reportURIs[r].get()));
+                     reportURICstring.get()));
       continue; // don't return yet, there may be more URIs
     }
 
     // make sure this is an anonymous request (no cookies) so in case the
     // policy URI is injected, it can't be abused for CSRF.
     nsLoadFlags flags;
     rv = reportChannel->GetLoadFlags(&flags);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -766,17 +767,17 @@ nsCSPContext::SendReports(nsISupports* a
                         &shouldLoad);
 
     // refuse to load if we can't do a security check
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (NS_CP_REJECTED(shouldLoad)) {
       // skip unauthorized URIs
       CSPCONTEXTLOG(("nsIContentPolicy blocked sending report to %s",
-                     reportURIs[r].get()));
+                     reportURICstring.get()));
       continue; // don't return yet, there may be more URIs
     }
 
     // wire in the string input stream to send the report
     nsCOMPtr<nsIStringInputStream> sis(do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID));
     NS_ASSERTION(sis, "nsIStringInputStream is needed but not available to send CSP violation reports");
     rv = sis->SetData(NS_ConvertUTF16toUTF8(csp_report).get(), csp_report.Length());
     NS_ENSURE_SUCCESS(rv, rv);
@@ -802,16 +803,18 @@ nsCSPContext::SendReports(nsISupports* a
 
     if (NS_FAILED(rv)) {
       const char16_t* params[] = { reportURIs[r].get() };
       CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", params[0]));
       CSP_LogLocalizedStr(NS_LITERAL_STRING("triedToSendReport").get(),
                           params, ArrayLength(params),
                           aSourceFile, aScriptSample, aLineNum, 0,
                           nsIScriptError::errorFlag, "CSP", mInnerWindowID);
+    } else {
+      CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
     }
   }
   return NS_OK;
 }
 
 /**
  * Dispatched from the main thread to send reports for one CSP violation.
  */
@@ -825,18 +828,17 @@ class CSPReportSenderRunnable MOZ_FINAL 
                             const nsAString& aViolatedDirective,
                             const nsAString& aObserverSubject,
                             const nsAString& aSourceFile,
                             const nsAString& aScriptSample,
                             uint32_t aLineNum,
                             uint64_t aInnerWindowID,
                             nsCSPContext* aCSPContext)
       : mBlockedContentSource(aBlockedContentSource)
-      , mOriginalURI(aOriginalURI)
-      , mViolatedPolicyIndex(aViolatedPolicyIndex)
+      , mOriginalURI(aOriginalURI) , mViolatedPolicyIndex(aViolatedPolicyIndex)
       , mReportOnlyFlag(aReportOnlyFlag)
       , mViolatedDirective(aViolatedDirective)
       , mSourceFile(aSourceFile)
       , mScriptSample(aScriptSample)
       , mLineNum(aLineNum)
       , mInnerWindowID(aInnerWindowID)
       , mCSPContext(aCSPContext)
     {
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4524,17 +4524,17 @@ nsContentUtils::IsInSameAnonymousTree(co
     return aContent->GetBindingParent() == nullptr;
   }
 
   const nsIContent* nodeAsContent = static_cast<const nsIContent*>(aNode);
 
   // For nodes in a shadow tree, it is insufficient to simply compare
   // the binding parent because a node may host multiple ShadowRoots,
   // thus nodes in different shadow tree may have the same binding parent.
-  if (aNode->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  if (aNode->IsInShadowTree()) {
     return nodeAsContent->GetContainingShadow() ==
       aContent->GetContainingShadow();
   }
 
   return nodeAsContent->GetBindingParent() == aContent->GetBindingParent();
 }
 
 class AnonymousContentDestroyer : public nsRunnable {
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -486,17 +486,17 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
                  "non-native anonymous parent!");
     DataSlots()->mBindingParent = aBindingParent; // Weak, so no addref happens.
     if (aParent->IsInNativeAnonymousSubtree()) {
       SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
     }
     if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
       SetFlags(NODE_CHROME_ONLY_ACCESS);
     }
-    if (aParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+    if (aParent->IsInShadowTree()) {
       ClearSubtreeRootPointer();
       SetFlags(NODE_IS_IN_SHADOW_TREE);
     }
     ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
     if (parentContainingShadow) {
       DataSlots()->mContainingShadow = parentContainingShadow;
     }
   }
@@ -523,17 +523,17 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
 
     // XXX See the comment in Element::BindToTree
     SetInDocument();
     if (mText.IsBidi()) {
       aDocument->SetBidiEnabled();
     }
     // Clear the lazy frame construction bits.
     UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
-  } else if (!HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  } else if (!IsInShadowTree()) {
     // If we're not in the doc and not in a shadow tree,
     // update our subtree pointer.
     SetSubtreeRootPointer(aParent->SubtreeRoot());
   }
 
   nsNodeUtils::ParentChainChanged(this);
 
   UpdateEditableState(false);
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -379,17 +379,17 @@ nsINode::ChildNodes()
 
 void
 nsINode::GetTextContentInternal(nsAString& aTextContent)
 {
   SetDOMStringToNull(aTextContent);
 }
 
 nsIDocument*
-nsINode::GetCrossShadowCurrentDocInternal() const
+nsINode::GetComposedDocInternal() const
 {
   MOZ_ASSERT(HasFlag(NODE_IS_IN_SHADOW_TREE) && IsContent(),
              "Should only be caled on nodes in the shadow tree.");
 
   // Cross ShadowRoot boundary.
   ShadowRoot* containingShadow = AsContent()->GetContainingShadow();
   return containingShadow->GetHost()->GetCrossShadowCurrentDoc();
 }
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -338,17 +338,17 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
       nsresult rv = oldURI->Equals(uri, &equal);
       if (NS_SUCCEEDED(rv) && equal) {
         return NS_OK; // We already loaded this stylesheet
       }
     }
   }
 
   if (mStyleSheet) {
-    if (thisContent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+    if (thisContent->IsInShadowTree()) {
       ShadowRoot* containingShadow = thisContent->GetContainingShadow();
       containingShadow->RemoveSheet(mStyleSheet);
     } else {
       doc->BeginUpdate(UPDATE_STYLE);
       doc->RemoveStyleSheet(mStyleSheet);
       doc->EndUpdate(UPDATE_STYLE);
     }
 
@@ -438,17 +438,17 @@ nsStyleLinkElement::UpdateStyleSheetScop
                                nullptr;
 
   if (oldScopeElement == newScopeElement) {
     return;
   }
 
   nsIDocument* document = thisContent->GetOwnerDocument();
 
-  if (thisContent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  if (thisContent->IsInShadowTree()) {
     ShadowRoot* containingShadow = thisContent->GetContainingShadow();
     containingShadow->RemoveSheet(mStyleSheet);
 
     mStyleSheet->SetScopeElement(newScopeElement);
 
     containingShadow->InsertSheet(mStyleSheet, thisContent);
   } else {
     document->BeginUpdate(UPDATE_STYLE);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -4060,22 +4060,21 @@ ArrayBufferBuilder::getArrayBuffer(JSCon
   // added
   if (mCapacity > mLength || mLength == 0) {
     if (!setCapacity(mLength)) {
       return nullptr;
     }
   }
 
   JSObject* obj = JS_NewArrayBufferWithContents(aCx, mLength, mDataPtr);
-  mDataPtr = nullptr;
   mLength = mCapacity = 0;
   if (!obj) {
     js_free(mDataPtr);
-    return nullptr;
   }
+  mDataPtr = nullptr;
   return obj;
 }
 
 nsresult
 ArrayBufferBuilder::mapToFileInPackage(const nsCString& aFile,
                                        nsIFile* aJarFile)
 {
 #ifdef XP_WIN
--- a/content/base/test/browser.ini
+++ b/content/base/test/browser.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 
 [browser_bug593387.js]
 skip-if = e10s # Bug ?????? - test directly touches content (contentWindow.iframe.addEventListener)
 [browser_bug902350.js]
 skip-if = e10s # Bug ?????? - test e10s utils don't support load events from iframe etc, which this test relies on.
 [browser_state_notifications.js]
-skip-if = e10s # Bug ?????? - content-document-* notifications come while document's URI is still about:blank, but test expects real URL.
+# skip-if = e10s # Bug ?????? - content-document-* notifications come while document's URI is still about:blank, but test expects real URL.
+skip-if = true # Intermittent failures - bug 987493. Restore the skip-if above once fixed
--- a/content/base/test/csp/test_bug949549.html
+++ b/content/base/test/csp/test_bug949549.html
@@ -9,17 +9,17 @@
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=949549">Mozilla Bug 949549</a>
 <div id="content" style="display: none"></div>
 <pre id="test">
 <script type="application/javascript;version=1.8">
   "use strict";
 
   // Ensure that `setRequestContext` doesn't throw with app:// URLs
 
-  const csp = SpecialPowers.Cc["@mozilla.org/contentsecuritypolicy;1"]
+  const csp = SpecialPowers.Cc["@mozilla.org/cspcontext;1"]
               .createInstance(SpecialPowers.Ci.nsIContentSecurityPolicy);
 
   const gManifestURL = "http://www.example.com/chrome/dom/tests/mochitest/webapps/apps/basic.webapp";
 
   SimpleTest.waitForExplicitFinish();
   var app;
 
   function setupTest() {
--- a/content/base/test/unit/test_cspreports.js
+++ b/content/base/test/unit/test_cspreports.js
@@ -2,17 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
-Cu.import('resource://gre/modules/CSPUtils.jsm');
 Cu.import('resource://gre/modules/NetUtil.jsm');
 
 var httpServer = new HttpServer();
 httpServer.start(-1);
 var testsToFinish = 0;
 
 const REPORT_SERVER_PORT = httpServer.identity.primaryPort;
 const REPORT_SERVER_URI = "http://localhost";
@@ -57,18 +56,17 @@ function makeReportHandler(testpath, mes
  * add a test here that will *not* cause a report to go out, you're gonna have
  * to make sure the test cleans up after itself.
  */
 function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
   testsToFinish++;
   do_test_pending();
 
   // set up a new CSP instance for each test.
-  var csp = Cc["@mozilla.org/contentsecuritypolicy;1"]
-  //var csp = Cc["@mozilla.org/cspcontext;1"]
+  var csp = Cc["@mozilla.org/cspcontext;1"]
               .createInstance(Ci.nsIContentSecurityPolicy);
   var policy = "default-src 'none'; " +
                "report-uri " + REPORT_SERVER_URI +
                                ":" + REPORT_SERVER_PORT +
                                "/test" + id;
   var selfuri = NetUtil.newURI(REPORT_SERVER_URI +
                                ":" + REPORT_SERVER_PORT +
                                "/foo/self");
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -554,17 +554,21 @@ NS_INTERFACE_MAP_END
 
 // Initialize our static variables.
 uint32_t CanvasRenderingContext2D::sNumLivingContexts = 0;
 DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
 
 
 
 CanvasRenderingContext2D::CanvasRenderingContext2D()
-  : mForceSoftware(false), mZero(false), mOpaque(false), mResetLayer(true)
+  : mForceSoftware(false)
+  // these are the default values from the Canvas spec
+  , mWidth(300), mHeight(150)
+  , mZero(false), mOpaque(false)
+  , mResetLayer(true)
   , mIPC(false)
   , mStream(nullptr)
   , mIsEntireFrameInvalid(false)
   , mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
   , mInvalidateCount(0)
 {
   sNumLivingContexts++;
   SetIsDOMBinding();
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -370,27 +370,51 @@ WebGLFramebuffer::Attachment::FinalizeAt
     }
 
     MOZ_ASSERT(false, "Should not get here.");
 }
 
 void
 WebGLFramebuffer::Delete()
 {
+    DetachAllAttachments();
     mColorAttachments.Clear();
     mDepthAttachment.Reset();
     mStencilAttachment.Reset();
     mDepthStencilAttachment.Reset();
 
     mContext->MakeContextCurrent();
     mContext->gl->fDeleteFramebuffers(1, &mGLName);
     LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
 }
 
 void
+WebGLFramebuffer::DetachAttachment(WebGLFramebuffer::Attachment& attachment)
+{
+    if (attachment.Texture())
+        attachment.Texture()->DetachFrom(this, attachment.mAttachmentPoint);
+
+    if (attachment.Renderbuffer())
+        attachment.Renderbuffer()->DetachFrom(this, attachment.mAttachmentPoint);
+}
+
+void
+WebGLFramebuffer::DetachAllAttachments()
+{
+    size_t count = mColorAttachments.Length();
+    for (size_t i = 0; i < count; i++) {
+        DetachAttachment(mColorAttachments[i]);
+    }
+
+    DetachAttachment(mDepthAttachment);
+    DetachAttachment(mStencilAttachment);
+    DetachAttachment(mDepthStencilAttachment);
+}
+
+void
 WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
                                           GLenum attachment,
                                           GLenum rbtarget,
                                           WebGLRenderbuffer* wrb)
 {
     MOZ_ASSERT(mContext->mBoundFramebuffer == this);
 
     if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb))
--- a/content/canvas/src/WebGLFramebuffer.h
+++ b/content/canvas/src/WebGLFramebuffer.h
@@ -105,16 +105,18 @@ public:
 
     void FramebufferTexture2D(GLenum target,
                               GLenum attachment,
                               GLenum textarget,
                               WebGLTexture* wtex,
                               GLint level);
 
 private:
+    void DetachAttachment(WebGLFramebuffer::Attachment& attachment);
+    void DetachAllAttachments();
     const WebGLRectangleObject& GetAnyRectObject() const;
     Attachment* GetAttachmentOrNull(GLenum attachment);
 
 public:
     bool HasDefinedAttachments() const;
     bool HasIncompleteAttachments() const;
     bool AllImageRectsMatch() const;
     GLenum PrecheckFramebufferStatus() const;
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3095,19 +3095,19 @@ nsGenericHTMLElement::SetItemValue(JSCon
                                    ErrorResult& aError)
 {
   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) ||
       HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
     aError.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
 
-  nsDependentString string;
+  nsAutoString string;
   JS::Rooted<JS::Value> value(aCx, aValue);
-  if (!ConvertJSValueToString(aCx, value, &value, eStringify, eStringify, string)) {
+  if (!ConvertJSValueToString(aCx, value, eStringify, eStringify, string)) {
     aError.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   SetItemValueText(string);
 }
 
 NS_IMETHODIMP
 nsGenericHTMLElement::SetItemValue(nsIVariant* aValue)
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -411,16 +411,17 @@ skip-if = true # bug 493692
 [test_referer.html]
 [test_replay_metadata.html]
 [test_reset_events_async.html]
 [test_reset_src.html]
 [test_resume.html]
 skip-if = true # bug 1021673
 [test_seek_out_of_range.html]
 [test_seek.html]
+skip-if = true # Intermittent test failures in bug 1023564 and bug 981153
 [test_seek2.html]
 [test_seekable1.html]
 [test_seekable2.html]
 [test_seekable3.html]
 [test_seekLies.html]
 [test_source.html]
 [test_source_media.html]
 [test_source_null.html]
@@ -462,8 +463,9 @@ skip-if = webm
 [test_can_play_type_wave.html]
 run-if = wave
 [test_can_play_type_no_wave.html]
 skip-if = wave
 [test_fragment_noplay.html]
 run-if = wave
 [test_fragment_play.html]
 run-if = wave
+skip-if = buildapp == 'b2g' || toolkit == 'android' # Intermittent failures - Bug 996465 & bug 924246
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2583,17 +2583,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
         JS_SetParent(cx, outerObject, newInnerGlobal);
 
         // Inform the nsJSContext, which is the canonical holder of the outer.
         mContext->SetWindowProxy(outerObject);
 
         NS_ASSERTION(!JS_IsExceptionPending(cx),
                      "We might overwrite a pending exception!");
-        XPCWrappedNativeScope* scope = xpc::GetObjectScope(outerObject);
+        XPCWrappedNativeScope* scope = xpc::ObjectScope(outerObject);
         if (scope->mWaiverWrapperMap) {
           scope->mWaiverWrapperMap->Reparent(cx, newInnerGlobal);
         }
       }
     }
 
     // Enter the new global's compartment.
     JSAutoCompartment ac(cx, GetWrapperPreserveColor());
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -297,22 +297,22 @@ public:
   // shadowing the one on the superclass.
   OwningNonNull<T>& Value()
   {
     return this->mImpl.ref();
   }
 };
 
 // Specialization for strings.
-// XXXbz we can't pull in FakeDependentString here, because it depends on
-// internal strings.  So we just have to forward-declare it and reimplement its
+// XXXbz we can't pull in FakeString here, because it depends on internal
+// strings.  So we just have to forward-declare it and reimplement its
 // ToAStringPtr.
 
 namespace binding_detail {
-struct FakeDependentString;
+struct FakeString;
 } // namespace binding_detail
 
 template<>
 class Optional<nsAString>
 {
 public:
   Optional() : mPassed(false) {}
 
@@ -324,21 +324,21 @@ public:
   void operator=(const nsAString* str)
   {
     MOZ_ASSERT(str);
     mStr = str;
     mPassed = true;
   }
 
   // If this code ever goes away, remove the comment pointing to it in the
-  // FakeDependentString class in BindingUtils.h.
-  void operator=(const binding_detail::FakeDependentString* str)
+  // FakeString class in BindingUtils.h.
+  void operator=(const binding_detail::FakeString* str)
   {
     MOZ_ASSERT(str);
-    mStr = reinterpret_cast<const nsDependentString*>(str);
+    mStr = reinterpret_cast<const nsString*>(str);
     mPassed = true;
   }
 
   const nsAString& Value() const
   {
     MOZ_ASSERT(WasPassed());
     return *mStr;
   }
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2099,40 +2099,38 @@ NonVoidByteStringToJsval(JSContext *cx, 
         return false;
 
     rval.setString(jsStr);
     return true;
 }
 
 bool
 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
-                           JS::MutableHandle<JS::Value> pval, bool nullable,
-                           nsACString& result)
+                           bool nullable, nsACString& result)
 {
   JS::Rooted<JSString*> s(cx);
   if (v.isString()) {
     s = v.toString();
   } else {
 
     if (nullable && v.isNullOrUndefined()) {
       result.SetIsVoid(true);
       return true;
     }
 
     s = JS::ToString(cx, v);
     if (!s) {
       return false;
     }
-    pval.set(JS::StringValue(s));  // Root the new string.
   }
 
   // Conversion from Javascript string to ByteString is only valid if all
   // characters < 256. This is always the case for Latin1 strings.
   size_t length;
-  if (!JS_StringHasLatin1Chars(s)) {
+  if (!js::StringHasLatin1Chars(s)) {
     // ThrowErrorMessage can GC, so we first scan the string for bad chars
     // and report the error outside the AutoCheckCannotGC scope.
     bool foundBadChar = false;
     size_t badCharIndex;
     jschar badChar;
     {
       JS::AutoCheckCannotGC nogc;
       const jschar* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, s, &length);
@@ -2163,22 +2161,22 @@ ConvertJSValueToByteString(JSContext* cx
       // terminator.
       char badCharArray[6];
       static_assert(sizeof(jschar) <= 2, "badCharArray too small");
       PR_snprintf(badCharArray, sizeof(badCharArray), "%d", badChar);
       ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
       return false;
     }
   } else {
-    length = JS_GetStringLength(s);
+    length = js::GetStringLength(s);
   }
 
-  if (length >= UINT32_MAX) {
-    return false;
-  }
+  static_assert(js::MaxStringLength < UINT32_MAX,
+                "length+1 shouldn't overflow");
+
   result.SetCapacity(length+1);
   JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length);
   result.BeginWriting()[length] = '\0';
   result.SetLength(length);
 
   return true;
 }
 
@@ -2472,28 +2470,31 @@ ConvertExceptionToPromise(JSContext* cx,
 void
 CreateGlobalOptions<nsGlobalWindow>::TraceGlobal(JSTracer* aTrc, JSObject* aObj)
 {
   mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
 
   // We might be called from a GC during the creation of a global, before we've
   // been able to set up the compartment private or the XPCWrappedNativeScope,
   // so we need to null-check those.
-  xpc::CompartmentPrivate* compartmentPrivate = xpc::GetCompartmentPrivate(aObj);
+  xpc::CompartmentPrivate* compartmentPrivate = xpc::CompartmentPrivate::Get(aObj);
   if (compartmentPrivate && compartmentPrivate->scope) {
     compartmentPrivate->scope->TraceSelf(aTrc);
   }
 }
 
 /* static */
 bool
 CreateGlobalOptions<nsGlobalWindow>::PostCreateGlobal(JSContext* aCx,
                                                       JS::Handle<JSObject*> aGlobal)
 {
-  return XPCWrappedNativeScope::GetNewOrUsed(aCx, aGlobal);
+  // Invoking the XPCWrappedNativeScope constructor automatically hooks it
+  // up to the compartment of aGlobal.
+  (void) new XPCWrappedNativeScope(aCx, aGlobal);
+  return true;
 }
 
 #ifdef DEBUG
 void
 AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitInfo,
                                JS::Handle<JS::Value> aValue)
 {
   switch (aJitInfo->returnType()) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1123,17 +1123,17 @@ FindEnumStringIndex(JSContext* cx, JS::H
     return 0;
   }
   JS::Anchor<JSString*> anchor(str);
 
   {
     int index;
     size_t length;
     JS::AutoCheckCannotGC nogc;
-    if (JS_StringHasLatin1Chars(str)) {
+    if (js::StringHasLatin1Chars(str)) {
       const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
                                                                      &length);
       if (!chars) {
         *ok = false;
         return 0;
       }
       index = FindEnumStringIndexImpl(chars, length, values);
     } else {
@@ -1716,108 +1716,175 @@ HasPropertyOnPrototype(JSContext* cx, JS
 // then the "proxy" argument is ignored.
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                        nsTArray<nsString>& names,
                        bool shadowPrototypeProperties, JS::AutoIdVector& props);
 
 namespace binding_detail {
 
-// A struct that has the same layout as an nsDependentString but much
-// faster constructor and destructor behavior
-struct FakeDependentString {
-  FakeDependentString() :
-    mFlags(nsDependentString::F_TERMINATED)
+// A struct that has the same layout as an nsString but much faster
+// constructor and destructor behavior. FakeString uses inline storage
+// for small strings and a nsStringBuffer for longer strings.
+struct FakeString {
+  FakeString() :
+    mFlags(nsString::F_TERMINATED)
   {
   }
 
-  void Rebind(const nsDependentString::char_type* aData,
-              nsDependentString::size_type aLength) {
-    MOZ_ASSERT(mFlags == nsDependentString::F_TERMINATED);
-    mData = aData;
+  ~FakeString() {
+    if (mFlags & nsString::F_SHARED) {
+      nsStringBuffer::FromData(mData)->Release();
+    }
+  }
+
+  void Rebind(const nsString::char_type* aData, nsString::size_type aLength) {
+    MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
+    mData = const_cast<nsString::char_type*>(aData);
     mLength = aLength;
   }
 
   void Truncate() {
-    mData = nsDependentString::char_traits::sEmptyBuffer;
+    MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
+    mData = nsString::char_traits::sEmptyBuffer;
     mLength = 0;
   }
 
   void SetIsVoid(bool aValue) {
     MOZ_ASSERT(aValue,
-               "We don't support SetIsVoid(false) on FakeDependentString!");
+               "We don't support SetIsVoid(false) on FakeString!");
     Truncate();
-    mFlags |= nsDependentString::F_VOIDED;
+    mFlags |= nsString::F_VOIDED;
   }
 
-  const nsDependentString::char_type* Data() const
+  const nsString::char_type* Data() const
+  {
+    return mData;
+  }
+
+  nsString::char_type* BeginWriting()
   {
     return mData;
   }
 
-  nsDependentString::size_type Length() const
+  nsString::size_type Length() const
   {
     return mLength;
   }
 
+  // Reserve space to write aCapacity chars, including null-terminator.
+  // Caller is responsible for calling SetLength and writing the null-
+  // terminator.
+  bool SetCapacity(nsString::size_type aCapacity, mozilla::fallible_t const&) {
+    MOZ_ASSERT(aCapacity > 0, "Capacity must include null-terminator");
+
+    // Use mInlineStorage for small strings.
+    if (aCapacity <= sInlineCapacity) {
+      SetData(mInlineStorage);
+      return true;
+    }
+
+    nsRefPtr<nsStringBuffer> buf = nsStringBuffer::Alloc(aCapacity * sizeof(nsString::char_type));
+    if (MOZ_UNLIKELY(!buf)) {
+      return false;
+    }
+
+    SetData(static_cast<nsString::char_type*>(buf.forget().take()->Data()));
+    mFlags = nsString::F_SHARED | nsString::F_TERMINATED;
+    return true;
+  }
+
+  void SetLength(nsString::size_type aLength) {
+    mLength = aLength;
+  }
+
   // If this ever changes, change the corresponding code in the
   // Optional<nsAString> specialization as well.
   const nsAString* ToAStringPtr() const {
-    return reinterpret_cast<const nsDependentString*>(this);
+    return reinterpret_cast<const nsString*>(this);
   }
 
   nsAString* ToAStringPtr() {
-    return reinterpret_cast<nsDependentString*>(this);
+    return reinterpret_cast<nsString*>(this);
   }
 
   operator const nsAString& () const {
-    return *reinterpret_cast<const nsDependentString*>(this);
+    return *reinterpret_cast<const nsString*>(this);
   }
 
 private:
-  const nsDependentString::char_type* mData;
-  nsDependentString::size_type mLength;
+  nsString::char_type* mData;
+  nsString::size_type mLength;
   uint32_t mFlags;
 
+  static const size_t sInlineCapacity = 64;
+  nsString::char_type mInlineStorage[sInlineCapacity];
+
+  FakeString(const FakeString& other) MOZ_DELETE;
+  void operator=(const FakeString& other) MOZ_DELETE;
+
+  void SetData(nsString::char_type* aData) {
+    MOZ_ASSERT(mFlags == nsString::F_TERMINATED);
+    mData = const_cast<nsString::char_type*>(aData);
+  }
+
   // A class to use for our static asserts to ensure our object layout
-  // matches that of nsDependentString.
-  class DependentStringAsserter;
-  friend class DependentStringAsserter;
-
-  class DepedentStringAsserter : public nsDependentString {
+  // matches that of nsString.
+  class StringAsserter;
+  friend class StringAsserter;
+
+  class StringAsserter : public nsString {
   public:
     static void StaticAsserts() {
-      static_assert(sizeof(FakeDependentString) == sizeof(nsDependentString),
-                    "Must have right object size");
-      static_assert(offsetof(FakeDependentString, mData) ==
-                      offsetof(DepedentStringAsserter, mData),
+      static_assert(offsetof(FakeString, mInlineStorage) ==
+                      sizeof(nsString),
+                    "FakeString should include all nsString members");
+      static_assert(offsetof(FakeString, mData) ==
+                      offsetof(StringAsserter, mData),
                     "Offset of mData should match");
-      static_assert(offsetof(FakeDependentString, mLength) ==
-                      offsetof(DepedentStringAsserter, mLength),
+      static_assert(offsetof(FakeString, mLength) ==
+                      offsetof(StringAsserter, mLength),
                     "Offset of mLength should match");
-      static_assert(offsetof(FakeDependentString, mFlags) ==
-                      offsetof(DepedentStringAsserter, mFlags),
+      static_assert(offsetof(FakeString, mFlags) ==
+                      offsetof(StringAsserter, mFlags),
                     "Offset of mFlags should match");
     }
   };
 };
 
+template<typename T>
+inline bool
+AssignJSString(JSContext *cx, T &dest, JSString *s)
+{
+  size_t len = js::GetStringLength(s);
+  static_assert(js::MaxStringLength < (1 << 28),
+                "Shouldn't overflow here or in FakeString::SetCapacity");
+  if (MOZ_UNLIKELY(!dest.SetCapacity(len + 1, mozilla::fallible_t()))) {
+    JS_ReportOutOfMemory(cx);
+    return false;
+  }
+  if (MOZ_UNLIKELY(!js::CopyStringChars(cx, dest.BeginWriting(), s, len))) {
+    return false;
+  }
+  dest.BeginWriting()[len] = '\0';
+  dest.SetLength(len);
+  return true;
+}
+
 } // namespace binding_detail
 
 enum StringificationBehavior {
   eStringify,
   eEmpty,
   eNull
 };
 
-// pval must not be null and must point to a rooted JS::Value
 template<typename T>
 static inline bool
 ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
-                       JS::MutableHandle<JS::Value> pval,
                        StringificationBehavior nullBehavior,
                        StringificationBehavior undefinedBehavior,
                        T& result)
 {
   JSString *s;
   if (v.isString()) {
     s = v.toString();
   } else {
@@ -1838,33 +1905,24 @@ ConvertJSValueToString(JSContext* cx, JS
       }
       return true;
     }
 
     s = JS::ToString(cx, v);
     if (!s) {
       return false;
     }
-    pval.set(JS::StringValue(s));  // Root the new string.
   }
 
-  size_t len;
-  const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
-  if (!chars) {
-    return false;
-  }
-
-  result.Rebind(chars, len);
-  return true;
+  return binding_detail::AssignJSString(cx, result, s);
 }
 
 bool
 ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
-                           JS::MutableHandle<JS::Value> pval, bool nullable,
-                           nsACString& result);
+                           bool nullable, nsACString& result);
 
 template<typename T>
 void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
 template<typename T>
 void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
 
 // Class for simple sequence arguments, only used internally by codegen.
 namespace binding_detail {
@@ -2401,44 +2459,44 @@ T& NonNullHelper(OwningNonNull<T>& aArg)
 
 template<typename T>
 const T& NonNullHelper(const OwningNonNull<T>& aArg)
 {
   return aArg;
 }
 
 inline
-void NonNullHelper(NonNull<binding_detail::FakeDependentString>& aArg)
+void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
 {
   // This overload is here to make sure that we never end up applying
-  // NonNullHelper to a NonNull<binding_detail::FakeDependentString>. If we
+  // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
   // try to, it should fail to compile, since presumably the caller will try to
   // use our nonexistent return value.
 }
 
 inline
-void NonNullHelper(const NonNull<binding_detail::FakeDependentString>& aArg)
+void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
 {
   // This overload is here to make sure that we never end up applying
-  // NonNullHelper to a NonNull<binding_detail::FakeDependentString>. If we
+  // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
   // try to, it should fail to compile, since presumably the caller will try to
   // use our nonexistent return value.
 }
 
 inline
-void NonNullHelper(binding_detail::FakeDependentString& aArg)
+void NonNullHelper(binding_detail::FakeString& aArg)
 {
   // This overload is here to make sure that we never end up applying
-  // NonNullHelper to a FakeDependentString before we've constified it.  If we
+  // NonNullHelper to a FakeString before we've constified it.  If we
   // try to, it should fail to compile, since presumably the caller will try to
   // use our nonexistent return value.
 }
 
 MOZ_ALWAYS_INLINE
-const nsAString& NonNullHelper(const binding_detail::FakeDependentString& aArg)
+const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
 {
   return aArg;
 }
 
 // Reparent the wrapper of aObj to whatever its native now thinks its
 // parent should be.
 nsresult
 ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3362,17 +3362,16 @@ class JSToNativeConversionInfo():
     def __init__(self, template, declType=None, holderType=None,
                  dealWithOptional=False, declArgs=None,
                  holderArgs=None):
         """
         template: A string representing the conversion code.  This will have
                   template substitution performed on it as follows:
 
           ${val} is a handle to the JS::Value in question
-          ${mutableVal} is a mutable handle to the JS::Value in question
           ${holderName} replaced by the holder's name, if any
           ${declName} replaced by the declaration's name
           ${haveValue} replaced by an expression that evaluates to a boolean
                        for whether we have a JS::Value.  Only used when
                        defaultValue is not None or when True is passed for
                        checkForValue to instantiateJSToNativeConversion.
 
         declType: A CGThing representing the native C++ type we're converting
@@ -3710,17 +3709,16 @@ def getJSToNativeConversionInfo(type, de
         if nullable:
             typeName = CGTemplatedType("Nullable", typeName)
             arrayRef = "${declName}.SetValue()"
         else:
             arrayRef = "${declName}"
 
         elementConversion = string.Template(elementInfo.template).substitute({
                 "val": "temp",
-                "mutableVal": "&temp",
                 "declName": "slot",
                 # We only need holderName here to handle isExternal()
                 # interfaces, which use an internal holder for the
                 # conversion even when forceOwningType ends up true.
                 "holderName": "tempHolder"
             })
 
         # NOTE: Keep this in sync with variadic conversions as needed
@@ -3815,17 +3813,16 @@ def getJSToNativeConversionInfo(type, de
         if nullable:
             typeName = CGTemplatedType("Nullable", typeName)
             mozMapRef = "${declName}.SetValue()"
         else:
             mozMapRef = "${declName}"
 
         valueConversion = string.Template(valueInfo.template).substitute({
                 "val": "temp",
-                "mutableVal": "&temp",
                 "declName": "slot",
                 # We only need holderName here to handle isExternal()
                 # interfaces, which use an internal holder for the
                 # conversion even when forceOwningType ends up true.
                 "holderName": "tempHolder"
             })
 
         templateBody = fill(
@@ -3840,21 +3837,21 @@ def getJSToNativeConversionInfo(type, de
             JS::Rooted<JS::Value> propNameValue(cx);
             JS::Rooted<JS::Value> temp(cx);
             JS::Rooted<jsid> curId(cx);
             for (size_t i = 0; i < ids.length(); ++i) {
               // Make sure we get the value before converting the name, since
               // getting the value can trigger GC but our name is a dependent
               // string.
               curId = ids[i];
-              binding_detail::FakeDependentString propName;
+              binding_detail::FakeString propName;
               if (!JS_GetPropertyById(cx, mozMapObj, curId, &temp) ||
                   !JS_IdToValue(cx, curId, &propNameValue) ||
-                  !ConvertJSValueToString(cx, propNameValue, &propNameValue,
-                                          eStringify, eStringify, propName)) {
+                  !ConvertJSValueToString(cx, propNameValue, eStringify,
+                                          eStringify, propName)) {
                 $*{exceptionCode}
               }
 
               ${valueType}* slotPtr = mozMap.AddEntry(propName);
               if (!slotPtr) {
                 JS_ReportOutOfMemory(cx);
                 $*{exceptionCode}
               }
@@ -3910,76 +3907,76 @@ def getJSToNativeConversionInfo(type, de
         names = []
 
         interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
         if len(interfaceMemberTypes) > 0:
             interfaceObject = []
             for memberType in interfaceMemberTypes:
                 name = getUnionMemberName(memberType)
                 interfaceObject.append(
-                    CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext" %
+                    CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext" %
                               (unionArgumentObj, name)))
                 names.append(name)
             interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
                                         pre="done = ", post=";\n\n", reindent=True)
         else:
             interfaceObject = None
 
         arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
         if len(arrayObjectMemberTypes) > 0:
             assert len(arrayObjectMemberTypes) == 1
             name = getUnionMemberName(arrayObjectMemberTypes[0])
             arrayObject = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             arrayObject = None
 
         dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
         if len(dateObjectMemberTypes) > 0:
             assert len(dateObjectMemberTypes) == 1
             memberType = dateObjectMemberTypes[0]
             name = getUnionMemberName(memberType)
-            dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${mutableVal});\n"
+            dateObject = CGGeneric("%s.SetTo%s(cx, ${val});\n"
                                    "done = true;\n" % (unionArgumentObj, name))
             dateObject = CGIfWrapper(dateObject, "JS_ObjectIsDate(cx, argObj)")
             names.append(name)
         else:
             dateObject = None
 
         callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
         if len(callbackMemberTypes) > 0:
             assert len(callbackMemberTypes) == 1
             memberType = callbackMemberTypes[0]
             name = getUnionMemberName(memberType)
             callbackObject = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             callbackObject = None
 
         dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
         if len(dictionaryMemberTypes) > 0:
             assert len(dictionaryMemberTypes) == 1
             name = getUnionMemberName(dictionaryMemberTypes[0])
             setDictionary = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             setDictionary = None
 
         mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
         if len(mozMapMemberTypes) > 0:
             assert len(mozMapMemberTypes) == 1
             name = getUnionMemberName(mozMapMemberTypes[0])
             mozMapObject = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             mozMapObject = None
 
         objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
         if len(objectMemberTypes) > 0:
             assert len(objectMemberTypes) == 1
@@ -4035,17 +4032,17 @@ def getJSToNativeConversionInfo(type, de
             assert len(stringTypes) <= 1
             assert len(numericTypes) <= 1
             assert len(booleanTypes) <= 1
 
             # We will wrap all this stuff in a do { } while (0); so we
             # can use "break" for flow control.
             def getStringOrPrimitiveConversion(memberType):
                 name = getUnionMemberName(memberType)
-                return CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n"
+                return CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n"
                                  "break;\n" % (unionArgumentObj, name))
             other = CGList([])
             stringConversion = map(getStringOrPrimitiveConversion, stringTypes)
             numericConversion = map(getStringOrPrimitiveConversion, numericTypes)
             booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes)
             if stringConversion:
                 if booleanConversion:
                     other.append(CGIfWrapper(booleanConversion[0],
@@ -4421,79 +4418,63 @@ def getJSToNativeConversionInfo(type, de
             # For nullable strings undefined also becomes a null string.
             undefinedBehavior = "eNull"
         else:
             undefinedBehavior = "eStringify"
         nullBehavior = treatAs[treatNullAs]
 
         def getConversionCode(varName):
             conversionCode = (
-                "if (!ConvertJSValueToString(cx, ${val}, ${mutableVal}, %s, %s, %s)) {\n"
+                "if (!ConvertJSValueToString(cx, ${val}, %s, %s, %s)) {\n"
                 "%s"
                 "}\n" % (nullBehavior, undefinedBehavior, varName,
                          exceptionCodeIndented.define()))
             if defaultValue is None:
                 return conversionCode
 
             if isinstance(defaultValue, IDLNullValue):
                 assert(type.nullable())
                 defaultCode = "%s.SetIsVoid(true)" % varName
             else:
                 defaultCode = handleDefaultStringValue(defaultValue,
                                                        "%s.Rebind" % varName)
             return handleDefault(conversionCode, defaultCode + ";\n")
 
         if isMember:
-            # We have to make a copy, except in the variadic case, because our
-            # jsval may well not live as long as our string needs to.
+            # Convert directly into the nsString member we have.
             declType = CGGeneric("nsString")
-            if isMember == "Variadic":
-                # The string is kept alive by the argument, so we can just
-                # depend on it.
-                assignString = "${declName}.Rebind(str.Data(), str.Length());\n"
-            else:
-                assignString = "${declName} = str;\n"
             return JSToNativeConversionInfo(
-                fill(
-                    """
-                    {
-                      binding_detail::FakeDependentString str;
-                      $*{convert}
-                      $*{assign}
-                    }
-                    """,
-                    convert=getConversionCode("str"),
-                    assign=assignString),
+                getConversionCode("${declName}"),
                 declType=declType,
                 dealWithOptional=isOptional)
 
         if isOptional:
             declType = "Optional<nsAString>"
-            holderType = CGGeneric("binding_detail::FakeDependentString")
+            holderType = CGGeneric("binding_detail::FakeString")
             conversionCode = ("%s"
                               "${declName} = &${holderName};\n" %
                               getConversionCode("${holderName}"))
         else:
-            declType = "binding_detail::FakeDependentString"
+            declType = "binding_detail::FakeString"
             holderType = None
             conversionCode = getConversionCode("${declName}")
 
         # No need to deal with optional here; we handled it already
         return JSToNativeConversionInfo(
             conversionCode,
             declType=CGGeneric(declType),
             holderType=holderType)
 
     if type.isByteString():
         assert not isEnforceRange and not isClamp
 
         nullable = toStringBool(type.nullable())
 
         conversionCode = (
-            "if (!ConvertJSValueToByteString(cx, ${val}, ${mutableVal}, %s, ${declName})) {\n"
+            "if (!ConvertJSValueToByteString(cx, ${val}, %s, ${declName})) {\n"
             "%s"
             "}\n" % (nullable, exceptionCodeIndented.define()))
         # ByteString arguments cannot have a default value.
         assert defaultValue is None
 
         return JSToNativeConversionInfo(
             conversionCode,
             declType=CGGeneric("nsCString"),
@@ -4970,17 +4951,16 @@ class CGArgumentConverter(CGThing):
         }
         self.replacementVariables = {
             "declName": "arg%d" % index,
             "holderName": ("arg%d" % index) + "_holder",
             "obj": "obj"
         }
         self.replacementVariables["val"] = string.Template(
             "args[${index}]").substitute(replacer)
-        self.replacementVariables["mutableVal"] = self.replacementVariables["val"]
         haveValueCheck = string.Template(
             "args.hasDefined(${index})").substitute(replacer)
         self.replacementVariables["haveValue"] = haveValueCheck
         self.descriptorProvider = descriptorProvider
         if self.argument.optional and not self.argument.defaultValue:
             self.argcAndIndex = replacer
         else:
             self.argcAndIndex = None
@@ -5039,17 +5019,16 @@ class CGArgumentConverter(CGThing):
                     ${elemType}& slot = *${declName}.AppendElement();
                 """)
         ).substitute(replacer)
 
         val = string.Template("args[variadicArg]").substitute(replacer)
         variadicConversion += indent(
             string.Template(typeConversion.template).substitute({
                 "val": val,
-                "mutableVal": val,
                 "declName": "slot",
                 # We only need holderName here to handle isExternal()
                 # interfaces, which use an internal holder for the
                 # conversion even when forceOwningType ends up true.
                 "holderName": "tempHolder",
                 # Use the same ${obj} as for the variadic arg itself
                 "obj": replacer["obj"]
             }), 4)
@@ -6519,17 +6498,16 @@ class CGMethodCall(CGThing):
                                                 isDefinitelyObject=isDefinitelyObject,
                                                 isNullOrUndefined=isNullOrUndefined,
                                                 isOptional=argIsOptional,
                                                 sourceDescription=(argDesc % (distinguishingIndex + 1))),
                     {
                         "declName": "arg%d" % distinguishingIndex,
                         "holderName": ("arg%d" % distinguishingIndex) + "_holder",
                         "val": distinguishingArg,
-                        "mutableVal": distinguishingArg,
                         "obj": "obj",
                         "haveValue": "args.hasDefined(%d)" % distinguishingIndex
                     },
                     checkForValue=argIsOptional)
                 caseBody.append(CGIndenter(testCode, indent))
 
                 # If we got this far, we know we unwrapped to the right
                 # C++ type, so just do the call.  Start conversion with
@@ -8112,17 +8090,16 @@ def getUnionTypeTemplateVars(unionType, 
                 holderArgs = ""
             initHolder = "%s.construct(%s);\n" % (holderName, holderArgs)
         else:
             initHolder = ""
 
         jsConversion = fill(
             initHolder + conversionInfo.template,
             val="value",
-            mutableVal="pvalue",
             declName="memberSlot",
             holderName=(holderName if ownsMembers else "%s.ref()" % holderName),
             destroyHolder=destroyHolder)
 
         jsConversion = fill(
             """
             tryNext = false;
             { // scope for memberSlot
@@ -8134,17 +8111,16 @@ def getUnionTypeTemplateVars(unionType, 
             structType=structType,
             name=name,
             ctorArgs=ctorArgs,
             jsConversion=jsConversion)
 
         setter = ClassMethod("TrySetTo" + name, "bool",
                              [Argument("JSContext*", "cx"),
                               Argument("JS::Handle<JS::Value>", "value"),
-                              Argument("JS::MutableHandle<JS::Value>", "pvalue"),
                               Argument("bool&", "tryNext")],
                              inline=not ownsMembers,
                              bodyInHeader=not ownsMembers,
                              body=jsConversion)
 
     return {
         "name": name,
         "structType": structType,
@@ -9227,17 +9203,16 @@ class CGProxySpecialOperation(CGPerSigna
                 sourceDescription=("value being assigned to %s setter" %
                                    descriptor.interface.identifier.name))
             if argumentMutableValue is None:
                 argumentMutableValue = "desc.value()"
             templateValues = {
                 "declName": argument.identifier.name,
                 "holderName": argument.identifier.name + "_holder",
                 "val": argumentMutableValue,
-                "mutableVal": argumentMutableValue,
                 "obj": "obj"
             }
             self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
         elif operation.isGetter() or operation.isDeleter():
             self.cgRoot.prepend(CGGeneric("bool found;\n"))
 
     def getArguments(self):
         args = [(a, a.identifier.name) for a in self.arguments]
@@ -9358,31 +9333,31 @@ class CGProxyNamedOperation(CGProxySpeci
             # deal with the name collision
             idDecl = "JS::Rooted<jsid> id_(cx, id);\n"
             idName = "id_"
         else:
             idDecl = ""
             idName = "id"
         unwrapString = fill(
             """
-            if (!ConvertJSValueToString(cx, nameVal, &nameVal,
-                                        eStringify, eStringify, ${argName})) {
+            if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify,
+                                        ${argName})) {
               return false;
             }
             """,
             argName=argName)
         if self.value is None:
             # We're just using 'id', and if it's an atom we can take a
             # fast path here.
             unwrapString = fill(
                 """
-                if (MOZ_LIKELY(JSID_IS_ATOM(${idName}))) {
-                  JS::AutoCheckCannotGC nogc;
-                  JSAtom* atom = JSID_TO_ATOM(${idName});
-                  ${argName}.Rebind(js::GetTwoByteAtomChars(nogc, atom), js::GetAtomLength(atom));
+                if (MOZ_LIKELY(JSID_IS_STRING(${idName}))) {
+                  if (!AssignJSString(cx, ${argName}, JSID_TO_STRING(${idName}))) {
+                    return false;
+                  }
                 } else {
                   nameVal = js::IdToValue(${idName});
                   $*{unwrapString}
                 }
                 """,
                 idName=idName,
                 argName=argName,
                 unwrapString=unwrapString)
@@ -9392,17 +9367,17 @@ class CGProxyNamedOperation(CGProxySpeci
         # Sadly, we have to set up nameVal even if we have an atom id,
         # because we don't know for sure, and we can end up needing it
         # so it needs to be higher up the stack.  Using a Maybe here
         # seems like probable overkill.
         return fill(
             """
             JS::Rooted<JS::Value> nameVal(cx);
             $*{idDecl}
-            binding_detail::FakeDependentString ${argName};
+            binding_detail::FakeString ${argName};
             $*{unwrapString}
 
             ${nativeType}* self = UnwrapProxy(proxy);
             $*{op}
             """,
             idDecl=idDecl,
             argName=argName,
             unwrapString=unwrapString,
@@ -10940,17 +10915,16 @@ class CGDictionary(CGThing):
         if conversionInfo.dealWithOptional:
             declType = CGTemplatedType("Optional", declType)
         return declType.define()
 
     def getMemberConversion(self, memberInfo):
         member, conversionInfo = memberInfo
         replacements = {
             "val": "temp.ref()",
-            "mutableVal": "&temp.ref()",
             "declName": self.makeMemberName(member.identifier.name),
             # We need a holder name for external interfaces, but
             # it's scoped down to the conversion so we can just use
             # anything we want.
             "holderName": "holder"
         }
         # We can't handle having a holderType here
         assert conversionInfo.holderType is None
@@ -12949,17 +12923,16 @@ class CallbackMember(CGNativeMember):
         doCall = self.getCall()
         returnResult = self.getResultConversion()
 
         return setupCall + declRval + argvDecl + convertArgs + doCall + returnResult
 
     def getResultConversion(self):
         replacements = {
             "val": "rval",
-            "mutableVal": "&rval",
             "holderName": "rvalHolder",
             "declName": "rvalDecl",
             # We actually want to pass in a null scope object here, because
             # wrapping things into our current compartment (that of mCallback)
             # is what we want.
             "obj": "nullptr"
         }
 
@@ -13538,17 +13511,17 @@ class GlobalGenRoots():
         (includes, implincludes,
          declarations, unions) = UnionTypes(config.getDescriptors(),
                                             config.getDictionaries(),
                                             config.getCallbacks(),
                                             config)
         includes.add("mozilla/dom/OwningNonNull.h")
         includes.add("mozilla/dom/UnionMember.h")
         includes.add("mozilla/dom/BindingDeclarations.h")
-        # Need BindingUtils.h for FakeDependentString
+        # Need BindingUtils.h for FakeString
         includes.add("mozilla/dom/BindingUtils.h")
         implincludes.add("mozilla/dom/PrimitiveConversions.h")
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 
         curr = CGWrapper(curr, post='\n')
 
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -74,20 +74,17 @@ DOMProxyHandler::GetAndClearExpandoObjec
   MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
   JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
   if (v.isUndefined()) {
     return nullptr;
   }
 
   if (v.isObject()) {
     js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue());
-    XPCWrappedNativeScope* scope = xpc::MaybeGetObjectScope(obj);
-    if (scope) {
-      scope->RemoveDOMExpandoObject(obj);
-    }
+    xpc::ObjectScope(obj)->RemoveDOMExpandoObject(obj);
   } else {
     js::ExpandoAndGeneration* expandoAndGeneration =
       static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
     v = expandoAndGeneration->expando;
     if (v.isUndefined()) {
       return nullptr;
     }
     expandoAndGeneration->expando = UndefinedValue();
@@ -129,18 +126,17 @@ DOMProxyHandler::EnsureExpandoObject(JSC
   CallQueryInterface(native, &cache);
   if (expandoAndGeneration) {
     cache->PreserveWrapper(native);
     expandoAndGeneration->expando.setObject(*expando);
 
     return expando;
   }
 
-  XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj);
-  if (!scope->RegisterDOMExpandoObject(obj)) {
+  if (!xpc::ObjectScope(obj)->RegisterDOMExpandoObject(obj)) {
     return nullptr;
   }
 
   cache->SetPreservingWrapper(true);
   js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
 
   return expando;
 }
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1557,27 +1557,16 @@ EventStateManager::GenerateDragGesture(n
   if (IsTrackingDragGesture()) {
     mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
 
     if (!mCurrentTarget) {
       StopTrackingDragGesture();
       return;
     }
 
-    // Check if selection is tracking drag gestures, if so
-    // don't interfere!
-    if (mCurrentTarget)
-    {
-      nsRefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
-      if (frameSel && frameSel->GetMouseDownState()) {
-        StopTrackingDragGesture();
-        return;
-      }
-    }
-
     // If non-native code is capturing the mouse don't start a drag.
     if (nsIPresShell::IsMouseCapturePreventingDrag()) {
       StopTrackingDragGesture();
       return;
     }
 
     static int32_t pixelThresholdX = 0;
     static int32_t pixelThresholdY = 0;
@@ -1591,35 +1580,71 @@ EventStateManager::GenerateDragGesture(n
         pixelThresholdX = 5;
       if (!pixelThresholdY)
         pixelThresholdY = 5;
     }
 
     // fire drag gesture if mouse has moved enough
     LayoutDeviceIntPoint pt = aEvent->refPoint +
       LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset());
-    if (DeprecatedAbs(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
-        DeprecatedAbs(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
+    if (Abs(pt.x - mGestureDownPoint.x) > Abs(pixelThresholdX) ||
+        Abs(pt.y - mGestureDownPoint.y) > Abs(pixelThresholdY)) {
       if (Prefs::ClickHoldContextMenu()) {
         // stop the click-hold before we fire off the drag gesture, in case
         // it takes a long time
         KillClickHoldTimer();
       }
 
+      nsCOMPtr<nsIContent> eventContent;
+      mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
+
+      // Make it easier to select link text by only dragging in the vertical direction
+      bool isLinkDraggedVertical = false;
+      bool isDraggableLink = false;
+      nsCOMPtr<nsIContent> dragLinkNode = eventContent;
+      while (dragLinkNode) {
+        if (nsContentUtils::IsDraggableLink(dragLinkNode)) {
+          isDraggableLink = true;
+          // Treat as vertical drag when cursor exceeds the top or bottom of the threshold box
+          isLinkDraggedVertical = Abs(pt.y - mGestureDownPoint.y) > Abs(pixelThresholdY);
+          break;
+        }
+        dragLinkNode = dragLinkNode->GetParent();
+      }
+
+      // Check if selection is tracking drag gestures, if so
+      // don't interfere!
+      if (mCurrentTarget) {
+        nsRefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
+        if (frameSel && frameSel->GetMouseDownState()) {
+          if (isLinkDraggedVertical) {
+            // Stop selecting when link dragged vertically
+            frameSel->SetMouseDownState(PR_FALSE);
+            // Clear any selection to prevent it being dragged instead of link
+            frameSel->ClearNormalSelection();
+          } else {
+            StopTrackingDragGesture();
+            // Don't register click for draggable links when selecting
+            if (isDraggableLink)
+              mLClickCount = 0;
+            return;
+          }
+        }
+      }
+
       nsCOMPtr<nsISupports> container = aPresContext->GetContainerWeak();
       nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
       if (!window)
         return;
 
       nsRefPtr<DataTransfer> dataTransfer =
         new DataTransfer(window, NS_DRAGDROP_START, false, -1);
 
       nsCOMPtr<nsISelection> selection;
-      nsCOMPtr<nsIContent> eventContent, targetContent;
-      mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
+      nsCOMPtr<nsIContent> targetContent;
       if (eventContent)
         DetermineDragTarget(window, eventContent, dataTransfer,
                             getter_AddRefs(selection), getter_AddRefs(targetContent));
 
       // Stop tracking the drag gesture now. This should stop us from
       // reentering GenerateDragGesture inside DOM event processing.
       StopTrackingDragGesture();
 
--- a/dom/events/test/test_dragstart.html
+++ b/dom/events/test/test_dragstart.html
@@ -58,18 +58,25 @@ function afterDragTests()
   $("synthetic").dispatchEvent(evt);
 
   var evt = document.createEvent("dragevents");
   ok(evt instanceof DragEvent, "synthetic dragevents class")
   evt.initDragEvent("dragover", true, true, window, 0, 40, 35, 20, 15,
                     true, false, true, true, 2, document.documentElement, null);
   $("synthetic2").dispatchEvent(evt);
 
-  // next, dragging links and images
-  sendMouseEventsForDrag("link");
+  // link vertical dragging
+  sendMouseEventsForVerticalDrag("link");
+  is(window.getSelection().isCollapsed, true, "link vertical drag clears selection");
+
+  // link horizontal selection
+  sendMouseEventsForHorizontalSelection("link");
+  is(window.getSelection().isCollapsed, false, "link horizontal selection");
+
+  // images
   sendMouseEventsForDrag("image");
 
 //  disable testing input dragging for now, as it doesn't seem to be testable 
 //  draggable = $("input");
 //  draggable.setSelectionRange(0, 4);
 //  synthesizeMouse(draggable, 8, 8, { type: "mousedown" });
 //  synthesizeMouse(draggable, 15, 15, { type: "mousemove" });
 //  sendMouseEventsForDrag("input");
@@ -80,28 +87,47 @@ function afterDragTests()
   gDragInfo = { target: $("dragtrue"), testid: "draggable true child" };
   sendMouseEventsForDrag("spantrue");
   gDragInfo = { target: $("dragfalse").firstChild, testid: "draggable false node" };
   sendMouseEventsForDrag("dragfalse");
   gDragInfo = { target: $("spanfalse").firstChild, testid: "draggable false child" };
   sendMouseEventsForDrag("spanfalse");
 
   synthesizeMouse(draggable, 12, 12, { type: "mouseup" });
-  if (gExtraDragTests == 4)
-    SimpleTest.finish();
+
+  is(gExtraDragTests, 4, "number of drag events");
+
+  SimpleTest.finish();
 }
 
 function sendMouseEventsForDrag(nodeid)
 {
   var draggable = $(nodeid);
   synthesizeMouse(draggable, 3, 3, { type: "mousedown" });
   synthesizeMouse(draggable, 10, 10, { type: "mousemove" });
   synthesizeMouse(draggable, 12, 12, { type: "mousemove" });
 }
 
+function sendMouseEventsForVerticalDrag(nodeid)
+{
+  var draggable = $(nodeid);
+  synthesizeMouse(draggable, 3, 3, { type: "mousedown" });
+  synthesizeMouse(draggable, 3, 10, { type: "mousemove" });
+  synthesizeMouse(draggable, 3, 12, { type: "mousemove" });
+}
+
+function sendMouseEventsForHorizontalSelection(nodeid)
+{
+  var draggable = $(nodeid);
+  synthesizeMouse(draggable, 3, 3, { type: "mousedown" });
+  synthesizeMouse(draggable, 10, 3, { type: "mousemove" });
+  synthesizeMouse(draggable, 12, 3, { type: "mousemove" });
+  synthesizeMouse(draggable, 12, 3, { type: "mouseup" });
+}
+
 function doDragStartSelection(event)
 {
   is(event.type, "dragstart", "dragstart event type");
   is(event.target, $("draggable").firstChild, "dragstart event target");
   is(event.bubbles, true, "dragstart event bubbles");
   is(event.cancelable, true, "dragstart event cancelable");
 
   is(event.clientX, 14, "dragstart clientX");
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -480,21 +480,20 @@ nsPluginTag::HasSameNameAndMimes(const n
 
   return true;
 }
 
 void nsPluginTag::TryUnloadPlugin(bool inShutdown)
 {
   // We never want to send NPP_Shutdown to an in-process plugin unless
   // this process is shutting down.
-  if (mLibrary && !inShutdown) {
+  if (!mPlugin) {
     return;
   }
-
-  if (mPlugin) {
+  if (inShutdown || mPlugin->GetLibrary()->IsOOP()) {
     mPlugin->Shutdown();
     mPlugin = nullptr;
   }
 }
 
 nsCString nsPluginTag::GetNiceFileName() {
   if (!mNiceFileName.IsEmpty()) {
     return mNiceFileName;
--- a/dom/system/gonk/Volume.cpp
+++ b/dom/system/gonk/Volume.cpp
@@ -54,21 +54,21 @@ static int32_t sMountGeneration = 0;
 // assume it's present, and we'll be told that it's missing.
 Volume::Volume(const nsCSubstring& aName)
   : mMediaPresent(true),
     mState(nsIVolume::STATE_INIT),
     mName(aName),
     mMountGeneration(-1),
     mMountLocked(true),  // Needs to agree with nsVolume::nsVolume
     mSharingEnabled(false),
-    mCanBeShared(true),
-    mIsSharing(false),
     mFormatRequested(false),
     mMountRequested(false),
     mUnmountRequested(false),
+    mCanBeShared(true),
+    mIsSharing(false),
     mIsFormatting(false)
 {
   DBG("Volume %s: created", NameStr());
 }
 
 void
 Volume::SetIsSharing(bool aIsSharing)
 {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2477,17 +2477,17 @@ WorkerPrivateParent<Derived>::Suspend(JS
 
     mSharedWorkers.EnumerateRead(Closure::Suspend, &closure);
 
     if (!closure.mAllSuspended || mParentSuspended) {
       return true;
     }
   }
 
-  MOZ_ASSERT(!mParentSuspended, "Suspended more than once!");
+//  MOZ_ASSERT(!mParentSuspended, "Suspended more than once!");
 
   mParentSuspended = true;
 
   {
     MutexAutoLock lock(mMutex);
 
     if (mParentStatus >= Terminating) {
       return true;
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -87,17 +87,16 @@ support-files =
 [test_bug1010784.html]
 [test_bug1014466.html]
 [test_bug1020226.html]
 [test_bug998474.html]
 [test_chromeWorker.html]
 [test_clearTimeouts.html]
 [test_close.html]
 [test_closeOnGC.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #bug 881404 # b2g-debug(times out) b2g-desktop(times out)
 [test_console.html]
 [test_consoleReplaceable.html]
 [test_contentWorker.html]
 [test_csp.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_csp.html^headers^]
 [test_csp.js]
 [test_dataURLWorker.html]
--- a/gfx/cairo/cairo/src/cairo-compiler-private.h
+++ b/gfx/cairo/cairo/src/cairo-compiler-private.h
@@ -246,25 +246,23 @@ ffs (int x)
 
 #if defined(_MSC_VER) && defined(_M_IX86)
 /* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
    The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
    will never be folded into another one. Something like this might eventually
    be needed for GCC but it seems fine for now. */
 #define CAIRO_ENSURE_UNIQUE                       \
     do {                                          \
-	char func[] = __FUNCTION__;               \
 	char file[] = __FILE__;                   \
 	__asm {                                   \
 	    __asm jmp __internal_skip_line_no     \
-	    __asm _emit (__LINE__ & 0xff)         \
-	    __asm _emit ((__LINE__>>8) & 0xff)    \
-	    __asm _emit ((__LINE__>>16) & 0xff)   \
-	    __asm _emit ((__LINE__>>24) & 0xff)   \
-	    __asm lea eax, func                   \
+	    __asm _emit (__COUNTER__ & 0xff)      \
+	    __asm _emit ((__COUNTER__>>8) & 0xff) \
+	    __asm _emit ((__COUNTER__>>16) & 0xff)\
+	    __asm _emit ((__COUNTER__>>24) & 0xff)\
 	    __asm lea eax, file                   \
 	    __asm __internal_skip_line_no:        \
 	};                                        \
     } while (0)
 #else
 #define CAIRO_ENSURE_UNIQUE    do { } while (0)
 #endif
 
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -563,17 +563,26 @@ public:
   void Dump(std::stringstream& aStream, const char* aPrefix="", bool aDumpHtml=false);
   /**
    * Dump information about just this layer manager itself to aStream
    */
   void DumpSelf(std::stringstream& aStream, const char* aPrefix="");
   void Dump() {
     std::stringstream ss;
     Dump(ss);
-    printf_stderr("%s", ss.str().c_str());
+    char line[1024];
+    while (!ss.eof()) {
+      ss.getline(line, sizeof(line));
+      printf_stderr("%s", line);
+      if (ss.fail()) {
+        // line was too long, skip to next newline
+        ss.clear();
+        ss.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+      }
+    }
   }
 
   /**
    * Log information about this layer manager and its managed tree to
    * the NSPR log (if enabled for "Layers").
    */
   void Log(const char* aPrefix="");
   /**
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -425,17 +425,17 @@ gfxFontEntry::NotifyGlyphsChanged()
 {
     for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
         gfxFont* font = mFontsUsingSVGGlyphs[i];
         font->NotifyGlyphsChanged();
     }
 }
 
 bool
-gfxFontEntry::TryGetMathTable(gfxFont* aFont)
+gfxFontEntry::TryGetMathTable()
 {
     if (!mMathInitialized) {
         mMathInitialized = true;
 
         // If UnitsPerEm is not known/valid, we can't use MATH table
         if (UnitsPerEm() == kInvalidUPEM) {
             return false;
         }
@@ -5221,16 +5221,29 @@ gfxFontGroup::HasFont(const gfxFontEntry
     return false;
 }
 
 gfxFontGroup::~gfxFontGroup()
 {
     mFonts.Clear();
 }
 
+gfxFont *
+gfxFontGroup::GetFirstMathFont()
+{
+    uint32_t count = mFonts.Length();
+    for (uint32_t i = 0; i < count; ++i) {
+        gfxFont* font = GetFontAt(i);
+        if (font->GetFontEntry()->TryGetMathTable()) {
+            return font;
+        }
+    }
+    return nullptr;
+}
+
 gfxFontGroup *
 gfxFontGroup::Copy(const gfxFontStyle *aStyle)
 {
     gfxFontGroup *fg = new gfxFontGroup(mFamilyList, aStyle, mUserFontSet);
     fg->SetTextPerfMetrics(mTextPerf);
     return fg;
 }
 
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -394,17 +394,17 @@ public:
         RadicalKernBeforeDegree,
         RadicalKernAfterDegree,
         RadicalDegreeBottomRaisePercent
     };
 
     // Call TryGetMathTable to try to load the Open Type MATH table. The other
     // functions forward the call to the gfxMathTable class. The GetMath...()
     // functions MUST NOT be called unless TryGetMathTable() has returned true.
-    bool     TryGetMathTable(gfxFont* aFont);
+    bool     TryGetMathTable();
     gfxFloat GetMathConstant(MathConstant aConstant);
     bool     GetMathItalicsCorrection(uint32_t aGlyphID,
                                       gfxFloat* aItalicCorrection);
     uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
                                  uint16_t aSize);
     bool     GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
                                   uint32_t aGlyphs[4]);
 
@@ -1955,16 +1955,34 @@ public:
         return mFontEntry->TryGetSVGData(this);
     }
 
     static void DestroySingletons() {
         delete sScriptTagToCode;
         delete sDefaultFeatures;
     }
 
+    // Get a font dimension from the MATH table, scaled to appUnits;
+    // may only be called if mFontEntry->TryGetMathTable has succeeded
+    // (i.e. the font is known to be a valid OpenType math font).
+    nscoord GetMathConstant(gfxFontEntry::MathConstant aConstant,
+                            uint32_t aAppUnitsPerDevPixel)
+    {
+        return NSToCoordRound(mFontEntry->GetMathConstant(aConstant) *
+                              GetAdjustedSize() * aAppUnitsPerDevPixel);
+    }
+
+    // Get a dimensionless math constant (e.g. a percentage);
+    // may only be called if mFontEntry->TryGetMathTable has succeeded
+    // (i.e. the font is known to be a valid OpenType math font).
+    float GetMathConstant(gfxFontEntry::MathConstant aConstant)
+    {
+        return mFontEntry->GetMathConstant(aConstant);
+    }
+
 protected:
     // Return a font that is a "clone" of this one, but reduced to 80% size
     // (and with variantCaps set to normal).
     // Default implementation relies on gfxFontEntry::CreateFontInstance;
     // backends that don't implement that will need to override this and use
     // an alternative technique. (gfxPangoFonts, I'm looking at you...)
     virtual already_AddRefed<gfxFont> GetSmallCapsFont();
 
@@ -3552,16 +3570,21 @@ public:
                      "Whoever was caching this font group should have "
                      "called UpdateFontList on it");
         NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(), 
                      "Requesting a font index that doesn't exist");
 
         return mFonts[i].Font();
     }
 
+    // Returns the first font in the font-group that has an OpenType MATH table,
+    // or null if no such font is available. The GetMathConstant methods may be
+    // called on the returned font.
+    gfxFont *GetFirstMathFont();
+
     uint32_t FontListLength() const {
         return mFonts.Length();
     }
 
     const gfxFontStyle *GetStyle() const { return &mStyle; }
 
     virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3213,17 +3213,17 @@ EmitDestructuringOpsHelper(ExclusiveCont
          */
         doElemOp = true;
         if (pn->isKind(PNK_ARRAY)) {
             if (!EmitNumberOp(cx, index, bce))
                 return false;
             pn3 = pn2;
         } else {
             JS_ASSERT(pn->isKind(PNK_OBJECT));
-            JS_ASSERT(pn2->isKind(PNK_COLON));
+            JS_ASSERT(pn2->isKind(PNK_COLON) || pn2->isKind(PNK_SHORTHAND));
 
             ParseNode *key = pn2->pn_left;
             if (key->isKind(PNK_NUMBER)) {
                 if (!EmitNumberOp(cx, key->pn_dval, bce))
                     return false;
             } else {
                 MOZ_ASSERT(key->isKind(PNK_STRING) || key->isKind(PNK_NAME));
                 PropertyName *name = key->pn_atom->asPropertyName();
@@ -5918,21 +5918,16 @@ EmitConditionalExpression(ExclusiveConte
 
 /*
  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
  * the comment on EmitSwitch.
  */
 MOZ_NEVER_INLINE static bool
 EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
-    if (pn->pn_xflags & PNX_DESTRUCT) {
-        bce->reportError(pn, JSMSG_BAD_OBJECT_INIT);
-        return false;
-    }
-
     if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
         return EmitSingletonInitialiser(cx, bce, pn);
 
     /*
      * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
      * a new object and defining (in source order) each property on the object
      * (or mutating the object's [[Prototype]], in the case of __proto__).
      */
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -247,30 +247,29 @@ class FullParseHandler
     ParseNode *newObjectLiteral(uint32_t begin) {
         ParseNode *literal = new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1));
         // Later in this stack: remove dependency on this opcode.
         if (literal)
             literal->setOp(JSOP_NEWINIT);
         return literal;
     }
 
-    bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr) {
-        ParseNode *propdef = newBinary(PNK_COLON, name, expr, JSOP_INITPROP);
+    bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr,
+                               bool isShorthand = false) {
+        JS_ASSERT(literal->isArity(PN_LIST));
+        ParseNode *propdef = newBinary(isShorthand ? PNK_SHORTHAND : PNK_COLON, name, expr,
+                                       JSOP_INITPROP);
+        if (isShorthand)
+            literal->pn_xflags |= PNX_NONCONST;
         if (!propdef)
             return false;
         literal->append(propdef);
         return true;
     }
 
-    bool addShorthandPropertyDefinition(ParseNode *literal, ParseNode *name) {
-        JS_ASSERT(literal->isArity(PN_LIST));
-        literal->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST;  // XXX why PNX_DESTRUCT?
-        return addPropertyDefinition(literal, name, name);
-    }
-
     bool addAccessorPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *fn, JSOp op)
     {
         JS_ASSERT(literal->isArity(PN_LIST));
         literal->pn_xflags |= PNX_NONCONST;
 
         ParseNode *propdef = newBinary(PNK_COLON, name, fn, op);
         if (!propdef)
             return false;
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -145,18 +145,19 @@ class NameResolver
                         /* Don't skip too high in the tree */
                         break;
                     }
                     cur = parents[tmp];
                 }
                 break;
 
               case PNK_COLON:
+              case PNK_SHORTHAND:
                 /*
-                 * Record the PNK_COLON but skip the PNK_OBJECT so we're not
+                 * Record the PNK_COLON/SHORTHAND but skip the PNK_OBJECT so we're not
                  * flagged as a contributor.
                  */
                 pos--;
                 /* fallthrough */
 
               default:
                 /* Save any other nodes we encounter on the way up. */
                 JS_ASSERT(*size < MaxParents);
@@ -216,17 +217,17 @@ class NameResolver
         /*
          * Other than the actual assignment, other relevant nodes to naming are
          * those in object initializers and then particular nodes marking a
          * contribution.
          */
         for (int pos = size - 1; pos >= 0; pos--) {
             ParseNode *node = toName[pos];
 
-            if (node->isKind(PNK_COLON)) {
+            if (node->isKind(PNK_COLON) || node->isKind(PNK_SHORTHAND)) {
                 ParseNode *left = node->pn_left;
                 if (left->isKind(PNK_NAME) || left->isKind(PNK_STRING)) {
                     if (!appendPropertyReference(left->pn_atom))
                         return false;
                 } else if (left->isKind(PNK_NUMBER)) {
                     if (!appendNumericPropertyReference(left->pn_dval))
                         return false;
                 }
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -455,26 +455,26 @@ Parser<FullParseHandler>::cloneLeftHandS
 
     if (opn->isArity(PN_LIST)) {
         JS_ASSERT(opn->isKind(PNK_ARRAY) || opn->isKind(PNK_OBJECT));
         pn->makeEmpty();
         for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
             ParseNode *pn2;
             if (opn->isKind(PNK_OBJECT)) {
                 JS_ASSERT(opn2->isArity(PN_BINARY));
-                JS_ASSERT(opn2->isKind(PNK_COLON));
+                JS_ASSERT(opn2->isKind(PNK_COLON) || opn2->isKind(PNK_SHORTHAND));
 
                 ParseNode *tag = cloneParseTree(opn2->pn_left);
                 if (!tag)
                     return nullptr;
                 ParseNode *target = cloneLeftHandSide(opn2->pn_right);
                 if (!target)
                     return nullptr;
 
-                pn2 = handler.new_<BinaryNode>(PNK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target);
+                pn2 = handler.new_<BinaryNode>(opn2->getKind(), JSOP_INITPROP, opn2->pn_pos, tag, target);
             } else if (opn2->isArity(PN_NULLARY)) {
                 JS_ASSERT(opn2->isKind(PNK_ELISION));
                 pn2 = cloneParseTree(opn2);
             } else {
                 pn2 = cloneLeftHandSide(opn2);
             }
 
             if (!pn2)
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -68,16 +68,17 @@ class UpvarCookie
 };
 
 #define FOR_EACH_PARSE_NODE_KIND(F) \
     F(NOP) \
     F(SEMI) \
     F(COMMA) \
     F(CONDITIONAL) \
     F(COLON) \
+    F(SHORTHAND) \
     F(POS) \
     F(NEG) \
     F(PREINCREMENT) \
     F(POSTINCREMENT) \
     F(PREDECREMENT) \
     F(POSTDECREMENT) \
     F(DOT) \
     F(ELEM) \
@@ -383,19 +384,18 @@ enum ParseNodeKind
  *                          in the desugaring of a generator-expression.
  * PNK_ARRAY    list        pn_head: list of pn_count array element exprs
  *                          [,,] holes are represented by PNK_ELISION nodes
  *                          pn_xflags: PN_ENDCOMMA if extra comma at end
  * PNK_OBJECT   list        pn_head: list of pn_count binary PNK_COLON nodes
  * PNK_COLON    binary      key-value pair in object initializer or
  *                          destructuring lhs
  *                          pn_left: property id, pn_right: value
- *                          var {x} = object destructuring shorthand shares
- *                          PN_NAME node for x on left and right of PNK_COLON
- *                          node in PNK_OBJECT's list, has PNX_DESTRUCT flag
+ * PNK_SHORTHAND binary     Same fields as PNK_COLON. This is used for object
+ *                          literal properties using shorthand ({x}).
  * PNK_NAME,    name        pn_atom: name, string, or object atom
  * PNK_STRING               pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT
  *                          If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
  *                          with pn_cookie telling (staticLevel, slot) (see
  *                          jsscript.h's UPVAR macros) and pn_dflags telling
  *                          const-ness and static analysis results
  * PNK_REGEXP   nullary     pn_objbox: RegExp model object
  * PNK_NAME     name        If pn_used, PNK_NAME uses the lexdef member instead
@@ -672,22 +672,18 @@ class ParseNode
 #define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_CLOSED)
 
 /* PN_LIST pn_xflags bits. */
 #define PNX_POPVAR      0x01            /* PNK_VAR or PNK_CONST last result
                                            needs popping */
 #define PNX_GROUPINIT   0x02            /* var [a, b] = [c, d]; unit list */
 #define PNX_FUNCDEFS    0x04            /* contains top-level function statements */
 #define PNX_SETCALL     0x08            /* call expression in lvalue context */
-#define PNX_DESTRUCT    0x10            /* destructuring special cases:
-                                           1. shorthand syntax used, at present
-                                              object destructuring ({x,y}) only;
-                                           2. code evaluating destructuring
-                                              arguments occurs before function
-                                              body */
+#define PNX_DESTRUCT    0x10            /* code evaluating destructuring
+                                           arguments occurs before function body */
 #define PNX_SPECIALARRAYINIT 0x20       /* one or more of
                                            1. array initialiser has holes
                                            2. array initializer has spread node */
 #define PNX_NONCONST    0x40            /* initialiser has non-constants */
 
     static_assert(PNX_NONCONST < (1 << NumListFlagBits), "Not enough bits");
 
     unsigned frameLevel() const {
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -722,17 +722,17 @@ HasFinalReturn(ParseNode *pn)
         return ENDS_IN_BREAK;
 
       case PNK_WITH:
         return HasFinalReturn(pn->pn_right);
 
       case PNK_RETURN:
         return ENDS_IN_RETURN;
 
-      case PNK_COLON:
+      case PNK_LABEL:
       case PNK_LEXICALSCOPE:
         return HasFinalReturn(pn->expr());
 
       case PNK_THROW:
         return ENDS_IN_RETURN;
 
       case PNK_TRY:
         /* If we have a finally block that returns, we are done. */
@@ -3189,17 +3189,17 @@ Parser<FullParseHandler>::checkDestructu
                 }
                 if (!ok)
                     return false;
             }
         }
     } else {
         JS_ASSERT(left->isKind(PNK_OBJECT));
         for (ParseNode *member = left->pn_head; member; member = member->pn_next) {
-            MOZ_ASSERT(member->isKind(PNK_COLON));
+            MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND));
             ParseNode *expr = member->pn_right;
 
             if (expr->isKind(PNK_ARRAY) || expr->isKind(PNK_OBJECT)) {
                 ok = checkDestructuring(data, expr, false);
             } else if (data) {
                 if (!expr->isKind(PNK_NAME)) {
                     report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME);
                     return false;
@@ -4215,31 +4215,29 @@ Parser<FullParseHandler>::forStatement()
              * expressions involving an 'in' operator are illegal in the init
              * clause of an ordinary for loop.
              */
             pc->parsingForInit = true;
             if (tt == TOK_VAR || tt == TOK_CONST) {
                 isForDecl = true;
                 tokenStream.consumeKnownToken(tt);
                 pn1 = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST);
-            }
-            else if (tt == TOK_LET) {
+            } else if (tt == TOK_LET) {
                 handler.disableSyntaxParser();
                 (void) tokenStream.getToken();
                 if (tokenStream.peekToken() == TOK_LP) {
                     pn1 = letBlock(LetExpresion);
                 } else {
                     isForDecl = true;
                     blockObj = StaticBlockObject::create(context);
                     if (!blockObj)
                         return null();
                     pn1 = variables(PNK_LET, nullptr, blockObj, DontHoistVars);
                 }
-            }
-            else {
+            } else {
                 pn1 = expr();
             }
             pc->parsingForInit = false;
             if (!pn1)
                 return null();
         }
     }
 
@@ -7298,36 +7296,35 @@ Parser<ParseHandler>::objectLiteral()
                  * so that we can later assume singleton objects delegate to
                  * the default Object.prototype.
                  */
                 if (!handler.isConstant(propexpr) || atom == context->names().proto)
                     handler.setListFlag(literal, PNX_NONCONST);
 
                 if (!handler.addPropertyDefinition(literal, propname, propexpr))
                     return null();
-            }
-            else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
+            } else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
                 /*
                  * Support, e.g., |var {x, y} = o| as destructuring shorthand
                  * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
                  */
                 if (!abortIfSyntaxParser())
                     return null();
                 tokenStream.ungetToken();
                 if (!tokenStream.checkForKeyword(atom, nullptr))
                     return null();
                 PropertyName *name = handler.isName(propname);
                 JS_ASSERT(atom);
                 propname = newName(name);
                 if (!propname)
                     return null();
-                if (!handler.addShorthandPropertyDefinition(literal, propname))
+                Node ident = identifierName();
+                if (!handler.addPropertyDefinition(literal, propname, ident, true))
                     return null();
-            }
-            else {
+            } else {
                 report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
                 return null();
             }
         } else {
             /* NB: Getter function in { get x(){} } is unnamed. */
             Rooted<PropertyName*> funName(context, nullptr);
             TokenStream::Position start(keepAtoms);
             tokenStream.tell(&start);
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -118,18 +118,17 @@ class SyntaxParseHandler
     }
     Node newArrayLiteral(uint32_t begin, unsigned blockid) { return NodeGeneric; }
     bool addElision(Node literal, const TokenPos &pos) { return true; }
     bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
     bool addArrayElement(Node literal, Node element) { return true; }
 
     Node newObjectLiteral(uint32_t begin) { return NodeGeneric; }
     bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
-    bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
-    bool addShorthandPropertyDefinition(Node literal, Node name) { return true; }
+    bool addPropertyDefinition(Node literal, Node name, Node expr, bool isShorthand = false) { return true; }
     bool addAccessorPropertyDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
 
     // Statements
 
     Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; }
     void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler> *pc) {}
     Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; }
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -275,18 +275,19 @@ class GCRuntime
 
     bool shouldCleanUpEverything() { return cleanUpEverything; }
 
     bool areGrayBitsValid() { return grayBitsValid; }
     void setGrayBitsInvalid() { grayBitsValid = false; }
 
     bool isGcNeeded() { return isNeeded; }
 
-    double computeHeapGrowthFactor(size_t lastBytes);
-    size_t computeTriggerBytes(double growthFactor, size_t lastBytes, JSGCInvocationKind gckind);
+    double computeHeapGrowthFactor(size_t lastBytes) const;
+    size_t computeTriggerBytes(double growthFactor, size_t lastBytes,
+                               JSGCInvocationKind gckind) const;
     size_t allocationThreshold() { return allocThreshold; }
 
     JSGCMode gcMode() const { return mode; }
     void setGCMode(JSGCMode m) {
         mode = m;
         marker.setGCMode(mode);
     }
 
@@ -332,17 +333,17 @@ class GCRuntime
     void findZoneGroups();
     bool findZoneEdgesForWeakMaps();
     void getNextZoneGroup();
     void endMarkingZoneGroup();
     void beginSweepingZoneGroup();
     bool releaseObservedTypes();
     void endSweepingZoneGroup();
     bool sweepPhase(SliceBudget &sliceBudget);
-    void endSweepPhase(JSGCInvocationKind gckind, bool lastGC);
+    void endSweepPhase(bool lastGC);
     void sweepZones(FreeOp *fop, bool lastGC);
     void decommitArenasFromAvailableList(Chunk **availableListHeadp);
     void decommitArenas();
     void expireChunksAndArenas(bool shouldShrink);
     void sweepBackgroundThings(bool onBackgroundThread);
     void assertBackgroundSweepingFinished();
 
     void computeNonIncrementalMarkingForValidation();
@@ -452,16 +453,19 @@ class GCRuntime
     uint64_t              startNumber;
 
     /* Whether the currently running GC can finish in multiple slices. */
     bool                  isIncremental;
 
     /* Whether all compartments are being collected in first GC slice. */
     bool                  isFull;
 
+    /* The kind of the last collection. */
+    JSGCInvocationKind    lastKind;
+
     /* The reason that an interrupt-triggered GC should be called. */
     JS::gcreason::Reason  triggerReason;
 
     /*
      * If this is 0, all cross-compartment proxies must be registered in the
      * wrapper map. This checking must be disabled temporarily while creating
      * new wrappers. When non-zero, this records the recursion depth of wrapper
      * creation.
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -177,18 +177,17 @@ class FreeSpan
 
     // This sets |first| and |last|, and also sets the next span stored at
     // |last| as empty. (As a result, |firstArg| and |lastArg| cannot represent
     // an empty span.)
     void initFinal(uintptr_t firstArg, uintptr_t lastArg, size_t thingSize) {
         first = firstArg;
         last = lastArg;
         FreeSpan *lastSpan = reinterpret_cast<FreeSpan*>(last);
-        lastSpan->first = 0;
-        lastSpan->last = 0;
+        lastSpan->initAsEmpty();
         JS_ASSERT(!isEmpty());
         checkSpan(thingSize);
     }
 
     bool isEmpty() const {
         checkSpan();
         return !first;
     }
@@ -1105,17 +1104,17 @@ Cell::address() const
     return addr;
 }
 
 Chunk *
 Cell::chunk() const
 {
     uintptr_t addr = uintptr_t(this);
     JS_ASSERT(addr % CellSize == 0);
-    addr &= ~(ChunkSize - 1);
+    addr &= ~ChunkMask;
     return reinterpret_cast<Chunk *>(addr);
 }
 
 inline StoreBuffer *
 Cell::storeBuffer() const
 {
     return chunk()->info.trailer.storeBuffer;
 }
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -26,16 +26,17 @@ JS::Zone::Zone(JSRuntime *rt)
     allocator(this),
     types(this),
     compartments(),
     gcGrayRoots(),
     gcHeapGrowthFactor(3.0),
     gcMallocBytes(0),
     gcMallocGCTriggered(false),
     gcBytes(0),
+    gcBytesAfterGC(0),
     gcTriggerBytes(0),
     data(nullptr),
     isSystem(false),
     usedByExclusiveThread(false),
     scheduledForDestruction(false),
     maybeAlive(true),
     active(false),
     jitZone_(nullptr),
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -101,17 +101,16 @@ struct Zone : public JS::shadow::Zone,
 
     void discardJitCode(js::FreeOp *fop);
 
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t *typePool,
                                 size_t *baselineStubsOptimized);
 
     void setGCLastBytes(size_t lastBytes, js::JSGCInvocationKind gckind);
-    void reduceGCTriggerBytes(size_t amount);
 
     void resetGCMallocBytes();
     void setGCMaxMallocBytes(size_t value);
     void updateMallocCounter(size_t nbytes) {
         // Note: this code may be run from worker threads. We tolerate any
         // thread races when updating gcMallocBytes.
         gcMallocBytes -= ptrdiff_t(nbytes);
         if (MOZ_UNLIKELY(isTooMuchMalloc()))
@@ -243,18 +242,22 @@ struct Zone : public JS::shadow::Zone,
     // This should be a bool, but Atomic only supports 32-bit and pointer-sized
     // types.
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> gcMallocGCTriggered;
 
     // Counts the number of bytes allocated in the GC heap for this zone. It is
     // updated by both the main and GC helper threads.
     mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gcBytes;
 
-    // GC trigger threshold for allocations on the GC heap.
-    size_t gcTriggerBytes;
+    // The number of bytes allocated in the GC heap for this zone after the last GC.
+    size_t gcBytesAfterGC;
+
+    // GC trigger threshold for allocations on the GC heap. It is updated by
+    // both the main and GC helper threads.
+    mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gcTriggerBytes;
 
     // Per-zone data for use by an embedder.
     void *data;
 
     bool isSystem;
 
     bool usedByExclusiveThread;
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/object-shorthand.js
@@ -0,0 +1,90 @@
+
+load(libdir + 'asserts.js');
+
+// globals:
+a = b = get = set = eval = arguments = 10;
+
+assertEq({arguments}.arguments, 10);
+
+var o = {a, b: b, get, set: set};
+assertEq(o.a, 10);
+assertEq(o.b, 10);
+assertEq(o.get, 10);
+assertEq(o.set, 10);
+
+var names = ['a', 'get', 'set', 'eval'];
+// global
+names.forEach(ident =>
+  assertEq(new Function('return {' + ident + '}.' + ident + ';')(), 10));
+// local
+names.forEach(ident =>
+  assertEq(new Function('var ' + ident + ' = 20; return {' + ident + '}.' + ident + ';')(), 20));
+// scope
+names.forEach(ident =>
+  assertEq(new Function('var ' + ident + ' = 30; return (function () {return {' + ident + '}.' + ident + ';})();')(), 30));
+
+var reserved = [
+  'break',
+  'do',
+  'in',
+  'typeof',
+  'case',
+  'else',
+  'instanceof',
+  'var',
+  'catch',
+  'export',
+  'new',
+  'void',
+  'class',
+  'extends',
+  'return',
+  'while',
+  'const',
+  'finally',
+  'super',
+  'with',
+  'continue',
+  'for',
+  'switch',
+  'debugger',
+  'function',
+  'this',
+  'delete',
+  'import',
+  'try',
+  'enum',
+  'null',
+  'true',
+  'false'
+];
+
+// non-identifiers should also throw
+var nonidents = [
+  '"str"',
+  '0'
+];
+
+reserved.concat(nonidents).forEach(ident =>
+  assertThrowsInstanceOf(() => new Function('return {' + ident + '}'), SyntaxError));
+
+var reservedStrict = [
+  'implements',
+  'interface',
+  'package',
+  'private',
+  'protected',
+  'public',
+  'static',
+  // XXX: according to 12.1.1, these should only be errors in strict code:
+  // see https://bugzilla.mozilla.org/show_bug.cgi?id=1032150
+  //'let',
+  //'yield'
+];
+
+reservedStrict.forEach(ident =>
+  assertEq(new Function('var ' + ident + ' = 10; return {' + ident + '}.' + ident + ';')(), 10));
+
+reservedStrict.concat(['let', 'yield']).forEach(ident =>
+  assertThrowsInstanceOf(() => new Function('"use strict"; return {' + ident + '}'), SyntaxError));
+
--- a/js/src/jit-test/tests/basic/testBug775807.js
+++ b/js/src/jit-test/tests/basic/testBug775807.js
@@ -1,9 +1,9 @@
-// |jit-test| dump-bytecode;error:SyntaxError
+// |jit-test| dump-bytecode
 
 (function() {
     const x = ((function() {
         return {
             e: function() {
                 (function() {
                     for (e in x) {}
                 })()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/latin1/bug1033113.js
@@ -0,0 +1,20 @@
+var s = "aaaaaaaaaaaaaaaaaa111aaaa";
+var latin1Rope1 = "foo" + s;
+var latin1Rope2 = "bar" + latin1Rope1;
+var twoByteRope = "\u1200--" + latin1Rope1;
+
+// Flatten twoByteRope.
+assertEq(twoByteRope.lastIndexOf("11"), 25);
+
+// latin1Rope1 is now a TwoByte dependent string.
+assertEq(isLatin1(latin1Rope1), false);
+assertEq(latin1Rope1, "fooaaaaaaaaaaaaaaaaaa111aaaa");
+
+// latin1Rope2 should still be Latin1, but now has a
+// TwoByte descendent (latin1Rope1).
+if (isLatin1(s))
+    assertEq(isLatin1(latin1Rope2), true);
+
+// Flatten latin1Rope2.
+assertEq(latin1Rope2.lastIndexOf("11"), 25);
+assertEq(latin1Rope2, "barfooaaaaaaaaaaaaaaaaaa111aaaa");
--- a/js/src/jit-test/tests/latin1/regexp.js
+++ b/js/src/jit-test/tests/latin1/regexp.js
@@ -31,8 +31,12 @@ assertEq(toLatin1("1abcdefghijklm4").sea
 assertEq("\u12001abcdefghijklm0".search(re), 2);
 assertEq(toLatin1("1abcdefghijklm8").search(re), -1);
 assertEq("\u12001abcdefghijklm8".search(re), -1);
 
 // If the input is Latin1, case-independent matches should work
 // correctly for characters outside Latin1 with Latin1 equivalents.
 var s = toLatin1("foobar\xff5baz");
 assertEq(s.search(/bar\u0178\d/i), 3);
+
+// Bug 1032067.
+''.match(eval("/(:[aaaaa\cC]\u1200)(?:\S|(?=(\3)))+?/y"));
+assertEq(Function("return /(\uB0DA()})/.toString();")(), "/(\uB0DA()})/");
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -270,33 +270,33 @@ FunctionStatementList(ParseNode *fn)
     ParseNode *last = fn->pn_body->last();
     JS_ASSERT(last->isKind(PNK_STATEMENTLIST));
     return last;
 }
 
 static inline bool
 IsNormalObjectField(ExclusiveContext *cx, ParseNode *pn)
 {
-    JS_ASSERT(pn->isKind(PNK_COLON));
+    JS_ASSERT(pn->isKind(PNK_COLON) || pn->isKind(PNK_SHORTHAND));
     return pn->getOp() == JSOP_INITPROP &&
            BinaryLeft(pn)->isKind(PNK_NAME) &&
            BinaryLeft(pn)->name() != cx->names().proto;
 }
 
 static inline PropertyName *
 ObjectNormalFieldName(ExclusiveContext *cx, ParseNode *pn)
 {
     JS_ASSERT(IsNormalObjectField(cx, pn));
     return BinaryLeft(pn)->name();
 }
 
 static inline ParseNode *
 ObjectFieldInitializer(ParseNode *pn)
 {
-    JS_ASSERT(pn->isKind(PNK_COLON));
+    JS_ASSERT(pn->isKind(PNK_COLON) || pn->isKind(PNK_SHORTHAND));
     return BinaryRight(pn);
 }
 
 static inline bool
 IsDefinition(ParseNode *pn)
 {
     return pn->isKind(PNK_NAME) && pn->isDefn();
 }
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -168,17 +168,17 @@ jit::EnterBaselineAtBranch(JSContext *cx
     BaselineScript *baseline = fp->script()->baselineScript();
 
     EnterJitData data(cx);
     data.jitcode = baseline->nativeCodeForPC(fp->script(), pc);
 
     // Skip debug breakpoint/trap handler, the interpreter already handled it
     // for the current op.
     if (cx->compartment()->debugMode())
-        data.jitcode += MacroAssembler::ToggledCallSize();
+        data.jitcode += MacroAssembler::ToggledCallSize(data.jitcode);
 
     data.osrFrame = fp;
     data.osrNumStackValues = fp->script()->nfixed() + cx->interpreterRegs().stackDepth();
 
     RootedValue thisv(cx);
 
     if (fp->isNonEvalFunctionFrame()) {
         data.constructing = fp->isConstructing();
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -176,21 +176,18 @@ void
 LBlock::dump()
 {
     dump(stderr);
 }
 
 static size_t
 TotalOperandCount(LRecoverInfo *recoverInfo)
 {
-    LRecoverInfo::OperandIter it(recoverInfo->begin());
-    LRecoverInfo::OperandIter end(recoverInfo->end());
     size_t accum = 0;
-
-    for (; it != end; ++it) {
+    for (LRecoverInfo::OperandIter it(recoverInfo); !it; ++it) {
         if (!it->isRecoveredOnBailout())
             accum++;
     }
     return accum;
 }
 
 LRecoverInfo::LRecoverInfo(TempAllocator &alloc)
   : instructions_(alloc),
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -960,41 +960,54 @@ class LRecoverInfo : public TempObject
     size_t numInstructions() const {
         return instructions_.length();
     }
 
     class OperandIter
     {
       private:
         MNode **it_;
+        MNode **end_;
         size_t op_;
 
       public:
-        explicit OperandIter(MNode **it)
-          : it_(it), op_(0)
-        { }
+        explicit OperandIter(LRecoverInfo *recoverInfo)
+          : it_(recoverInfo->begin()), end_(recoverInfo->end()), op_(0)
+        {
+            settle();
+        }
+
+        void settle() {
+            while ((*it_)->numOperands() == 0) {
+                ++it_;
+                op_ = 0;
+            }
+        }
 
         MDefinition *operator *() {
             return (*it_)->getOperand(op_);
         }
         MDefinition *operator ->() {
             return (*it_)->getOperand(op_);
         }
 
         OperandIter &operator ++() {
             ++op_;
             if (op_ == (*it_)->numOperands()) {
                 op_ = 0;
                 ++it_;
             }
+            if (!*this)
+                settle();
+
             return *this;
         }
 
-        bool operator !=(const OperandIter &where) const {
-            return it_ != where.it_ || op_ != where.op_;
+        operator bool() const {
+            return it_ == end_;
         }
 
 #ifdef DEBUG
         bool canOptimizeOutIfUnused();
 #endif
     };
 };
 
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -512,16 +512,17 @@ Imm16::Imm16()
 { }
 
 void
 jit::PatchJump(CodeLocationJump &jump_, CodeLocationLabel label)
 {
     // We need to determine if this jump can fit into the standard 24+2 bit address
     // or if we need a larger branch (or just need to use our pool entry)
     Instruction *jump = (Instruction*)jump_.raw();
+    // jumpWithPatch() returns the offset of the jump and never a pool or nop.
     Assembler::Condition c;
     jump->extractCond(&c);
     JS_ASSERT(jump->is<InstBranchImm>() || jump->is<InstLDR>());
 
     int jumpOffset = label.raw() - jump_.raw();
     if (BOffImm::isInRange(jumpOffset)) {
         // This instruction started off as a branch, and will remain one
         Assembler::retargetNearBranch(jump, jumpOffset, c);
@@ -727,17 +728,17 @@ Assembler::getPtr32Target(Iter *start, R
         InstMovW *bottom = load1->as<InstMovW>();
         bottom->extractImm(&targ_bot);
         bottom->extractDest(&temp);
 
         // Extract the top part of the immediate.
         InstMovT *top = load2->as<InstMovT>();
         top->extractImm(&targ_top);
 
-        // Make sure they are being loaded intothe same register.
+        // Make sure they are being loaded into the same register.
         JS_ASSERT(top->checkDest(temp));
 
         if (dest)
             *dest = temp;
         if (style)
             *style = L_MOVWT;
 
         uint32_t *value = (uint32_t*) (targ_bot.decode() | (targ_top.decode() << 16));
@@ -780,31 +781,31 @@ Assembler::TraceJumpRelocations(JSTracer
     }
 }
 
 static void
 TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader)
 {
     while (reader.more()) {
         size_t offset = reader.readUnsigned();
-        InstructionIterator iter((Instruction*)(buffer+offset));
+        InstructionIterator iter((Instruction*)(buffer + offset));
         void *ptr = const_cast<uint32_t *>(Assembler::getPtr32Target(&iter));
         // No barrier needed since these are constants.
         gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
     }
 
 }
 static void
 TraceDataRelocations(JSTracer *trc, ARMBuffer *buffer,
                      Vector<BufferOffset, 0, SystemAllocPolicy> *locs)
 {
     for (unsigned int idx = 0; idx < locs->length(); idx++) {
         BufferOffset bo = (*locs)[idx];
         ARMBuffer::AssemblerBufferInstIterator iter(bo, buffer);
-        void *ptr = const_cast<uint32_t *>(jit::Assembler::getPtr32Target(&iter));
+        void *ptr = const_cast<uint32_t *>(Assembler::getPtr32Target(&iter));
 
         // No barrier needed since these are constants.
         gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
     }
 
 }
 void
 Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
@@ -1302,16 +1303,21 @@ BufferOffset
 Assembler::writeInst(uint32_t x, uint32_t *dest)
 {
     if (dest == nullptr)
         return m_buffer.putInt(x);
 
     writeInstStatic(x, dest);
     return BufferOffset();
 }
+BufferOffset
+Assembler::writeBranchInst(uint32_t x)
+{
+    return m_buffer.putInt(x, /* markAsBranch = */ true);
+}
 void
 Assembler::writeInstStatic(uint32_t x, uint32_t *dest)
 {
     JS_ASSERT(dest != nullptr);
     *dest = x;
 }
 
 BufferOffset
@@ -1693,18 +1699,18 @@ Assembler::as_WritePoolEntry(Instruction
     JS_ASSERT(orig_cond == c);
 }
 
 BufferOffset
 Assembler::as_BranchPool(uint32_t value, RepatchLabel *label, ARMBuffer::PoolEntry *pe, Condition c)
 {
     PoolHintPun php;
     php.phd.init(0, c, PoolHintData::poolBranch, pc);
-    m_buffer.markNextAsBranch();
-    BufferOffset ret = m_buffer.insertEntry(4, (uint8_t*)&php.raw, int32Pool, (uint8_t*)&value, pe);
+    BufferOffset ret = m_buffer.insertEntry(4, (uint8_t*)&php.raw, int32Pool, (uint8_t*)&value, pe,
+                                            /* markAsBranch = */ true);
     // If this label is already bound, then immediately replace the stub load with
     // a correct branch.
     if (label->bound()) {
         BufferOffset dest(label);
         as_b(dest.diffB<BOffImm>(ret), c, ret);
     } else {
         label->use(ret.getOffset());
     }
@@ -1821,33 +1827,33 @@ Assembler::writePoolGuard(BufferOffset b
     *dest = InstBImm(off, Always);
 }
 // Branch can branch to an immediate *or* to a register.
 // Branches to immediates are pc relative, branches to registers
 // are absolute
 BufferOffset
 Assembler::as_b(BOffImm off, Condition c, bool isPatchable)
 {
-    m_buffer.markNextAsBranch();
-    BufferOffset ret =writeInst(((int)c) | op_b | off.encode());
+    BufferOffset ret = writeBranchInst(((int)c) | op_b | off.encode());
     if (c == Always && !isPatchable)
         m_buffer.markGuard();
     return ret;
 }
 
 BufferOffset
 Assembler::as_b(Label *l, Condition c, bool isPatchable)
 {
     if (m_buffer.oom()) {
         BufferOffset ret;
         return ret;
     }
-    m_buffer.markNextAsBranch();
+
     if (l->bound()) {
-        BufferOffset ret = as_nop();
+        // Note only one instruction is emitted here, the NOP is overwritten.
+        BufferOffset ret = writeBranchInst(Always | InstNOP::NopInst);
         as_b(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
         return ret;
     }
 
     int32_t old;
     BufferOffset ret;
     if (l->used()) {
         old = l->offset();
@@ -1885,30 +1891,30 @@ Assembler::as_blx(Register r, Condition 
     return writeInst(((int) c) | op_blx | r.code());
 }
 
 // bl can only branch to an pc-relative immediate offset
 // It cannot change the processor state.
 BufferOffset
 Assembler::as_bl(BOffImm off, Condition c)
 {
-    m_buffer.markNextAsBranch();
-    return writeInst(((int)c) | op_bl | off.encode());
+    return writeBranchInst(((int)c) | op_bl | off.encode());
 }
 
 BufferOffset
 Assembler::as_bl(Label *l, Condition c)
 {
     if (m_buffer.oom()) {
         BufferOffset ret;
         return ret;
     }
-    m_buffer.markNextAsBranch();
+
     if (l->bound()) {
-        BufferOffset ret = as_nop();
+        // Note only one instruction is emitted here, the NOP is overwritten.
+        BufferOffset ret = writeBranchInst(Always | InstNOP::NopInst);
         as_bl(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
         return ret;
     }
 
     int32_t old;
     BufferOffset ret;
     // See if the list was empty :(
     if (l->used()) {
@@ -2605,16 +2611,35 @@ InstIsBNop(Instruction *inst) {
 static bool
 InstIsArtificialGuard(Instruction *inst, const PoolHeader **ph)
 {
     if (!InstIsGuard(inst, ph))
         return false;
     return !(*ph)->isNatural();
 }
 
+// If the instruction points to a artificial pool guard then skip the pool.
+Instruction *
+Instruction::skipPool()
+{
+    const PoolHeader *ph;
+    // If this is a guard, and the next instruction is a header,
+    // always work around the pool. If it isn't a guard, then start
+    // looking ahead.
+    if (InstIsGuard(this, &ph)) {
+        // Don't skip a natural guard.
+        if (ph->isNatural())
+            return this;
+        return (this + 1 + ph->size())->skipPool();
+    }
+    if (InstIsBNop(this))
+        return (this + 1)->skipPool();
+    return this;
+}
+
 // Cases to be handled:
 // 1) no pools or branches in sight => return this+1
 // 2) branch to next instruction => return this+2, because a nop needed to be inserted into the stream.
 // 3) this+1 is an artificial guard for a pool => return first instruction after the pool
 // 4) this+1 is a natural guard => return the branch
 // 5) this is a branch, right before a pool => return first instruction after the pool
 // in assembly form:
 // 1) add r0, r0, r0 <= this
@@ -2644,22 +2669,20 @@ InstIsArtificialGuard(Instruction *inst,
 Instruction *
 Instruction::next()
 {
     Instruction *ret = this+1;
     const PoolHeader *ph;
     // If this is a guard, and the next instruction is a header, always work around the pool
     // If it isn't a guard, then start looking ahead.
     if (InstIsGuard(this, &ph))
-        return ret + ph->size();
+        return (ret + ph->size())->skipPool();
     if (InstIsArtificialGuard(ret, &ph))
-        return ret + 1 + ph->size();
-    if (InstIsBNop(ret))
-        return ret + 1;
-    return ret;
+        return (ret + 1 + ph->size())->skipPool();
+    return ret->skipPool();
 }
 
 void
 Assembler::ToggleToJmp(CodeLocationLabel inst_)
 {
     uint32_t *ptr = (uint32_t *)inst_.raw();
 
     DebugOnly<Instruction *> inst = (Instruction *)inst_.raw();
@@ -2693,16 +2716,18 @@ Assembler::ToggleToCmp(CodeLocationLabel
 
     AutoFlushICache::flush(uintptr_t(ptr), 4);
 }
 
 void
 Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled)
 {
     Instruction *inst = (Instruction *)inst_.raw();
+    // Skip a pool with an artificial guard.
+    inst = inst->skipPool();
     JS_ASSERT(inst->is<InstMovW>() || inst->is<InstLDR>());
 
     if (inst->is<InstMovW>()) {
         // If it looks like the start of a movw/movt sequence,
         // then make sure we have all of it (and advance the iterator
         // past the full sequence)
         inst = inst->next();
         JS_ASSERT(inst->is<InstMovT>());
@@ -2719,16 +2744,47 @@ Assembler::ToggleCall(CodeLocationLabel 
     if (enabled)
         *inst = InstBLXReg(ScratchRegister, Always);
     else
         *inst = InstNOP();
 
     AutoFlushICache::flush(uintptr_t(inst), 4);
 }
 
+size_t
+Assembler::ToggledCallSize(uint8_t *code)
+{
+    Instruction *inst = (Instruction *)code;
+    // Skip a pool with an artificial guard.
+    inst = inst->skipPool();
+    JS_ASSERT(inst->is<InstMovW>() || inst->is<InstLDR>());
+
+    if (inst->is<InstMovW>()) {
+        // If it looks like the start of a movw/movt sequence,
+        // then make sure we have all of it (and advance the iterator
+        // past the full sequence)
+        inst = inst->next();
+        JS_ASSERT(inst->is<InstMovT>());
+    }
+
+    inst = inst->next();
+    JS_ASSERT(inst->is<InstNOP>() || inst->is<InstBLXReg>());
+    return uintptr_t(inst) + 4 - uintptr_t(code);
+}
+
+uint8_t *
+Assembler::BailoutTableStart(uint8_t *code)
+{
+    Instruction *inst = (Instruction *)code;
+    // Skip a pool with an artificial guard or NOP fill.
+    inst = inst->skipPool();
+    JS_ASSERT(inst->is<InstBLImm>());
+    return (uint8_t *) inst;
+}
+
 void Assembler::updateBoundsCheck(uint32_t heapSize, Instruction *inst)
 {
     JS_ASSERT(inst->is<InstCMP>());
     InstCMP *cmp = inst->as<InstCMP>();
 
     Register index;
     cmp->extractOp1(&index);
 
@@ -2738,17 +2794,30 @@ void Assembler::updateBoundsCheck(uint32
     Imm8 imm8 = Imm8(heapSize);
     JS_ASSERT(!imm8.invalid);
 
     *inst = InstALU(InvalidReg, index, imm8, op_cmp, SetCond, Always);
     // NOTE: we don't update the Auto Flush Cache!  this function is currently only called from
     // within AsmJSModule::patchHeapAccesses, which does that for us.  Don't call this!
 }
 
-InstructionIterator::InstructionIterator(Instruction *i_) : i(i_) {
-    const PoolHeader *ph;
-    // If this is a guard, and the next instruction is a header, always work around the pool
-    // If it isn't a guard, then start looking ahead.
-    if (InstIsArtificialGuard(i, &ph)) {
-        i = i->next();
-    }
+InstructionIterator::InstructionIterator(Instruction *i_) : i(i_)
+{
+    // Work around pools with an artificial pool guard and around nop-fill.
+    i = i->skipPool();
 }
 Assembler *Assembler::dummy = nullptr;
+
+uint32_t Assembler::NopFill = 0;
+
+uint32_t
+Assembler::GetNopFill()
+{
+    static bool isSet = false;
+    if (!isSet) {
+        char *fillStr = getenv("ARM_ASM_NOP_FILL");
+        uint32_t fill;
+        if (fillStr && sscanf(fillStr, "%u", &fill) == 1)
+            NopFill = fill;
+        isSet = true;
+    }
+    return NopFill;
+}
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1142,16 +1142,18 @@ class Assembler : public AssemblerShared
         return m_buffer.getInst(bo);
     }
   public:
     void resetCounter();
     uint32_t actualOffset(uint32_t) const;
     uint32_t actualIndex(uint32_t) const;
     static uint8_t *PatchableJumpAddress(JitCode *code, uint32_t index);
     BufferOffset actualOffset(BufferOffset) const;
+    static uint32_t NopFill;
+    static uint32_t GetNopFill();
   protected:
 
     // structure for fixing up pc-relative loads/jumps when a the machine code
     // gets moved (executable copy, gc, etc.)
     struct RelativePatch
     {
         void *target;
         Relocation::Kind kind;
@@ -1168,17 +1170,16 @@ class Assembler : public AssemblerShared
     js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpDataRelocations_;
     js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpPreBarriers_;
 
     CompactBufferWriter jumpRelocations_;
     CompactBufferWriter dataRelocations_;
     CompactBufferWriter relocations_;
     CompactBufferWriter preBarriers_;
 
-    //typedef JSC::AssemblerBufferWithConstantPool<1024, 4, 4, js::jit::Assembler> ARMBuffer;
     ARMBuffer m_buffer;
 
     // There is now a semi-unified interface for instruction generation.
     // During assembly, there is an active buffer that instructions are
     // being written into, but later, we may wish to modify instructions
     // that have already been created.  In order to do this, we call the
     // same assembly function, but pass it a destination address, which
     // will be overwritten with a new instruction. In order to do this very
@@ -1186,18 +1187,19 @@ class Assembler : public AssemblerShared
     // dest parameter, a this object is still needed.  dummy always happens
     // to be null, but we shouldn't be looking at it in any case.
     static Assembler *dummy;
     mozilla::Array<Pool, 4> pools_;
     Pool *int32Pool;
     Pool *doublePool;
 
   public:
+    // For the nopFill use a branch to the next instruction: 0xeaffffff.
     Assembler()
-      : m_buffer(4, 4, 0, &pools_[0], 8),
+      : m_buffer(4, 4, 0, &pools_[0], 8, 0xeaffffff, GetNopFill()),
         int32Pool(m_buffer.getPool(1)),
         doublePool(m_buffer.getPool(0)),
         isFinished(false),
         dtmActive(false),
         dtmCond(Always)
     {
     }
 
@@ -1296,16 +1298,20 @@ class Assembler : public AssemblerShared
     size_t bytesNeeded() const;
 
     // Write a blob of binary into the instruction stream *OR*
     // into a destination address. If dest is nullptr (the default), then the
     // instruction gets written into the instruction stream. If dest is not null
     // it is interpreted as a pointer to the location that we want the
     // instruction to be written.
     BufferOffset writeInst(uint32_t x, uint32_t *dest = nullptr);
+
+    // As above, but also mark the instruction as a branch.
+    BufferOffset writeBranchInst(uint32_t x);
+
     // A static variant for the cases where we don't want to have an assembler
     // object at all. Normally, you would use the dummy (nullptr) object.
     static void writeInstStatic(uint32_t x, uint32_t *dest);
 
   public:
     void writeCodePointer(AbsoluteLabel *label);
 
     BufferOffset align(int alignment);
@@ -1712,16 +1718,19 @@ class Assembler : public AssemblerShared
         return (offset+1)&~1;
     }
     static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr);
     // Toggle a jmp or cmp emitted by toggledJump().
 
     static void ToggleToJmp(CodeLocationLabel inst_);
     static void ToggleToCmp(CodeLocationLabel inst_);
 
+    static uint8_t *BailoutTableStart(uint8_t *code);
+
+    static size_t ToggledCallSize(uint8_t *code);
     static void ToggleCall(CodeLocationLabel inst_, bool enabled);
 
     static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
     void processCodeLabels(uint8_t *rawCode);
     static int32_t extractCodeLabelOffset(uint8_t *code) {
         return *(uintptr_t *)code;
     }
 
@@ -1770,16 +1779,19 @@ class Instruction
     void extractCond(Assembler::Condition *c) {
         if (data >> 28 != 0xf )
             *c = (Assembler::Condition)(data & 0xf0000000);
     }
     // Get the next instruction in the instruction stream.
     // This does neat things like ignoreconstant pools and their guards.
     Instruction *next();
 
+    // Skipping pools with artificial guards.
+    Instruction *skipPool();
+
     // Sometimes, an api wants a uint32_t (or a pointer to it) rather than
     // an instruction.  raw() just coerces this into a pointer to a uint32_t
     const uint32_t *raw() const { return &data; }
     uint32_t size() const { return 4; }
 }; // Instruction
 
 // make sure that it is the right size
 JS_STATIC_ASSERT(sizeof(Instruction) == 4);
@@ -1815,19 +1827,19 @@ class InstLDR : public InstDTR
     static bool isTHIS(const Instruction &i);
     static InstLDR *asTHIS(const Instruction &i);
 
 };
 JS_STATIC_ASSERT(sizeof(InstDTR) == sizeof(InstLDR));
 
 class InstNOP : public Instruction
 {
+  public:
     static const uint32_t NopInst = 0x0320f000;
 
-  public:
     InstNOP()
       : Instruction(NopInst, Assembler::Always)
     { }
 
     static bool isTHIS(const Instruction &i);
     static InstNOP *asTHIS(Instruction &i);
 };
 
--- a/js/src/jit/arm/Bailouts-arm.cpp
+++ b/js/src/jit/arm/Bailouts-arm.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 
+#include "jit/arm/Assembler-arm.h"
 #include "jit/Bailouts.h"
 #include "jit/JitCompartment.h"
 
 using namespace js;
 using namespace js::jit;
 
 namespace js {
 namespace jit {
@@ -91,17 +92,17 @@ IonBailoutIterator::IonBailoutIterator(c
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
     JitActivation *activation = activations.activation()->asJit();
     JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
     JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
-    uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
+    uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw()));
 
     JS_ASSERT(tableOffset >= tableStart &&
               tableOffset < tableStart + code->instructionsSize());
     JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
     JS_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
 
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -193,17 +193,17 @@ CodeGeneratorARM::bailoutIf(Assembler::C
 
     // Though the assembler doesn't track all frame pushes, at least make sure
     // the known value makes sense. We can't use bailout tables if the stack
     // isn't properly aligned to the static frame size.
     JS_ASSERT_IF(frameClass_ != FrameSizeClass::None(),
                  frameClass_.frameSize() == masm.framePushed());
 
     if (assignBailoutId(snapshot)) {
-        uint8_t *code = deoptTable_->raw() + snapshot->bailoutId() * BAILOUT_TABLE_ENTRY_SIZE;
+        uint8_t *code = Assembler::BailoutTableStart(deoptTable_->raw()) + snapshot->bailoutId() * BAILOUT_TABLE_ENTRY_SIZE;
         masm.ma_b(code, Relocation::HARDCODED, condition);
         return true;
     }
 
     // We could not use a jump table, either because all bailout IDs were
     // reserved, or a jump table is not optimal for this frame size or
     // platform. Whatever, we will generate a lazy bailout.
     OutOfLineBailout *ool = new(alloc()) OutOfLineBailout(snapshot, masm.framePushed());
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -422,20 +422,17 @@ NextInst(Instruction *i)
 void
 MacroAssemblerARM::ma_movPatchable(Imm32 imm_, Register dest, Assembler::Condition c,
                                    RelocStyle rs, Instruction *i)
 {
     int32_t imm = imm_.value;
     if (i) {
         // Make sure the current instruction is not an artificial guard
         // inserted by the assembler buffer.
-        // The InstructionIterator already does this and handles edge cases,
-        // so, just asking an iterator for its current instruction should be
-        // enough to make sure we don't accidentally inspect an artificial guard.
-        i = InstructionIterator(i).cur();
+        i = i->skipPool();
     }
     switch(rs) {
       case L_MOVWT:
         as_movw(dest, Imm16(imm & 0xffff), c, i);
         // i can be nullptr here.  that just means "insert in the next in sequence."
         // NextInst is special cased to not do anything when it is passed nullptr, so
         // two consecutive instructions will be inserted.
         i = NextInst(i);
@@ -446,18 +443,18 @@ MacroAssemblerARM::ma_movPatchable(Imm32
             as_Imm32Pool(dest, imm, c);
         else
             as_WritePoolEntry(i, c, imm);
         break;
     }
 }
 
 void
-MacroAssemblerARM::ma_movPatchable(ImmPtr imm, Register dest,
-                                   Assembler::Condition c, RelocStyle rs, Instruction *i)
+MacroAssemblerARM::ma_movPatchable(ImmPtr imm, Register dest, Assembler::Condition c,
+                                   RelocStyle rs, Instruction *i)
 {
     return ma_movPatchable(Imm32(int32_t(imm.value)), dest, c, rs, i);
 }
 
 void
 MacroAssemblerARM::ma_mov(Register src, Register dest,
             SetCond_ sc, Assembler::Condition c)
 {
@@ -4359,25 +4356,23 @@ MacroAssemblerARMCompat::toggledJump(Lab
     CodeOffsetLabel ret(b.getOffset());
     return ret;
 }
 
 CodeOffsetLabel
 MacroAssemblerARMCompat::toggledCall(JitCode *target, bool enabled)
 {
     BufferOffset bo = nextOffset();
-    CodeOffsetLabel offset(bo.getOffset());
     addPendingJump(bo, ImmPtr(target->raw()), Relocation::JITCODE);
     ma_movPatchable(ImmPtr(target->raw()), ScratchRegister, Always, HasMOVWT() ? L_MOVWT : L_LDR);
     if (enabled)
         ma_blx(ScratchRegister);
     else
         ma_nop();
-    JS_ASSERT(nextOffset().getOffset() - offset.offset() == ToggledCallSize());
-    return offset;
+    return CodeOffsetLabel(bo.getOffset());
 }
 
 void
 MacroAssemblerARMCompat::round(FloatRegister input, Register output, Label *bail, FloatRegister tmp)
 {
     Label handleZero;
     Label handleNeg;
     Label fin;
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -674,24 +674,16 @@ class MacroAssemblerARMCompat : public M
     }
 
     CodeOffsetLabel toggledJump(Label *label);
 
     // Emit a BLX or NOP instruction. ToggleCall can be used to patch
     // this instruction.
     CodeOffsetLabel toggledCall(JitCode *target, bool enabled);
 
-    static size_t ToggledCallSize() {
-        if (HasMOVWT())
-            // Size of a movw, movt, nop/blx instruction.
-            return 12;
-        // Size of a ldr, nop/blx instruction
-        return 8;
-    }
-
     CodeOffsetLabel pushWithPatch(ImmWord imm) {
         CodeOffsetLabel label = movWithPatch(imm, ScratchRegister);
         ma_push(ScratchRegister);
         return label;
     }
 
     CodeOffsetLabel movWithPatch(ImmWord imm, Register dest) {
         CodeOffsetLabel label = CodeOffsetLabel(currentOffset());
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -644,20 +644,24 @@ GenerateParallelBailoutThunk(MacroAssemb
     masm.as_dtr(IsLoad, 32, PostIndex, pc, DTRAddr(sp, DtrOffImm(4)));
 }
 
 JitCode *
 JitRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
 {
     MacroAssembler masm(cx);
 
-    Label bailout;
-    for (size_t i = 0; i < BAILOUT_TABLE_SIZE; i++)
-        masm.ma_bl(&bailout);
-    masm.bind(&bailout);
+    {
+        // Emit the table without any pools being inserted.
+        Label bailout;
+        AutoForbidPools afp(&masm);
+        for (size_t i = 0; i < BAILOUT_TABLE_SIZE; i++)
+            masm.ma_bl(&bailout);
+        masm.bind(&bailout);
+    }
 
     GenerateBailoutThunk(cx, masm, frameClass);
 
     Linker linker(masm);
     AutoFlushICache afc("BailoutTable");
     JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
 
 #ifdef JS_ION_PERF
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -312,19 +312,17 @@ CodeGeneratorShared::encode(LSnapshot *s
             if (ins->mirRaw()->trackedPc())
                 pcOpcode = *ins->mirRaw()->trackedPc();
         }
     }
     snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
 #endif
 
     uint32_t allocIndex = 0;
-    LRecoverInfo::OperandIter it(recoverInfo->begin());
-    LRecoverInfo::OperandIter end(recoverInfo->end());
-    for (; it != end; ++it) {
+    for (LRecoverInfo::OperandIter it(recoverInfo); !it; ++it) {
         DebugOnly<uint32_t> allocWritten = snapshots_.allocWritten();
         if (!encodeAllocation(snapshot, *it, &allocIndex))
             return false;
         MOZ_ASSERT(allocWritten + 1 == snapshots_.allocWritten());
     }
 
     MOZ_ASSERT(allocIndex == snapshot->numSlots());
     snapshots_.endSnapshot();
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -342,16 +342,26 @@ struct AssemblerBufferWithConstantPool :
     // we need to keep track of how large the pools are, so we can allocate
     // enough space for them later.  This should include any amount of padding
     // necessary to keep the pools aligned.
     int poolSize;
     // The Assembler should set this to true if it does not want us to dump a pool here
     int canNotPlacePool;
     // Are we filling up the forwards or backwards pools?
     bool inBackref;
+
+    // Insert a number of NOP instructions between each requested instruction at all
+    // locations at which a pool can potentially spill. This is useful for checking
+    // that instruction locations are correctly referenced and/or followed.
+    const uint32_t nopFillInst;
+    const uint32_t nopFill;
+    // Inhibit the insertion of fill NOPs in the dynamic context in which they are
+    // being inserted.
+    bool inhibitNops;
+
     // Cache the last place we saw an opportunity to dump the pool
     BufferOffset perforation;
     BufferSlice *perforatedNode;
   public:
     int id;
   private:
     static const int logBasePoolInfo = 3;
     BufferSlice ** getHead() {
@@ -366,23 +376,26 @@ struct AssemblerBufferWithConstantPool :
         if (!tmp) {
             this->m_oom = true;
             return nullptr;
         }
         new (tmp) BufferSlice;
         return tmp;
     }
   public:
-    AssemblerBufferWithConstantPool(int guardSize_, int headerSize_, int footerSize_, Pool *pools_, int instBufferAlign_)
+    AssemblerBufferWithConstantPool(int guardSize_, int headerSize_, int footerSize_,
+                                    Pool *pools_, int instBufferAlign_,
+                                    uint32_t nopFillInst_, uint32_t nopFill_ = 0)
         : guardSize(guardSize_), headerSize(headerSize_),
           footerSize(footerSize_),
           pools(pools_),
           instBufferAlign(instBufferAlign_), numDumps(0),
           poolInfo(nullptr),
           poolSize(0), canNotPlacePool(0), inBackref(false),
+          nopFillInst(nopFillInst_), nopFill(nopFill_), inhibitNops(false),
           perforatedNode(nullptr), id(-1)
     {
         for (int idx = 0; idx < numPoolKinds; idx++) {
             entryCount[idx] = 0;
         }
     }
 
     // We need to wait until an AutoIonContextAlloc is created by the
@@ -449,19 +462,36 @@ struct AssemblerBufferWithConstantPool :
                 Asm::writePoolFooter(poolDest, cur->data, cur->isNatural);
                 poolDest += footerSize;
                 // at this point, poolDest had better still be aligned to a chunk boundary.
                 dest = (Chunk*) poolDest;
             }
         }
     }
 
-    BufferOffset insertEntry(uint32_t instSize, uint8_t *inst, Pool *p, uint8_t *data, PoolEntry *pe = nullptr) {
+    void insertNopFill() {
+        // Insert fill for testing.
+        if (nopFill > 0 && !inhibitNops && !canNotPlacePool) {
+            inhibitNops = true;
+
+            // Fill using a branch-nop rather than a NOP so this can
+            // be distinguished and skipped.
+            for (int i = 0; i < nopFill; i++)
+                putInt(nopFillInst);
+
+            inhibitNops = false;
+        }
+    }
+
+    BufferOffset insertEntry(uint32_t instSize, uint8_t *inst, Pool *p, uint8_t *data,
+                             PoolEntry *pe = nullptr, bool markAsBranch = false) {
         if (this->oom() && !this->bail())
             return BufferOffset();
+        insertNopFill();
+
         int token;
         if (p != nullptr) {
             int poolId = p - pools;
             const char sigil = inBackref ? 'B' : 'F';
 
             IonSpew(IonSpew_Pools, "[%d]{%c} Inserting entry into pool %d", id, sigil, poolId);
             IonSpewStart(IonSpew_Pools, "[%d] data is: 0x", id);
             spewEntry(data, p->immSize);
@@ -484,16 +514,18 @@ struct AssemblerBufferWithConstantPool :
             JS_ASSERT(poolId >= 0);
             // Figure out the offset within like-kinded pool entries
             retPE = PoolEntry(entryCount[poolId], poolId);
             entryCount[poolId]++;
         }
         // Now inst is a valid thing to insert into the instruction stream
         if (pe != nullptr)
             *pe = retPE;
+        if (markAsBranch)
+            this->markNextAsBranch();
         return this->putBlob(instSize, inst);
     }
 
     uint32_t insertEntryBackwards(uint32_t instSize, uint8_t *inst, Pool *p, uint8_t *data) {
         // unlike the forward case, inserting an instruction without inserting
         // anything into a pool after a pool has been placed, we don't affect
         // anything relevant, so we can skip this check entirely!
 
@@ -587,18 +619,19 @@ struct AssemblerBufferWithConstantPool :
             }
             nextOffset += tmp->immSize * tmp->numEntries;
         }
         if (p == nullptr) {
             return INT_MIN;
         }
         return p->insertEntry(data, this->nextOffset(), this->LifoAlloc_);
     }
-    BufferOffset putInt(uint32_t value) {
-        return insertEntry(sizeof(uint32_t) / sizeof(uint8_t), (uint8_t*)&value, nullptr, nullptr);
+    BufferOffset putInt(uint32_t value, bool markAsBranch = false) {
+        return insertEntry(sizeof(uint32_t) / sizeof(uint8_t), (uint8_t*)&value,
+                           nullptr, nullptr, nullptr, markAsBranch);
     }
     // Mark the current section as an area where we can
     // later go to dump a pool
     void perforate() {
         // If we're filling the backrefrences, we don't want to start looking for a new dumpsite.
         if (inBackref)
             return;
         if (canNotPlacePool)
@@ -867,16 +900,17 @@ struct AssemblerBufferWithConstantPool :
             // If there is no data in the pool being dumped, don't dump anything.
             inBackref = true;
             IonSpew(IonSpew_Pools, "[%d]Abort, no pool data", id);
             return;
         }
 
         IonSpew(IonSpew_Pools, "[%d] Dumping %d bytes", id, newPoolInfo.size);
         if (!perforation.assigned()) {
+            JS_ASSERT(!canNotPlacePool);
             IonSpew(IonSpew_Pools, "[%d] No Perforation point selected, generating a new one", id);
             // There isn't a perforation here, we need to dump the pool with a guard.
             BufferOffset branch = this->nextOffset();
             bool shouldMarkAsBranch = this->isNextBranch();
             this->markNextAsBranch();
             this->putBlob(guardSize, nullptr);
             BufferOffset afterPool = this->nextOffset();
             Asm::writePoolGuard(branch, this->getInst(branch), afterPool);
@@ -991,16 +1025,17 @@ struct AssemblerBufferWithConstantPool :
             return;
         // There is no point in trying to grab a new slot if we've already
         // found one and are in the process of filling it in.
         if (inBackref)
             return;
         perforate();
     }
     void enterNoPool() {
+        insertNopFill();
         if (!canNotPlacePool && !perforation.assigned()) {
             // Embarassing mode: The Assembler requests the start of a no pool section
             // and there have been no valid places that a pool could be dumped thusfar.
             // If a pool were to fill up before this no-pool section ends, we need to go back
             // in the stream and enter a pool guard after the fact.  This is feasable, but
             // for now, it is easier to just allocate a junk instruction, default it to a nop, and
             // finally, if the pool *is* needed, patch the nop to  apool guard.
             // What the assembler requests:
--- a/js/src/jit/shared/Lowering-shared.cpp
+++ b/js/src/jit/shared/Lowering-shared.cpp
@@ -101,19 +101,17 @@ LIRGeneratorShared::buildSnapshot(LInstr
     if (!recoverInfo)
         return nullptr;
 
     LSnapshot *snapshot = LSnapshot::New(gen, recoverInfo, kind);
     if (!snapshot)
         return nullptr;
 
     size_t index = 0;
-    LRecoverInfo::OperandIter it(recoverInfo->begin());
-    LRecoverInfo::OperandIter end(recoverInfo->end());
-    for (; it != end; ++it) {
+    for (LRecoverInfo::OperandIter it(recoverInfo); !it; ++it) {
         // Check that optimized out operands are in eliminable slots.
         MOZ_ASSERT(it.canOptimizeOutIfUnused());
 
         MDefinition *ins = *it;
 
         if (ins->isRecoveredOnBailout())
             continue;
 
@@ -161,19 +159,17 @@ LIRGeneratorShared::buildSnapshot(LInstr
     if (!recoverInfo)
         return nullptr;
 
     LSnapshot *snapshot = LSnapshot::New(gen, recoverInfo, kind);
     if (!snapshot)
         return nullptr;
 
     size_t index = 0;
-    LRecoverInfo::OperandIter it(recoverInfo->begin());
-    LRecoverInfo::OperandIter end(recoverInfo->end());
-    for (; it != end; ++it) {
+    for (LRecoverInfo::OperandIter it(recoverInfo); !it; ++it) {
         // Check that optimized out operands are in eliminable slots.
         MOZ_ASSERT(it.canOptimizeOutIfUnused());
 
         MDefinition *def = *it;
 
         if (def->isRecoveredOnBailout())
             continue;
 
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -702,21 +702,21 @@ class Assembler : public AssemblerX86Sha
     }
 
     // Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch
     // this instruction.
     CodeOffsetLabel toggledCall(JitCode *target, bool enabled) {
         CodeOffsetLabel offset(size());
         JmpSrc src = enabled ? masm.call() : masm.cmp_eax();
         addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE);
-        JS_ASSERT(size() - offset.offset() == ToggledCallSize());
+        JS_ASSERT(size() - offset.offset() == ToggledCallSize(nullptr));
         return offset;
     }
 
-    static size_t ToggledCallSize() {
+    static size_t ToggledCallSize(uint8_t *code) {
         // Size of a call instruction.
         return 5;
     }
 
     // Do not mask shared implementations.
     using AssemblerX86Shared::call;
 
     void cvttsd2sq(FloatRegister src, Register dest) {
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -391,21 +391,21 @@ class Assembler : public AssemblerX86Sha
     }
 
     // Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch
     // this instruction.
     CodeOffsetLabel toggledCall(JitCode *target, bool enabled) {
         CodeOffsetLabel offset(size());
         JmpSrc src = enabled ? masm.call() : masm.cmp_eax();
         addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE);
-        JS_ASSERT(size() - offset.offset() == ToggledCallSize());
+        JS_ASSERT(size() - offset.offset() == ToggledCallSize(nullptr));
         return offset;
     }
 
-    static size_t ToggledCallSize() {
+    static size_t ToggledCallSize(uint8_t *code) {
         // Size of a call instruction.
         return 5;
     }
 
     // Re-routes pending jumps to an external target, flushing the label in the
     // process.
     void retarget(Label *label, ImmPtr target, Relocation::Kind reloc) {
         if (label->used()) {
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -269,17 +269,17 @@ MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX,   21
 MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE,    216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
 MSG_DEF(JSMSG_LET_COMP_BINDING,       217, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
 MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE,     218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
 MSG_DEF(JSMSG_BAD_SYMBOL,             219, 1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol")
 MSG_DEF(JSMSG_BAD_DELETE_OPERAND,     220, 0, JSEXN_REFERENCEERR, "invalid delete operand")
 MSG_DEF(JSMSG_BAD_INCOP_OPERAND,      221, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
 MSG_DEF(JSMSG_UNEXPECTED_TYPE,        222, 2, JSEXN_TYPEERR, "{0} is {1}")
 MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK,  223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")
-MSG_DEF(JSMSG_BAD_OBJECT_INIT,        224, 0, JSEXN_SYNTAXERR, "invalid object initializer")
+MSG_DEF(JSMSG_UNUSED224,              224, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS,   225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties")
 MSG_DEF(JSMSG_EVAL_ARITY,             226, 0, JSEXN_TYPEERR, "eval accepts only one parameter")
 MSG_DEF(JSMSG_MISSING_FUN_ARG,        227, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
 MSG_DEF(JSMSG_JSON_BAD_PARSE,         228, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
 MSG_DEF(JSMSG_JSON_BAD_STRINGIFY,     229, 0, JSEXN_ERR, "JSON.stringify")
 MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 230, 0, JSEXN_TYPEERR, "value is not a function or undefined")
 MSG_DEF(JSMSG_NOT_NONNULL_OBJECT,     231, 0, JSEXN_TYPEERR, "value is not a non-null object")
 MSG_DEF(JSMSG_DEPRECATED_OCTAL,       232, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -669,16 +669,22 @@ js::VisitGrayWrapperTargets(Zone *zone, 
 JS_FRIEND_API(JSObject *)
 js::GetWeakmapKeyDelegate(JSObject *key)
 {
     if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp)
         return op(key);
     return nullptr;
 }
 
+JS_FRIEND_API(JSLinearString *)
+js::StringToLinearStringSlow(JSContext *cx, JSString *str)
+{
+    return str->ensureLinear(cx);
+}
+
 JS_FRIEND_API(void)
 JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
 {
     rt->telemetryCallback = callback;
 }
 
 JS_FRIEND_API(JSObject *)
 JS_CloneObject(JSContext *cx, HandleObject obj, HandleObject protoArg, HandleObject parent)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -570,19 +570,22 @@ struct Function {
     uint16_t nargs;
     uint16_t flags;
     /* Used only for natives */
     JSNative native;
     const JSJitInfo *jitinfo;
     void *_1;
 };
 
-struct Atom {
+struct String
+{
     static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
     static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
+    static const uint32_t ROPE_FLAGS       = 0;
+    static const uint32_t TYPE_FLAGS_MASK  = JS_BIT(6) - 1;
     uint32_t flags;
     uint32_t length;
     union {
         const JS::Latin1Char *nonInlineCharsLatin1;
         const jschar *nonInlineCharsTwoByte;
         JS::Latin1Char inlineStorageLatin1[1];
         jschar inlineStorageTwoByte[1];
     };
@@ -756,56 +759,121 @@ GetObjectSlotSpan(JSObject *obj);
 
 inline const JS::Value &
 GetObjectSlot(JSObject *obj, size_t slot)
 {
     JS_ASSERT(slot < GetObjectSlotSpan(obj));
     return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot);
 }
 
-inline size_t
+MOZ_ALWAYS_INLINE size_t
 GetAtomLength(JSAtom *atom)
 {
-    return reinterpret_cast<shadow::Atom*>(atom)->length;
+    return reinterpret_cast<shadow::String*>(atom)->length;
+}
+
+static const uint32_t MaxStringLength = (1 << 28) - 1;
+
+MOZ_ALWAYS_INLINE size_t
+GetStringLength(JSString *s)
+{
+    return reinterpret_cast<shadow::String*>(s)->length;
+}
+
+MOZ_ALWAYS_INLINE bool
+LinearStringHasLatin1Chars(JSLinearString *s)
+{
+    return reinterpret_cast<shadow::String *>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
+}
+
+MOZ_ALWAYS_INLINE bool
+AtomHasLatin1Chars(JSAtom *atom)
+{
+    return reinterpret_cast<shadow::String *>(atom)->flags & shadow::String::LATIN1_CHARS_BIT;
+}
+
+MOZ_ALWAYS_INLINE bool
+StringHasLatin1Chars(JSString *s)
+{
+    return reinterpret_cast<shadow::String *>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
+}
+
+MOZ_ALWAYS_INLINE const JS::Latin1Char *
+GetLatin1LinearStringChars(const JS::AutoCheckCannotGC &nogc, JSLinearString *linear)
+{
+    MOZ_ASSERT(LinearStringHasLatin1Chars(linear));
+
+    using shadow::String;
+    String *s = reinterpret_cast<String *>(linear);
+    if (s->flags & String::INLINE_CHARS_BIT)
+        return s->inlineStorageLatin1;
+    return s->nonInlineCharsLatin1;
+}
+
+MOZ_ALWAYS_INLINE const jschar *
+GetTwoByteLinearStringChars(const JS::AutoCheckCannotGC &nogc, JSLinearString *linear)
+{
+    MOZ_ASSERT(!LinearStringHasLatin1Chars(linear));
+
+    using shadow::String;
+    String *s = reinterpret_cast<String *>(linear);
+    if (s->flags & String::INLINE_CHARS_BIT)
+        return s->inlineStorageTwoByte;
+    return s->nonInlineCharsTwoByte;
+}
+
+MOZ_ALWAYS_INLINE JSLinearString *
+AtomToLinearString(JSAtom *atom)
+{
+    return reinterpret_cast<JSLinearString *>(atom);
+}
+
+MOZ_ALWAYS_INLINE const JS::Latin1Char *
+GetLatin1AtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
+{
+    return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom));
+}
+
+MOZ_ALWAYS_INLINE const jschar *
+GetTwoByteAtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
+{
+    return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom));
+}
+
+JS_FRIEND_API(JSLinearString *)
+StringToLinearStringSlow(JSContext *cx, JSString *str);
+
+MOZ_ALWAYS_INLINE JSLinearString *
+StringToLinearString(JSContext *cx, JSString *str)
+{
+    using shadow::String;
+    String *s = reinterpret_cast<String *>(str);
+    if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS))
+        return StringToLinearStringSlow(cx, str);
+    return reinterpret_cast<JSLinearString *>(str);
 }
 
 inline bool
-AtomHasLatin1Chars(JSAtom *atom)
-{
-    return reinterpret_cast<shadow::Atom *>(atom)->flags & shadow::Atom::LATIN1_CHARS_BIT;
-}
-
-inline const JS::Latin1Char *
-GetLatin1AtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
+CopyStringChars(JSContext *cx, jschar *dest, JSString *s, size_t len)
 {
-    MOZ_ASSERT(AtomHasLatin1Chars(atom));
-
-    using shadow::Atom;
-    Atom *atom_ = reinterpret_cast<Atom *>(atom);
-    if (atom_->flags & Atom::INLINE_CHARS_BIT)
-        return atom_->inlineStorageLatin1;
-    return atom_->nonInlineCharsLatin1;
-}
+    JSLinearString *linear = StringToLinearString(cx, s);
+    if (!linear)
+        return false;
 
-inline const jschar *
-GetTwoByteAtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
-{
-    MOZ_ASSERT(!AtomHasLatin1Chars(atom));
+    JS::AutoCheckCannotGC nogc;
+    if (LinearStringHasLatin1Chars(linear)) {
+        const JS::Latin1Char *src = GetLatin1LinearStringChars(nogc, linear);
+        for (size_t i = 0; i < len; i++)
+            dest[i] = src[i];
+    } else {
+        const jschar *src = GetTwoByteLinearStringChars(nogc, linear);
+        mozilla::PodCopy(dest, src, len);
+    }
 
-    using shadow::Atom;
-    Atom *atom_ = reinterpret_cast<Atom *>(atom);
-    if (atom_->flags & Atom::INLINE_CHARS_BIT)
-        return atom_->inlineStorageTwoByte;
-    return atom_->nonInlineCharsTwoByte;
-}
-
-inline JSLinearString *
-AtomToLinearString(JSAtom *atom)
-{
-    return reinterpret_cast<JSLinearString *>(atom);
+    return true;
 }
 
 JS_FRIEND_API(bool)
 GetPropertyNames(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props);
 
 JS_FRIEND_API(bool)
 AppendUnique(JSContext *cx, JS::AutoIdVector &base, JS::AutoIdVector &others);
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -222,18 +222,16 @@
 #include "jsscriptinlines.h"
 
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
-using mozilla::ArrayEnd;
-using mozilla::DebugOnly;
 using mozilla::Maybe;
 using mozilla::Swap;
 
 using JS::AutoGCRooter;
 
 /* Perform a Full GC every 20 seconds if MaybeGC is called */
 static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
 
@@ -241,17 +239,16 @@ static const uint64_t GC_IDLE_FULL_SPAN 
 static const int IGC_MARK_SLICE_MULTIPLIER = 2;
 
 #if defined(ANDROID) || defined(MOZ_B2G)
 static const int MAX_EMPTY_CHUNK_COUNT = 2;
 #else
 static const int MAX_EMPTY_CHUNK_COUNT = 30;
 #endif
 
-/* This array should be const, but that doesn't link right under GCC. */
 const AllocKind gc::slotsToThingKind[] = {
     /* 0 */  FINALIZE_OBJECT0,  FINALIZE_OBJECT2,  FINALIZE_OBJECT2,  FINALIZE_OBJECT4,
     /* 4 */  FINALIZE_OBJECT4,  FINALIZE_OBJECT8,  FINALIZE_OBJECT8,  FINALIZE_OBJECT8,
     /* 8 */  FINALIZE_OBJECT8,  FINALIZE_OBJECT12, FINALIZE_OBJECT12, FINALIZE_OBJECT12,
     /* 12 */ FINALIZE_OBJECT12, FINALIZE_OBJECT16, FINALIZE_OBJECT16, FINALIZE_OBJECT16,
     /* 16 */ FINALIZE_OBJECT16
 };
 
@@ -425,17 +422,17 @@ ArenaHeader::checkSynchronizedWithFreeLi
     if (firstSpan.isEmpty())
         return;
     const FreeList *freeList = zone->allocator.arenas.getFreeList(getAllocKind());
     if (freeList->isEmpty() || firstSpan.arenaAddress() != freeList->arenaAddress())
         return;
 
     /*
      * Here this arena has free things, FreeList::lists[thingKind] is not
-     * empty and also points to this arena. Thus they must the same.
+     * empty and also points to this arena. Thus they must be the same.
      */
     JS_ASSERT(freeList->isSameNonEmptySpan(firstSpan));
 }
 #endif
 
 /* static */ void
 Arena::staticAsserts()
 {
@@ -963,17 +960,17 @@ Chunk::releaseArena(ArenaHeader *aheader
     JSRuntime *rt = zone->runtimeFromAnyThread();
     AutoLockGC maybeLock;
     if (rt->gc.isBackgroundSweeping())
         maybeLock.lock(rt);
 
     JS_ASSERT(rt->gc.bytes >= ArenaSize);
     JS_ASSERT(zone->gcBytes >= ArenaSize);
     if (rt->gc.isBackgroundSweeping())
-        zone->reduceGCTriggerBytes(zone->gcHeapGrowthFactor * ArenaSize);
+        zone->gcBytesAfterGC -= ArenaSize;
     rt->gc.bytes -= ArenaSize;
     zone->gcBytes -= ArenaSize;
 
     aheader->setAsNotAllocated();
     addArenaToFreeList(rt, aheader);
 
     if (info.numArenasFree == 1) {
         JS_ASSERT(!info.prevp);
@@ -1096,17 +1093,17 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     allocThreshold(30 * 1024 * 1024),
     highFrequencyGC(false),
     highFrequencyTimeThreshold(1000),
     highFrequencyLowLimitBytes(100 * 1024 * 1024),
     highFrequencyHighLimitBytes(500 * 1024 * 1024),
     highFrequencyHeapGrowthMax(3.0),
     highFrequencyHeapGrowthMin(1.5),
     lowFrequencyHeapGrowth(1.5),
-    dynamicHeapGrowth(false),
+    dynamicHeapGrowth(true),
     dynamicMarkSlice(false),
     decommitThreshold(32 * 1024 * 1024),
     cleanUpEverything(false),
     grayBitsValid(false),
     isNeeded(0),
     number(0),
     startNumber(0),
     isFull(false),
@@ -1382,19 +1379,23 @@ GCRuntime::setParameter(JSGCParamKey key
       case JSGC_MARK_STACK_LIMIT:
         setMarkStackLimit(value);
         break;
       case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
         highFrequencyTimeThreshold = value;
         break;
       case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
         highFrequencyLowLimitBytes = value * 1024 * 1024;
+        if (highFrequencyLowLimitBytes >= highFrequencyHighLimitBytes)
+            highFrequencyHighLimitBytes = highFrequencyLowLimitBytes + 1;
         break;
       case JSGC_HIGH_FREQUENCY_HIGH_LIMIT:
         highFrequencyHighLimitBytes = value * 1024 * 1024;
+        if (highFrequencyLowLimitBytes >= highFrequencyHighLimitBytes)
+            highFrequencyLowLimitBytes = highFrequencyHighLimitBytes - 1;
         break;
       case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX:
         highFrequencyHeapGrowthMax = value / 100.0;
         MOZ_ASSERT(highFrequencyHeapGrowthMax / 0.85 > 1.0);
         break;
       case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN:
         highFrequencyHeapGrowthMin = value / 100.0;
         MOZ_ASSERT(highFrequencyHeapGrowthMin / 0.85 > 1.0);
@@ -1665,25 +1666,26 @@ GCRuntime::updateMallocCounter(JS::Zone 
 void
 GCRuntime::onTooMuchMalloc()
 {
     if (!mallocGCTriggered)
         mallocGCTriggered = triggerGC(JS::gcreason::TOO_MUCH_MALLOC);
 }
 
 size_t
-GCRuntime::computeTriggerBytes(double growthFactor, size_t lastBytes, JSGCInvocationKind gckind)
+GCRuntime::computeTriggerBytes(double growthFactor, size_t lastBytes,
+                               JSGCInvocationKind gckind) const
 {
     size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, allocThreshold);
     double trigger = double(base) * growthFactor;
     return size_t(Min(double(maxBytes), trigger));
 }
 
 double
-GCRuntime::computeHeapGrowthFactor(size_t lastBytes)
+GCRuntime::computeHeapGrowthFactor(size_t lastBytes) const
 {
     /*
      * The heap growth factor depends on the heap size after a GC and the GC frequency.
      * For low frequency GCs (more than 1sec between GCs) we let the heap grow to 150%.
      * For high frequency GCs we let the heap grow depending on the heap size:
      *   lastBytes < highFrequencyLowLimit: 300%
      *   lastBytes > highFrequencyHighLimit: 150%
      *   otherwise: linear interpolation between 150% and 300% based on lastBytes
@@ -1691,59 +1693,45 @@ GCRuntime::computeHeapGrowthFactor(size_
 
     double factor;
     if (!dynamicHeapGrowth) {
         factor = 3.0;
     } else if (lastBytes < 1 * 1024 * 1024) {
         factor = lowFrequencyHeapGrowth;
     } else {
         JS_ASSERT(highFrequencyHighLimitBytes > highFrequencyLowLimitBytes);
-        uint64_t now = PRMJ_Now();
-        if (lastGCTime && lastGCTime + highFrequencyTimeThreshold * PRMJ_USEC_PER_MSEC > now) {
+        if (highFrequencyGC) {
             if (lastBytes <= highFrequencyLowLimitBytes) {
                 factor = highFrequencyHeapGrowthMax;
             } else if (lastBytes >= highFrequencyHighLimitBytes) {
                 factor = highFrequencyHeapGrowthMin;
             } else {
                 double k = (highFrequencyHeapGrowthMin - highFrequencyHeapGrowthMax)
                            / (double)(highFrequencyHighLimitBytes - highFrequencyLowLimitBytes);
                 factor = (k * (lastBytes - highFrequencyLowLimitBytes)
                                      + highFrequencyHeapGrowthMax);
                 JS_ASSERT(factor <= highFrequencyHeapGrowthMax
                           && factor >= highFrequencyHeapGrowthMin);
             }
-            highFrequencyGC = true;
         } else {
             factor = lowFrequencyHeapGrowth;
-            highFrequencyGC = false;
         }
     }
 
     return factor;
 }
 
 void
 Zone::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
 {
-    GCRuntime &gc = runtimeFromMainThread()->gc;
+    const GCRuntime &gc = runtimeFromAnyThread()->gc;
     gcHeapGrowthFactor = gc.computeHeapGrowthFactor(lastBytes);
     gcTriggerBytes = gc.computeTriggerBytes(gcHeapGrowthFactor, lastBytes, gckind);
 }
 
-void
-Zone::reduceGCTriggerBytes(size_t amount)
-{
-    JS_ASSERT(amount > 0);
-    JS_ASSERT(gcTriggerBytes >= amount);
-    GCRuntime &gc = runtimeFromAnyThread()->gc;
-    if (gcTriggerBytes - amount < gc.allocationThreshold() * gcHeapGrowthFactor)
-        return;
-    gcTriggerBytes -= amount;
-}
-
 Allocator::Allocator(Zone *zone)
   : zone_(zone)
 {}
 
 inline void
 GCMarker::delayMarkingArena(ArenaHeader *aheader)
 {
     if (aheader->hasDelayedMarking) {
@@ -2563,16 +2551,25 @@ GCRuntime::sweepBackgroundThings(bool on
                 AllocKind kind = BackgroundPhases[phase][index];
                 ArenaHeader *arenas = zone->allocator.arenas.arenaListsToSweep[kind];
                 if (arenas)
                     ArenaLists::backgroundFinalize(&fop, arenas, onBackgroundThread);
             }
         }
     }
 
+    if (onBackgroundThread) {
+        /*
+         * Update zone triggers a second time now we have completely finished
+         * sweeping these zones.
+         */
+        for (Zone *zone = sweepingZones; zone; zone = zone->gcNextGraphNode)
+            zone->setGCLastBytes(zone->gcBytesAfterGC, lastKind);
+    }
+
     sweepingZones = nullptr;
 }
 
 void
 GCRuntime::assertBackgroundSweepingFinished()
 {
 #if defined(JS_THREADSAFE) && defined(DEBUG)
     JS_ASSERT(!sweepingZones);
@@ -4360,17 +4357,17 @@ GCRuntime::sweepPhase(SliceBudget &slice
         if (!currentZoneGroup)
             return true;  /* We're finished. */
         endMarkingZoneGroup();
         beginSweepingZoneGroup();
     }
 }
 
 void
-GCRuntime::endSweepPhase(JSGCInvocationKind gckind, bool lastGC)
+GCRuntime::endSweepPhase(bool lastGC)
 {
     gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP);
     FreeOp fop(rt, sweepOnBackgroundThread);
 
     JS_ASSERT_IF(lastGC, !sweepOnBackgroundThread);
 
     JS_ASSERT(marker.isDrained());
     marker.stop();
@@ -4433,17 +4430,17 @@ GCRuntime::endSweepPhase(JSGCInvocationK
         if (!sweepOnBackgroundThread) {
             /*
              * Destroy arenas after we finished the sweeping so finalizers can
              * safely use IsAboutToBeFinalized(). This is done on the
              * GCHelperState if possible. We acquire the lock only because
              * Expire needs to unlock it for other callers.
              */
             AutoLockGC lock(rt);
-            expireChunksAndArenas(gckind == GC_SHRINK);
+            expireChunksAndArenas(lastKind == GC_SHRINK);
         }
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_FINALIZE_END);
 
         for (Callback<JSFinalizeCallback> *p = rt->gc.finalizeCallbacks.begin();
              p < rt->gc.finalizeCallbacks.end(); p++)
@@ -4471,20 +4468,25 @@ GCRuntime::endSweepPhase(JSGCInvocationK
 
         rt->freeLifoAlloc.freeAll();
 
         /* Ensure the compartments get swept if it's the last GC. */
         if (lastGC)
             sweepZones(&fop, lastGC);
     }
 
+    uint64_t currentTime = PRMJ_Now();
+    highFrequencyGC = dynamicHeapGrowth && lastGCTime &&
+        lastGCTime + highFrequencyTimeThreshold * PRMJ_USEC_PER_MSEC > currentTime;
+
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
-        zone->setGCLastBytes(zone->gcBytes, gckind);
+        zone->setGCLastBytes(zone->gcBytes, lastKind);
         if (zone->isCollecting()) {
             JS_ASSERT(zone->isGCFinished());
+            zone->gcBytesAfterGC = zone->gcBytes;
             zone->setGCState(Zone::NoGC);
         }
 
 #ifdef DEBUG
         JS_ASSERT(!zone->isCollecting());
         JS_ASSERT(!zone->wasGCStarted());
 
         for (unsigned i = 0 ; i < FINALIZE_LIMIT ; ++i) {
@@ -4504,17 +4506,17 @@ GCRuntime::endSweepPhase(JSGCInvocationK
             if (e.front().key().kind != CrossCompartmentKey::StringWrapper)
                 AssertNotOnGrayList(&e.front().value().get().toObject());
         }
     }
 #endif
 
     finishMarkingValidation();
 
-    lastGCTime = PRMJ_Now();
+    lastGCTime = currentTime;
 }
 
 /* Start a new heap session. */
 AutoTraceSession::AutoTraceSession(JSRuntime *rt, js::HeapState heapState)
   : lock(rt),
     runtime(rt),
     prevState(rt->gc.heapState)
 {
@@ -4756,16 +4758,18 @@ GCRuntime::incrementalCollectSlice(int64
          */
         zeal = zealMode;
     }
 #endif
 
     JS_ASSERT_IF(incrementalState != NO_INCREMENTAL, isIncremental);
     isIncremental = budget != SliceBudget::Unlimited;
 
+    lastKind = gckind;
+
     if (zeal == ZealIncrementalRootsThenFinish || zeal == ZealIncrementalMarkAllThenFinish) {
         /*
          * Yields between slices occurs at predetermined points in these modes;
          * the budget is not used.
          */
         budget = SliceBudget::Unlimited;
     }
 
@@ -4843,17 +4847,17 @@ GCRuntime::incrementalCollectSlice(int64
         /* fall through */
       }
 
       case SWEEP: {
         bool finished = sweepPhase(sliceBudget);
         if (!finished)
             break;
 
-        endSweepPhase(gckind, lastGC);
+        endSweepPhase(lastGC);
 
         if (sweepOnBackgroundThread)
             helperState.startBackgroundSweep(gckind == GC_SHRINK);
 
         incrementalState = NO_INCREMENTAL;
         break;
       }
 
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -527,18 +527,18 @@ class NodeBuilder
     bool variableDeclarator(HandleValue id, HandleValue init, TokenPos *pos,
                             MutableHandleValue dst);
 
     bool switchCase(HandleValue expr, NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
 
     bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos *pos,
                      MutableHandleValue dst);
 
-    bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, TokenPos *pos,
-                             MutableHandleValue dst);
+    bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
+                             TokenPos *pos, MutableHandleValue dst);
 
 
     /*
      * statements
      */
 
     bool blockStatement(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
 
@@ -660,17 +660,18 @@ class NodeBuilder
     /*
      * patterns
      */
 
     bool arrayPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
 
     bool objectPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
 
-    bool propertyPattern(HandleValue key, HandleValue patt, TokenPos *pos, MutableHandleValue dst);
+    bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos *pos,
+                         MutableHandleValue dst);
 };
 
 } /* anonymous namespace */
 
 bool
 NodeBuilder::newNode(ASTType type, TokenPos *pos, MutableHandleObject dst)
 {
     JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
@@ -1222,55 +1223,61 @@ bool
 NodeBuilder::spreadExpression(HandleValue expr, TokenPos *pos, MutableHandleValue dst)
 {
     return newNode(AST_SPREAD_EXPR, pos,
                    "expression", expr,
                    dst);
 }
 
 bool
-NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, TokenPos *pos,
+NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos *pos,
                              MutableHandleValue dst)
 {
     RootedValue kindName(cx);
     if (!atomValue("init", &kindName))
         return false;
 
+    RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
+
     RootedValue cb(cx, callbacks[AST_PROP_PATT]);
     if (!cb.isNull())
         return callback(cb, key, patt, pos, dst);
 
     return newNode(AST_PROP_PATT, pos,
                    "key", key,
                    "value", patt,
                    "kind", kindName,
+                   "shorthand", isShorthandVal,
                    dst);
 }
 
 bool
-NodeBuilder::propertyInitializer(HandleValue key, HandleValue val, PropKind kind, TokenPos *pos,
-                                 MutableHandleValue dst)
+NodeBuilder::propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
+                                 TokenPos *pos, MutableHandleValue dst)
 {
     RootedValue kindName(cx);
     if (!atomValue(kind == PROP_INIT
                    ? "init"
                    : kind == PROP_GETTER
                    ? "get"
                    : "set", &kindName)) {
         return false;
     }
 
+    RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
+
     RootedValue cb(cx, callbacks[AST_PROPERTY]);
     if (!cb.isNull())
         return callback(cb, kindName, key, val, pos, dst);
 
     return newNode(AST_PROPERTY, pos,
                    "key", key,
                    "value", val,
                    "kind", kindName,
+                   "shorthand", isShorthandVal,
                    dst);
 }
 
 bool
 NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
 {
     return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
 }
@@ -2797,21 +2804,16 @@ ASTSerializer::expression(ParseNode *pn,
       {
           RootedValue expr(cx);
           return expression(pn->pn_kid, &expr) &&
                  builder.spreadExpression(expr, &pn->pn_pos, dst);
       }
 
       case PNK_OBJECT:
       {
-        /* The parser notes any uninitialized properties by setting the PNX_DESTRUCT flag. */
-        if (pn->pn_xflags & PNX_DESTRUCT) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_OBJECT_INIT);
-            return false;
-        }
         NodeVector elts(cx);
         if (!elts.reserve(pn->pn_count))
             return false;
 
         for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
             JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
 
             RootedValue prop(cx);
@@ -2919,20 +2921,21 @@ ASTSerializer::property(ParseNode *pn, M
       case JSOP_INITPROP_SETTER:
         kind = PROP_SETTER;
         break;
 
       default:
         LOCAL_NOT_REACHED("unexpected object-literal property");
     }
 
+    bool isShorthand = pn->isKind(PNK_SHORTHAND);
     RootedValue key(cx), val(cx);
     return propertyName(pn->pn_left, &key) &&
            expression(pn->pn_right, &val) &&
-           builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
+           builder.propertyInitializer(key, val, kind, isShorthand, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::literal(ParseNode *pn, MutableHandleValue dst)
 {
     RootedValue val(cx);
     switch (pn->getKind()) {
 #ifdef JS_HAS_TEMPLATE_STRINGS
@@ -3011,17 +3014,18 @@ ASTSerializer::objectPattern(ParseNode *
         return false;
 
     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
         LOCAL_ASSERT(next->isOp(JSOP_INITPROP));
 
         RootedValue key(cx), patt(cx), prop(cx);
         if (!propertyName(next->pn_left, &key) ||
             !pattern(next->pn_right, pkind, &patt) ||
-            !builder.propertyPattern(key, patt, &next->pn_pos, &prop)) {
+            !builder.propertyPattern(key, patt, next->isKind(PNK_SHORTHAND), &next->pn_pos,
+                                     &prop)) {
             return false;
         }
 
         elts.infallibleAppend(prop);
     }
 
     return builder.objectPattern(elts, &pn->pn_pos, dst);
 }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6093,16 +6093,20 @@ SetRuntimeOptions(JSRuntime *rt, const O
         return false;
     }
 
 #endif // JS_ION
 
 #if defined(JS_CODEGEN_ARM)
     if (const char *str = op.getStringOption("arm-hwcap"))
         jit::ParseARMHwCapFlags(str);
+
+    int32_t fill = op.getIntOption("arm-asm-nop-fill");
+    if (fill >= 0)
+        jit::Assembler::NopFill = fill;
 #endif
 
 #if defined(JS_ARM_SIMULATOR)
     if (op.getBoolOption("arm-sim-icache-checks"))
         jit::Simulator::ICacheCheckingEnabled = true;
 
     int32_t stopAt = op.getIntOption("arm-sim-stop-at");
     if (stopAt >= 0)
@@ -6317,16 +6321,18 @@ main(int argc, char **argv, char **envp)
 #ifdef JSGC_GENERATIONAL
         || !op.addBoolOption('\0', "no-ggc", "Disable Generational GC")
 #endif
         || !op.addIntOption('\0', "available-memory", "SIZE",
                             "Select GC settings based on available memory (MB)", 0)
 #if defined(JS_CODEGEN_ARM)
         || !op.addStringOption('\0', "arm-hwcap", "[features]",
                                "Specify ARM code generation features, or 'help' to list all features.")
+        || !op.addIntOption('\0', "arm-asm-nop-fill", "SIZE",
+                            "Insert the given number of NOP instructions at all possible pool locations.", 0)
 #endif
 #if defined(JS_ARM_SIMULATOR)
         || !op.addBoolOption('\0', "arm-sim-icache-checks", "Enable icache flush checks in the ARM "
                              "simulator.")
         || !op.addIntOption('\0', "arm-sim-stop-at", "NUMBER", "Stop the ARM simulator after the given "
                             "NUMBER of instructions.", -1)
 #elif defined(JS_MIPS_SIMULATOR)
 	|| !op.addBoolOption('\0', "mips-sim-icache-checks", "Enable icache flush checks in the MIPS "
--- a/js/src/tests/js1_8_5/extensions/reflect-parse.js
+++ b/js/src/tests/js1_8_5/extensions/reflect-parse.js
@@ -338,16 +338,18 @@ assertExpr("[,,,1,2,3,,]", arrExpr([null
 assertExpr("[,,,1,2,3,,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null,null]));
 assertExpr("[,,,,,]", arrExpr([null,null,null,null,null]));
 assertExpr("[1, ...a, 2]", arrExpr([lit(1), spread(ident("a")), lit(2)]));
 assertExpr("[,, ...a,, ...b, 42]", arrExpr([null,null, spread(ident("a")),, spread(ident("b")), lit(42)]));
 assertExpr("[1,(2,3)]", arrExpr([lit(1),seqExpr([lit(2),lit(3)])]));
 assertExpr("[,(2,3)]", arrExpr([null,seqExpr([lit(2),lit(3)])]));
 assertExpr("({})", objExpr([]));
 assertExpr("({x:1})", objExpr([{ key: ident("x"), value: lit(1) }]));
+assertExpr("({x:x, y})", objExpr([{ key: ident("x"), value: ident("x"), shorthand: false },
+                                  { key: ident("y"), value: ident("y"), shorthand: true }]));
 assertExpr("({x:1, y:2})", objExpr([{ key: ident("x"), value: lit(1) },
                                     { key: ident("y"), value: lit(2) } ]));
 assertExpr("({x:1, y:2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
                                          { key: ident("y"), value: lit(2) },
                                          { key: ident("z"), value: lit(3) } ]));
 assertExpr("({x:1, 'y':2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
                                            { key: lit("y"), value: lit(2) },
                                            { key: ident("z"), value: lit(3) } ]));
@@ -481,18 +483,20 @@ assertStmt("function f() { function g() 
 //           funDecl(ident("f"), [], blockStmt([funDecl(ident("g"), [], blockStmt([])),
 //                                              funDecl(ident("g"), [], blockStmt([returnStmt(lit(42))]))])));
 
 assertStmt("function f() { var x = 42; var x = 43; }",
            funDecl(ident("f"), [], blockStmt([varDecl([{ id: ident("x"), init: lit(42) }]),
                                               varDecl([{ id: ident("x"), init: lit(43) }])])));
 
 
-assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
+assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y"), shorthand: false }]),
                                           init: ident("foo") }]));
+assertDecl("var {x} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("x"), shorthand: true }]),
+                                        init: ident("foo") }]));
 
 // Bug 632030: redeclarations between var and funargs, var and function
 assertStmt("function g(x) { var x }",
            funDecl(ident("g"), [ident("x")], blockStmt([varDecl[{ id: ident("x"), init: null }]])));
 assertProg("f.p = 1; var f; f.p; function f(){}",
            [exprStmt(aExpr("=", dotExpr(ident("f"), ident("p")), lit(1))),
             varDecl([{ id: ident("f"), init: null }]),
             exprStmt(dotExpr(ident("f"), ident("p"))),
@@ -994,23 +998,16 @@ var thrown = false;
 try {
     Reflect.parse("42", { builder: { program: function() { throw "expected" } } });
 } catch (e if e === "expected") {
     thrown = true;
 }
 if (!thrown)
     throw new Error("builder exception not propagated");
 
-// Missing property RHS's in an object literal should throw.
-try {
-    Reflect.parse("({foo})");
-    throw new Error("object literal missing property RHS didn't throw");
-} catch (e if e instanceof SyntaxError) { }
-
-
 // A simple proof-of-concept that the builder API can be used to generate other
 // formats, such as JsonMLAst:
 // 
 //     http://code.google.com/p/es-lab/wiki/JsonMLASTFormat
 // 
 // It's incomplete (e.g., it doesn't convert source-location information and
 // doesn't use all the direct-eval rules), but I think it proves the point.
 
--- a/js/src/tests/js1_8_5/extensions/regress-696109.js
+++ b/js/src/tests/js1_8_5/extensions/regress-696109.js
@@ -2,18 +2,12 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/licenses/publicdomain/
  * Contributor: Dave Herman <dherman@mozilla.com>
  */
 
 // Bug 696109 - fixed a precedence bug in with/while nodes
-try {
-    Reflect.parse("with({foo})bar");
-    throw new Error("supposed to be a syntax error");
-} catch (e if e instanceof SyntaxError) { }
-try {
-    Reflect.parse("while({foo})bar");
-    throw new Error("supposed to be a syntax error");
-} catch (e if e instanceof SyntaxError) { }
+Reflect.parse("with({foo})bar");
+Reflect.parse("while({foo})bar");
 
 reportCompare(true, true);
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -551,29 +551,33 @@ GlobalHelperThreadState::canStartAsmJSCo
         return false;
 
     return true;
 }
 
 static bool
 IonBuilderHasHigherPriority(jit::IonBuilder *first, jit::IonBuilder *second)
 {
+#ifdef JS_ION
     // This method can return whatever it wants, though it really ought to be a
     // total order. The ordering is allowed to race (change on the fly), however.
 
     // A lower optimization level indicates a higher priority.
     if (first->optimizationInfo().level() != second->optimizationInfo().level())
         return first->optimizationInfo().level() < second->optimizationInfo().level();
 
     // A script without an IonScript has precedence on one with.
     if (first->script()->hasIonScript() != second->script()->hasIonScript())
         return !first->script()->hasIonScript();
 
     // A higher useCount indicates a higher priority.
     return first->script()->getUseCount() > second->script()->getUseCount();
+#else
+    MOZ_ASSUME_UNREACHABLE("Cannot infer priority without Ion");
+#endif
 }
 
 bool
 GlobalHelperThreadState::canStartIonCompile()
 {
     return !ionWorklist().empty();
 }
 
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -285,17 +285,34 @@ CopyChars(jschar *dest, const JSLinearSt
         CopyAndInflateChars(dest, str.latin1Chars(nogc), str.length());
 }
 
 template <>
 void
 CopyChars(Latin1Char *dest, const JSLinearString &str)
 {
     AutoCheckCannotGC nogc;
-    PodCopy(dest, str.latin1Chars(nogc), str.length());
+    if (str.hasLatin1Chars()) {
+        PodCopy(dest, str.latin1Chars(nogc), str.length());
+    } else {
+        /*
+         * When we flatten a TwoByte rope, we turn child ropes (including Latin1
+         * ropes) into TwoByte dependent strings. If one of these strings is
+         * also part of another Latin1 rope tree, we can have a Latin1 rope with
+         * a TwoByte descendent and we end up here when we flatten it. Although
+         * the chars are stored as TwoByte, we know they must be in the Latin1
+         * range, so we can safely deflate here.
+         */
+        size_t len = str.length();
+        const jschar *chars = str.twoByteChars(nogc);
+        for (size_t i = 0; i < len; i++) {
+            MOZ_ASSERT(chars[i] <= JSString::MAX_LATIN1_CHAR);
+            dest[i] = chars[i];
+        }
+    }
 }
 
 } /* namespace js */
 
 template<JSRope::UsingBarrier b, typename CharT>
 JSFlatString *
 JSRope::flattenInternal(ExclusiveContext *maybecx)
 {
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -251,17 +251,17 @@ class JSString : public js::gc::Barriere
     /* Initial flags for inline and fat inline strings. */
     static const uint32_t INIT_INLINE_FLAGS     = FLAT_BIT | INLINE_CHARS_BIT;
     static const uint32_t INIT_FAT_INLINE_FLAGS = FLAT_BIT | FAT_INLINE_MASK;
 
     static const uint32_t TYPE_FLAGS_MASK       = JS_BIT(6) - 1;
 
     static const uint32_t LATIN1_CHARS_BIT      = JS_BIT(6);
 
-    static const uint32_t MAX_LENGTH            = JS_BIT(28) - 1;
+    static const uint32_t MAX_LENGTH            = js::MaxStringLength;
 
     static const JS::Latin1Char MAX_LATIN1_CHAR = 0xff;
 
     /*
      * Helper function to validate that a string of a given length is
      * representable by a JSString. An allocation overflow is reported if false
      * is returned.
      */
@@ -273,34 +273,38 @@ class JSString : public js::gc::Barriere
                       (offsetof(JSString, d.inlineStorageLatin1) +
                        NUM_INLINE_CHARS_LATIN1 * sizeof(char)),
                       "Inline chars must fit in a JSString");
         static_assert(sizeof(JSString) ==
                       (offsetof(JSString, d.inlineStorageTwoByte) +
                        NUM_INLINE_CHARS_TWO_BYTE * sizeof(jschar)),
                       "Inline chars must fit in a JSString");
 
-        /* Ensure js::shadow::Atom has the same layout. */
-        using js::shadow::Atom;
-        static_assert(offsetof(JSString, d.u1.length) == offsetof(Atom, length),
-                      "shadow::Atom length offset must match JSString");
-        static_assert(offsetof(JSString, d.u1.flags) == offsetof(Atom, flags),
-                      "shadow::Atom flags offset must match JSString");
-        static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(Atom, nonInlineCharsLatin1),
-                      "shadow::Atom nonInlineChars offset must match JSString");
-        static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(Atom, nonInlineCharsTwoByte),
-                      "shadow::Atom nonInlineChars offset must match JSString");
-        static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(Atom, inlineStorageLatin1),
-                      "shadow::Atom inlineStorage offset must match JSString");
-        static_assert(offsetof(JSString, d.inlineStorageTwoByte) == offsetof(Atom, inlineStorageTwoByte),
-                      "shadow::Atom inlineStorage offset must match JSString");
-        static_assert(INLINE_CHARS_BIT == Atom::INLINE_CHARS_BIT,
-                      "shadow::Atom::INLINE_CHARS_BIT must match JSString::INLINE_CHARS_BIT");
-        static_assert(LATIN1_CHARS_BIT == Atom::LATIN1_CHARS_BIT,
-                      "shadow::Atom::LATIN1_CHARS_BIT must match JSString::LATIN1_CHARS_BIT");
+        /* Ensure js::shadow::String has the same layout. */
+        using js::shadow::String;
+        static_assert(offsetof(JSString, d.u1.length) == offsetof(String, length),
+                      "shadow::String length offset must match JSString");
+        static_assert(offsetof(JSString, d.u1.flags) == offsetof(String, flags),
+                      "shadow::String flags offset must match JSString");
+        static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(String, nonInlineCharsLatin1),
+                      "shadow::String nonInlineChars offset must match JSString");
+        static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(String, nonInlineCharsTwoByte),
+                      "shadow::String nonInlineChars offset must match JSString");
+        static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(String, inlineStorageLatin1),
+                      "shadow::String inlineStorage offset must match JSString");
+        static_assert(offsetof(JSString, d.inlineStorageTwoByte) == offsetof(String, inlineStorageTwoByte),
+                      "shadow::String inlineStorage offset must match JSString");
+        static_assert(INLINE_CHARS_BIT == String::INLINE_CHARS_BIT,
+                      "shadow::String::INLINE_CHARS_BIT must match JSString::INLINE_CHARS_BIT");
+        static_assert(LATIN1_CHARS_BIT == String::LATIN1_CHARS_BIT,
+                      "shadow::String::LATIN1_CHARS_BIT must match JSString::LATIN1_CHARS_BIT");
+        static_assert(TYPE_FLAGS_MASK == String::TYPE_FLAGS_MASK,
+                      "shadow::String::TYPE_FLAGS_MASK must match JSString::TYPE_FLAGS_MASK");
+        static_assert(ROPE_FLAGS == String::ROPE_FLAGS,
+                      "shadow::String::ROPE_FLAGS must match JSString::ROPE_FLAGS");
     }
 
     /* Avoid lame compile errors in JSRope::flatten */
     friend class JSRope;
 
   protected:
     template <typename CharT>
     MOZ_ALWAYS_INLINE
--- a/js/src/vm/StringBuffer.cpp
+++ b/js/src/vm/StringBuffer.cpp
@@ -50,19 +50,28 @@ StringBuffer::stealChars()
 }
 
 bool
 StringBuffer::inflateChars()
 {
     MOZ_ASSERT(isLatin1());
 
     TwoByteCharBuffer twoByte(cx);
-    if (!twoByte.append(latin1Chars().begin(), latin1Chars().length()))
+
+    /*
+     * Note: we don't use Vector::capacity() because it always returns a
+     * value >= sInlineCapacity. Since Latin1CharBuffer::sInlineCapacity >
+     * TwoByteCharBuffer::sInlineCapacitychars, we'd always malloc here.
+     */
+    size_t capacity = Max(reserved_, latin1Chars().length());
+    if (!twoByte.reserve(capacity))
         return false;
 
+    twoByte.infallibleAppend(latin1Chars().begin(), latin1Chars().length());
+
     cb.destroy();
     cb.construct<TwoByteCharBuffer>(Move(twoByte));
     return true;
 }
 
 template <typename CharT, class Buffer>
 static JSFlatString *
 FinishStringFlat(ExclusiveContext *cx, StringBuffer &sb, Buffer &cb)
--- a/js/src/vm/StringBuffer.h
+++ b/js/src/vm/StringBuffer.h
@@ -46,16 +46,19 @@ class StringBuffer
     mozilla::MaybeOneOf<Latin1CharBuffer, TwoByteCharBuffer> cb;
 
     /*
      * Make sure ensureTwoByteChars() is called before calling
      * infallibleAppend(jschar).
      */
     mozilla::DebugOnly<bool> hasEnsuredTwoByteChars_;
 
+    /* Number of reserve()'d chars, see inflateChars. */
+    size_t reserved_;
+
     StringBuffer(const StringBuffer &other) MOZ_DELETE;
     void operator=(const StringBuffer &other) MOZ_DELETE;
 
     MOZ_ALWAYS_INLINE bool isLatin1() const { return cb.constructed<Latin1CharBuffer>(); }
     MOZ_ALWAYS_INLINE bool isTwoByte() const { return !isLatin1(); }
 
     MOZ_ALWAYS_INLINE Latin1CharBuffer &latin1Chars() { return cb.ref<Latin1CharBuffer>(); }
     MOZ_ALWAYS_INLINE TwoByteCharBuffer &twoByteChars() { return cb.ref<TwoByteCharBuffer>(); }
@@ -66,25 +69,27 @@ class StringBuffer
     MOZ_ALWAYS_INLINE const TwoByteCharBuffer &twoByteChars() const {
         return cb.ref<TwoByteCharBuffer>();
     }
 
     bool inflateChars();
 
   public:
     explicit StringBuffer(ExclusiveContext *cx)
-      : cx(cx), hasEnsuredTwoByteChars_(false)
+      : cx(cx), hasEnsuredTwoByteChars_(false), reserved_(0)
     {
         if (EnableLatin1Strings)
             cb.construct<Latin1CharBuffer>(cx);
         else
             cb.construct<TwoByteCharBuffer>(cx);
     }
 
     inline bool reserve(size_t len) {
+        if (len > reserved_)
+            reserved_ = len;
         return isLatin1() ? latin1Chars().reserve(len) : twoByteChars().reserve(len);
     }
     inline bool resize(size_t len) {
         return isLatin1() ? latin1Chars().resize(len) : twoByteChars().resize(len);
     }
     inline bool empty() const {
         return isLatin1() ? latin1Chars().empty() : twoByteChars().empty();
     }
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -269,31 +269,24 @@ interface nsIXPCFunctionThisTranslator :
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[noscript, uuid(523da588-95a4-469f-ba1b-c637c3ad4142)]
+[noscript, uuid(febddcc9-5a88-4121-815a-934cd159b3e9)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
-     * Initializes classes on a global object that has already been created.
-     */
-    void
-    initClasses(in JSContextPtr aJSContext,
-                in JSObjectPtr  aGlobalJSObj);
-
-    /**
      * Creates a new global object using the given aCOMObj as the global
      * object. The object will be set up according to the flags (defined
      * below). If you do not pass INIT_JS_STANDARD_CLASSES, then aCOMObj
      * must implement nsIXPCScriptable so it can resolve the standard
      * classes when asked by the JS engine.
      *
      * @param aJSContext the context to use while creating the global object.
      * @param aCOMObj the native object that represents the global object.
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -409,17 +409,17 @@ struct AutoSkipPropertyMirroring
 // properties is changed (on either side), the change should be reflected on
 // both sides. We use this functionality to create sandboxes that are
 // essentially "sub-globals" of another global. This is useful for running
 // add-ons in a separate compartment while still giving them access to the
 // chrome window.
 static bool
 sandbox_addProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
-    CompartmentPrivate *priv = GetCompartmentPrivate(obj);
+    CompartmentPrivate *priv = CompartmentPrivate::Get(obj);
     MOZ_ASSERT(priv->writeToGlobalPrototype);
 
     // Whenever JS_EnumerateStandardClasses is called (by sandbox_enumerate for
     // example), it defines the "undefined" property, even if it's already
     // defined. We don't want to do anything in that case.
     if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_UNDEFINED))
         return true;
 
@@ -886,29 +886,29 @@ xpc::CreateSandboxObject(JSContext *cx, 
                          ? &SandboxWriteToProtoClass
                          : &SandboxClass;
 
     RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, clasp,
                                                      principal, compartmentOptions));
     if (!sandbox)
         return NS_ERROR_FAILURE;
 
-    xpc::GetCompartmentPrivate(sandbox)->writeToGlobalPrototype =
+    CompartmentPrivate::Get(sandbox)->writeToGlobalPrototype =
       options.writeToGlobalPrototype;
 
     // Set up the wantXrays flag, which indicates whether xrays are desired even
     // for same-origin access.
     //
     // This flag has historically been ignored for chrome sandboxes due to
     // quirks in the wrapping implementation that have now been removed. Indeed,
     // same-origin Xrays for chrome->chrome access seems a bit superfluous.
     // Arguably we should just flip the default for chrome and still honor the
     // flag, but such a change would break code in subtle ways for minimal
     // benefit. So we just switch it off here.
-    xpc::GetCompartmentPrivate(sandbox)->wantXrays =
+    CompartmentPrivate::Get(sandbox)->wantXrays =
       AccessCheck::isChrome(sandbox) ? false : options.wantXrays;
 
     {
         JSAutoCompartment ac(cx, sandbox);
 
         if (options.proto) {
             bool ok = JS_WrapObject(cx, &options.proto);
             if (!ok)
@@ -942,22 +942,22 @@ xpc::CreateSandboxObject(JSContext *cx, 
 
         nsCOMPtr<nsIScriptObjectPrincipal> sbp =
             new SandboxPrivate(principal, sandbox);
 
         // Pass on ownership of sbp to |sandbox|.
         JS_SetPrivate(sandbox, sbp.forget().take());
 
         // Don't try to mirror the properties that are set below.
-        AutoSkipPropertyMirroring askip(GetCompartmentPrivate(sandbox));
+        AutoSkipPropertyMirroring askip(CompartmentPrivate::Get(sandbox));
 
         bool allowComponents = nsContentUtils::IsSystemPrincipal(principal) ||
                                nsContentUtils::IsExpandedPrincipal(principal);
         if (options.wantComponents && allowComponents &&
-            !GetObjectScope(sandbox)->AttachComponentsObject(cx))
+            !ObjectScope(sandbox)->AttachComponentsObject(cx))
             return NS_ERROR_XPC_UNEXPECTED;
 
         if (!XPCNativeWrapper::AttachNewConstructorObject(cx, sandbox))
             return NS_ERROR_XPC_UNEXPECTED;
 
         if (!JS_DefineFunctions(cx, sandbox, SandboxFunctions))
             return NS_ERROR_XPC_UNEXPECTED;
 
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2358,17 +2358,17 @@ nsXPCComponents_Constructor::CallOrConst
     // make sure we have at least one arg
 
     if (args.length() < 1)
         return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval);
 
     // get the various other object pointers we need
 
     nsXPConnect* xpc = nsXPConnect::XPConnect();
-    XPCWrappedNativeScope* scope = GetObjectScope(obj);
+    XPCWrappedNativeScope* scope = ObjectScope(obj);
     nsCOMPtr<nsIXPCComponents> comp;
 
     if (!xpc || !scope || !(comp = do_QueryInterface(scope->GetComponents())))
         return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
 
     // Do the security check if necessary
 
     if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, nsXPCConstructor::GetCID()))) {
@@ -3140,45 +3140,45 @@ nsXPCComponents_Utils::RecomputeWrappers
 /* jsval setWantXrays(jsval vscope); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext *cx)
 {
     if (!vscope.isObject())
         return NS_ERROR_INVALID_ARG;
     JSObject *scopeObj = js::UncheckedUnwrap(&vscope.toObject());
     JSCompartment *compartment = js::GetObjectCompartment(scopeObj);
-    EnsureCompartmentPrivate(scopeObj)->wantXrays = true;
+    CompartmentPrivate::Get(scopeObj)->wantXrays = true;
     bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
                                     js::AllCompartments());
     NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
     return NS_OK;
 }
 
 /* jsval forcePrivilegedComponentsForScope(jsval vscope); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForcePrivilegedComponentsForScope(HandleValue vscope,
                                                          JSContext *cx)
 {
     if (!vscope.isObject())
         return NS_ERROR_INVALID_ARG;
     JSObject *scopeObj = js::UncheckedUnwrap(&vscope.toObject());
-    XPCWrappedNativeScope *scope = GetObjectScope(scopeObj);
+    XPCWrappedNativeScope *scope = ObjectScope(scopeObj);
     scope->ForcePrivilegedComponents();
     return NS_OK;
 }
 
 /* jsval getComponentsForScope(jsval vscope); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetComponentsForScope(HandleValue vscope, JSContext *cx,
                                              MutableHandleValue rval)
 {
     if (!vscope.isObject())
         return NS_ERROR_INVALID_ARG;
     JSObject *scopeObj = js::UncheckedUnwrap(&vscope.toObject());
-    XPCWrappedNativeScope *scope = GetObjectScope(scopeObj);
+    XPCWrappedNativeScope *scope = ObjectScope(scopeObj);
     RootedObject components(cx);
     if (!scope->GetComponentsJSObject(&components))
         return NS_ERROR_FAILURE;
     if (!JS_WrapObject(cx, &components))
         return NS_ERROR_FAILURE;
     rval.setObject(*components);
     return NS_OK;
 }
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -808,17 +808,17 @@ XPCConvert::NativeInterface2JSObject(Mut
     // We used to have code here that unwrapped and simply exposed the
     // underlying JSObject. That caused anomolies when JSComponents were
     // accessed from other JS code - they didn't act like other xpconnect
     // wrapped components. So, instead, we create "double wrapped" objects
     // (that means an XPCWrappedNative around an nsXPCWrappedJS). This isn't
     // optimal -- we could detect this and roll the functionality into a
     // single wrapper, but the current solution is good enough for now.
     AutoJSContext cx;
-    XPCWrappedNativeScope* xpcscope = GetObjectScope(JS::CurrentGlobalOrNull(cx));
+    XPCWrappedNativeScope* xpcscope = ObjectScope(JS::CurrentGlobalOrNull(cx));
     if (!xpcscope)
         return false;
 
     // First, see if this object supports the wrapper cache.
     // Note: If |cache->IsDOMBinding()| is true, then it means that the object
     // implementing it doesn't want a wrapped native as its JS Object, but
     // instead it provides its own proxy object. In that case, the object
     // to use is found as cache->GetWrapper(). If that is null, then the
@@ -846,94 +846,66 @@ XPCConvert::NativeInterface2JSObject(Mut
     RootedObject cpow(cx, UnwrapNativeCPOW(aHelper.Object()));
     if (cpow) {
         if (!JS_WrapObject(cx, &cpow))
             return false;
         d.setObject(*cpow);
         return true;
     }
 
-    // We can't simply construct a slim wrapper. Go ahead and create an
-    // XPCWrappedNative for this object. At this point, |flat| could be
-    // non-null, meaning that either we already have a wrapped native from
-    // the cache (which might need to be QI'd to the new interface) or that
-    // we found a slim wrapper that we'll have to morph.
+    // Go ahead and create an XPCWrappedNative for this object.
     AutoMarkingNativeInterfacePtr iface(cx);
     if (iid) {
         if (Interface)
             iface = *Interface;
 
         if (!iface) {
             iface = XPCNativeInterface::GetNewOrUsed(iid);
             if (!iface)
                 return false;
 
             if (Interface)
                 *Interface = iface;
         }
     }
 
-    MOZ_ASSERT(!flat || IS_WN_REFLECTOR(flat), "What kind of wrapper is this?");
-
-    nsresult rv;
-    XPCWrappedNative* wrapper;
-    nsRefPtr<XPCWrappedNative> strongWrapper;
-    if (!flat) {
-        rv = XPCWrappedNative::GetNewOrUsed(aHelper, xpcscope, iface,
-                                            getter_AddRefs(strongWrapper));
-
-        wrapper = strongWrapper;
-    } else {
-        MOZ_ASSERT(IS_WN_REFLECTOR(flat));
-
-        wrapper = XPCWrappedNative::Get(flat);
-
-        // If asked to return the wrapper we'll return a strong reference,
-        // otherwise we'll just return its JSObject in d (which should be
-        // rooted in that case).
-        if (dest)
-            strongWrapper = wrapper;
-        if (iface)
-            wrapper->FindTearOff(iface, false, &rv);
-        else
-            rv = NS_OK;
-    }
-
+    nsRefPtr<XPCWrappedNative> wrapper;
+    nsresult rv = XPCWrappedNative::GetNewOrUsed(aHelper, xpcscope, iface,
+                                                 getter_AddRefs(wrapper));
     if (NS_FAILED(rv) && pErr)
         *pErr = rv;
 
     // If creating the wrapped native failed, then return early.
     if (NS_FAILED(rv) || !wrapper)
         return false;
 
     // If we're not creating security wrappers, we can return the
     // XPCWrappedNative as-is here.
     flat = wrapper->GetFlatJSObject();
-    jsval v = OBJECT_TO_JSVAL(flat);
     if (!allowNativeWrapper) {
-        d.set(v);
+        d.setObjectOrNull(flat);
         if (dest)
-            strongWrapper.forget(dest);
+            wrapper.forget(dest);
         if (pErr)
             *pErr = NS_OK;
         return true;
     }
 
     // The call to wrap here handles both cross-compartment and same-compartment
     // security wrappers.
     RootedObject original(cx, flat);
     if (!JS_WrapObject(cx, &flat))
         return false;
 
     d.setObjectOrNull(flat);
 
     if (dest) {
-        // The strongWrapper still holds the original flat object.
+        // The wrapper still holds the original flat object.
         if (flat == original) {
-            strongWrapper.forget(dest);
+            wrapper.forget(dest);
         } else {
             nsRefPtr<XPCJSObjectHolder> objHolder =
                 XPCJSObjectHolder::newHolder(flat);
             if (!objHolder)
                 return false;
 
             objHolder.forget(dest);
         }
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -245,27 +245,27 @@ public:
 
 namespace xpc {
 
 static uint32_t kLivingAdopters = 0;
 
 void
 RecordAdoptedNode(JSCompartment *c)
 {
-    CompartmentPrivate *priv = EnsureCompartmentPrivate(c);
+    CompartmentPrivate *priv = CompartmentPrivate::Get(c);
     if (!priv->adoptedNode) {
         priv->adoptedNode = true;
         ++kLivingAdopters;
     }
 }
 
 void
 RecordDonatedNode(JSCompartment *c)
 {
-    EnsureCompartmentPrivate(c)->donatedNode = true;
+    CompartmentPrivate::Get(c)->donatedNode = true;
 }
 
 CompartmentPrivate::~CompartmentPrivate()
 {
     MOZ_COUNT_DTOR(xpc::CompartmentPrivate);
 
     Telemetry::Accumulate(Telemetry::COMPARTMENT_ADOPTED_NODE, adoptedNode);
     Telemetry::Accumulate(Telemetry::COMPARTMENT_DONATED_NODE, donatedNode);
@@ -372,47 +372,16 @@ bool CompartmentPrivate::TryParseLocatio
 
         // Current chain item couldn't be parsed.
         // Strip current item and continue.
         chain = Substring(chain, 0, idx);
     }
     MOZ_ASSUME_UNREACHABLE("Chain parser loop does not terminate");
 }
 
-CompartmentPrivate*
-EnsureCompartmentPrivate(JSObject *obj)
-{
-    return EnsureCompartmentPrivate(js::GetObjectCompartment(obj));
-}
-
-CompartmentPrivate*
-EnsureCompartmentPrivate(JSCompartment *c)
-{
-    CompartmentPrivate *priv = GetCompartmentPrivate(c);
-    if (priv)
-        return priv;
-    priv = new CompartmentPrivate(c);
-    JS_SetCompartmentPrivate(c, priv);
-    return priv;
-}
-
-XPCWrappedNativeScope*
-MaybeGetObjectScope(JSObject *obj)
-{
-    MOZ_ASSERT(obj);
-    JSCompartment *compartment = js::GetObjectCompartment(obj);
-
-    MOZ_ASSERT(compartment);
-    CompartmentPrivate *priv = GetCompartmentPrivate(compartment);
-    if (!priv)
-        return nullptr;
-
-    return priv->scope;
-}
-
 static bool
 PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal)
 {
     // System principal gets a free pass.
     if (nsXPConnect::SecurityManager()->IsSystemPrincipal(aPrincipal))
         return true;
 
     // nsExpandedPrincipal gets a free pass.
@@ -498,47 +467,45 @@ Scriptability::SetDocShellAllowsScript(b
 {
     mDocShellAllowsScript = aAllowed || mImmuneToScriptPolicy;
 }
 
 /* static */
 Scriptability&
 Scriptability::Get(JSObject *aScope)
 {
-    return EnsureCompartmentPrivate(aScope)->scriptability;
+    return CompartmentPrivate::Get(aScope)->scriptability;
 }
 
 bool
 IsContentXBLScope(JSCompartment *compartment)
 {
     // We always eagerly create compartment privates for XBL scopes.
-    CompartmentPrivate *priv = GetCompartmentPrivate(compartment);
+    CompartmentPrivate *priv = CompartmentPrivate::Get(compartment);
     if (!priv || !priv->scope)
         return false;
     return priv->scope->IsContentXBLScope();
 }
 
 bool
 IsInContentXBLScope(JSObject *obj)
 {
     return IsContentXBLScope(js::GetObjectCompartment(obj));
 }
 
 bool
 IsInAddonScope(JSObject *obj)
 {
-    // We always eagerly create compartment privates for addon scopes.
-    XPCWrappedNativeScope *scope = MaybeGetObjectScope(obj);
-    return scope && scope->IsAddonScope();
+    return ObjectScope(obj)->IsAddonScope();
 }
 
 bool
 IsUniversalXPConnectEnabled(JSCompartment *compartment)
 {
-    CompartmentPrivate *priv = GetCompartmentPrivate(compartment);
+    CompartmentPrivate *priv = CompartmentPrivate::Get(compartment);
     if (!priv)
         return false;
     return priv->universalXPConnectEnabled;
 }
 
 bool
 IsUniversalXPConnectEnabled(JSContext *cx)
 {
@@ -553,17 +520,17 @@ EnableUniversalXPConnect(JSContext *cx)
 {
     JSCompartment *compartment = js::GetContextCompartment(cx);
     if (!compartment)
         return true;
     // Never set universalXPConnectEnabled on a chrome compartment - it confuses
     // the security wrapping code.
     if (AccessCheck::isChrome(compartment))
         return true;
-    CompartmentPrivate *priv = GetCompartmentPrivate(compartment);
+    CompartmentPrivate *priv = CompartmentPrivate::Get(compartment);
     if (!priv)
         return true;
     priv->universalXPConnectEnabled = true;
 
     // Recompute all the cross-compartment wrappers leaving the newly-privileged
     // compartment.
     bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
                                     js::AllCompartments());
@@ -647,17 +614,17 @@ WindowGlobalOrNull(JSObject *aObj)
 static void
 CompartmentDestroyedCallback(JSFreeOp *fop, JSCompartment *compartment)
 {
     // NB - This callback may be called in JS_DestroyRuntime, which happens
     // after the XPCJSRuntime has been torn down.
 
     // Get the current compartment private into an AutoPtr (which will do the
     // cleanup for us), and null out the private (which may already be null).
-    nsAutoPtr<CompartmentPrivate> priv(GetCompartmentPrivate(compartment));
+    nsAutoPtr<CompartmentPrivate> priv(CompartmentPrivate::Get(compartment));
     JS_SetCompartmentPrivate(compartment, nullptr);
 }
 
 void XPCJSRuntime::TraceNativeBlackRoots(JSTracer* trc)
 {
     // Skip this part if XPConnect is shutting down. We get into
     // bad locking problems with the thread iteration otherwise.
     if (!nsXPConnect::XPConnect()->IsShuttingDown()) {
@@ -1711,17 +1678,17 @@ GetCompartmentName(JSCompartment *c, nsC
         *anonymizeID += 1;
     } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
         nsJSPrincipals::get(principals)->GetScriptLocation(name);
 
         // If the compartment's location (name) differs from the principal's
         // script location, append the compartment's location to allow
         // differentiation of multiple compartments owned by the same principal
         // (e.g. components owned by the system or null principal).
-        CompartmentPrivate *compartmentPrivate = GetCompartmentPrivate(c);
+        CompartmentPrivate *compartmentPrivate = CompartmentPrivate::Get(c);
         if (compartmentPrivate) {
             const nsACString& location = compartmentPrivate->GetLocation();
             if (!location.IsEmpty() && !location.Equals(name)) {
                 name.AppendLiteral(", ");
                 name.Append(location);
             }
         }
 
@@ -2722,17 +2689,17 @@ class XPCJSRuntimeStats : public JS::Run
 
     virtual void initExtraCompartmentStats(JSCompartment *c,
                                            JS::CompartmentStats *cstats) MOZ_OVERRIDE
     {
         xpc::CompartmentStatsExtras *extras = new xpc::CompartmentStatsExtras;
         nsCString cName;
         GetCompartmentName(c, cName, &mAnonymizeID, /* replaceSlashes = */ true);
         if (mGetLocations) {
-            CompartmentPrivate *cp = GetCompartmentPrivate(c);
+            CompartmentPrivate *cp = CompartmentPrivate::Get(c);
             if (cp)
               cp->GetLocationURI(CompartmentPrivate::LocationHintAddon,
                                  getter_AddRefs(extras->location));
             // Note: cannot use amIAddonManager implementation at this point,
             // as it is a JS service and the JS heap is currently not idle.
             // Otherwise, we could have computed the add-on id at this point.
         }
 
--- a/js/xpconnect/src/XPCMaps.h
+++ b/js/xpconnect/src/XPCMaps.h
@@ -638,17 +638,17 @@ public:
     /* Note: If the entry already exists, return the old value. */
     inline JSObject* Add(JSContext *cx, JSObject *key, JSObject *value) {
         NS_PRECONDITION(key,"bad param");
         Map::AddPtr p = mTable.lookupForAdd(key);
         if (p)
             return p->value();
         if (!mTable.add(p, key, value))
             return nullptr;
-        MOZ_ASSERT(xpc::GetCompartmentPrivate(key)->scope->mWaiverWrapperMap == this);
+        MOZ_ASSERT(xpc::CompartmentPrivate::Get(key)->scope->mWaiverWrapperMap == this);
         JS_StoreObjectPostBarrierCallback(cx, KeyMarkCallback, key, this);
         return value;
     }
 
     inline void Remove(JSObject* key) {
         NS_PRECONDITION(key,"bad param");
         mTable.remove(key);
     }
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -168,17 +168,17 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
     const JSClass *clasp = si->GetJSClass();
     MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
 
     // Create the global.
     aOptions.setTrace(XPCWrappedNative::Trace);
     RootedObject global(cx, xpc::CreateGlobalObject(cx, clasp, principal, aOptions));
     if (!global)
         return NS_ERROR_FAILURE;
-    XPCWrappedNativeScope *scope = GetCompartmentPrivate(global)->scope;
+    XPCWrappedNativeScope *scope = CompartmentPrivate::Get(global)->scope;
 
     // Immediately enter the global's compartment, so that everything else we
     // create ends up there.
     JSAutoCompartment ac(cx, global);
 
     // If requested, initialize the standard classes on the global.
     if (initStandardClasses && ! JS_InitStandardClasses(cx, global))
         return NS_ERROR_FAILURE;
@@ -367,17 +367,17 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
         rv = NS_OK;
 
         MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(parent),
                    "Xray wrapper being used to parent XPCWrappedNative?");
 
         ac.construct(static_cast<JSContext*>(cx), parent);
 
         if (parent != plannedParent) {
-            XPCWrappedNativeScope* betterScope = GetObjectScope(parent);
+            XPCWrappedNativeScope* betterScope = ObjectScope(parent);
             if (betterScope != Scope)
                 return GetNewOrUsed(helper, betterScope, Interface, resultWrapper);
 
             newParentVal = OBJECT_TO_JSVAL(parent);
         }
 
         // Take the performance hit of checking the hashtable again in case
         // the preCreate call caused the wrapper to get created through some
@@ -1297,18 +1297,18 @@ RescueOrphans(HandleObject obj)
     if (!js::IsCrossCompartmentWrapper(parentObj))
         return NS_OK;
 
     // We've been orphaned. Find where our parent went, and follow it.
     if (IS_WN_REFLECTOR(obj)) {
         RootedObject realParent(cx, js::UncheckedUnwrap(parentObj));
         XPCWrappedNative *wn =
             static_cast<XPCWrappedNative*>(js::GetObjectPrivate(obj));
-        return wn->ReparentWrapperIfFound(GetObjectScope(parentObj),
-                                          GetObjectScope(realParent),
+        return wn->ReparentWrapperIfFound(ObjectScope(parentObj),
+                                          ObjectScope(realParent),
                                           realParent, wn->GetIdentityObject());
     }
 
     JSAutoCompartment ac(cx, obj);
     return ReparentWrapper(cx, obj);
 }
 
 // Recursively fix up orphans on the parent chain of a wrapper. Note that this
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -20,33 +20,20 @@ using namespace mozilla;
 using namespace xpc;
 using namespace JS;
 
 /***************************************************************************/
 
 XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr;
 XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
 
-// static
-XPCWrappedNativeScope*
-XPCWrappedNativeScope::GetNewOrUsed(JSContext *cx, JS::HandleObject aGlobal)
-{
-    XPCWrappedNativeScope* scope = GetObjectScope(aGlobal);
-    if (!scope) {
-        scope = new XPCWrappedNativeScope(cx, aGlobal);
-    }
-    return scope;
-}
-
 static bool
 RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal)
 {
-  // Check for random JSD scopes that don't have a principal.
-  if (!aPrincipal)
-      return false;
+  MOZ_ASSERT(aPrincipal);
 
   // The SafeJSContext is lazily created, and tends to be created at really
   // weird times, at least for xpcshell (often very early in startup or late
   // in shutdown). Its scope isn't system principal, so if we proceeded we'd
   // end up calling into AllowXULXBLForPrincipal, which depends on all kinds
   // of persistent storage and permission machinery that may or not be running.
   // We know the answer to the question here, so just short-circuit.
   if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass)
@@ -89,18 +76,23 @@ XPCWrappedNativeScope::XPCWrappedNativeS
 #endif
 
         mNext = gScopes;
         gScopes = this;
     }
 
     MOZ_COUNT_CTOR(XPCWrappedNativeScope);
 
+    // Create the compartment private.
+    JSCompartment *c = js::GetObjectCompartment(aGlobal);
+    MOZ_ASSERT(!JS_GetCompartmentPrivate(c));
+    CompartmentPrivate *priv = new CompartmentPrivate(c);
+    JS_SetCompartmentPrivate(c, priv);
+
     // Attach ourselves to the compartment private.
-    CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal);
     priv->scope = this;
 
     // Determine whether we would allow an XBL scope in this situation.
     // In addition to being pref-controlled, we also disable XBL scopes for
     // remote XUL domains, _except_ if we have an additional pref override set.
     nsIPrincipal *principal = GetPrincipal();
     mAllowContentXBLScope = !RemoteXULForbidsXBLScope(principal, aGlobal);
 
@@ -242,17 +234,17 @@ XPCWrappedNativeScope::EnsureContentXBLS
 
     // Create the sandbox.
     RootedValue v(cx);
     nsresult rv = CreateSandboxObject(cx, &v, ep, options);
     NS_ENSURE_SUCCESS(rv, nullptr);
     mContentXBLScope = &v.toObject();
 
     // Tag it.
-    EnsureCompartmentPrivate(js::UncheckedUnwrap(mContentXBLScope))->scope->mIsContentXBLScope = true;
+    CompartmentPrivate::Get(js::UncheckedUnwrap(mContentXBLScope))->scope->mIsContentXBLScope = true;
 
     // Good to go!
     return mContentXBLScope;
 }
 
 bool
 XPCWrappedNativeScope::AllowContentXBLScope()
 {
@@ -265,34 +257,34 @@ XPCWrappedNativeScope::AllowContentXBLSc
 namespace xpc {
 JSObject *
 GetXBLScope(JSContext *cx, JSObject *contentScopeArg)
 {
     MOZ_ASSERT(!IsInAddonScope(contentScopeArg));
 
     JS::RootedObject contentScope(cx, contentScopeArg);
     JSAutoCompartment ac(cx, contentScope);
-    JSObject *scope = EnsureCompartmentPrivate(contentScope)->scope->EnsureContentXBLScope(cx);
+    JSObject *scope = CompartmentPrivate::Get(contentScope)->scope->EnsureContentXBLScope(cx);
     NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
     scope = js::UncheckedUnwrap(scope);
     JS::ExposeObjectToActiveJS(scope);
     return scope;
 }
 
 JSObject *
 GetScopeForXBLExecution(JSContext *cx, HandleObject contentScope, JSAddonId *addonId)
 {
     MOZ_RELEASE_ASSERT(!IsInAddonScope(contentScope));
 
     RootedObject global(cx, js::GetGlobalForObjectCrossCompartment(contentScope));
     if (IsInContentXBLScope(contentScope))
         return global;
 
     JSAutoCompartment ac(cx, contentScope);
-    XPCWrappedNativeScope *nativeScope = EnsureCompartmentPrivate(contentScope)->scope;
+    XPCWrappedNativeScope *nativeScope = CompartmentPrivate::Get(contentScope)->scope;
 
     RootedObject scope(cx);
     if (nativeScope->UseContentXBLScope())
         scope = nativeScope->EnsureContentXBLScope(cx);
     else if (addonId && CompartmentPerAddon())
         scope = nativeScope->EnsureAddonScope(cx, addonId);
     else
         scope = global;
@@ -301,24 +293,24 @@ GetScopeForXBLExecution(JSContext *cx, H
     scope = js::UncheckedUnwrap(scope);
     JS::ExposeObjectToActiveJS(scope);
     return scope;
 }
 
 bool
 AllowContentXBLScope(JSCompartment *c)
 {
-  XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
+  XPCWrappedNativeScope *scope = CompartmentPrivate::Get(c)->scope;
   return scope && scope->AllowContentXBLScope();
 }
 
 bool
 UseContentXBLScope(JSCompartment *c)
 {
-  XPCWrappedNativeScope *scope = EnsureCompartmentPrivate(c)->scope;
+  XPCWrappedNativeScope *scope = CompartmentPrivate::Get(c)->scope;
   return scope && scope->UseContentXBLScope();
 }
 
 } /* namespace xpc */
 
 JSObject*
 XPCWrappedNativeScope::EnsureAddonScope(JSContext *cx, JSAddonId *addonId)
 {
@@ -342,31 +334,31 @@ XPCWrappedNativeScope::EnsureAddonScope(
     options.addonId = JS::StringOfAddonId(addonId);
     options.writeToGlobalPrototype = true;
 
     RootedValue v(cx);
     nsresult rv = CreateSandboxObject(cx, &v, GetPrincipal(), options);
     NS_ENSURE_SUCCESS(rv, nullptr);
     mAddonScopes.AppendElement(&v.toObject());
 
-    EnsureCompartmentPrivate(js::UncheckedUnwrap(&v.toObject()))->scope->mIsAddonScope = true;
+    CompartmentPrivate::Get(js::UncheckedUnwrap(&v.toObject()))->scope->mIsAddonScope = true;
     return &v.toObject();
 }
 
 JSObject *
 xpc::GetAddonScope(JSContext *cx, JS::HandleObject contentScope, JSAddonId *addonId)
 {
     MOZ_RELEASE_ASSERT(!IsInAddonScope(contentScope));
 
     if (!addonId || !CompartmentPerAddon()) {
         return js::GetGlobalForObjectCrossCompartment(contentScope);
     }
 
     JSAutoCompartment ac(cx, contentScope);
-    XPCWrappedNativeScope *nativeScope = EnsureCompartmentPrivate(contentScope)->scope;
+    XPCWrappedNativeScope *nativeScope = CompartmentPrivate::Get(contentScope)->scope;
     JSObject *scope = nativeScope->EnsureAddonScope(cx, addonId);
     NS_ENSURE_TRUE(scope, nullptr);
 
     scope = js::UncheckedUnwrap(scope);
     JS::ExposeObjectToActiveJS(scope);
     return scope;
 }
 
@@ -671,53 +663,32 @@ XPCWrappedNativeScope::SystemIsBeingShut
 
     // Now it is safe to kill all the scopes.
     KillDyingScopes();
 }
 
 
 /***************************************************************************/
 
-static PLDHashOperator
-WNProtoRemover(PLDHashTable *table, PLDHashEntryHdr *hdr,
-               uint32_t number, void *arg)
-{
-    XPCWrappedNativeProtoMap* detachedMap = (XPCWrappedNativeProtoMap*)arg;
-
-    XPCWrappedNativeProto* proto = (XPCWrappedNativeProto*)
-        ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value;
-
-    detachedMap->Add(proto);
-
-    return PL_DHASH_REMOVE;
-}
-
-void
-XPCWrappedNativeScope::RemoveWrappedNativeProtos()
-{
-    mWrappedNativeProtoMap->Enumerate(WNProtoRemover,
-                                      GetRuntime()->GetDetachedWrappedNativeProtoMap());
-}
-
 JSObject *
 XPCWrappedNativeScope::GetExpandoChain(HandleObject target)
 {
-    MOZ_ASSERT(GetObjectScope(target) == this);
+    MOZ_ASSERT(ObjectScope(target) == this);
     if (!mXrayExpandos.initialized())
         return nullptr;
     return mXrayExpandos.lookup(target);
 }
 
 bool
 XPCWrappedNativeScope::SetExpandoChain(JSContext *cx, HandleObject target,
                                        HandleObject chain)
 {
-    MOZ_ASSERT(GetObjectScope(target) == this);
+    MOZ_ASSERT(ObjectScope(target) == this);
     MOZ_ASSERT(js::IsObjectInContextCompartment(target, cx));
-    MOZ_ASSERT_IF(chain, GetObjectScope(chain) == this);
+    MOZ_ASSERT_IF(chain, ObjectScope(chain) == this);
     if (!mXrayExpandos.initialized() && !mXrayExpandos.init(cx))
         return false;
     return mXrayExpandos.put(cx, target, chain);
 }
 
 /***************************************************************************/
 
 // static
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -292,40 +292,16 @@ xpc_TryUnmarkWrappedGrayObject(nsISuppor
 
 template<typename T>
 static inline T UnexpectedFailure(T rv)
 {
     NS_ERROR("This is not supposed to fail!");
     return rv;
 }
 
-/* void initClasses (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
-NS_IMETHODIMP
-nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
-{
-    MOZ_ASSERT(aJSContext, "bad param");
-    MOZ_ASSERT(aGlobalJSObj, "bad param");
-    RootedObject globalJSObj(aJSContext, aGlobalJSObj);
-
-    JSAutoCompartment ac(aJSContext, globalJSObj);
-
-    XPCWrappedNativeScope* scope =
-        XPCWrappedNativeScope::GetNewOrUsed(aJSContext, globalJSObj);
-
-    if (!scope)
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-
-    scope->RemoveWrappedNativeProtos();
-
-    if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj))
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-
-    return NS_OK;
-}
-
 void
 TraceXPCGlobal(JSTracer *trc, JSObject *obj)
 {
     if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
         mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
 }
 
 namespace xpc {
@@ -378,17 +354,17 @@ CreateGlobalObject(JSContext *cx, const 
 bool
 InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags)
 {
     // Immediately enter the global's compartment, so that everything else we
     // create ends up there.
     JSAutoCompartment ac(aJSContext, aGlobal);
     if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
         // XPCCallContext gives us an active request needed to save/restore.
-        if (!GetCompartmentPrivate(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
+        if (!CompartmentPrivate::Get(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
             !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
             return UnexpectedFailure(false);
         }
     }
 
     if (ShouldDiscardSystemSource()) {
         nsIPrincipal *prin = GetObjectPrincipal(aGlobal);
         bool isSystem = nsContentUtils::IsSystemPrincipal(prin);
@@ -646,17 +622,17 @@ nsXPConnect::GetWrappedNativeOfNativeObj
     MOZ_ASSERT(aScopeArg, "bad param");
     MOZ_ASSERT(aCOMObj, "bad param");
     MOZ_ASSERT(_retval, "bad param");
 
     *_retval = nullptr;
 
     RootedObject aScope(aJSContext, aScopeArg);
 
-    XPCWrappedNativeScope* scope = GetObjectScope(aScope);
+    XPCWrappedNativeScope* scope = ObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     AutoMarkingNativeInterfacePtr iface(aJSContext);
     iface = XPCNativeInterface::GetNewOrUsed(&aIID);
     if (!iface)
         return NS_ERROR_FAILURE;
 
@@ -677,18 +653,18 @@ NS_IMETHODIMP
 nsXPConnect::ReparentWrappedNativeIfFound(JSContext * aJSContext,
                                           JSObject * aScopeArg,
                                           JSObject * aNewParentArg,
                                           nsISupports *aCOMObj)
 {
     RootedObject aScope(aJSContext, aScopeArg);
     RootedObject aNewParent(aJSContext, aNewParentArg);
 
-    XPCWrappedNativeScope* scope = GetObjectScope(aScope);
-    XPCWrappedNativeScope* scope2 = GetObjectScope(aNewParent);
+    XPCWrappedNativeScope* scope = ObjectScope(aScope);
+    XPCWrappedNativeScope* scope2 = ObjectScope(aNewParent);
     if (!scope || !scope2)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     RootedObject newParent(aJSContext, aNewParent);
     return XPCWrappedNative::
         ReparentWrapperIfFound(scope, scope2, newParent, aCOMObj);
 }
 
@@ -708,17 +684,17 @@ MoveableWrapperFinder(PLDHashTable *tabl
 }
 
 /* void rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr  aScope); */
 NS_IMETHODIMP
 nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScopeArg)
 {
     RootedObject aScope(aJSContext, aScopeArg);
 
-    XPCWrappedNativeScope *scope = GetObjectScope(aScope);
+    XPCWrappedNativeScope *scope = ObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     // First, look through the old scope and find all of the wrappers that we
     // might need to rescue.
     nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
 
     Native2WrappedNativeMap *map = scope->GetWrappedNativeMap();
@@ -834,17 +810,17 @@ NS_IMETHODIMP
 nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext,
                                        JSObject * aScopeArg,
                                        nsIClassInfo *aClassInfo,
                                        nsIXPConnectJSObjectHolder **_retval)
 {
     RootedObject aScope(aJSContext, aScopeArg);
     JSAutoCompartment ac(aJSContext, aScope);
 
-    XPCWrappedNativeScope* scope = GetObjectScope(aScope);
+    XPCWrappedNativeScope* scope = ObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCNativeScriptableCreateInfo sciProto;
     XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
 
     AutoMarkingWrappedNativeProtoPtr proto(aJSContext);
     proto = XPCWrappedNativeProto::GetNewOrUsed(scope, aClassInfo, &sciProto);
@@ -1226,24 +1202,24 @@ Base64Decode(JSContext *cx, HandleValue 
     out.setString(str);
     return true;
 }
 
 void
 SetLocationForGlobal(JSObject *global, const nsACString& location)
 {
     MOZ_ASSERT(global);
-    EnsureCompartmentPrivate(global)->SetLocation(location);
+    CompartmentPrivate::Get(global)->SetLocation(location);
 }
 
 void
 SetLocationForGlobal(JSObject *global, nsIURI *locationURI)
 {
     MOZ_ASSERT(global);
-    EnsureCompartmentPrivate(global)->SetLocationURI(locationURI);
+    CompartmentPrivate::Get(global)->SetLocationURI(locationURI);
 }
 
 } // namespace xpc
 
 NS_IMETHODIMP
 nsXPConnect::NotifyDidPaint()
 {
     JS::NotifyDidPaint(GetRuntime()->Runtime());
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -957,19 +957,16 @@ static inline bool IS_PROTO_CLASS(const 
 /***************************************************************************/
 // XPCWrappedNativeScope is one-to-one with a JS global object.
 
 class nsXPCComponentsBase;
 class XPCWrappedNativeScope : public PRCList
 {
 public:
 
-    static XPCWrappedNativeScope*
-    GetNewOrUsed(JSContext *cx, JS::HandleObject aGlobal);
-
     XPCJSRuntime*
     GetRuntime() const {return XPCJSRuntime::Get();}
 
     Native2WrappedNativeMap*
     GetWrappedNativeMap() const {return mWrappedNativeMap;}
 
     ClassInfo2WrappedNativeProtoMap*
     GetWrappedNativeProtoMap() const {return mWrappedNativeProtoMap;}
@@ -1004,18 +1001,16 @@ public:
     }
 
     JSObject*
     GetExpandoChain(JS::HandleObject target);
 
     bool
     SetExpandoChain(JSContext *cx, JS::HandleObject target, JS::HandleObject chain);
 
-    void RemoveWrappedNativeProtos();
-
     static void
     SystemIsBeingShutDown();
 
     static void
     TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt);
 
     void TraceSelf(JSTracer *trc) {
         MOZ_ASSERT(mGlobalJSObject);
@@ -3534,16 +3529,30 @@ public:
         , scriptability(c)
         , scope(nullptr)
     {
         MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
     }
 
     ~CompartmentPrivate();
 
+    static CompartmentPrivate* Get(JSCompartment *compartment)
+    {
+        MOZ_ASSERT(compartment);
+        void *priv = JS_GetCompartmentPrivate(compartment);
+        return static_cast<CompartmentPrivate*>(priv);
+    }
+
+    static CompartmentPrivate* Get(JSObject *object)
+    {
+        JSCompartment *compartment = js::GetObjectCompartment(object);
+        return Get(compartment);
+    }
+
+
     bool wantXrays;
 
     // This flag is intended for a very specific use, internal to Gecko. It may
     // go away or change behavior at any time. It should not be added to any
     // documentation and it should not be used without consulting the XPConnect
     // module owner.
     bool writeToGlobalPrototype;
 
@@ -3604,55 +3613,26 @@ public:
 
 private:
     nsCString location;
     nsCOMPtr<nsIURI> locationURI;
 
     bool TryParseLocationURI(LocationHint aType, nsIURI** aURI);
 };
 
-CompartmentPrivate*
-EnsureCompartmentPrivate(JSObject *obj);
-
-CompartmentPrivate*
-EnsureCompartmentPrivate(JSCompartment *c);
-
-inline CompartmentPrivate*
-GetCompartmentPrivate(JSCompartment *compartment)
-{
-    MOZ_ASSERT(compartment);
-    void *priv = JS_GetCompartmentPrivate(compartment);
-    return static_cast<CompartmentPrivate*>(priv);
-}
-
-inline CompartmentPrivate*
-GetCompartmentPrivate(JSObject *object)
-{
-    MOZ_ASSERT(object);
-    JSCompartment *compartment = js::GetObjectCompartment(object);
-
-    MOZ_ASSERT(compartment);
-    return GetCompartmentPrivate(compartment);
-}
-
 bool IsUniversalXPConnectEnabled(JSCompartment *compartment);
 bool IsUniversalXPConnectEnabled(JSContext *cx);
 bool EnableUniversalXPConnect(JSContext *cx);
 
-// This returns null if and only if it is called on an object in a non-XPConnect
-// compartment.
 inline XPCWrappedNativeScope*
-GetObjectScope(JSObject *obj)
+ObjectScope(JSObject *obj)
 {
-    return EnsureCompartmentPrivate(obj)->scope;
+    return CompartmentPrivate::Get(obj)->scope;
 }
 
-// This returns null if a scope doesn't already exist.
-XPCWrappedNativeScope* MaybeGetObjectScope(JSObject *obj);
-
 extern const JSClass SafeJSContextGlobalClass;
 
 JSObject* NewOutObject(JSContext* cx, JSObject* scope);
 bool IsOutObject(JSContext* cx, JSObject* obj);
 
 nsresult HasInstance(JSContext *cx, JS::HandleObject objArg, const nsID *iid, bool *bp);
 
 /**
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -48,17 +48,17 @@ WrapperFactory::IsCOW(JSObject *obj)
 }
 
 JSObject *
 WrapperFactory::GetXrayWaiver(HandleObject obj)
 {
     // Object should come fully unwrapped but outerized.
     MOZ_ASSERT(obj == UncheckedUnwrap(obj));
     MOZ_ASSERT(!js::GetObjectClass(obj)->ext.outerObject);
-    XPCWrappedNativeScope *scope = GetObjectScope(obj);
+    XPCWrappedNativeScope *scope = ObjectScope(obj);
     MOZ_ASSERT(scope);
 
     if (!scope->mWaiverWrapperMap)
         return nullptr;
 
     JSObject* xrayWaiver = scope->mWaiverWrapperMap->Find(obj);
     if (xrayWaiver)
         JS::ExposeObjectToActiveJS(xrayWaiver);
@@ -67,17 +67,17 @@ WrapperFactory::GetXrayWaiver(HandleObje
 }
 
 JSObject *
 WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
 {
     // The caller is required to have already done a lookup.
     // NB: This implictly performs the assertions of GetXrayWaiver.
     MOZ_ASSERT(!GetXrayWaiver(obj));
-    XPCWrappedNativeScope *scope = GetObjectScope(obj);
+    XPCWrappedNativeScope *scope = ObjectScope(obj);
 
     JSAutoCompartment ac(cx, obj);
     JSObject *waiver = Wrapper::New(cx, obj,
                                     JS_GetGlobalForObject(cx, obj),
                                     &XrayWaiver);
     if (!waiver)
         return nullptr;
 
@@ -416,17 +416,17 @@ WrapperFactory::Rewrap(JSContext *cx, Ha
     bool targetIsChrome = AccessCheck::isChrome(target);
     bool originSubsumesTarget = AccessCheck::subsumesConsideringDomain(origin, target);
     bool targetSubsumesOrigin = AccessCheck::subsumesConsideringDomain(target, origin);
     bool sameOrigin = targetSubsumesOrigin && originSubsumesTarget;
     XrayType xrayType = GetXrayType(obj);
     bool waiveXrayFlag = flags & WAIVE_XRAY_WRAPPER_FLAG;
 
     const Wrapper *wrapper;
-    CompartmentPrivate *targetdata = EnsureCompartmentPrivate(target);
+    CompartmentPrivate *targetdata = CompartmentPrivate::Get(target);
 
     //
     // First, handle the special cases.
     //
 
     // If UniversalXPConnect is enabled, this is just some dumb mochitest. Use
     // a vanilla CCW.
     if (xpc::IsUniversalXPConnectEnabled(target)) {
@@ -588,17 +588,17 @@ FixWaiverAfterTransplant(JSContext *cx, 
     // Update all the cross-compartment references to oldWaiver to point to
     // newWaiver.
     if (!js::RemapAllWrappersForObject(cx, oldWaiver, newWaiver))
         return false;
 
     // There should be no same-compartment references to oldWaiver, and we
     // just remapped all cross-compartment references. It's dead, so we can
     // remove it from the map.
-    XPCWrappedNativeScope *scope = GetObjectScope(oldWaiver);
+    XPCWrappedNativeScope *scope = ObjectScope(oldWaiver);
     JSObject *key = Wrapper::wrappedObject(oldWaiver);
     MOZ_ASSERT(scope->mWaiverWrapperMap->Find(key));
     scope->mWaiverWrapperMap->Remove(key);
     return true;
 }
 
 JSObject *
 TransplantObject(JSContext *cx, JS::HandleObject origobj, JS::HandleObject target)
@@ -612,18 +612,16 @@ TransplantObject(JSContext *cx, JS::Hand
         return nullptr;
     return newIdentity;
 }
 
 nsIGlobalObject *
 GetNativeForGlobal(JSObject *obj)
 {
     MOZ_ASSERT(JS_IsGlobalObject(obj));
-    if (!MaybeGetObjectScope(obj))
-        return nullptr;
 
     // Every global needs to hold a native as its private or be a
     // WebIDL object with an nsISupports DOM object.
     MOZ_ASSERT((GetObjectClass(obj)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
                                              JSCLASS_HAS_PRIVATE)) ||
                dom::UnwrapDOMObjectToISupports(obj));
 
     nsISupports *native = dom::UnwrapDOMObjectToISupports(obj);
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -204,21 +204,21 @@ public:
     JSObject* ensureExpandoObject(JSContext *cx, HandleObject wrapper,
                                   HandleObject target);
 
     JSObject* getHolder(JSObject *wrapper);
     JSObject* ensureHolder(JSContext *cx, HandleObject wrapper);
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) = 0;
 
     JSObject* getExpandoChain(HandleObject obj) {
-      return GetObjectScope(obj)->GetExpandoChain(obj);
+      return ObjectScope(obj)->GetExpandoChain(obj);
     }
 
     bool setExpandoChain(JSContext *cx, HandleObject obj, HandleObject chain) {
-      return GetObjectScope(obj)->SetExpandoChain(cx, obj, chain);
+      return ObjectScope(obj)->SetExpandoChain(cx, obj, chain);
     }
     bool cloneExpandoChain(JSContext *cx, HandleObject dst, HandleObject src);
 
 private:
     bool expandoObjectMatchesConsumer(JSContext *cx, HandleObject expandoObject,
                                       nsIPrincipal *consumerOrigin,
                                       HandleObject exclusiveGlobal);
     JSObject* getExpandoObjectInternal(JSContext *cx, HandleObject target,
@@ -2279,18 +2279,17 @@ XrayWrapper<Base, Traits>::getPropertyDe
     //
     // While we have to do some sketchy walking through content land, we should
     // be protected by read-only/non-configurable properties, and any functions
     // we end up with should _always_ be living in an XBL scope (usually ours,
     // but could be another if the node has been adopted).
     //
     // Make sure to assert this.
     nsCOMPtr<nsIContent> content;
-    if (!desc.object() &&
-        EnsureCompartmentPrivate(wrapper)->scope->IsContentXBLScope() &&
+    if (!desc.object() && ObjectScope(wrapper)->IsContentXBLScope() &&
         (content = do_QueryInterfaceNative(cx, wrapper)))
     {
         if (!nsContentUtils::LookupBindingMember(cx, content, id, desc))
             return false;
         DEBUG_CheckXBLLookup(cx, desc.address());
     }
 
     // If we still have nothing, we're done.
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2974,17 +2974,26 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
         FrameLayerBuilder::DumpRetainedLayerTree(layerManager, ss,
                                                  gfxUtils::sDumpPaintingToFile);
       }
     }
     if (gfxUtils::sDumpPaintingToFile) {
       ss << "</body></html>";
     }
 
-    fprintf(gfxUtils::sDumpPaintFile, "%s", ss.str().c_str());
+    char line[1024];
+    while (!ss.eof()) {
+      ss.getline(line, sizeof(line));
+      fprintf_stderr(gfxUtils::sDumpPaintFile, "%s", line);
+      if (ss.fail()) {
+        // line was too long, skip to next newline
+        ss.clear();
+        ss.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+      }
+    }
 
     if (gfxUtils::sDumpPaintingToFile) {
       fclose(gfxUtils::sDumpPaintFile);
     }
     gfxUtils::sDumpPaintFile = savedDumpFile;
     gPaintCount++;
   }
 #endif
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2677,18 +2677,20 @@ nsFrame::HandlePress(nsPresContext* aPre
   //weaaak. only the editor can display frame selection not just text and images
   isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
 
   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
 
   if (!mouseEvent->IsAlt()) {
     for (nsIContent* content = mContent; content;
          content = content->GetParent()) {
+      // Prevent selection of draggable content with the exception of links
       if (nsContentUtils::ContentIsDraggable(content) &&
-          !content->IsEditable()) {
+          !content->IsEditable() &&
+          !nsContentUtils::IsDraggableLink(content)) {
         // coordinate stuff is the fix for bug #55921
         if ((mRect - GetPosition()).Contains(
               nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this))) {
           return NS_OK;
         }
       }
     }
   }
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -421,17 +421,17 @@ public:
                                   gfxFontGroup*      aFontGroup,
                                   const nsGlyphCode& aGlyph) MOZ_OVERRIDE;
 
   // This returns a new OpenTypeTable instance to give access to OpenType MATH
   // table or nullptr if the font does not have such table. Ownership is passed
   // to the caller.
   static nsOpenTypeTable* Create(gfxFont* aFont)
   {
-    if (!aFont->GetFontEntry()->TryGetMathTable(aFont)) {
+    if (!aFont->GetFontEntry()->TryGetMathTable()) {
       return nullptr;
     }
     return new nsOpenTypeTable(aFont->GetFontEntry());
   }
 
 private:
   nsRefPtr<gfxFontEntry> mFontEntry;
   FontFamilyName mFontFamilyName;
@@ -1116,36 +1116,37 @@ StretchEnumContext::TryVariants(nsGlyphT
   int32_t size = 1;
   nsGlyphCode ch;
   nscoord displayOperatorMinHeight = 0;
   if (largeopOnly) {
     NS_ASSERTION(isVertical, "Stretching should be in the vertical direction");
     ch = aGlyphTable->BigOf(mThebesContext, oneDevPixel, *aFontGroup, uchar,
                             isVertical, 0);
     if (ch.IsGlyphID()) {
-      gfxFont* mathFont = aFontGroup->get()->GetFontAt(0);
+      gfxFont* mathFont = aFontGroup->get()->GetFirstMathFont();
       // For OpenType MATH fonts, we will rely on the DisplayOperatorMinHeight
       // to select the right size variant. Note that the value is sometimes too
       // small so we use kLargeOpFactor/kIntegralFactor as a minimum value.
-      displayOperatorMinHeight =
-        NSToCoordRound(mathFont->GetFontEntry()->
-                       GetMathConstant(gfxFontEntry::DisplayOperatorMinHeight) *
-                       mathFont->GetAdjustedSize() * oneDevPixel);
-      nsAutoPtr<gfxTextRun> textRun;
-      textRun = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel,
-                                         *aFontGroup, ch);
-      nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun);
-      float largeopFactor = kLargeOpFactor;
-      if (NS_STRETCH_INTEGRAL & mStretchHint) {
-        // integrals are drawn taller
-        largeopFactor = kIntegralFactor;
-      }
-      nscoord minHeight = largeopFactor * (bm.ascent + bm.descent);
-      if (displayOperatorMinHeight < minHeight) {
-        displayOperatorMinHeight = minHeight;
+      if (mathFont) {
+        displayOperatorMinHeight =
+          mathFont->GetMathConstant(gfxFontEntry::DisplayOperatorMinHeight,
+                                    oneDevPixel);
+        nsAutoPtr<gfxTextRun> textRun;
+        textRun = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel,
+                                           *aFontGroup, ch);
+        nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun);
+        float largeopFactor = kLargeOpFactor;
+        if (NS_STRETCH_INTEGRAL & mStretchHint) {
+          // integrals are drawn taller
+          largeopFactor = kIntegralFactor;
+        }
+        nscoord minHeight = largeopFactor * (bm.ascent + bm.descent);
+        if (displayOperatorMinHeight < minHeight) {
+          displayOperatorMinHeight = minHeight;
+        }
       }
     }
   }
 #ifdef NOISY_SEARCH
   printf("  searching in %s ...\n",
            NS_LossyConvertUTF16toASCII(aFamily).get());
 #endif
   while ((ch = aGlyphTable->BigOf(mThebesContext, oneDevPixel, *aFontGroup,
@@ -1159,18 +1160,18 @@ StretchEnumContext::TryVariants(nsGlyphT
       continue;
     }
 
     nsAutoPtr<gfxTextRun> textRun;
     textRun = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel,
                                        *aFontGroup, ch);
     nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun);
     if (ch.IsGlyphID()) {
-      gfxFont* mathFont = aFontGroup->get()->GetFontAt(0);
-      if (mathFont->GetFontEntry()->TryGetMathTable(mathFont)) {
+      gfxFont* mathFont = aFontGroup->get()->GetFirstMathFont();
+      if (mathFont) {
         // MeasureTextRun should have set the advance width to the right
         // bearing for OpenType MATH fonts. We now subtract the italic
         // correction, so that nsMathMLmmultiscripts will place the scripts
         // correctly.
         // Note that STIX-Word does not provide italic corrections but its
         // advance widths do not match right bearings.
         // (http://sourceforge.net/p/stixfonts/tracking/50/)
         gfxFloat italicCorrection;
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -171,16 +171,24 @@ nsMathMLFrame::GetRuleThickness(nsRender
   }
 }
 
 /* static */ void
 nsMathMLFrame::GetAxisHeight(nsRenderingContext& aRenderingContext,
                              nsFontMetrics*      aFontMetrics,
                              nscoord&             aAxisHeight)
 {
+  gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
+  if (mathFont) {
+    aAxisHeight =
+      mathFont->GetMathConstant(gfxFontEntry::AxisHeight,
+                                aFontMetrics->AppUnitsPerDevPixel());
+    return;
+  }
+
   // get the bounding metrics of the minus sign, the rendering context
   // is assumed to have been set with the font of the current style context
   NS_ASSERTION(aRenderingContext.FontMetrics()->Font().
                Equals(aFontMetrics->Font()),
                "unexpected state");
 
   nscoord xHeight = aFontMetrics->XHeight();
   char16_t minus = 0x2212; // not '-', but official Unicode minus sign
@@ -346,8 +354,54 @@ nsMathMLFrame::DisplayBar(nsDisplayListB
                           nsIFrame* aFrame, const nsRect& aRect,
                           const nsDisplayListSet& aLists) {
   if (!aFrame->StyleVisibility()->IsVisible() || aRect.IsEmpty())
     return;
 
   aLists.Content()->AppendNewToTop(new (aBuilder)
     nsDisplayMathMLBar(aBuilder, aFrame, aRect));
 }
+
+void
+nsMathMLFrame::GetRadicalParameters(nsFontMetrics* aFontMetrics,
+                                    bool aDisplayStyle,
+                                    nscoord& aRadicalRuleThickness,
+                                    nscoord& aRadicalExtraAscender,
+                                    nscoord& aRadicalVerticalGap)
+{
+  nscoord oneDevPixel = aFontMetrics->AppUnitsPerDevPixel();
+  gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
+
+  // get the radical rulethickness
+  if (mathFont) {
+    aRadicalRuleThickness =
+      mathFont->GetMathConstant(gfxFontEntry::RadicalRuleThickness,
+                                oneDevPixel);
+  } else {
+    GetRuleThickness(aFontMetrics, aRadicalRuleThickness);
+  }
+
+  // get the leading to be left at the top of the resulting frame
+  if (mathFont) {
+    aRadicalExtraAscender =
+      mathFont->GetMathConstant(gfxFontEntry::RadicalExtraAscender,
+                                oneDevPixel);
+  } else {
+    // This seems more reliable than using aFontMetrics->GetLeading() on
+    // suspicious fonts.
+    nscoord em;
+    GetEmHeight(aFontMetrics, em);
+    aRadicalExtraAscender = nscoord(0.2f * em);
+  }
+
+  // get the clearance between rule and content
+  if (mathFont) {
+    aRadicalVerticalGap =
+      mathFont->GetMathConstant(aDisplayStyle ?
+                                gfxFontEntry::RadicalDisplayStyleVerticalGap :
+                                gfxFontEntry::RadicalVerticalGap,
+                                oneDevPixel);
+  } else {
+    // Rule 11, App. G, TeXbook
+    aRadicalVerticalGap = aRadicalRuleThickness +
+      (aDisplayStyle ? aFontMetrics->XHeight() : aRadicalRuleThickness) / 4;
+  }
+}
--- a/layout/mathml/nsMathMLFrame.h
+++ b/layout/mathml/nsMathMLFrame.h
@@ -334,16 +334,23 @@ public:
                    nsFontMetrics*      aFontMetrics,
                    nscoord&             aRuleThickness);
 
   static void
   GetAxisHeight(nsRenderingContext& aRenderingContext, 
                 nsFontMetrics*      aFontMetrics,
                 nscoord&             aAxisHeight);
 
+  static void
+  GetRadicalParameters(nsFontMetrics* aFontMetrics,
+                       bool aDisplayStyle,
+                       nscoord& aRadicalRuleThickness,
+                       nscoord& aRadicalExtraAscender,
+                       nscoord& aRadicalVerticalGap);
+
 protected:
 #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
   nsresult DisplayBoundingMetrics(nsDisplayListBuilder* aBuilder,
                                   nsIFrame* aFrame, const nsPoint& aPt,
                                   const nsBoundingMetrics& aMetrics,
                                   const nsDisplayListSet& aLists);
 #endif
 
--- a/layout/mathml/nsMathMLmencloseFrame.cpp
+++ b/layout/mathml/nsMathMLmencloseFrame.cpp
@@ -207,17 +207,17 @@ nsMathMLmencloseFrame::BuildDisplayList(
   mencloseRect.x = mencloseRect.y = 0;
 
   if (IsToDraw(NOTATION_RADICAL)) {
     mMathMLChar[mRadicalCharIndex].Display(aBuilder, this, aLists, 0);
 
     nsRect rect;
     mMathMLChar[mRadicalCharIndex].GetRect(rect);
     rect.MoveBy(StyleVisibility()->mDirection ? -mContentWidth : rect.width, 0);
-    rect.SizeTo(mContentWidth, mRuleThickness);
+    rect.SizeTo(mContentWidth, mRadicalRuleThickness);
     DisplayBar(aBuilder, this, rect, aLists);
   }
 
   if (IsToDraw(NOTATION_PHASORANGLE)) {
     DisplayNotation(aBuilder, this, mencloseRect, aLists,
                 mRuleThickness, NOTATION_PHASORANGLE);
   }
 
@@ -324,59 +324,61 @@ nsMathMLmencloseFrame::PlaceInternal(nsR
     }
 
   nsBoundingMetrics bmBase = baseSize.mBoundingMetrics;
   nscoord dx_left = 0, dx_right = 0;
   nsBoundingMetrics bmLongdivChar, bmRadicalChar;
   nscoord radicalAscent = 0, radicalDescent = 0;
   nscoord longdivAscent = 0, longdivDescent = 0;
   nscoord psi = 0;
+  nscoord leading = 0;
 
   ///////////////
   // Thickness of bars and font metrics
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
 
-  nscoord mEmHeight;
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   aRenderingContext.SetFont(fm);
   GetRuleThickness(aRenderingContext, fm, mRuleThickness);
-  GetEmHeight(fm, mEmHeight);
+  if (mRuleThickness < onePixel) {
+    mRuleThickness = onePixel;
+  }
 
   char16_t one = '1';
   nsBoundingMetrics bmOne = aRenderingContext.GetBoundingMetrics(&one, 1);
 
   ///////////////
   // General rules: the menclose element takes the size of the enclosed content.
   // We add a padding when needed.
 
   // determine padding & psi
   nscoord padding = 3 * mRuleThickness;
   nscoord delta = padding % onePixel;
   if (delta)
     padding += onePixel - delta; // round up
 
   if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
-      nscoord phi;
-      // Rule 11, App. G, TeXbook
-      // psi = clearance between rule and content
-      if (StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK)
-        phi = fm->XHeight();
-      else
-        phi = mRuleThickness;
-      psi = mRuleThickness + phi / 4;
+    GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
+                         NS_MATHML_DISPLAYSTYLE_BLOCK,
+                         mRadicalRuleThickness, leading, psi);
 
-      delta = psi % onePixel;
-      if (delta)
-        psi += onePixel - delta; // round up
+    // make sure that the rule appears on on screen
+    if (mRadicalRuleThickness < onePixel) {
+      mRadicalRuleThickness = onePixel;
     }
 
-  if (mRuleThickness < onePixel)
-    mRuleThickness = onePixel;
- 
+    // adjust clearance psi to get an exact number of pixels -- this
+    // gives a nicer & uniform look on stacked radicals (bug 130282)
+    delta = psi % onePixel;
+    if (delta) {
+      psi += onePixel - delta; // round up
+    }
+  }
+
   // Set horizontal parameters
   if (IsToDraw(NOTATION_ROUNDEDBOX) ||
       IsToDraw(NOTATION_TOP) ||
       IsToDraw(NOTATION_LEFT) ||
       IsToDraw(NOTATION_BOTTOM) ||
       IsToDraw(NOTATION_CIRCLE))
     dx_left = padding;
 
@@ -516,32 +518,32 @@ nsMathMLmencloseFrame::PlaceInternal(nsR
         GetMaxWidth(PresContext(), aRenderingContext);
       
       // Update horizontal parameters
       *dx_leading = std::max(*dx_leading, radical_width);
     } else {
       // Stretch the radical symbol to the appropriate height if it is not
       // big enough.
       nsBoundingMetrics contSize = bmBase;
-      contSize.ascent = mRuleThickness;
+      contSize.ascent = mRadicalRuleThickness;
       contSize.descent = bmBase.ascent + bmBase.descent + psi;
 
-      // height(radical) should be >= height(base) + psi + mRuleThickness
+      // height(radical) should be >= height(base) + psi + mRadicalRuleThickness
       mMathMLChar[mRadicalCharIndex].Stretch(PresContext(), aRenderingContext,
                                              NS_STRETCH_DIRECTION_VERTICAL,
                                              contSize, bmRadicalChar,
                                              NS_STRETCH_LARGER,
                                              StyleVisibility()->mDirection);
       mMathMLChar[mRadicalCharIndex].GetBoundingMetrics(bmRadicalChar);
 
       // Update horizontal parameters
       *dx_leading = std::max(*dx_leading, bmRadicalChar.width);
 
       // Update vertical parameters
-      radicalAscent = bmBase.ascent + psi + mRuleThickness;
+      radicalAscent = bmBase.ascent + psi + mRadicalRuleThickness;
       radicalDescent = std::max(bmBase.descent,
                               (bmRadicalChar.ascent + bmRadicalChar.descent -
                                radicalAscent));
 
       mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent,
                                        radicalAscent);
       mBoundingMetrics.descent = std::max(mBoundingMetrics.descent,
                                         radicalDescent);
@@ -569,36 +571,32 @@ nsMathMLmencloseFrame::PlaceInternal(nsR
 
   aDesiredSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent,
                                             baseSize.BlockStartAscent()));
   aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
     std::max(mBoundingMetrics.descent,
              baseSize.Height() - baseSize.BlockStartAscent());
 
   if (IsToDraw(NOTATION_LONGDIV) || IsToDraw(NOTATION_RADICAL)) {
-    // get the leading to be left at the top of the resulting frame
-    // this seems more reliable than using fm->GetLeading() on suspicious
-    // fonts
-    nscoord leading = nscoord(0.2f * mEmHeight);
     nscoord desiredSizeAscent = aDesiredSize.BlockStartAscent();
     nscoord desiredSizeDescent = aDesiredSize.Height() -
                                  aDesiredSize.BlockStartAscent();
     
     if (IsToDraw(NOTATION_LONGDIV)) {
       desiredSizeAscent = std::max(desiredSizeAscent,
                                  longdivAscent + leading);
       desiredSizeDescent = std::max(desiredSizeDescent,
                                   longdivDescent + mRuleThickness);
     }
     
     if (IsToDraw(NOTATION_RADICAL)) {
       desiredSizeAscent = std::max(desiredSizeAscent,
                                  radicalAscent + leading);
       desiredSizeDescent = std::max(desiredSizeDescent,
-                                  radicalDescent + mRuleThickness);
+                                    radicalDescent + mRadicalRuleThickness);
     }
 
     aDesiredSize.SetBlockStartAscent(desiredSizeAscent);
     aDesiredSize.Height() = desiredSizeAscent + desiredSizeDescent;
   }
     
   if (IsToDraw(NOTATION_CIRCLE) ||
       IsToDraw(NOTATION_ROUNDEDBOX) ||
--- a/layout/mathml/nsMathMLmencloseFrame.h
+++ b/layout/mathml/nsMathMLmencloseFrame.h
@@ -104,16 +104,17 @@ protected:
   // Description of the notations to draw
   uint32_t mNotationsToDraw;
   bool IsToDraw(nsMencloseNotation mask)
   {
     return mask & mNotationsToDraw;
   }
 
   nscoord mRuleThickness;
+  nscoord mRadicalRuleThickness;
   nsTArray<nsMathMLChar> mMathMLChar;
   int8_t mLongDivCharIndex, mRadicalCharIndex;
   nscoord mContentWidth;
   nsresult AllocateMathMLChar(nsMencloseNotation mask);
 
   // Display a frame of the specified type.
   // @param aType Type of frame to display
   void DisplayNotation(nsDisplayListBuilder* aBuilder,
--- a/layout/mathml/nsMathMLmfracFrame.cpp
+++ b/layout/mathml/nsMathMLmfracFrame.cpp
@@ -214,17 +214,25 @@ nsMathMLmfracFrame::PlaceInternal(nsRend
   nsPresContext* presContext = PresContext();
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   aRenderingContext.SetFont(fm);
 
   nscoord defaultRuleThickness, axisHeight;
-  GetRuleThickness(aRenderingContext, fm, defaultRuleThickness);
+  nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
+  gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
+  if (mathFont) {
+    defaultRuleThickness =
+      mathFont->GetMathConstant(gfxFontEntry::FractionRuleThickness,
+                                oneDevPixel);
+  } else {
+    GetRuleThickness(aRenderingContext, fm, defaultRuleThickness);
+  }
   GetAxisHeight(aRenderingContext, fm, axisHeight);
 
   bool outermostEmbellished = false;
   if (mEmbellishData.coreFrame) {
     nsEmbellishData parentData;
     GetEmbellishDataFrom(GetParent(), parentData);
     outermostEmbellished = parentData.coreFrame != mEmbellishData.coreFrame;
   }
@@ -234,16 +242,18 @@ nsMathMLmfracFrame::PlaceInternal(nsRend
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::linethickness_, value);
   mLineThickness = CalcLineThickness(presContext, mStyleContext, value,
                                      onePixel, defaultRuleThickness);
 
   // bevelled attribute
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::bevelled_, value);
   mIsBevelled = value.EqualsLiteral("true");
 
+  bool displayStyle = StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK;
+
   if (!mIsBevelled) {
     mLineRect.height = mLineThickness;
 
     // by default, leave at least one-pixel padding at either end, and add
     // lspace & rspace that may come from <mo> if we are an outermost
     // embellished container (we fetch values from the core since they may use
     // units that depend on style data, and style changes could have occurred
     // in the core since our last visit there)
@@ -253,85 +263,126 @@ nsMathMLmfracFrame::PlaceInternal(nsRend
       nsEmbellishData coreData;
       GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
       leftSpace += StyleVisibility()->mDirection ?
                      coreData.trailingSpace : coreData.leadingSpace;
       rightSpace += StyleVisibility()->mDirection ?
                       coreData.leadingSpace : coreData.trailingSpace;
     }
 
+    nscoord actualRuleThickness =  mLineThickness;
+
     //////////////////
     // Get shifts
     nscoord numShift = 0;
     nscoord denShift = 0;
 
     // Rule 15b, App. G, TeXbook
     nscoord numShift1, numShift2, numShift3;
     nscoord denShift1, denShift2;
 
     GetNumeratorShifts(fm, numShift1, numShift2, numShift3);
     GetDenominatorShifts(fm, denShift1, denShift2);
-    if (StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK) {
-      // C > T
-      numShift = numShift1;
-      denShift = denShift1;
+
+    if (0 == actualRuleThickness) {
+      numShift = displayStyle ? numShift1 : numShift3;
+      denShift = displayStyle ? denShift1 : denShift2;
+      if (mathFont) {
+        numShift = mathFont->
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::StackTopDisplayStyleShiftUp :
+                          gfxFontEntry::StackTopShiftUp,
+                          oneDevPixel);
+        denShift = mathFont->
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::StackBottomDisplayStyleShiftDown :
+                          gfxFontEntry::StackBottomShiftDown,
+                          oneDevPixel);
+      }
+    } else {
+      numShift = displayStyle ? numShift1 : numShift2;
+      denShift = displayStyle ? denShift1 : denShift2;
+      if (mathFont) {
+        numShift = mathFont->
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::FractionNumeratorDisplayStyleShiftUp :
+                          gfxFontEntry::FractionNumeratorShiftUp,
+                          oneDevPixel);
+        denShift = mathFont->
+          GetMathConstant(
+            displayStyle ?
+            gfxFontEntry::FractionDenominatorDisplayStyleShiftDown :
+            gfxFontEntry::FractionDenominatorShiftDown,
+            oneDevPixel);
+      }
     }
-    else {
-      numShift = (0 < mLineRect.height) ? numShift2 : numShift3;
-      denShift = denShift2;
-    }
-
-    nscoord minClearance = 0;
-    nscoord actualClearance = 0;
-
-    nscoord actualRuleThickness =  mLineThickness;
 
     if (0 == actualRuleThickness) {
       // Rule 15c, App. G, TeXbook
 
       // min clearance between numerator and denominator
-      minClearance = StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK ?
+      nscoord minClearance = displayStyle ?
         7 * defaultRuleThickness : 3 * defaultRuleThickness;
-      actualClearance =
+      if (mathFont) {
+        minClearance =
+          mathFont->GetMathConstant(displayStyle ?
+                                    gfxFontEntry::StackDisplayStyleGapMin :
+                                    gfxFontEntry::StackGapMin,
+                                    oneDevPixel);
+      }
+      nscoord actualClearance =
         (numShift - bmNum.descent) - (bmDen.ascent - denShift);
       // actualClearance should be >= minClearance
       if (actualClearance < minClearance) {
         nscoord halfGap = (minClearance - actualClearance)/2;
         numShift += halfGap;
         denShift += halfGap;
       }
     }
     else {
     // Rule 15d, App. G, TeXbook
 
     // min clearance between numerator or denominator and middle of bar
 
     // TeX has a different interpretation of the thickness.
     // Try $a \above10pt b$ to see. Here is what TeX does:
-    // minClearance = StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK
-    // ? 3 * actualRuleThickness : actualRuleThickness;
+    // minClearance = displayStyle ?
+    //   3 * actualRuleThickness : actualRuleThickness;
  
     // we slightly depart from TeX here. We use the defaultRuleThickness instead
     // of the value coming from the linethickness attribute, i.e., we recover what
     // TeX does if the user hasn't set linethickness. But when the linethickness
     // is set, we avoid the wide gap problem.
-     minClearance = StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK ?
-      3 * defaultRuleThickness : defaultRuleThickness + onePixel;
+      nscoord minClearanceNum = displayStyle ?
+        3 * defaultRuleThickness : defaultRuleThickness + onePixel;
+      nscoord minClearanceDen = minClearanceNum;
+      if (mathFont) {
+        minClearanceNum = mathFont->
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::FractionNumDisplayStyleGapMin :
+                          gfxFontEntry::FractionNumeratorGapMin,
+                          oneDevPixel);
+        minClearanceDen = mathFont->
+          GetMathConstant(displayStyle ?
+                          gfxFontEntry::FractionDenomDisplayStyleGapMin :
+                          gfxFontEntry::FractionDenominatorGapMin,
+                          oneDevPixel);
+      }
 
-      // adjust numShift to maintain minClearance if needed
-      actualClearance =
+      // adjust numShift to maintain minClearanceNum if needed
+      nscoord actualClearanceNum =
         (numShift - bmNum.descent) - (axisHeight + actualRuleThickness/2);
-      if (actualClearance < minClearance) {
-        numShift += (minClearance - actualClearance);
+      if (actualClearanceNum < minClearanceNum) {
+        numShift += (minClearanceNum - actualClearanceNum);
       }
-      // adjust denShift to maintain minClearance if needed
-      actualClearance =
+      // adjust denShift to maintain minClearanceDen if needed
+      nscoord actualClearanceDen =
         (axisHeight - actualRuleThickness/2) - (bmDen.ascent - denShift);
-      if (actualClearance < minClearance) {
-        denShift += (minClearance - actualClearance);
+      if (actualClearanceDen < minClearanceDen) {
+        denShift += (minClearanceDen - actualClearanceDen);
       }
     }
 
     //////////////////
     // Place Children
 
     // XXX Need revisiting the width. TeX uses the exact width
     // e.g. in $$\huge\frac{\displaystyle\int}{i}$$
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
@@ -130,36 +130,30 @@ nsMathMLmmultiscriptsFrame::Place(nsRend
   //
   if (tag != nsGkAtoms::msub_) {
     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::superscriptshift_, value);
     if (!value.IsEmpty()) {
       ParseNumericValue(value, &supScriptShift, 0, PresContext(),
                         mStyleContext);
     }
   }
-  // scriptspace from TeX for extra spacing after sup/subscript 
-  // (0.5pt in plain TeX)
-  nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
-
   return PlaceMultiScript(PresContext(), aRenderingContext, aPlaceOrigin,
-                          aDesiredSize, this, subScriptShift, supScriptShift,
-                          scriptSpace);
+                          aDesiredSize, this, subScriptShift, supScriptShift);
 }
 
 // exported routine that both munderover and mmultiscripts share.
 // munderover uses this when movablelimits is set.
 nsresult
 nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext*      aPresContext,
                                         nsRenderingContext& aRenderingContext,
                                         bool                 aPlaceOrigin,
                                         nsHTMLReflowMetrics& aDesiredSize,
                                         nsMathMLContainerFrame* aFrame,
                                         nscoord              aUserSubScriptShift,
-                                        nscoord              aUserSupScriptShift,
-                                        nscoord              aScriptSpace)
+                                        nscoord              aUserSupScriptShift)
 {
   nsIAtom* tag = aFrame->GetContent()->Tag();
 
   // This function deals with both munderover etc. as well as msubsup etc.
   // As the former behaves identically to the later, we treat it as such
   // to avoid additional checks later.
   if (tag == nsGkAtoms::mover_)
     tag = nsGkAtoms::msup_;
@@ -182,83 +176,108 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
   if (!baseFrame) {
     if (tag == nsGkAtoms::mmultiscripts_)
       aFrame->ReportErrorToConsole("NoBase");
     else
       aFrame->ReportChildCountError();
     return aFrame->ReflowError(aRenderingContext, aDesiredSize);
   }
 
-
   // get x-height (an ex)
   const nsStyleFont* font = aFrame->StyleFont();
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
   aRenderingContext.SetFont(fm);
 
   nscoord xHeight = fm->XHeight();
 
-  nscoord ruleSize;
-  GetRuleThickness (aRenderingContext, fm, ruleSize);
+  nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
+  gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
+  // scriptspace from TeX for extra spacing after sup/subscript
+  nscoord scriptSpace;
+  if (mathFont) {
+    scriptSpace =
+      mathFont->GetMathConstant(gfxFontEntry::SpaceAfterScript, oneDevPixel);
+  } else {
+    // (0.5pt in plain TeX)
+    scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
+  }
 
   // force the scriptSpace to be at least 1 pixel
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
-  aScriptSpace = std::max(onePixel, aScriptSpace);
+  scriptSpace = std::max(onePixel, scriptSpace);
 
   /////////////////////////////////////
   // first the shift for the subscript
 
-  // subScriptShift{1,2}
-  // = minimum amount to shift the subscript down
-  // = sub{1,2} in TeXbook
-  // subScriptShift1 = subscriptshift attribute * x-height
-  nscoord subScriptShift1, subScriptShift2;
+  nscoord subScriptShift;
+  if (mathFont) {
+    // Try and get the sub script shift from the MATH table. Note that contrary
+    // to TeX we only have one parameter.
+    subScriptShift =
+      mathFont->GetMathConstant(gfxFontEntry::SubscriptShiftDown, oneDevPixel);
+  } else {
+    // subScriptShift{1,2}
+    // = minimum amount to shift the subscript down
+    // = sub{1,2} in TeXbook
+    // subScriptShift1 = subscriptshift attribute * x-height
+    nscoord subScriptShift1, subScriptShift2;
+    // Get subScriptShift{1,2} default from font
+    GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
+    if (tag == nsGkAtoms::msub_) {
+      subScriptShift = subScriptShift1;
+    } else {
+      subScriptShift = std::max(subScriptShift1, subScriptShift2);
+    }
+  }
 
-  // Get subScriptShift{1,2} default from font
-  GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
-  nscoord subScriptShift;
-  if (tag == nsGkAtoms::msub_) {
-    subScriptShift = subScriptShift1;
-  } else {
-    subScriptShift = std::max(subScriptShift1, subScriptShift2);
-  }
   if (0 < aUserSubScriptShift) {
     // the user has set the subscriptshift attribute
     subScriptShift = std::max(subScriptShift, aUserSubScriptShift);
   }
 
   /////////////////////////////////////
   // next the shift for the superscript
 
-  // supScriptShift{1,2,3}
-  // = minimum amount to shift the supscript up
-  // = sup{1,2,3} in TeX
-  // supScriptShift1 = superscriptshift attribute * x-height
-  // Note that there are THREE values for supscript shifts depending
-  // on the current style
-  nscoord supScriptShift1, supScriptShift2, supScriptShift3;
-  // Set supScriptShift{1,2,3} default from font
-  GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);
-
-  // get sup script shift depending on current script level and display style
-  // Rule 18c, App. G, TeXbook
+  nscoord supScriptShift;
   nsPresentationData presentationData;
   aFrame->GetPresentationData(presentationData);
-  nscoord supScriptShift;
-  if (font->mScriptLevel == 0 &&
-      font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
-      !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
-    // Style D in TeXbook
-    supScriptShift = supScriptShift1;
-  } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
-    // Style C' in TeXbook = D',T',S',SS'
-    supScriptShift = supScriptShift3;
+  if (mathFont) {
+    // Try and get the super script shift from the MATH table. Note that
+    // contrary to TeX we only have two parameters.
+    supScriptShift = mathFont->
+      GetMathConstant(NS_MATHML_IS_COMPRESSED(presentationData.flags) ?
+                      gfxFontEntry::SuperscriptShiftUpCramped :
+                      gfxFontEntry::SuperscriptShiftUp,
+                      oneDevPixel);
   } else {
-    // everything else = T,S,SS
-    supScriptShift = supScriptShift2;
+    // supScriptShift{1,2,3}
+    // = minimum amount to shift the supscript up
+    // = sup{1,2,3} in TeX
+    // supScriptShift1 = superscriptshift attribute * x-height
+    // Note that there are THREE values for supscript shifts depending
+    // on the current style
+    nscoord supScriptShift1, supScriptShift2, supScriptShift3;
+    // Set supScriptShift{1,2,3} default from font
+    GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);
+
+    // get sup script shift depending on current script level and display style
+    // Rule 18c, App. G, TeXbook
+    if (font->mScriptLevel == 0 &&
+        font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
+        !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
+      // Style D in TeXbook
+      supScriptShift = supScriptShift1;
+    } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
+      // Style C' in TeXbook = D',T',S',SS'
+      supScriptShift = supScriptShift3;
+    } else {
+      // everything else = T,S,SS
+      supScriptShift = supScriptShift2;
+    }
   }
 
   if (0 < aUserSupScriptShift) {
     // the user has set the supscriptshift attribute
     supScriptShift = std::max(supScriptShift, aUserSupScriptShift);
   }
 
   ////////////////////////////////////
@@ -379,58 +398,72 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
            std::max(multiSubSize.BlockStartAscent(),
                     subScriptSize.BlockStartAscent()));
         bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent);
         bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent);
         multiSubSize.Height() = 
           std::max(multiSubSize.Height(),
                    subScriptSize.Height() - subScriptSize.BlockStartAscent());
         if (bmSubScript.width)
-          width = bmSubScript.width + aScriptSpace;
+          width = bmSubScript.width + scriptSpace;
         rightBearing = bmSubScript.rightBearing;
 
         if (tag == nsGkAtoms::msub_) {
           boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
           boundingMetrics.width += width;
 
-          // get min subscript shift limit from x-height
-          // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
-          nscoord minShiftFromXHeight = (nscoord) 
-            (bmSubScript.ascent - (4.0f/5.0f) * xHeight);
+          nscoord subscriptTopMax;
+          if (mathFont) {
+            subscriptTopMax =
+              mathFont->GetMathConstant(gfxFontEntry::SubscriptTopMax,
+                                        oneDevPixel);
+          } else {
+            // get min subscript shift limit from x-height
+            // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
+            subscriptTopMax = NSToCoordRound((4.0f/5.0f) * xHeight);
+          }
+          nscoord minShiftFromXHeight = bmSubScript.ascent - subscriptTopMax;
           maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);
 
           maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
           trySubScriptShift = subScriptShift;
         }
       } else {
         // supscript
         supScriptFrame = childFrame;
         GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
         // get the supdrop from the supscript font
         GetSupDropFromChild (supScriptFrame, supDrop);
         // parameter u, Rule 18a, App. G, TeXbook
         minSupScriptShift = bmBase.ascent - supDrop;
-        // get min supscript shift limit from x-height
-        // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
-        minShiftFromXHeight = NSToCoordRound
-          ((bmSupScript.descent + (1.0f/4.0f) * xHeight));
+        nscoord superscriptBottomMin;
+        if (mathFont) {
+          superscriptBottomMin =
+            mathFont->GetMathConstant(gfxFontEntry::SuperscriptBottomMin,
+                                      oneDevPixel);
+        } else {
+          // get min supscript shift limit from x-height
+          // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
+          superscriptBottomMin = NSToCoordRound((1.0f / 4.0f) * xHeight);
+        }
+        minShiftFromXHeight = bmSupScript.descent + superscriptBottomMin;
         trySupScriptShift = std::max(minSupScriptShift,
                                      std::max(minShiftFromXHeight,
                                               supScriptShift));
         multiSupSize.SetBlockStartAscent(
           std::max(multiSupSize.BlockStartAscent(),
                    supScriptSize.BlockStartAscent()));
         bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent);
         bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
         multiSupSize.Height() =
           std::max(multiSupSize.Height(),
                    supScriptSize.Height() - supScriptSize.BlockStartAscent());
 
         if (bmSupScript.width)
-          width = std::max(width, bmSupScript.width + aScriptSpace);
+          width = std::max(width, bmSupScript.width + scriptSpace);
 
         if (!prescriptsFrame) { // we are still looping over base & postscripts
           rightBearing = std::max(rightBearing,
                                   italicCorrection + bmSupScript.rightBearing);
           boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
           boundingMetrics.width += width;
         } else {
           prescriptsWidth += width;
@@ -442,28 +475,47 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
         }
         width = rightBearing = 0;
 
         // negotiate between the various shifts so that
         // there is enough gap between the sup and subscripts
         // Rule 18e, App. G, TeXbook
         if (tag == nsGkAtoms::mmultiscripts_ || 
             tag == nsGkAtoms::msubsup_) {
+          nscoord subSuperscriptGapMin;
+          if (mathFont) {
+            subSuperscriptGapMin =
+              mathFont->GetMathConstant(gfxFontEntry::SubSuperscriptGapMin,
+                                        oneDevPixel);
+          } else {
+            nscoord ruleSize;
+            GetRuleThickness(aRenderingContext, fm, ruleSize);
+            subSuperscriptGapMin = 4 * ruleSize;
+          }
           nscoord gap =
             (trySupScriptShift - bmSupScript.descent) -
             (bmSubScript.ascent - trySubScriptShift);
-          if (gap < 4.0f * ruleSize) {
-            // adjust trySubScriptShift to get a gap of (4.0 * ruleSize)
-            trySubScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap);
+          if (gap < subSuperscriptGapMin) {
+            // adjust trySubScriptShift to get a gap of subSuperscriptGapMin
+            trySubScriptShift += subSuperscriptGapMin - gap;
           }
 
           // next we want to ensure that the bottom of the superscript
-          // will be > (4/5) * x-height above baseline
-          gap = NSToCoordRound ((4.0f/5.0f) * xHeight -
-                  (trySupScriptShift - bmSupScript.descent));
+          // will be > superscriptBottomMaxWithSubscript
+          nscoord superscriptBottomMaxWithSubscript;
+          if (mathFont) {
+            superscriptBottomMaxWithSubscript = mathFont->
+              GetMathConstant(gfxFontEntry::SuperscriptBottomMaxWithSubscript,
+                              oneDevPixel);
+          } else {
+            superscriptBottomMaxWithSubscript =
+              NSToCoordRound((4.0f / 5.0f) * xHeight);
+          }
+          gap = superscriptBottomMaxWithSubscript -
+            (trySupScriptShift - bmSupScript.descent);
           if (gap > 0) {
             trySupScriptShift += gap;
             trySubScriptShift -= gap;
           }
         }
 
         maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
         maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);
@@ -623,17 +675,17 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
               maxSupScriptShift;
             FinishReflowChild (supScriptFrame, aPresContext, supScriptSize,
                                nullptr,
                                aFrame->MirrorIfRTL(aDesiredSize.Width(),
                                                    supScriptSize.Width(),
                                                    x),
                                dy, 0);
           }
-          dx += width + aScriptSpace;
+          dx += width + scriptSpace;
         }
       }
       childFrame = childFrame->GetNextSibling();
     } while (prescriptsFrame != childFrame);
   }
 
   return NS_OK;
 }
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.h
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.h
@@ -32,18 +32,17 @@ public:
 
   static nsresult
   PlaceMultiScript(nsPresContext*      aPresContext,
                     nsRenderingContext& aRenderingContext,
                     bool                 aPlaceOrigin,
                     nsHTMLReflowMetrics& aDesiredSize,
                     nsMathMLContainerFrame* aForFrame,
                     nscoord              aUserSubScriptShift,
-                    nscoord              aUserSupScriptShift,
-                    nscoord              aScriptSpace);
+                    nscoord              aUserSupScriptShift);
 
   uint8_t
   ScriptIncrement(nsIFrame* aFrame) MOZ_OVERRIDE;
 
 protected:
   nsMathMLmmultiscriptsFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
   virtual ~nsMathMLmmultiscriptsFrame();
   
--- a/layout/mathml/nsMathMLmrootFrame.cpp
+++ b/layout/mathml/nsMathMLmrootFrame.cpp
@@ -4,28 +4,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsMathMLmrootFrame.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include <algorithm>
 
 //
-// <msqrt> and <mroot> -- form a radical - implementation
+// <mroot> -- form a radical - implementation
 //
 
-//NOTE:
-//  The code assumes that TeX fonts are picked.
-//  There is no fall-back to draw the branches of the sqrt explicitly
-//  in the case where TeX fonts are not there. In general, there are no
-//  fall-back(s) in MathML when some (freely-downloadable) fonts are missing.
-//  Otherwise, this will add much work and unnecessary complexity to the core
-//  MathML  engine. Assuming that authors have the free fonts is part of the
-//  deal. We are not responsible for cases of misconfigurations out there.
-
 // additional style context to be used by our MathMLChar.
 #define NS_SQR_CHAR_STYLE_CONTEXT_INDEX   0
 
 static const char16_t kSqrChar = char16_t(0x221A);
 
 nsIFrame*
 NS_NewMathMLmrootFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
@@ -103,44 +94,64 @@ nsMathMLmrootFrame::BuildDisplayList(nsD
     mSqrChar.GetRect(rect);
     nsBoundingMetrics bm;
     mSqrChar.GetBoundingMetrics(bm);
     DisplayBoundingMetrics(aBuilder, this, rect.TopLeft(), bm, aLists);
 #endif
   }
 }
 
-static void
-GetRadicalXOffsets(nscoord aIndexWidth, nscoord aSqrWidth,
-                   nsFontMetrics* aFontMetrics,
-                   nscoord* aIndexOffset, nscoord* aSqrOffset)
+void
+nsMathMLmrootFrame::GetRadicalXOffsets(nscoord aIndexWidth, nscoord aSqrWidth,
+                                       nsFontMetrics* aFontMetrics,
+                                       nscoord* aIndexOffset,
+                                       nscoord* aSqrOffset)
 {
   // The index is tucked in closer to the radical while making sure
   // that the kern does not make the index and radical collide
   nscoord dxIndex, dxSqr;
   nscoord xHeight = aFontMetrics->XHeight();
   nscoord indexRadicalKern = NSToCoordRound(1.35f * xHeight);
+  nscoord oneDevPixel = aFontMetrics->AppUnitsPerDevPixel();
+  gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
+  if (mathFont) {
+    indexRadicalKern =
+      mathFont->GetMathConstant(gfxFontEntry::RadicalKernAfterDegree,
+                                oneDevPixel);
+    indexRadicalKern = -indexRadicalKern;
+  }
   if (indexRadicalKern > aIndexWidth) {
     dxIndex = indexRadicalKern - aIndexWidth;
     dxSqr = 0;
   }
   else {
     dxIndex = 0;
     dxSqr = aIndexWidth - indexRadicalKern;
   }
-  // avoid collision by leaving a minimum space between index and radical
-  nscoord minimumClearance = aSqrWidth/2;
-  if (dxIndex + aIndexWidth + minimumClearance > dxSqr + aSqrWidth) {
-    if (aIndexWidth + minimumClearance < aSqrWidth) {
-      dxIndex = aSqrWidth - (aIndexWidth + minimumClearance);
-      dxSqr = 0;
-    }
-    else {
-      dxIndex = 0;
-      dxSqr = (aIndexWidth + minimumClearance) - aSqrWidth;
+
+  if (mathFont) {
+    // add some kern before the radical index
+    nscoord indexRadicalKernBefore = 0;
+    indexRadicalKernBefore =
+      mathFont->GetMathConstant(gfxFontEntry::RadicalKernBeforeDegree,
+                                oneDevPixel);
+    dxIndex += indexRadicalKernBefore;
+    dxSqr += indexRadicalKernBefore;
+  } else {
+    // avoid collision by leaving a minimum space between index and radical
+    nscoord minimumClearance = aSqrWidth / 2;
+    if (dxIndex + aIndexWidth + minimumClearance > dxSqr + aSqrWidth) {
+      if (aIndexWidth + minimumClearance < aSqrWidth) {
+        dxIndex = aSqrWidth - (aIndexWidth + minimumClearance);
+        dxSqr = 0;
+      }
+      else {
+        dxIndex = 0;
+        dxSqr = (aIndexWidth + minimumClearance) - aSqrWidth;
+      }
     }
   }
 
   if (aIndexOffset)
     *aIndexOffset = dxIndex;
   if (aSqrOffset)
     *aSqrOffset = dxSqr;
 }
@@ -207,41 +218,24 @@ nsMathMLmrootFrame::Reflow(nsPresContext
 
   ////////////
   // Prepare the radical symbol and the overline bar
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   renderingContext.SetFont(fm);
 
-  // For radical glyphs from TeX fonts and some of the radical glyphs from
-  // Mathematica fonts, the thickness of the overline can be obtained from the
-  // ascent of the glyph.  Most fonts however have radical glyphs above the
-  // baseline so no assumption can be made about the meaning of the ascent.
-  nscoord ruleThickness, leading, em;
-  GetRuleThickness(renderingContext, fm, ruleThickness);
+  nscoord ruleThickness, leading, psi;
+  GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
+                       NS_MATHML_DISPLAYSTYLE_BLOCK,
+                       ruleThickness, leading, psi);
 
+  // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131)
   char16_t one = '1';
   nsBoundingMetrics bmOne = renderingContext.GetBoundingMetrics(&one, 1);
-
-  // get the leading to be left at the top of the resulting frame
-  // this seems more reliable than using fm->GetLeading() on suspicious fonts
-  GetEmHeight(fm, em);
-  leading = nscoord(0.2f * em); 
-
-  // Rule 11, App. G, TeXbook
-  // psi = clearance between rule and content
-  nscoord phi = 0, psi = 0;
-  if (StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK)
-    phi = fm->XHeight();
-  else
-    phi = ruleThickness;
-  psi = ruleThickness + phi/4;
-
-  // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131)
   if (bmOne.ascent > bmBase.ascent)
     psi += bmOne.ascent - bmBase.ascent;
 
   // make sure that the rule appears on on screen
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   if (ruleThickness < onePixel) {
     ruleThickness = onePixel;
   }
@@ -285,17 +279,24 @@ nsMathMLmrootFrame::Reflow(nsPresContext
              mBoundingMetrics.descent + ruleThickness);
   aDesiredSize.Width() = mBoundingMetrics.width;
 
   /////////////
   // Re-adjust the desired size to include the index.
   
   // the index is raised by some fraction of the height
   // of the radical, see \mroot macro in App. B, TexBook
-  nscoord raiseIndexDelta = NSToCoordRound(0.6f * (bmSqr.ascent + bmSqr.descent));
+  float raiseIndexPercent = 0.6f;
+  gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
+  if (mathFont) {
+    raiseIndexPercent =
+      mathFont->GetMathConstant(gfxFontEntry::RadicalDegreeBottomRaisePercent);
+  }
+  nscoord raiseIndexDelta = NSToCoordRound(raiseIndexPercent *
+                                           (bmSqr.ascent + bmSqr.descent));
   nscoord indexRaisedAscent = mBoundingMetrics.ascent // top of radical 
     - (bmSqr.ascent + bmSqr.descent) // to bottom of radical
     + raiseIndexDelta + bmIndex.ascent + bmIndex.descent; // to top of raised index
 
   nscoord indexClearance = 0;
   if (mBoundingMetrics.ascent < indexRaisedAscent) {
     indexClearance = 
       indexRaisedAscent - mBoundingMetrics.ascent; // excess gap introduced by a tall index 
--- a/layout/mathml/nsMathMLmrootFrame.h
+++ b/layout/mathml/nsMathMLmrootFrame.h
@@ -35,16 +35,22 @@ public:
   TransmitAutomaticData() MOZ_OVERRIDE;
 
   virtual void
   Reflow(nsPresContext*          aPresContext,
          nsHTMLReflowMetrics&     aDesiredSize,
          const nsHTMLReflowState& aReflowState,
          nsReflowStatus&          aStatus) MOZ_OVERRIDE;
 
+  void
+  GetRadicalXOffsets(nscoord aIndexWidth, nscoord aSqrWidth,
+                     nsFontMetrics* aFontMetrics,
+                     nscoord* aIndexOffset,
+                     nscoord* aSqrOffset);
+
   virtual void
   GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext,
                            nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
--- a/layout/mathml/nsMathMLmsqrtFrame.cpp
+++ b/layout/mathml/nsMathMLmsqrtFrame.cpp
@@ -5,25 +5,16 @@
 
 #include "nsMathMLmsqrtFrame.h"
 #include "mozilla/gfx/2D.h"
 
 //
 // <msqrt> -- form a radical - implementation
 //
 
-//NOTE:
-//  The code assumes that TeX fonts are picked.
-//  There is no fall-back to draw the branches of the sqrt explicitly
-//  in the case where TeX fonts are not there. In general, there are no
-//  fall-back(s) in MathML when some (freely-downloadable) fonts are missing.
-//  Otherwise, this will add much work and unnecessary complexity to the core
-//  MathML  engine. Assuming that authors have the free fonts is part of the
-//  deal. We are not responsible for cases of misconfigurations out there.
-
 nsIFrame*
 NS_NewMathMLmsqrtFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsMathMLmsqrtFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmsqrtFrame)
 
--- a/layout/mathml/nsMathMLmunderoverFrame.cpp
+++ b/layout/mathml/nsMathMLmunderoverFrame.cpp
@@ -282,39 +282,35 @@ i.e.,:
 nsMathMLmunderoverFrame::Place(nsRenderingContext& aRenderingContext,
                                bool                 aPlaceOrigin,
                                nsHTMLReflowMetrics& aDesiredSize)
 {
   nsIAtom* tag = mContent->Tag();
   if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
       StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
     //place like sub sup or subsup
-    nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
     if (tag == nsGkAtoms::munderover_) {
       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
                                                           aRenderingContext,
                                                           aPlaceOrigin,
                                                           aDesiredSize,
-                                                          this, 0, 0,
-                                                          scriptSpace);
+                                                          this, 0, 0);
     } else if (tag == nsGkAtoms::munder_) {
       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
                                                           aRenderingContext,
                                                           aPlaceOrigin,
                                                           aDesiredSize,
-                                                          this, 0, 0,
-                                                          scriptSpace);
+                                                          this, 0, 0);
     } else {
       NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized");
       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
                                                           aRenderingContext,
                                                           aPlaceOrigin,
                                                           aDesiredSize,
-                                                          this, 0, 0,
-                                                          scriptSpace);
+                                                          this, 0, 0);
     }
     
   }
 
   ////////////////////////////////////
   // Get the children's desired sizes
 
   nsBoundingMetrics bmBase, bmUnder, bmOver;
@@ -376,16 +372,18 @@ nsMathMLmunderoverFrame::Place(nsRenderi
   ////////////////////
   // Place Children
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   aRenderingContext.SetFont(fm);
 
   nscoord xHeight = fm->XHeight();
+  nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
+  gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
 
   nscoord ruleThickness;
   GetRuleThickness (aRenderingContext, fm, ruleThickness);
 
   nscoord correction = 0;
   GetItalicCorrection (bmBase, correction);
 
   // there are 2 different types of placement depending on 
@@ -396,43 +394,71 @@ nsMathMLmunderoverFrame::Place(nsRenderi
 
   if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
     // Rule 13a, App. G, TeXbook
     nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; 
     GetBigOpSpacings (fm, 
                       dummy, bigOpSpacing2, 
                       dummy, bigOpSpacing4, 
                       bigOpSpacing5);
+    if (mathFont) {
+      // XXXfredw The Open Type MATH table has some StretchStack* parameters
+      // that we may use when the base is a stretchy horizontal operator. See
+      // bug 963131.
+      bigOpSpacing2 =
+        mathFont->GetMathConstant(gfxFontEntry::LowerLimitGapMin,
+                                  oneDevPixel);
+      bigOpSpacing4 =
+        mathFont->GetMathConstant(gfxFontEntry::LowerLimitBaselineDropMin,
+                                  oneDevPixel);
+      bigOpSpacing5 = 0;
+    }
     underDelta1 = std::max(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent));
     underDelta2 = bigOpSpacing5;
   }
   else {
     // No corresponding rule in TeXbook - we are on our own here
     // XXX tune the gap delta between base and underscript 
-
-    // Should we use Rule 10 like \underline does?
+    // XXX Should we use Rule 10 like \underline does?
+    // XXXfredw Perhaps use the Underbar* parameters of the MATH table. See
+    // bug 963125.
     underDelta1 = ruleThickness + onePixel/2;
     underDelta2 = ruleThickness;
   }
   // empty under?
   if (!(bmUnder.ascent + bmUnder.descent)) {
     underDelta1 = 0;
     underDelta2 = 0;
   }
 
   nscoord overDelta1 = 0; // gap between base and overscript
   nscoord overDelta2 = 0; // extra space above overscript
 
   if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {    
     // Rule 13a, App. G, TeXbook
+    // XXXfredw The Open Type MATH table has some StretchStack* parameters
+    // that we may use when the base is a stretchy horizontal operator. See
+    // bug 963131.
     nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; 
     GetBigOpSpacings (fm, 
                       bigOpSpacing1, dummy, 
                       bigOpSpacing3, dummy, 
                       bigOpSpacing5);
+    if (mathFont) {
+      // XXXfredw The Open Type MATH table has some StretchStack* parameters
+      // that we may use when the base is a stretchy horizontal operator. See
+      // bug 963131.
+      bigOpSpacing1 =
+        mathFont->GetMathConstant(gfxFontEntry::UpperLimitGapMin,
+                                  oneDevPixel);
+      bigOpSpacing3 =
+        mathFont->GetMathConstant(gfxFontEntry::UpperLimitBaselineRiseMin,
+                                  oneDevPixel);
+      bigOpSpacing5 = 0;
+    }
     overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent));
     overDelta2 = bigOpSpacing5;
 
     // XXX This is not a TeX rule... 
     // delta1 (as computed abvove) can become really big when bmOver.descent is
     // negative,  e.g., if the content is &OverBar. In such case, we use the height
     if (bmOver.descent < 0)    
       overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent)));
@@ -463,19 +489,25 @@ nsMathMLmunderoverFrame::Place(nsRenderi
     // do not follow this convention. So we modify TeX's rule 
     // so that TeX's rule gets subsumed for accents that follow 
     // TeX's convention,
     // while also allowing accents that do not follow the convention :
     // we try to keep the *bottom* of the accent char atleast x-height 
     // from the baseline of the base char. we also slap on an extra
     // padding between the accent and base chars.
     overDelta1 = ruleThickness + onePixel/2;
-    if (bmBase.ascent < xHeight) {
-      // also ensure at least x-height above the baseline of the base
-      overDelta1 += xHeight - bmBase.ascent;
+    nscoord accentBaseHeight = xHeight;
+    if (mathFont) {
+      accentBaseHeight =
+        mathFont->GetMathConstant(gfxFontEntry::AccentBaseHeight,
+                                  oneDevPixel);
+    }
+    if (bmBase.ascent < accentBaseHeight) {
+      // also ensure at least accentBaseHeight above the baseline of the base
+      overDelta1 += accentBaseHeight - bmBase.ascent;
     }
     overDelta2 = ruleThickness;
   }
   // empty over?
   if (!(bmOver.ascent + bmOver.descent)) {
     overDelta1 = 0;
     overDelta2 = 0;
   }
--- a/layout/mathml/tests/mochitest.ini
+++ b/layout/mathml/tests/mochitest.ini
@@ -1,8 +1,16 @@
 [DEFAULT]
 
 [test_bug330964.html]
 [test_bug553917.html]
 [test_bug706406.html]
 [test_bug827713-2.html]
 [test_bug827713.html]
 [test_bug975681.html]
+[test_opentype-axis-height.html]
+[test_opentype-fraction.html]
+[test_opentype-limits.html]
+skip-if = os == "win" # Fails on WinXP
+[test_opentype-radical.html]
+skip-if = os == "win" # Fails on WinXP
+[test_opentype-scripts.html]
+[test_opentype-stack.html]
new file mode 100644
--- /dev/null
+++ b/layout/mathml/tests/test_opentype-axis-height.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Open Type MATH - axis-height</title>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <meta charset="utf-8"/>
+    <style type="text/css">
+      math {
+        font-size: 10px;
+      }
+      @font-face {
+        font-family: axis-height-1;
+        src: url(/tests/fonts/math/axis-height-1.otf);
+      }
+      @font-face {
+        font-family: axis-height-2;
+        src: url(/tests/fonts/math/axis-height-2.otf);
+      }
+    </style>
+    <script type="application/javascript">
+      SimpleTest.waitForExplicitFinish();
+
+      var epsilon = 5;
+      function almostEqual(x, y) { return Math.abs(x - y) < epsilon; }
+
+      function getBox(aId) {
+        return document.getElementById(aId).getBoundingClientRect();
+      }
+
+      function doTest() {
+        ok(almostEqual(getBox("plus1").top - getBox("plus2").top, 10 * 20),
+           "Bad AxisHeight");
+
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="doTest()">
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=961365">
+      Mozilla Bug 961365
+    </a>
+
+    <p id="display"></p>
+
+    <p>
+      <math style="font-family: axis-height-1;">
+        <mo id="plus1">+</mo>
+      </math>
+      <math style="font-family: axis-height-2;">
+        <mo id="plus2">+</mo>
+      </math>
+    </p>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/mathml/tests/test_opentype-fraction.html
@@ -0,0 +1,187 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Open Type MATH - fraction</title>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <meta charset="utf-8"/>
+    <style type="text/css">
+      math {
+        font-size: 10px;
+      }
+      @font-face {
+        font-family: fraction-1;
+        src: url(/tests/fonts/math/fraction-1.otf);
+      }
+      @font-face {
+        font-family: fraction-2;
+        src: url(/tests/fonts/math/fraction-2.otf);
+      }
+      @font-face {
+        font-family: fraction-3;
+        src: url(/tests/fonts/math/fraction-3.otf);
+      }
+      @font-face {
+        font-family: fraction-4;
+        src: url(/tests/fonts/math/fraction-4.otf);
+      }
+      @font-face {
+        font-family: fraction-5;
+        src: url(/tests/fonts/math/fraction-5.otf);
+      }
+      @font-face {
+        font-family: fraction-6;
+        src: url(/tests/fonts/math/fraction-6.otf);
+      }
+      @font-face {
+        font-family: fraction-7;
+        src: url(/tests/fonts/math/fraction-7.otf);
+      }
+      @font-face {
+        font-family: fraction-8;
+        src: url(/tests/fonts/math/fraction-8.otf);
+      }
+      @font-face {
+        font-family: fraction-9;
+        src: url(/tests/fonts/math/fraction-9.otf);
+      }
+    </style>
+    <script type="text/javascript">
+      var epsilon = 5;
+      function almostEqual(x, y) { return Math.abs(x - y) < epsilon; }
+
+      function getBox(aId) {
+        return document.getElementById(aId).getBoundingClientRect();
+      }
+
+      function doTest() {
+        /* inline style */
+        var ref = getBox("ref").height;
+
+        ok(almostEqual(getBox("d1").top - getBox("n1").bottom, ref * 20),
+           "Bad FractionRuleThickness");
+
+        ok(almostEqual(getBox("n1").top, getBox("n2").top) &&
+           almostEqual(getBox("d2").top - getBox("n2").bottom, ref * 10.5),
+           "Bad FractionNumeratorGapMin");
+
+        ok(almostEqual(getBox("d1").bottom, getBox("d3").bottom) &&
+           almostEqual(getBox("d3").top - getBox("n3").bottom, ref * 10.5),
+           "Bad FractionDenominatorGapMin");
+
+        ok(almostEqual(getBox("ref").top - getBox("n4").top, ref*3),
+           "Bad FractionNumeratorShiftUp");
+
+        ok(almostEqual(getBox("d5").bottom - getBox("ref").bottom, ref*3),
+           "Bad FractionDenominatorShiftDown");
+
+        /* display style */
+        ref = getBox("dref").height;
+
+        ok(almostEqual(getBox("dd1").top - getBox("dn1").bottom, ref * 20),
+           "Bad FractionRuleThickness");
+
+        ok(almostEqual(getBox("dn1").top, getBox("n6").top) &&
+           almostEqual(getBox("d6").top - getBox("n6").bottom, ref * 10.5),
+           "Bad FractionNumeratorDisplayStyleGapMin");
+
+        ok(almostEqual(getBox("dd1").bottom, getBox("d7").bottom) &&
+           almostEqual(getBox("d7").top - getBox("n7").bottom, ref * 10.5),
+           "Bad FractionDenominatorDisplayStyleGapMin");
+
+        ok(almostEqual(getBox("dref").top - getBox("n8").top, ref*3),
+           "Bad FractionNumeratorDisplayStyleShiftUp");
+
+        ok(almostEqual(getBox("d9").bottom - getBox("dref").bottom, ref*3),
+           "Bad FractionDenominatorDisplayStyleShiftDown");
+
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="doTest()">
+
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=961365">
+      Mozilla Bug 961365
+    </a>
+
+    <p id="display"></p>
+
+    <p>
+      <math>
+        <mspace id="ref" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math style="font-family: fraction-1;">
+        <mfrac>
+          <mspace id="n1" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d1" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math style="font-family: fraction-2;">
+        <mfrac>
+          <mspace id="n2" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d2" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math style="font-family: fraction-3;">
+        <mfrac>
+          <mspace id="n3" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d3" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math style="font-family: fraction-4;">
+        <mfrac>
+          <mspace id="n4" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d4" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math style="font-family: fraction-5;">
+        <mfrac>
+          <mspace id="n5" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d5" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+    </p>
+
+    <p>
+      <math displaystyle="true">
+        <mspace id="dref" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math displaystyle="true" style="font-family: fraction-1;">
+        <mfrac>
+          <mspace id="dn1" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="dd1" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math displaystyle="true" style="font-family: fraction-6;">
+        <mfrac>
+          <mspace id="n6" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d6" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math displaystyle="true" style="font-family: fraction-7;">
+        <mfrac>
+          <mspace id="n7" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d7" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math displaystyle="true" style="font-family: fraction-8;">
+        <mfrac>
+          <mspace id="n8" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d8" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math displaystyle="true" style="font-family: fraction-9;">
+        <mfrac>
+          <mspace id="n9" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d9" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+    </p>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/mathml/tests/test_opentype-limits.html
@@ -0,0 +1,172 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Open Type MATH - limits</title>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <meta charset="utf-8"/>
+    <style type="text/css">
+      math {
+        font-size: 10px;
+      }
+      @font-face {
+        font-family: limits-1;
+        src: url(/tests/fonts/math/limits-1.otf);
+      }
+      @font-face {
+        font-family: limits-2;
+        src: url(/tests/fonts/math/limits-2.otf);
+      }
+      @font-face {
+        font-family: limits-3;
+        src: url(/tests/fonts/math/limits-3.otf);
+      }
+      @font-face {
+        font-family: limits-4;
+        src: url(/tests/fonts/math/limits-4.otf);
+      }
+      @font-face {
+        font-family: limits-5;
+        src: url(/tests/fonts/math/limits-5.otf);
+      }
+    </style>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+
+      var epsilon = 5;
+      function almostEqual(x, y) { return Math.abs(x - y) < epsilon; }
+
+      function getBox(aId) {
+        return document.getElementById(aId).getBoundingClientRect();
+      }
+
+      function doTest() {
+        ok(almostEqual(getBox("base1").top - getBox("over1").bottom, 7 * 10) &&
+           almostEqual(getBox("base2").top - getBox("over2").bottom, 7 * 10),
+           "Bad UpperLimitGapMin");
+
+        ok(almostEqual(getBox("under3").top - getBox("base3").bottom, 5 * 10) &&
+           almostEqual(getBox("under4").top - getBox("base4").bottom, 5 * 10),
+           "Bad LowerLimitGapMin");
+
+        ok(almostEqual(getBox("ref3").top - getBox("over5").bottom, 9 * 10) &&
+           almostEqual(getBox("ref3").top - getBox("over6").bottom, 9 * 10),
+           "UpperLimitBaselineRiseMin");
+
+        ok(almostEqual(getBox("under7").top - getBox("ref4").bottom, 2 * 10) &&
+           almostEqual(getBox("under8").top - getBox("ref4").bottom, 2 * 10),
+           "LowerLimitBaselineDropMin");
+
+        ok(almostEqual(getBox("base9").top - getBox("over9").bottom,
+                       (6 - 2) * 10) &&
+           almostEqual(getBox("base10").top - getBox("over10").bottom,
+                       (6 - 2) * 10),
+           "Bad AccentBaseHeight");
+
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="doTest()">
+
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=961365">
+      Mozilla Bug 961365
+    </a>
+
+    <p id="display"></p>
+
+    <p>
+      <math style="font-family: limits-1;" displaystyle="true">
+        <mover>
+          <mo id="base1">∑</mo>
+          <mspace id="over1" height="1em" width="1em" mathbackground="red"/>
+        </mover>
+      </math>
+      <math style="font-family: limits-1;" displaystyle="true">
+        <munderover>
+          <mo id="base2">∑</mo>
+          <mspace id="under2" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="over2" height="1em" width="1em" mathbackground="red"/>
+        </munderover>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: limits-2;" displaystyle="true">
+        <munder>
+          <mo id="base3">∑</mo>
+          <mspace id="under3" height="1em" width="1em" mathbackground="red"/>
+        </munder>
+      </math>
+      <math style="font-family: limits-2;" displaystyle="true">
+        <munderover>
+          <mo id="base4">∑</mo>
+          <mspace id="under4" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="over4" height="1em" width="1em" mathbackground="red"/>
+        </munderover>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: limits-3;" displaystyle="true">
+        <mspace id="ref3" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math style="font-family: limits-3;" displaystyle="true">
+        <mover>
+          <mo id="base5">∑</mo>
+          <mspace id="over5" height="1em" width="1em" mathbackground="red"/>
+        </mover>
+      </math>
+      <math style="font-family: limits-3;" displaystyle="true">
+        <munderover>
+          <mo id="base6">∑</mo>
+          <mspace id="under6" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="over6" height="1em" width="1em" mathbackground="red"/>
+        </munderover>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: limits-4;" displaystyle="true">
+        <mspace id="ref4" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math style="font-family: limits-4;" displaystyle="true">
+        <munder>
+          <mo id="base7">∑</mo>
+          <mspace id="under7" height="1em" width="1em" mathbackground="red"/>
+        </munder>
+      </math>
+      <math style="font-family: limits-4;" displaystyle="true">
+        <munderover>
+          <mo id="base8">∑</mo>
+          <mspace id="under8" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="over8" height="1em" width="1em" mathbackground="red"/>
+        </munderover>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: limits-5;" displaystyle="true">
+        <mspace id="ref5" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math style="font-family: limits-5;" displaystyle="true">
+        <mover>
+          <mspace id="base9" height="2em" width="2em" mathbackground="blue"/>
+          <mo id="over9" stretchy="false">~</mo>
+        </mover>
+      </math>
+      <math style="font-family: limits-5;" displaystyle="true">
+        <munderover>
+          <mspace id="base10" height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="under10" height="1em" width="1em" mathbackground="red"/>
+          <mo id="over10" stretchy="false">~</mo>
+        </munderover>
+      </math>
+    </p>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/mathml/tests/test_opentype-radical.html
@@ -0,0 +1,196 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Open Type MATH - radical</title>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <meta charset="utf-8"/>
+    <style type="text/css">
+      math {
+        font-size: 10px;
+      }
+      @font-face {
+        font-family: radical-1;
+        src: url(/tests/fonts/math/radical-1.otf);
+      }
+      @font-face {
+        font-family: radical-2;
+        src: url(/tests/fonts/math/radical-2.otf);
+      }
+      @font-face {
+        font-family: radical-3;
+        src: url(/tests/fonts/math/radical-3.otf);
+      }
+      @font-face {
+        font-family: radical-4;
+        src: url(/tests/fonts/math/radical-4.otf);
+      }
+      @font-face {
+        font-family: radical-5;
+        src: url(/tests/fonts/math/radical-5.otf);
+      }
+      @font-face {
+        font-family: radical-6;
+        src: url(/tests/fonts/math/radical-6.otf);
+      }
+      @font-face {
+        font-family: radical-7;
+        src: url(/tests/fonts/math/radical-7.otf);
+      }
+    </style>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+
+      var epsilon = 5;
+      function almostEqual(x, y) { return Math.abs(x - y) < epsilon; }
+
+      function getBox(aId) {
+        return document.getElementById(aId).getBoundingClientRect();
+      }
+
+      function doTest() {
+        ok(almostEqual(getBox("inner1").top -
+                       getBox("outer1").top, 5*10) &&
+           almostEqual(getBox("inner2").top -
+                       getBox("outer2").top, 5*10) &&
+           almostEqual(getBox("inner3").top -
+                       getBox("outer3").top, 5*10),
+           "Bad RadicalRuleThickness");
+
+        ok(almostEqual(getBox("inner4").top -
+                       getBox("outer4").top, (7+1)*10) &&
+           almostEqual(getBox("inner5").top -
+                       getBox("outer5").top, (7+1)*10) &&
+           almostEqual(getBox("inner6").top -
+                       getBox("outer6").top, (7+1)*10),
+           "Bad RadicalExtraAscender");
+
+        ok(almostEqual(getBox("inner7").top -
+                       getBox("outer7").top, (3+1)*10) &&
+           almostEqual(getBox("inner7").top -
+                       getBox("outer8").top, (3+1)*10) &&
+           almostEqual(getBox("inner8").top -
+                       getBox("outer9").top, (3+1)*10),
+           "Bad RadicalVerticalGap");
+
+        ok(almostEqual(getBox("inner10").top -
+                       getBox("outer10").top, (9+1)*10) &&
+           almostEqual(getBox("inner11").top -
+                       getBox("outer11").top, (9+1)*10) &&
+           almostEqual(getBox("inner12").top -
+                       getBox("outer12").top, (9+1)*10),
+           "Bad RadicalDisplayStyleVerticalGap");
+
+        ok(almostEqual(getBox("base5").bottom - getBox("index5").bottom,
+                       (getBox("base5").bottom - getBox("root5").top) * .25),
+           "Bad RadicalDegreeBottomRaisePercent")
+
+        ok(almostEqual(getBox("index6").left - getBox("root6").left, 10 * 5),
+           "Bad RadicalKernBeforeDegree")
+
+        ok(almostEqual(getBox("base7").left -
+                       getBox("index7").right, 10 * (7+1)),
+           "Bad RadicalKernAfterDegree")
+
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="doTest()">
+
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=961365">
+      Mozilla Bug 961365
+    </a>
+
+    <p id="display"></p>
+
+    <p>
+      <math style="font-family: radical-1;">
+        <msqrt id="outer1" mathbackground="green">
+          <mspace id="inner1" width="1em" height="1em" mathbackground="red"/>
+        </msqrt>
+        <menclose id="outer2" notation="radical" mathbackground="green">
+          <mspace id="inner2" width="1em" height="1em" mathbackground="red"/>
+        </menclose>
+        <mroot id="outer3" mathbackground="green">
+          <mspace id="inner3" width="1em" height="1em" mathbackground="red"/>
+          <mspace/>
+        </mroot>
+      </math>
+    </p>
+    <p>
+      <math style="font-family: radical-2;">
+        <msqrt id="outer4" mathbackground="green">
+          <mspace id="inner4" width="1em" height="1em" mathbackground="red"/>
+        </msqrt>
+        <menclose id="outer5" notation="radical" mathbackground="green">
+          <mspace id="inner5" width="1em" height="1em" mathbackground="red"/>
+        </menclose>
+        <mroot id="outer6" mathbackground="green">
+          <mspace id="inner6" width="1em" height="1em" mathbackground="red"/>
+          <mspace/>
+        </mroot>
+      </math>
+    </p>
+    <p>
+      <math style="font-family: radical-3;">
+        <msqrt id="outer7" mathbackground="green">
+          <mspace id="inner7" width="1em" height="1em" mathbackground="red"/>
+        </msqrt>
+        <menclose id="outer8" notation="radical" mathbackground="green">
+          <mspace id="inner8" width="1em" height="1em" mathbackground="red"/>
+        </menclose>
+        <mroot id="outer9" mathbackground="green">
+          <mspace id="inner9" width="1em" height="1em" mathbackground="red"/>
+          <mspace/>
+        </mroot>
+      </math>
+    </p>
+    <p>
+      <math style="font-family: radical-4;" displaystyle="true">
+        <msqrt id="outer10" mathbackground="green">
+          <mspace id="inner10" width="1em" height="1em" mathbackground="red"/>
+        </msqrt>
+        <menclose id="outer11" notation="radical" mathbackground="green">
+          <mspace id="inner11" width="1em" height="1em" mathbackground="red"/>
+        </menclose>
+        <mroot id="outer12" mathbackground="green">
+          <mspace id="inner12" width="1em" height="1em" mathbackground="red"/>
+          <mspace/>
+        </mroot>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: radical-5;">
+        <mroot id="root5" mathbackground="green">
+          <mspace id="base5" width="1em" height="10em" mathbackground="red"/>
+          <mspace id="index5" width="1em" height="1em" mathbackground="blue"/>
+        </mroot>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: radical-6;">
+        <mroot id="root6" mathbackground="green">
+          <mspace id="base6" width="1em" height="10em" mathbackground="red"/>
+          <mspace id="index6" width="1em" height="1em" mathbackground="blue"/>
+        </mroot>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: radical-7;">
+        <mroot id="root7" mathbackground="green">
+          <mspace id="base7" width="1em" height="10em" mathbackground="red"/>
+          <mspace id="index7" width="1em" height="1em" mathbackground="blue"/>
+        </mroot>
+      </math>
+    </p>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/mathml/tests/test_opentype-scripts.html
@@ -0,0 +1,268 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Open Type MATH - scripts</title>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <meta charset="utf-8"/>
+    <style type="text/css">
+      math {
+        font-size: 10px;
+      }
+      @font-face {
+        font-family: scripts-1;
+        src: url(/tests/fonts/math/scripts-1.otf);
+      }
+      @font-face {
+        font-family: scripts-2;
+        src: url(/tests/fonts/math/scripts-2.otf);
+      }
+      @font-face {
+        font-family: scripts-3;
+        src: url(/tests/fonts/math/scripts-3.otf);
+      }
+      @font-face {
+        font-family: scripts-4;
+        src: url(/tests/fonts/math/scripts-4.otf);
+      }
+      @font-face {
+        font-family: scripts-5;
+        src: url(/tests/fonts/math/scripts-5.otf);
+      }
+      @font-face {
+        font-family: scripts-6;
+        src: url(/tests/fonts/math/scripts-6.otf);
+      }
+      @font-face {
+        font-family: scripts-7;
+        src: url(/tests/fonts/math/scripts-7.otf);
+      }
+      @font-face {
+        font-family: scripts-8;
+        src: url(/tests/fonts/math/scripts-8.otf);
+      }
+    </style>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+
+      function doTest() {
+        var epsilon = 5;
+        function almostEqual(x, y) { return Math.abs(x - y) < epsilon; }
+
+        function getBox(aId) {
+          return document.getElementById(aId).getBoundingClientRect();
+        }
+
+        ok(almostEqual(getBox("ref1").left - getBox("sub1").right, 3*10) &&
+           almostEqual(getBox("ref2").left - getBox("sup2").right, 3*10) &&
+           almostEqual(getBox("sup32").left - getBox("sup31").right, 3*10) &&
+           almostEqual(getBox("ref3").left - getBox("sup32").right, 3*10),
+           "SpaceAfterScript");
+
+        ok(almostEqual(getBox("ref4").bottom -
+                       getBox("sup41").bottom, 7 * 10) &&
+           almostEqual(getBox("ref4").bottom -
+                       getBox("sup42").bottom, 7 * 10) &&
+           almostEqual(getBox("ref4").bottom -
+                       getBox("sup43").bottom, 7 * 10) &&
+           almostEqual(getBox("ref4").bottom -
+                     getBox("sup44").bottom, 7 * 10),
+                     "Bad SuperscriptShiftUp")
+        ok(almostEqual(getBox("ref5").bottom -
+                       getBox("sup51").bottom, 5 * 10) &&
+           almostEqual(getBox("ref5").bottom -
+                       getBox("sup52").bottom, 5 * 10) &&
+           almostEqual(getBox("ref5").bottom -
+                       getBox("sup53").bottom, 5 * 10) &&
+           almostEqual(getBox("ref5").bottom -
+                       getBox("sup54").bottom, 5 * 10),
+           "Bad SuperscriptShiftUpCramped")
+
+        ok(almostEqual(getBox("ref6").bottom -
+                       getBox("sub61").bottom, -6 * 10) &&
+           almostEqual(getBox("ref6").bottom -
+                       getBox("sub62").bottom, -6 * 10) &&
+           almostEqual(getBox("ref6").bottom -
+                       getBox("sub63").bottom, -6 * 10) &&
+           almostEqual(getBox("ref6").bottom -
+                       getBox("sub64").bottom, -6 * 10),
+           "Bad SubscriptShiftDown")
+
+        ok(almostEqual(getBox("sub7").top -
+                       getBox("sup7").bottom, 11 * 10),
+                      "Bad SubSuperscriptGapMin");
+
+        ok(almostEqual(getBox("sub8").top -
+                       getBox("sup8").bottom, 11 * 10) &&
+           almostEqual(getBox("ref8").bottom -
+                       getBox("sup8").bottom, 3 * 10),
+           "Bad SuperscriptBottomMaxWithSubscript");
+
+        ok(almostEqual(getBox("ref9").top, getBox("sub9").top),
+           "Bad SubscriptTopMax");
+
+        ok(almostEqual(getBox("ref10").bottom - getBox("sup10").bottom, 9 * 10),
+           "Bad SuperscriptBottomMin");
+
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="doTest()">
+
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=961365">
+      Mozilla Bug 961365
+    </a>
+
+    <p id="display"></p>
+
+    <p>
+      <math style="font-family: scripts-1;">
+        <msub>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sub1" height="1em" width="1em" mathbackground="red"/>
+        </msub>
+        <mspace id="ref1" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math style="font-family: scripts-1;">
+        <msup>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sup2" height="1em" width="1em" mathbackground="red"/>
+        </msup>
+        <mspace id="ref2" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math style="font-family: scripts-1;">
+        <mmultiscripts>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <none/>
+          <mspace id="sup31" height="1em" width="1em" mathbackground="red"/>
+          <none/>
+          <mspace id="sup32" height="1em" width="1em" mathbackground="red"/>
+        </mmultiscripts>
+        <mspace id="ref3" height="1em" width="1em" mathbackground="green"/>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: scripts-2;">
+        <mspace id="ref4" height="1em" width="1em" mathbackground="green"/>
+        <msup>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sup41" height="1em" width="1em" mathbackground="red"/>
+        </msup>
+        <msubsup>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace height="1em" width="1em" mathbackground="red"/>
+          <mspace id="sup42" height="1em" width="1em" mathbackground="red"/>
+        </msubsup>
+        <mmultiscripts>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <none/>
+          <mspace id="sup43" height="1em" width="1em" mathbackground="red"/>
+          <none/>
+          <mspace id="sup44" height="1em" width="1em" mathbackground="red"/>
+        </mmultiscripts>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: scripts-3;">
+        <msqrt>
+          <mspace id="ref5" height="1em" width="1em" mathbackground="green"/>
+          <msup>
+            <mspace height="2em" width="2em" mathbackground="blue"/>
+            <mspace id="sup51" height="1em" width="1em" mathbackground="red"/>
+          </msup>
+          <msubsup>
+            <mspace height="2em" width="2em" mathbackground="blue"/>
+            <mspace height="1em" width="1em" mathbackground="red"/>
+            <mspace id="sup52" height="1em" width="1em" mathbackground="red"/>
+          </msubsup>
+          <mmultiscripts>
+            <mspace height="2em" width="2em" mathbackground="blue"/>
+            <mspace height="1em" width="1em" mathbackground="red"/>
+            <mspace id="sup53" height="1em" width="1em" mathbackground="red"/>
+            <mspace height="1em" width="1em" mathbackground="red"/>
+            <mspace id="sup54" height="1em" width="1em" mathbackground="red"/>
+          </mmultiscripts>
+        </msqrt>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: scripts-4;">
+        <mspace id="ref6" height="1em" width="1em" mathbackground="green"/>
+        <msub>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sub61" height="1em" width="1em" mathbackground="red"/>
+        </msub>
+        <msubsup>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sub62" height="1em" width="1em" mathbackground="red"/>
+          <mspace height="1em" width="1em" mathbackground="red"/>
+        </msubsup>
+        <mmultiscripts>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sub63" height="1em" width="1em" mathbackground="red"/>
+          <mspace height="1em" width="1em" mathbackground="red"/>
+          <mspace id="sub64" height="1em" width="1em" mathbackground="red"/>
+          <mspace height="1em" width="1em" mathbackground="red"/>
+        </mmultiscripts>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: scripts-5;">
+        <msubsup>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sub7" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="sup7" height="1em" width="1em" mathbackground="red"/>
+        </msubsup>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: scripts-6;">
+        <mspace id="ref8" height="1em" width="1em" mathbackground="green"/>
+        <msubsup>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sub8" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="sup8" height="1em" width="1em" mathbackground="red"/>
+        </msubsup>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: scripts-7;">
+        <msub>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="ref9" height="5em"
+                  width="1em" mathbackground="green"/>
+        </msub>
+        <msub>
+          <mspace height="2em" width="2em" mathbackground="blue"/>
+          <mspace id="sub9" height="9em"
+                  width="1em" mathbackground="red"/>
+        </msub>
+      </math>
+    </p>
+
+    <p>
+      <math style="font-family: scripts-8;">
+        <mspace id="ref10" height="1em"
+                width="1em" mathbackground="green"/>
+        <msup>
+          <mspace id="base10" height="2em"
+                  width="2em" mathbackground="blue"/>
+          <mspace id="sup10" height="1em"
+                  width="1em" mathbackground="red"/>
+        </msup>
+      </math>
+    </p>
+
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/mathml/tests/test_opentype-stack.html
@@ -0,0 +1,137 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Open Type MATH - stack</title>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="application/javascript"
+            src="/tests/SimpleTest/EventUtils.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <meta charset="utf-8"/>
+    <style type="text/css">
+      math {
+        font-size: 10px;
+      }
+      @font-face {
+        font-family: stack-1;
+        src: url(/tests/fonts/math/stack-1.otf);
+      }
+      @font-face {
+        font-family: stack-2;
+        src: url(/tests/fonts/math/stack-2.otf);
+      }
+      @font-face {
+        font-family: stack-3;
+        src: url(/tests/fonts/math/stack-3.otf);
+      }
+      @font-face {
+        font-family: stack-4;
+        src: url(/tests/fonts/math/stack-4.otf);
+      }
+      @font-face {
+        font-family: stack-5;
+        src: url(/tests/fonts/math/stack-5.otf);
+      }
+      @font-face {
+        font-family: stack-6;
+        src: url(/tests/fonts/math/stack-6.otf);
+      }
+    </style>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+
+      function doTest() {
+        var epsilon = 5;
+        function almostEqual(x, y) { return Math.abs(x - y) < epsilon; }
+
+        function getBox(aId) {
+          return document.getElementById(aId).getBoundingClientRect();
+        }
+
+        /* inline style */
+        var ref = getBox("ref").height;
+
+        ok(almostEqual(getBox("d1").top - getBox("n1").bottom, ref * 20),
+           "Bad StackGapMin");
+
+        ok(almostEqual(getBox("ref").top - getBox("n2").top, ref*3),
+           "Bad StackTopShiftMin");
+
+        ok(almostEqual(getBox("d3").bottom - getBox("ref").bottom, ref*3),
+           "Bad StackBottomShiftDown");
+
+        /* display style */
+        ref = getBox("ref").height;
+
+        ok(almostEqual(getBox("d4").top - getBox("n4").bottom, ref * 20),
+           "Bad StackGapDisplayStyleMin");
+
+        ok(almostEqual(getBox("dref").top - getBox("n5").top, ref*3),
+           "Bad StackTopDisplayStyleShiftMin");
+
+        ok(almostEqual(getBox("d6").bottom - getBox("dref").bottom, ref*3),
+           "Bad StackDisplayStyleBottomShiftDown");
+
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="doTest()">
+
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=961365">
+      Mozilla Bug 961365
+    </a>
+
+    <p id="display"></p>
+
+    <p>
+      <math>
+        <mspace id="ref" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math style="font-family: stack-1;">
+        <mfrac linethickness="0">
+          <mspace id="n1" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d1" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math style="font-family: stack-2;">
+        <mfrac linethickness="0">
+          <mspace id="n2" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d2" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math style="font-family: stack-3;">
+        <mfrac linethickness="0">
+          <mspace id="n3" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d3" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+    </p>
+
+    <p>
+      <math displaystyle="true">
+        <mspace id="dref" height="1em" width="1em" mathbackground="green"/>
+      </math>
+      <math displaystyle="true" style="font-family: stack-4;">
+        <mfrac linethickness="0">
+          <mspace id="n4" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d4" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math displaystyle="true" style="font-family: stack-5;">
+        <mfrac linethickness="0">
+          <mspace id="n5" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d5" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+      <math displaystyle="true" style="font-family: stack-6;">
+        <mfrac linethickness="0">
+          <mspace id="n6" height="1em" width="1em" mathbackground="red"/>
+          <mspace id="d6" height="1em" width="1em" mathbackground="red"/>
+        </mfrac>
+      </math>
+    </p>
+
+  </body>
+</html>
--- a/layout/moz.build
+++ b/layout/moz.build
@@ -26,14 +26,15 @@ TEST_TOOL_DIRS += [
 ]
 
 DIRS += ['build', 'media']
 
 if CONFIG['MOZ_DEBUG']:
     TEST_DIRS += ['tools/layout-debug']
 
 MOCHITEST_MANIFESTS += [
+    'reftests/fonts/math/mochitest.ini',
     'reftests/fonts/mochitest.ini',
-    'reftests/fonts/mplus/mochitest.ini',
+    'reftests/fonts/mplus/mochitest.ini'
 ]
 
 REFTEST_MANIFESTS += ['reftests/reftest.list']
 CRASHTEST_MANIFESTS += ['../testing/crashtest/crashtests.list']
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1670,17 +1670,17 @@ needs-focus == 652301-1b.html 652301-1-r
 == 653930-1.html 653930-1-ref.html
 HTTP(..) == 654057-1.html 654057-1-ref.html
 fails-if(layersGPUAccelerated&&cocoaWidget) fails-if(Android&&AndroidVersion!=17&&AndroidVersion!=10) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 == 655549-1.html 655549-1-ref.html
 == 655836-1.html 655836-1-ref.html
 != 656875.html about:blank
 == 658952.html 658952-ref.html
 == 660682-1.html 660682-1-ref.html
-skip-if(B2G&&browserIsRemote) == 664127-1.xul 664127-1-ref.xul # bug 974780
+skip-if(B2G&&browserIsRemote) skip-if(Android) == 664127-1.xul 664127-1-ref.xul # B2G: bug 974780. Android: Intermittent failures - bug 1019131
 skip-if(B2G) == 665597-1.html 665597-1-ref.html
 skip-if(B2G) == 665597-2.html 665597-2-ref.html
 skip-if(B2G&&browserIsRemote) == 668319-1.xul about:blank # bug 974780
 skip-if(B2G&&browserIsRemote) != 669015-1.xul 669015-1-notref.xul # bug 974780
 skip-if(azureSkiaGL) == 670442-1.html 670442-1-ref.html
 == 670467-1.html 670467-1-ref.html
 == 670467-2.html 670467-2-ref.html
 == 690164-1.html 690164-1-ref.html
--- a/layout/reftests/fonts/math/README
+++ b/layout/reftests/fonts/math/README
@@ -1,6 +1,6 @@
 The fonts in this directory are autogenerated with FontForge using the Python
 script generate.py. See the comments in that file for more information on how
 to run the script.
 
 These fonts are intended to test the The MATH table and OpenType Features used
-in MathML. See layout/reftests/mathml/
+in MathML. See layout/reftests/mathml/ and layout/mathml/tests.
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2d6cc2fa0ab8768d8221bdc1f7e3b1a8b24b2af9
GIT binary patch
literal 1968
zc%0Q$O=uHA6#iy+v(?(BRaz|?WznK7lDLhwiqwNvf~d8Mr4$e9T0;|UyI~ulN(vRh
zgAqgzUOWim#fu^q4`RTh2el&ja}a-S6+C#TG*&czv%9T{T4;~%GV{Lo-uLFcnSGgb
zbar-N5k{cGY>UN=dtY{}00P|rUd3Xa?I&-&y8-AX^-%lv&RvRLS)jfb5ZxUIH$)d7
ztJy$o(0{b2-%4SR`V>$<)3!Siw~i~$$aVT2a<n99&^HI(6Hjo|C;HPvWzUIFc9T<i
zzcrMCx}Q+ganc8@{`jiVH!rA<0LqD!J(w<>$41t-g?<A<Qh`gm)@P1XwSL7SbzH7C
zc7NrkVyTY1_61PjJ&X|(VgiReK4*c_hfLO?5^3r<nE{$EC~_AUJt;n*Nhp%2FPw?`
za~0qbt6cBpa_3@>;qM@b+cVa+*ym$`N?i7_!rJfpSVe=V@UezUalpp`REx7d)@i>@
zrqE<<d)+9B1(xHKj}=tox{p<E_JNNzEEml_4!{sce5})c1#PgA!f7~2q8ACIxrYYy
zpph~P6HVAe)K1nJGWz&h)Mb>zI5}I4NfHeJZFcIklk82TjfS2^BWgBnGTQAk$-X|z
zXtSM^?O5rgO`e4zh72Oigz=fgVJ3q$lpG8v;&PEN)xZ3|T`@Oj+LaC|akt_KYc{Zz
zWA-GTznQp&V|tf}*#qgA?exZtXv8$O8YQJrZw|MF<(}qKe;54@nce{zOeK>=Tqz4h
zSKJxonHZ+o6fsTHn9t%~_jn`ZcgjxrbzNQKca)u@QCDQw77A{UQWicIUjOb}q5rGV
zOP?aYGCS+PepF8s&aor@aUcR3Pg00r=||v|ArQ`2A-_W8LrQ+7nqQ_}tPt7kRAwp@
z2;pi~2&fL>+Tsuvgz#($R2j049k+dMzn7APf3<)>1ymtcuL);!lfyZY%Y7Toskx<7
zb(0@|*6F$LcWNhxzm0w$E(->;nk?#PrYty>sma!6E6V+?@p-cC#+Z~Pcdhi4<AaFs
zK4}fSo#%-@_GRN7xK~-m;W_Z49@mxAxM+<Md$ed2#fw_t$4lZ?-oi^M>nW%2X!(|E
j_3jZbK^<1jT9wDFA*0?!L3drxIxUM{`7h=DQvtsKyP^*R
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fdb7c97ce00941025516f0cb50faf562e1cb7ac0
GIT binary patch
literal 1968
zc%0Q$O=uKJ6#lBar=u}W5=k`ZsD&FeL1yfXCW>SaVPp_B#>F5(L~Y}c8BNkdXM`vT
zWLZ#jyzCyl>_HGOUKCM0hyxz?u>KtO2Soh2McB(iBx6L!uev*N#u$i4tLb{*d+&So
zURA%T>FMq5!7@xhhm}Ys<(>Z%5g^nD;Gbl&xBK*s7uNvOq8{n)>fNoGN7hr{2Z+9&
zgInVDCmOa8OZt!Z57}Al)gJ-+f3)pMr|grOJ8_l12YfryG??2%FNvr4Hm8Sjqg79d
zP<5SC^^iT9g?@lgG;uPA?V;3$d(Zx&J^^T_vd&1ZbRJt--wygEgrWi$x-NDctL=P?
zW%{IA?a95hZ_1@U>DiY+gFhG}ro<Eu`+Uv<m4i&yp%WSUB$*+aE@^5PmwhQ-p-pIt
zXfB<L`f?TEA*<Z%=kn%qjtq7X#?3kFM(hu;z;gT=V2!ok4zP|EQ4?ST%f(Lt4xvu`
z9AK07n`8<@)wa)zQdnR$&IDLP9j*pg=VtE**uZMh9^eq9I2K@&_TP|zgDlR%MFs;%
zBgZ|opdYQ2aad@>Hll8_&XF<5$EL2LT*j%{W=w`?7)UtTvu<V}os%v7tuk)4ZIj*3
zxy<08EfbELbzD1_amceV%8(I6nJ_h%ILd^uM>8YQbV@A}r8>|5*_HHi<~-?=lJY8!
zv1W;#d>2mQ``d{-Jl)?VlFo20>9_+a8IM_Vr>rQ2dV91Zs`m6P^&g_&CDT73$y6#?
z%#*5697?$(JQHbIZ86KT<hLyDcaQ%@f==0`zOJVm{En(~4C<Qd+EU5uQOeTm(!Zbk
zR+wLF^vY4@*A`}d*F*P3=@)g<^AAM8;7JM*uKWnRG6bT<S`^oaVni#h)r+f)%QYgO
zpBbAO3q^3Hme+4x1i#luuq1-VE1;{8P3*X?#r<9?63%M@fg0#SZ1^FXFHDaYM4|BR
zZb2`soN1bV{jtd`yuZ~rJ^t?Q`|+x9IB%$;K8{s|XT}=xjrp4DU~3$I{&?+)k`;HY
z@>JuMi19w@3_bTxV!vGEiT)AD)<tlyu#BUN;KhBeCuecl8Wr|<*;^Jb8i5ag6L<0!
tUP;+ZIeSN|r&4S7j(7!{ux`Psd}ad~%^nJS>-yGNS@x)ZDgU1e_ypTz4+8)I
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..24e7d5155be95b413bf2881ddce7b0c7bd862f06
GIT binary patch
literal 1876
zc%0o;O-vI(6#iy+Td-jHNzo=2ooM|bhO(_nBH}?w8lyrnHpH0tv(!QxDcdYHK>`WJ
z!~-S969?nTn-{$hy;$SPcrek6#)DD3;T=QONPV+AKx;78t23Q>-<$WnH*bD+8jHtc
zsKYc==snRWKXv%d4Z!6G@GKgQ_g;PQ@jmJANe}cMi=R;3=P!`H1h8|lvmKG9L0^zC
zC;R0@#>ir``T|hrY3z6^X<S*EnS4UFr_?%AG@!&>p9qsbf~ibyyygud)SRZSHe-xu
zq4X1EVt)6ikx6#!e7A%2X+Q~Q&9PkR77hSfk?b5yP=VO8D}AY<`zz|yMG@`w<JK?b
zQkGgM5|IyEVoNyh@STy0Ld<@<ho&wP(?!aRB33c$NVb45Qv}7mY0c~RD8O^dk~?$R
zeL08A6?pM*ZFCR%Bxdj+FR?=MuEZ*KV^Lxa9u}0?g+_KpVmFPC6O(Box6`(lzzjZI
zlUSiTC$Wl?xF@j&AM;A=qTD+qcGLJEdSD`p>#&f<FjC0T8ulT9Hj)wO2;(53USdrU
zV}z<fy702dPxJ=)qzR1zJ!ba0l^#yz_`XCNkLclpyw{vakBk_+$F#DhW#rN(@rG=-
z#F}F}O@krJNC<N~VdodMjX7IdlwH!!DMVRubWz(VjAJ=OxRcuI3J^6%b5YY8PVz`d
z=Use#GExq;ceaaUt4M5slCUr)&78uE2|~6MX<;B~jS-jYdN`!(I<F$8yai4R$P@1t
zr)2Az2ur<Y>%3HQ`qJmsJI34_UDV3*H~W83R7aF<(y4E-U<QqLkg>Y5t!Lsp++S=!
zaT_ZJlwzw|+^Wsivpf}70QrUh&=|n&rT}UKc-#zCIP9eZJW}0NU!SY;z!?<AcJ9g-
zmZu7=Q1~`qPzzhW`<Fkj_}zsck6M<ezRmxbs_}ZiPx|sL`Ff9B0+m-s@4ptZ;!PA5
z4;EO69=UGUhkx9;mr}M>!JVTtE><79k8d2qKBLHQI8w$T%vyk-Zy~;gT5KU1B)R&Q
kidw0Oce5VN@MHTQ({Y$SVgzmEwc|RYtFo+$e-qJu0omU02LJ#7
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d404810257674162a9e25c327ce5b980a97d7f14
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+TM)1)DM;dKCR$WtTDDb5RE$w#W0Z<ULW~D>sg*WTwpnTd1QLvi
z2Wvcd;9xv)^P(4m7i&Bj4<>ps;b8o^;aLntBlXShP+HW0S7&zSeQ)0P-n{wQ>F(+2
zMlB|w!sv`fdDp@FHvvyGfalR@Pwe`m4^yPilCH;&^_*0^?P=2I0d}GLd|PC5pFcpD
zll@9OZDz1heF>=3G<H0hFt0A%8GA~$XVlu0G@x{QJ`yH>1d{3OaMfEvsOqAwI&BVT
zpqwSh#QfetGo3I3vm*WkpoBBlP_}p*`v9##b`B<}!0E3ij$W?s_=Z|_PDFb%v+YZ{
zl%*PqMC8Nf**q?~e0QXx5c90lLsRF7=^^EgB35zNmFyG3Oc50ChLYFnD8LKKlDl&`
zeL08A75MPDG`b6CBxa~VPGW`R1Bq3%U`}EUH7p>p2b<VAiM=#FOiZSU+`1euff@X`
zA+bVrQeqXS@K9n6e&&<dL%Fv}?4|KObizUgBe0P|Ka$AO8ulQLR+14I2xC8?7_ml)
zF+kNMU3l5#Cwh~7QiKM9PAfBFr}~pwz9-(wBSv^Xk6ELsfdP|uT6V^=&1}jd-ZjT9
zUUCf5RJdlFabXS;cE6}&%sSGh>=I5+A<By55Vb#raV-Z3w>!GK0z|FBY}B&*6Fd?!
z_#wVB87T*X?Lm?3Iuh%pBy0>xGpF!kf{-IcTIfyKL&W8V5e^xK!PgN}-U7Gj^29sD
zDLJ|(!cwm}IxiO8zW90hjxq0_E^1|2%l;n})fL5CVt;>MFoQ-r$XIRJ)-&-R?k&`#
zu$2{brLavcY|-x4u^bhTj$FMCY|?RWvyN&VGYwFM!)`k9!|S{1D|1yIID^92j-9#u
z!g!wL^NZ7YHQ)5TdExU?vp4_aN#nx!;`ER4DxdHBm_OH;tE-Vqpz`|2)Egly-b7)k
z!6z1?N3O&3{vUVlm6WaP;7(E+m)54W=q|VP9#2-raLy>Q3P;K~gjpl-^Bu&$P>m*%
o0g}sasi>8jcsJ|NfM#s}Yg#VTPmF+rd`?_<bXk^Fk-ccY0H`$b1poj5
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2698e8c7c22b29b11f7599c79dc2418cf0f43985
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+Td-hJQ<TKTOtk(GL)}(rBEmsQsxeeB5@S55Yb~^qvdvNxAdp~8
zJW%4va4?>@dC?2Oi#48%2NS)R7-JM~c=CdwYNWo|9k4YR>(!agyzjmDy*F=mrqkQs
z--|j-L50yBi}Co8J2wDN6M!eNSbzN5{r7XEzad?ZAL~D<c%vE8mjQOZ_w1p_)+>P^
zVNU+biHw=WX7w4M&XetUDrsI_ot}6^zQ;78DKaR%o)3g69>G*5H(K+G5Ndj8s?C_A
zStxx3nONUDY-W<-eQ#Sxp8}L{)*8u`Zs9PX70J)R1Qj^(xvTwBL+2ONsY@c;%Z27o
z<x;j<C=yW&TV~6+;PPEdMI&aPGec9Ci0L6^S`oXLaV1+sm??td-LxL{dluj+Rmt78
zoVlFC<qrIKux{Ol(-JfIke65?c~@c;d$A<31|JJb?7<dxMq)47M~TTaQCp7_B``w(
z*Cke{&q}P~6z)l^A;A0+d#Lt95_`#h1>LZa#Taa)F^Cj$w1)#opoL@v2Eu3~6erd=
zF@~s{q>Ct<;>2uHOq$Rz&~0VM?DSwN#}6c0c*F>|@whdf9vU)vw`FH7+svgc;te=q
ziS@u%aRml!Ga=lqgxz1vapoLpQ*}wFrVv%d(LrOQG_I$eaFoW{4iK}3b1};vO!7#`
z;2r$eVx+XUMq5R(RTOrPim)*v-JH^k1wxJ#W#L@X9w9C_jBv;>3|>V}c?;a3%M<Su
zr{w6GNK3Qk=)6>N=hDZuJI1^lUDV3<H~)XoR9BR4(y4E-VFr!9AY*l9pPq^T;lW}9
ziaS|RSBlMQafdcj&+^nfI`R!Vutmr1tvYITENp`+0`}91AFb}H|5~f^z!?<AcJIj-
zRwfIqQ207uPz&3?HLZMHZSoerKWto?{5t=Avc~WKHWA1-=IecO3)Eh8&Ak+|;!PAD
z9~N1N9=T4>yMO$0&!udsf;&rPT&yxLam9PQS9fu_-8rMkZ#YuMA<P<qAFm<)3$@rz
oGDvdmEfu{|6Ypj{wxJ2T{#cRA3=kveAitB>wXVssE~*#fCxa~V1poj5
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..140793337177715805d35945d229e51ed7e736eb
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+Tgs2+Cq+ptW};OghO(_fqT)eG8e>2(5@S55OD(h!*k-8-5=k^B
z9xU<LgYm@8i(UwNu*Q?|V1gGD4@U8Z@hFBWk@{wLT3W<dug-Mleeb>R&Aiz+oq?gD
z0o39qROr2t2tR!|a|>{_0C*mW4E0}q_+gIpcclCKj}M(x+^yB5uK?`)z}e1l<FGG4
zn3Ml<blgZ{oB9$^=gD>=9y6}2-@WmKe9vff$H|}!xIPl5cm(3(si~?rgizH-lV{wR
zN<tYV$i)8c31d7KZhIdj{U)G<lICP8e+LHvEk}M1Ca6H~m(j16>U+MSR$UgWEiSZv
zE|s!*ph!e9Y=y1hg2Q(#WsR7F_6$v3CZ>y&yNWo)tRvYHLQD}9cXcsp^D4j#%91;K
z*>fp}%M*C<sA%1X(-Je(AT6;%^1j3>_F`FL4K*wvu?r3CjKprTPZ5)8BDX#}N?-;b
zu1Ty=&q%D|6dp*d!N<H3yD0ZgiQQx$MlVbxaUB*C7)2Z@Izt<xXeSwljt~wJ>L=DT
zF~+DHq>Ctv;>2uFOoGq^)y+&^w-TfA6mN^R^RON|#QV+Z#Mqd@drd28T1F~i5^ux~
zixvYrXcLTBMpU>v2s^)s?M&IyqU>UJPC?3w;|PtdmT^2?gu7`JPJoCxk&2ksXpD!0
zIzPfUHY260qq{>STR~#yC<zOb(#>gku|d$5A}ySYS(C)&x*iJZy3Q+DQ{Dn+_+`a=
zM3rn^6U)-9**eeXojL!haL1T?tBYFR{^tJ=n(B!BZL0bf2WHUd3o=$)^68oQA0Ein
zBe#>~{7SA>&F#=;>sXqa%a3%uA87F7UZWo#KNgyxih%u8@uQVp^^LvC3(lZ0wtG)H
zyE>C)+3ffEteV~aqh<BedW$=|_PBX<=KK8GOqJLB<AyKYoUW^pN1*ol*xaI!WpASJ
z)L@AP>5=Pkz5mBA_e#q43b+|c<Kpk;+NWD{i|=u!+-}z>ya|U(ID}a<@bfLif5C(8
oBm*Q1Z>i|zns_(s(1aH3`eXJE(?^VejlA}{j<q05y2xIPU&BZ91ONa4
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9903b4b00ad9fc33b2feb382eaaa83eb1094aee3
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+TYfD<3X)jNM5}^^x-CK?VvLeB#(>30i18pUwbDjlo24d5Ai<b;
zpu{6F#uGO$dLih+8c)W930_P*7}S$+$51d*-|P<18i;sxrZew*?|tvho1N)Iy1OGN
z!vs|5?cp$woO*N*aMc2M9S(PQ-hR3;L;5GueVymJFDUN164I9eb~SS4M5waQ>nF^~
ze<M0*B(X<*3#hYXJ0Fi3H`gb}UXbq<jg~kWl!)sKVTy-8KA0LQ`alRp9W)gW8Y4+4
zT?Cm}-#ugu#+r^TG?6|5D8ZyToXR}_=~|Zj986Gwv)_A{dMny~piEs9+2-f!mhz=+
z#ZV-o7`Duoan0d7mV!piE_;TiE)vs4%A_K8G37}16+xy5io0Yp>d!2|8>*5!YuR%?
zhszy!@NCn11eYXcC`DRgh2&$2RUF2m#2QMOUt$;bvda>?$v#3%rit1*>?na5ytpH=
zLVa3d6&LYDVhvvAk=RAGpODy1_CB=3L=tylA%T9xk)l1+BZ>x+A?OI=B%w}XjS^#k
zx<R^#vM5f>2E`-@4FT<D@~)NWkEeKjw1J28;7Q(TjwS{M4Bl>9Nz*b?36prY?6Bx&
zU?ZBzXc<xAZY1pd!nQMION*+D*);{IDvnkf+of?l&4gQMZ0rDGb0`%yt^ODf1$5rZ
zw-zI%xv`~D6uXPUdZ-8s!_v(uy;vY%OHmejV%9KmxvmETx~}tG<dnC-89sU9ZQ_({
zT@z_()@+^Ua?YIlwsFUpd%KHT*#74K51Q(T+<iLrZ8prH(HCT_Ebr4Z@jpDCtw44^
z%ledTotoXJO_j4WHJ1<R3Lmi7hliCu6#Fn&1yuwbr4v8ByQ{vnR^fp&D2yFEl+LV-
zXILh)I-5~5HEXpi-_~p0nV-+ASH@Roe~uS<JZod#balGCRBnOV`!h51LKeJ<!c&T`
zEI^N3o9pvGez|v2Htd2sO=Vo)*<JRskh}RFPZ!$lGYb8ILwOv+tQz?B5#qm4j2e=D
mk{fTS=!KeiH_K6lS{&H1JcsEehTldWJFjEika=BHFUD`1GxG!h
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01b139cfba5fd6a8ba3c2b55f7d195d2ec71429f
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+TPk2dQk2AECRz}pt=kGj0S`*j7z2Wl5aU5zYo(3AHcL&AK%z16
zV2MW##1n}zUi3onVvQ%`!9*`69*jb~;2lGOXnnIg{1h?PtFxVX-+S+SZ{GZLx_f)O
zQHI-4p?5^1yyy7T9l%us;AJ%0+jZl~=V{VElJ4(1*?U@XH$NhM5nva(&mW2Gy6OuM
z=H$N;8#GebslEo(8M2*9#Eok|?~gqv-wWz32{I_%t}lcs9)ZMQdZgq%A(V8|;2AVV
zQc!vbGBLk<$QX<_9iBTz`fWf7r_AAW{vM73T8{i2Oi+Qgul0{FSG0denYtjdy_>E5
zwpq&Nfg%ybutm0riw@th6f|P?*dsJ`ftW5*?ki#y6OLqa2s1@c+&k8zwq^ldQI*`8
z%N{p#xLko3PuH#WI4dzjDKZi(B&Q@+QHKSIHI%Y|#4c2_a}vABK0-{UiP}2tD1jM#
zxGAwh-=xGU&fuZM8hp$vv5RUyBC(t7SJ43zDcpjEB>Is+n%2;O7#c}Npd*YXLS4if
zCB^`K2I(ToqBt=c6q6)01az3GTUN3^k>(AtMjp|_O}xt-O%4ngyu-9ore&m)Ch@M@
zVX^hVAX><188P7w5_W!3+nKhdMb*XannF|+M=SO1(m0-G8wb}{fT%f?j+$0~oJT@B
zZ{-`4k<uJ&35sHiD6Ef)urMs$oYIR4LbeoTp)YO?6PN3HIHc=3FCwSB1y1+N6K@x%
zWb2wpOQUA%JfC;Q{QTM-WA5!PYGM1E|37G|Bl36Y)VEnMgGM{ZSlOnnXX1Z&C|7~p
zUY7GKxmq>1N1G^T8EP&+G8KNH(vJtb{P6fOTLo1F9HbL(EAFaq%vE^c3<_iW4`i}S
z<5`x?F3)7u?CzDCrTL#V?(FKb>ZS4Jnbq+UuXkn4m#NN_m&zqjdwXK~osb1@qVSYr
zj)mxvYj=J6$DMm4Wn&TCNh;$~5j;ABI@&$^J&ydI!?s1X;7DOSs|J32fcP(Xu$yFn
n<l0**zCumBo8_oN4fg%9Du?MKM!-g1JFjD1lbb$Kz39IH#;EcI
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6c628a823e8a215c6988437f335afef1a6ed18d4
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+TWZ0Aq$r6CnP~kXhPtf+QQ@E@jWHk)8)7`DYpt{q*k-8-8c8rF
z9<1@`!Qh3&gBQIJyjbJOcrd|>i3cO-3GWyRMC+T~;im*+y*ksG_r3SN_vX#cbb8|P
z9#mo+DvZupjQ1UzxC40V0lbdI;@#JueVHWv6X|;Q$@po-+wzq31%RFJId?d^<4Q0@
zn3Ml<V#v&3yZRPTr^t3Hl{ByZx_|p6`CidzO_4$A@yrsYc!W|z+0lv*giz5%lW)iz
z%|PiT$i({IVRI<i68_df`Z%COGS*18cn?Patw4SbCa6H$Y~zzl)$Kn}sm_aRGt&*<
zH%i%jP$Z%lw!ju}!R5P_l19v4XNIQE6VpS=eMRizfh*Y@B1{n!@3yt5%~^mqR3&%U
za^{U3E_V>X^EK;!oRyftkDSB`$;T3_*oS$EHTYRbVh?IqpTu6Wj}nt<qP8w4N??W{
zZb+<9e<ZPrGnkNALy!d|_E7DICH9j23OZpSgPX9C#sE^t(jE>XfhLks7>M8~p>AT`
zBE}$flXMYfQ=FJhib)e120E?GO*=i1%JPGWCLT2+M|rn(D?K=9@=nXnShkr>Tg1EO
zgeBGjo6$x_+e`>|Ghz1^bDUX6+EiWAsVPiVaU7?yRT|gRLb#R2>JAXIhO;rt9!T<N
z*x<+c`eLNCG`BX3V#_G3pNg<CBHf(Qiv_}t6lI}5X^#+>8%88-7zQsRr@RI3(B+A@
zi&JuRO{Aq+b97!Tx^waC>K$X=tuAV5`<wqiXsRoUcj?r(*f4`eUy!lN4WFKg|KXuR
zH43{~L01Y5YGIf5po-<Fd35Beb)ZJa!yP(&I;Lx(ihu)j;wQ?x>g#Kj9yo)-*q*()
z{Nh-i<?~BZc{RUtxqk8MuX=BO<wf1%*wWO>SVbVPd^?z{%T@X17O1`Nn4A%^<V_SF
zKjv7N9=UeU=YRZi@1$%hgZqfexL5`+>I&yQCcIBC&Efc?n{c!=p49<AKSKN$eAr1c
nL~`{l6}?mw?`9QhQIEzyR^>8-#0WVk;N*3!t8zmZ)r;{Pp`h{w
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..32376dff9e3916df3f5803825cdd8f09c6e1a6db
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+Td-geQk2BSOtdP*P`4F`A|8OGQ6u6HAx0B*sg*WTwpnU|1`>>k
z2TDA0FvbHnFM1*B!5UA-gNa^DOf>!^9`KH#XtciB9iT;wcy*>T?|bik@6DT?>GbsW
z_MigeP+@dMqx{6aJJ$eD9e^j%Xm9tWyYHt-e?z+7-O+nc@#-C<&jIXI&&l19>i$5G
zFem@{SjtRez4{DLXUNu>h?^IFPK-Vz-(woB2{I@>o)3g69>GK^Gg9`75Xz3wRGu<N
z(ol{OWMX~qkeQ0N8lO8!9|x3h+8WLjZeS0f<;l;%1Qpox_RyJgRqbC<q0WkIFCWx@
zDVDO8Ly?GL*c_X~X_xO>N*XbbIWshMmY5z=CKR!YNmsIu2s1@cyz7>tR%QX7QkC3Y
z%bANgT<*Y+drQ_GI4UuN4_S#7lD8yQu^qD#Yw)q4#2##5$0hcXeT0}y6SW<2q6B6L
z;IhOD^(l!}9L8;lH3XPnVh`26TVgNS`_TmpX<UJgBnFT`hW5~a7#c}NU?7ZULfyo=
zN{m73Cg~!|rZ_R16q6)01aw*HD|T`qk>L%oMjkQ3&Ai*Xnj9Q7d6#9UE!)f_E#h5t
z!eUE-P1s9D+l&c!6Jhrkb(|ST+EiWKsVPKNakSA`Esg7GA>2x1aR-Q6Lz$>$55##S
zWbih=ycj7hO|4C$*fkW^M@85emTpez#R4Hmin7obw}*+#4I>;f41=#Br@RI3(B+A@
zi&JuRO{Aq+b97!PxO3st;vHk&)h=pj`<wqiXsRm;*Xh((*)W4fUy!kiqEFAn|8Q5n
z3i-_}uPga_HNQ!ltYleg9v#^#9oV4bX0?uT9S>@tih!MT;``Tj)tA>QJ#Yqvv8~&(
zx%sgi%jFhka%yhlx4QXHKkK}?@Aqrx#};P3kCplT-$n!3+H9pyZh_j11Jf^sEO`@!
z$A^zBM2}p%=iNVkx#v<gu7Nv6Wt?5zRq?1uiMYafk0Zb5aBPtkxR^(n)dD|WL;M%Y
qv5{nu<l<W@dZ{Mf%}Ugu4qN_My~_*`Bj_N%lh?H_%Azi+7vmRL=kf&r
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9c194bf3d708585cf41af5d80d984df3a63587e6
GIT binary patch
literal 1876
zc%0o-O-vI(6#iy+TPk4rNkI}<GtsILL)livsCYn<Y77VlLW~D>sg*VY+blIf0|~~&
zgEbyK7!QV<7rhYlV2vl^!9*`c4@Tu;@Q$HCq`ui5phZ-?I@6i=z4yNN=FQG@I(vFL
zQHF7-FxsL~-hJr7b-+^x;CVFK({cIXrwP(Okgj*M_MA|>dMoL(06Wv!-4v<n3j_&s
z@?VGznkj5nUjphR*^VXR=EbF3qff~9j7D>U3`(cxGhvEHFfo`ODS1l>CG9l%2F;Na
zlrDlytnVE%2jd4LUyqYM4k+Q2HJr}h#6CdFk)MMJD$w-4_4N6QmhUK2XGFF)Q`^23
zO4)o+B%&BL%Vu%b<-3-mM$9f}hNjLC(?iNFMeO3XE7=!>nIb6OO)F7rvj8usO75=Z
z%!M2-ci_jP73*%Cl9-_s8Hp8=_as)a3o{aHC}ly3J*Z@-CH9higqTbdwY57@0y6|~
zMPh~eU5Qnk#C?f11ejl957pizv6t+9XoH0muEItV{YW59d#FbY4J0El5XOE&9mKju
zi~;H<=_1OeI5C?PlO!|*v{|XEcCtT_=Jl}#9x=lEd53i^IWS=IHp@;~wwX>^#Jl8#
z#a03vafpnz858bC!tO8XIMa@_sk*pRQ;4eKI80-`G_L0W;bt1kJ3!PLN=GfbKh7f|
zgCFLri;;4mvAIzcyMe-bsR$dx(#<KoSRmv`Q5JgR_Aqg|VT415Vek#)l()bgx;*g~
zaY~M^iL^9pj?VLWcg{~Q-!bN0@1hpBzxn@zrn(}3gHC;&4Krx;1sN+V`1DNt5BKIO
zklV^~x{}+b=C)|J%UOn+M@ObY2P$>ksnX%oF;xv!1ni*`KeDl_zPeWNfiozK?bw;g
z&W&YRHakC=RkO7Vb#v28b>8ga<C?j#`N_qx62E_8G?1yul$XjaP<wrJ;*F3+Z=&#&
z;tLDWBiG{j_>W)im6Qz|;NGP&&i$EE_LQcGi=Fp4@@o#q7FmM}d4yRF@Z%lCf5C@Z
ol0lNoZ>i|Tns_(MQH?rm|7~e5GeC@>gZxfj*SahVx~N`^pD@$%1poj5
--- a/layout/reftests/fonts/math/generate.py
+++ b/layout/reftests/fonts/math/generate.py
@@ -51,16 +51,25 @@ def saveMathFont(aFont):
     aFont.os2_typodescent = aFont.os2_windescent = em/2
     aFont.hhea_ascent_add = aFont.hhea_descent_add = 0
     aFont.os2_typoascent_add = aFont.os2_typodescent_add = 0
     aFont.os2_winascent_add = aFont.os2_windescent_add = 0
     aFont.os2_use_typo_metrics = True
     aFont.generate(aFont.fontname + ".otf")
     print(" done.")
 
+def createSquareGlyph(aFont, aCodePoint):
+    g = aFont.createChar(aCodePoint)
+    p = g.glyphPen()
+    p.moveTo(0, 0)
+    p.lineTo(em, 0)
+    p.lineTo(em, em)
+    p.lineTo(0, em)
+    p.closePath();
+
 ################################################################################
 # Glyph variants and constructions
 f = newMathFont("stretchy")
 nvariants = 3
 
 # Draw boxes for the size variants and glues
 for i in range(0, nvariants):
     s = em * (i + 1)
@@ -224,8 +233,267 @@ for i in [1, 2, 7, 8, 9]:
     p.lineTo(s, 0)
     p.closePath();
     g.width = s
 
 f[largeop[0]].verticalVariants = "uni2A1B L7 L8 L9"
 f[largeop[1]].verticalVariants = "uni2A1C L8"
 
 saveMathFont(f)
+
+################################################################################
+# Testing AxisHeight
+f = newMathFont("axis-height-1")
+f.math.AxisHeight = 0
+createSquareGlyph(f, ord("+"))
+saveMathFont(f)
+
+f = newMathFont("axis-height-2")
+f.math.AxisHeight = 20 * em
+createSquareGlyph(f, ord("+"))
+saveMathFont(f)
+
+################################################################################
+# Testing Fraction Parameters
+f = newMathFont("fraction-1")
+f.math.FractionRuleThickness = 20 * em
+f.math.FractionNumeratorShiftUp = 0
+f.math.FractionNumeratorDisplayStyleShiftUp = 0
+f.math.FractionDenominatorShiftDown = 0
+f.math.FractionNumeratorGapMin = 0
+f.math.FractionDenominatorGapMin = 0
+f.math.FractionNumeratorDisplayStyleShiftUp = 0
+f.math.FractionDenominatorDisplayStyleShiftDown = 0
+f.math.FractionNumeratorDisplayStyleGapMin = 0
+f.math.FractionDenominatorDisplayStyleGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("fraction-2")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorShiftUp = 0
+f.math.FractionDenominatorShiftDown = 0
+f.math.FractionNumeratorGapMin = 9.5 * em
+f.math.FractionDenominatorGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("fraction-3")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorShiftUp = 0
+f.math.FractionDenominatorShiftDown = 0
+f.math.FractionNumeratorGapMin = 0
+f.math.FractionDenominatorGapMin = 9.5 * em
+saveMathFont(f)
+
+f = newMathFont("fraction-4")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorShiftUp = 3 * em
+f.math.FractionDenominatorShiftDown = 0
+f.math.FractionNumeratorGapMin = 0
+f.math.FractionDenominatorGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("fraction-5")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorShiftUp = 0
+f.math.FractionDenominatorShiftDown = 3 * em
+f.math.FractionNumeratorGapMin = 0
+f.math.FractionDenominatorGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("fraction-6")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorDisplayStyleShiftUp = 0
+f.math.FractionDenominatorDisplayStyleShiftDown = 0
+f.math.FractionNumeratorDisplayStyleGapMin = 9.5 * em
+f.math.FractionDenominatorDisplayStyleGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("fraction-7")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorDisplayStyleShiftUp = 0
+f.math.FractionDenominatorDisplayStyleShiftDown = 0
+f.math.FractionNumeratorDisplayStyleGapMin = 0
+f.math.FractionDenominatorDisplayStyleGapMin = 9.5 * em
+saveMathFont(f)
+
+f = newMathFont("fraction-8")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorDisplayStyleShiftUp = 3 * em
+f.math.FractionDenominatorDisplayStyleShiftDown = 0
+f.math.FractionNumeratorDisplayStyleGapMin = 0
+f.math.FractionDenominatorDisplayStyleGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("fraction-9")
+f.math.FractionRuleThickness = 1 * em
+f.math.FractionNumeratorDisplayStyleShiftUp = 0
+f.math.FractionDenominatorDisplayStyleShiftDown = 3 * em
+f.math.FractionNumeratorDisplayStyleGapMin = 0
+f.math.FractionDenominatorDisplayStyleGapMin = 0
+saveMathFont(f)
+
+################################################################################
+# Testing Stack Parameters
+f = newMathFont("stack-1")
+f.math.StackTopShiftUp = 0
+f.math.StackBottomShiftDown = 0
+f.math.StackGapMin = 20 * em
+saveMathFont(f)
+
+f = newMathFont("stack-2")
+f.math.StackTopShiftUp = 3 * em
+f.math.StackBottomShiftDown = 0
+f.math.StackGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("stack-3")
+f.math.StackTopShiftUp = 0
+f.math.StackBottomShiftDown = 3 * em
+f.math.StackGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("stack-4")
+f.math.StackTopDisplayStyleShiftUp = 0
+f.math.StackBottomDisplayStyleShiftDown = 0
+f.math.StackDisplayStyleGapMin = 20 * em
+saveMathFont(f)
+
+f = newMathFont("stack-5")
+f.math.StackTopDisplayStyleShiftUp = 3 * em
+f.math.StackBottomDisplayStyleShiftDown = 0
+f.math.StackDisplayStyleGapMin = 0
+saveMathFont(f)
+
+f = newMathFont("stack-6")
+f.math.StackTopDisplayStyleShiftUp = 0
+f.math.StackBottomDisplayStyleShiftDown = 3 * em
+f.math.StackDisplayStyleGapMin = 0
+saveMathFont(f)
+
+################################################################################
+# Testing Radical Parameters
+f = newMathFont("radical-1")
+f.math.RadicalExtraAscender = 0
+f.math.RadicalRuleThickness = 5 * em
+f.math.RadicalVerticalGap = 0
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+f = newMathFont("radical-2")
+f.math.RadicalExtraAscender = 7 * em
+f.math.RadicalRuleThickness = 1 * em
+f.math.RadicalVerticalGap = 0
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+f = newMathFont("radical-3")
+f.math.RadicalExtraAscender = 0
+f.math.RadicalRuleThickness = 1 * em
+f.math.RadicalVerticalGap = 3 * em
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+f = newMathFont("radical-4")
+f.math.RadicalExtraAscender = 0
+f.math.RadicalRuleThickness = 1 * em
+f.math.RadicalDisplayStyleVerticalGap = 9 * em
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+f = newMathFont("radical-5")
+f.math.RadicalExtraAscender = 0
+f.math.RadicalRuleThickness = 1 * em
+f.math.RadicalVerticalGap = 0
+f.math.RadicalDegreeBottomRaisePercent = 25
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+f = newMathFont("radical-6")
+f.math.RadicalKernBeforeDegree = 5 * em
+f.math.RadicalKernAfterDegree = 0
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+f = newMathFont("radical-7")
+f.math.RadicalKernBeforeDegree = 0
+f.math.RadicalKernAfterDegree = 7 * em
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+################################################################################
+# Testing Scripts Parameters
+f = newMathFont("scripts-1")
+f.math.SpaceAfterScript = 3 * em
+saveMathFont(f)
+
+f = newMathFont("scripts-2")
+f.math.SuperscriptShiftUp = 7 * em
+saveMathFont(f)
+
+f = newMathFont("scripts-3")
+f.math.SuperscriptShiftUpCramped = 5 * em
+createSquareGlyph(f, 0x221a)
+saveMathFont(f)
+
+f = newMathFont("scripts-4")
+f.math.SubscriptShiftDown = 6 * em
+saveMathFont(f)
+
+f = newMathFont("scripts-5")
+f.math.SubSuperscriptGapMin = 11 * em
+saveMathFont(f)
+
+f = newMathFont("scripts-6")
+f.math.SubSuperscriptGapMin = 11 * em
+f.math.SuperscriptBottomMaxWithSubscript = 3 * em
+saveMathFont(f)
+
+f = newMathFont("scripts-7")
+f.math.SubscriptTopMax = 5 * em
+saveMathFont(f)
+
+f = newMathFont("scripts-8")
+f.math.SuperscriptBottomMin = 9 * em
+saveMathFont(f)
+
+################################################################################
+# Testing Limits Parameters
+f = newMathFont("limits-1")
+f.math.UpperLimitGapMin = 7 * em
+f.math.UpperLimitBaselineRiseMin = 0
+f.math.LowerLimitGapMin = 0
+f.math.LowerLimitBaselineDropMin = 0
+createSquareGlyph(f, 0x2211)
+saveMathFont(f)
+
+f = newMathFont("limits-2")
+f.math.UpperLimitGapMin = 0
+f.math.UpperLimitBaselineRiseMin = 0
+f.math.LowerLimitGapMin = 5 * em
+f.math.LowerLimitBaselineDropMin = 0
+createSquareGlyph(f, 0x2211)
+saveMathFont(f)
+
+f = newMathFont("limits-3")
+f.math.UpperLimitGapMin = 0
+f.math.UpperLimitBaselineRiseMin = 9 * em
+f.math.LowerLimitGapMin = 0
+f.math.LowerLimitBaselineDropMin = 0
+createSquareGlyph(f, 0x2211)
+saveMathFont(f)
+
+f = newMathFont("limits-4")
+f.math.UpperLimitGapMin = 0
+f.math.UpperLimitBaselineRiseMin = 0
+f.math.LowerLimitGapMin = 0
+f.math.LowerLimitBaselineDropMin = 2 * em
+createSquareGlyph(f, 0x2211)
+saveMathFont(f)
+
+f = newMathFont("limits-5")
+f.math.UpperLimitGapMin = 0
+f.math.UpperLimitBaselineRiseMin = 0
+f.math.LowerLimitGapMin = 0
+f.math.LowerLimitBaselineDropMin = 0
+f.math.AccentBaseHeight = 6 * em
+f.math.FlattenedAccentBaseHeight = 3 * em
+createSquareGlyph(f, ord("~"))
+saveMathFont(f)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ad657db6aa0d245a1bf7d8de6ffe41eabac5b882
GIT binary patch
literal 1884
zc$~#mO=whC6#njeZzeH@$qz}4bP_Hxh*`|^Wz<+gN-YUP6=Q^sR=TK8<B%CTlQ+D1
z0SyTR3JM(;rId722xRBRZh|WZT#5uDqPy0bm2p!jq-2cf_}%y3#EET9TzTJ|d%kn-
zIp?19&Yk<l5{WVF#T;~)!|}LmU0R+30`&kM#N&z4?`}L^r2ISO@aX4>FSKCaSCq?u
zI6wB~$FY{hfp%ia^^4=VWPYS$^(mnLO5MqHDtSq>=N7njn>3K7B6uwDC-FL|H=T1X
z*WD*V-5E{|x#Z<MbOl8xr{H8Vm+Jm&;UVQYK--_U3QpxJ4g<y-*Cm891x_4JoW0OA
z^bhvxN{^LWUC(N{zUJ!dp}`yU5$j?dUwihP1-1`bG7p`|(AQ`gpy~%rRdL<p;tBeN
zrVN97w!Bo7<J;ogf$VAV_Ht*`>?HjPLb$o5J&4mj7R>jWk2Uh2eXQdE9{bopy=e1s
z0L|hv9|x)bmX^X$xt(&o6c%X4l#ew&Kl)fl9P>Ul7)SGQ08(`MI7s~&48uYmS70N9
z38dk$hC>)fA9)NW`f-G4lvdNU$nr^2R$ey!)SRSGhG-HPw(?i(%tYFehsOJ4%<MlR
zN3H2hHk*{gmYuikq?55|m!(6F<e-2Ew?H<N%Q%Gyk@t(c@f?@i%q!()6J<UUgQT|u
zc-o`H1Egx+h+C6R+_EQ9G8Q%Epsa2~cr-E)Q3<{?nRDFOrrIk{GOP+5b-79f=Tdfo
z6-m?VkD8__-x<yCwnt&Vvm>e-u59qVt4<q~HFe4=6?LW*udM#@_nUJjg80|*etYb+
z{(*+Jv&pW9?y<`E?Du~ZEMV|W3bALa0Yd%jBIPEO!=l`!mAm!wKI3|$C>A$oHfI81
z{L~Z%n#1^|C5-wo?zO^DE)DGUCpcc1%H`biySr0f-L|&>LR^C`M9+apv9vK;5~b4f
zrIKFi*zDX`ebpH(z4)ztWA^#di`lwRsA#CHUd_~nHfP$3?Zw6hzbuaBPZw7d-*zvm
zl?FT!QC@UI?*0Bg<F3#9fRE1aU^~w=zS%|0m}l$qDz1sKO&_bF8h^oW(aT4~L%cmZ
t$a~4F_o;C2)LN;R)QDDeqWgcd@+{kE(d(j+8`slTdCjA~DBf2EcnuH{`u+d_
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d5fa8018b7666d852cfc223aa9f97a8da95556bf
GIT binary patch
literal 1884
zc$~#mO=weD6#njeFKMkMZS9X0QoW-^>>}xF)GAULrA`o;TEQaXVl-1j6HNNT%M*WS
zp&(c>E@Tkh2x50`oK10Mz~wLqir_-<uPZyd5jr$hZ05V~y|k&Kc2;v=&OP5b_ndRj
zdFST7!J(l+ti=R$nEmm%Y@U964hYl&covTj4V=06dW!N(%He_iLkG3s50jKjfH*#Q
zv^&-`)!RxexqfOmo5&q#n|TN5x2ZdnN+wQg_QV~oJtXy}s0i)~ydj<=b*8e;`I@Ih
zs5!!^E}J-?gRY=x=M)@GWRsizzWajm1fXrmS$U^?8QTG4mg^EinF2p`pL}<+q3<88
z)s-Gk9(4Rw&GlJVUkeT1ppTdnb2#DIa~4=RXvsWuB1500Wq_)ynyTWO$HiOp2u&FV
z*DQIdDEn5#c?7w+$=l1FQMHrwD+uBKl6ET&`&cmFNgr$EH+-yP3ts!!K&@!;aR80t
zM;`~N|CN@)P`Ul=dMPZ>h_gP{_+0m~jyP`m*kByZ#{o#u;o~6nN6-%oIb48^G)9nu
z!y2|>7+vHsnCQU{q5)c6q(z2Lg0k|m>8IudebPjuK);o{V5dh?j@&lfC1YmK4mn_5
zOlL9)*>Bl7%T73Hi*^}0WJwP4h;SQZ(%H0=j}UpkxEs%Lxy`(iZZ=WoBe93{c>qtl
zlepKFy}S{(MxD52k0fO*YRWybvJK(RNN+?X_|0UFabufmuRO`HDsa^0Dis_{+Idza
zO|vIznx_0_G{4&(h5gPRP~C84gYR8++MukdQ&ujkGo^TW=GFV<b0&iL;&^{PzPJ8A
z4ek3Ts~)<?%9qqz{<2^JgKtuZHA@W;>R%TrHJ}t0r4FsMQ7^4GuGNb|VPR}xED*+T
z4Pl@$j9X1%)Q0irIvC2Oj=kQEefhK5tb2Y}cgic<R`*|sN$5gs-V!Mk=f{hpSo|<u
z)QfEk?ejB>?ZM*5-&^O$KTLlduL*?;hRSMjtR}QD)>3FK)YtiCaXj8T^+fR%_o7;<
z!&?#MMc3!v@Bd}|;q$I#Rr8gv*xqCszpNr=%(HcQ1y{vbp^sHjmA~M(=+krJKHi>f
t<elV|`&77hYPHl!s>eFCW8+t|@+@0u(dnX)8`slTc-5o6DBf2E_!qQN`~3g_
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a667b520751c768487f183fd61d6a9b2ae2d1ee3
GIT binary patch
literal 1884
zc$~#mQD_rc6g_WdlGa+%R@!cbR35ghEs{9NYFDJ9QVGjqZNVb4A8M?j2_~H|8No^m
zg#`uUhlnVGAk;5^+@G>v8`#f91V!*qtNq&g=~8K|XgqIbQd3=P{qjxjyXW3_?|t{q
zeR(r9GBSjXn1&8>Ad!%*vkxYKKs|uRiNwg@nY(i{l%G-#4;~o#MGMBZQ7!}G*wB$3
z@s^psHe$*3lcTw0{$Tt3zkq&=x?j_&<Y~>GzRk72NPTH4f<FhI6EBjw(>do{-6JB@
z4RdP9CC}xdD=0cR1;>-Ql>G0`9OY?1+nl!wPUQlA0*nQ&O9*8O9N6A}^F&ksYi!h&
z9uNQQd|Au&1y^4W4c?%SSQLx+&9mn$uzJvvdFVujzCg<WRhKkX#bu9+7l;W>83s43
zc&RA+SH<}oa%+pXmph|oC+SxZ!o3ykk2vgO!F(_JSR=pYV;x<X^Ra<?(dy#>n#DdJ
z2dO_rOJS(o4!K?m3pC@bk2OA5e5@mZ>pnIZNAqz2Qgr$_Nc}JdU?GnQ*vMcEX*jH*
z2czgEkHbU^JBbEqb)FVkK1s^T%ch^2lk~|DjRON#e!|X-r5)Kb+AHH`Y^NNw&S$dO
zq#Us9yk#eyj77UF9daZG1w>T)vzc7RDMX08U&4*&xZGx5DL0!a^O4v?`ZR#2-9_9-
zs^*P^HSQ!Vdn_g6QB&@b)oloOMfxHt!8MaP%8hNRz49c(s=!f~t5k3_WfxeHG|gDl
zG)=i?G{4&(h5gPRRNZi8gYR8++MukdQ&y>{Go^TC{@JUK=S&3g+425#d~N+Z4ejeD
z>mIttD!;Se|5LDl!8a+yhLr{g^{<PRn@|pma;H|_qL+U#E;ou|ad~oiG7!eqrZCVP
z#*LOR>chCd35IfMV6S&$f8lH{=bqp7o$~6owfz_3B6K0Pc14P%rKyrAmEO#j^iunB
z$I|@!j$rBSA8kuhZ)V?4)rCSuLuK`TvM#hd*;;HXHa7TWaXi>N^HA|s_o7;9zzY%O
zMc41%@82^1@p-Sux_Z{Iz0Nd_uOnvMvvqkD*Th(*kJnI*zu>p%-4o(|-k$B`-Q?B#
oRJeC)t<+6w#3poL%NMiqEL&;O?V^wy*V9&c&7;03-d6?q0FZ6^{r~^~
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3dd80a3f98913f8577527bf6b62ff88d826a102f
GIT binary patch
literal 1884
zc$~#mO=whC6#njeZzey6Ng|mvg^64>ShJY%Wg4Ss#7Jb2(lmhvDK50rbjS>y$s680
zA<+Z^LIuZ#h{TN`1iI)(H^G$yU6vxG6x_9Gf{UihLQ2MnPQUx!n>drU8dsh-=brDJ
zd(OG%zH{fk(ed$7?7=*An8S&L3@<&o3IrMf{E|qFk9_m}$|Ch&sYgc6jGxnj;brP&
zKzuR!`H^`0;y{>Ka{kMSTrz*QbL|g6zen3A=~VJ-&7Qx{xyR&zG!4OHf!~QY$UW(t
zGu`kr5gNugH0P4jdFTp?E)Kz|WG=OT<GW|n=K<}*yj5^2-{NDySm(TiP_DqKkF1lI
zS_l8e9$ne7{HXiSTB)zQ_C{#%h%sVAY~X_D&rzVB=*c>CB12!NXMm;~n%c!pPl{Fa
z2~9Z$o3^7=mZ7>lKR_O6_ttVp)T|`^9fa^;+j<C}`B<>t>ps>f@Az29L9F=LK%?mJ
zaR6=Nw2y<de??DWsM<btqZAfs!(|_9d~W$zM*<5zHke2AaR5?u`#4DZ7=~dXj~Up=
zU=nFK+{0l^pqDZZ6Mg6>8ll$}dSv+|sjDcPacWF5CPOp@3|sjbJ2RPf<l%{488`d-
z<%o49lg%dOuw~~hJLzOB`ehlABReP{$_0?k<T6enO62_#Za&AAHtR~c)x=nj#0m1w
z1fKOM@c_A6HxkyAld$Z`l#Itrc|ul~Av_u#h^hkLSj>4YY}4#*Pcp4a9CM{A1?N+C
zfjg3>*%vcSQ@$~q-))a0erM0BZn(O^_pUl^P}kHct5npPQnIr4+h4EGnF!)v$9pHe
zZT>xx_I8(DlkSPiHTL^IHY{N9O$yPp-2kEfb<uJw$`MiS*2??z@(0Gv7Evs2&2G&G
zBDmce0oo$C+a5t<1V8PCp+cJ3>*E+IT+Zd(^SirKUR}1f|3X}cF2sR@(PC+Ht|UsO
z=SwBM)VbBQx%R3nSbFg=ygB!L>BU?_C{#35Rj+0nLR+&P#c;8u+20oF$*IL<CF|}*
zHPeh$5#vQS=-%(|LO=Slx8CgC<~wMCWnA1v&ba66$||nOQD=|Wa8116x9H_l;z8b?
uos>P4)%#SqcWSNHLvF!dbYb8BR^@qi(4)siAvdpQt;(85eNnux3h)m_@B94#
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fb8e9ec4fcb972c5229db675589c125be9205255
GIT binary patch
literal 1872
zc$~FWO=uHA6#iy+lh(GRKeSpgl|_rShr~^^6{I3k2_n`C77-8Dw1y_wbi;N9EvXb0
z1=E9wcoKwO#7n&t@nEnwJqUX7CjQ(i2wtj<6&t_V-PBan7Q~sndEa~U-kbMkCbPYL
zeZ8p01XLK^v6$XD-7*XKDgiu=#rk^A-hVSi`6cCG&;GuHia*ju`6D1s^d8$0tsiK-
zM67fE^k6!kQ9h|-fO?0zL&-$^jABjP<=kUZXOas4Zr@wtc~WaKZJ)1@kx_AgLsdF{
zJ_GeAp=jpdABm?ETfW?zqdWm98#CspUA&5&fJPm32x$sradTULZP#a1t5S~_4_iKz
zb9K(qS3-f?=p*LEJWjgy90gW3S~3rnNK@x%>7(kpBCD8mxp;?&P^6)M-LluOQGi)y
zdC^_V8Ov>SuYv%km$ln)#KVI5Uh}X*e#^ruw&IP4HB^d55BpFj_IcP({Qxb6CUZON
zcu6c!hjSiQ*l&1PMGUt+tTB$_VIOqS;$c7aN6`%v8C-yc6o!z5%^J325bfkq7>HmO
zQ4g)gXfezlr!2iJ`pGd)pA^vu&~0WeSgE0;t#2P}*P}*cm)>KJrG|&&dbeq1Oe=1u
zOxg|8Ax*L|iV!-eNTpNuXo$%D#hiGy!!72OaIy(AA02y0zXou%9mJiaQr?J}BX-QR
zh7x)-Z0LLR(lUe{q0W#@@UO`n=fW1%Zh1Px%D`cV%T#bYVU4mP-7q3y!!Y!}M)OYF
zrJ#4R2jpouvc`RvC#_Ld<Si=}ojXNdd|$ls^PUO+?=I%bw%Yu^HDz^^|KC)X6)*F=
ze^ao4#+?*m-SPnl`L7EVYEjrE3PGjNq82u2lQkljTg)zIeL-BS4FYvROx6cc8N`zY
zsM4hkJFt6gSG%-U`JoH+Llt7n)=)0LFrF9r{MVVhnqR-zyzqXh*`NRRplM<J>&&<D
zia;Qz$yAoI6@kTUW3DMzQ-xA(&-YHfkbK2kC}*nhPK5cmb@^WZtbRiVsD8A{4nFgE
z`x<upHq$t@2D_+h>+ljTi?Ko<Eu%7j(FA;dMcl;~b3J)0dFc%m&O2HzwUTPkfM#s|
aV^*$ZBQ07T6ma6Y+7d78@+;zgNq`@cANK$N
new file mode 100644
--- /dev/null
+++ b/layout/reftests/fonts/math/mochitest.ini
@@ -0,0 +1,39 @@
+[DEFAULT]
+support-files =
+  /tests/fonts/math/axis-height-1.otf
+  /tests/fonts/math/axis-height-2.otf
+  /tests/fonts/math/fraction-1.otf
+  /tests/fonts/math/fraction-2.otf
+  /tests/fonts/math/fraction-3.otf
+  /tests/fonts/math/fraction-4.otf
+  /tests/fonts/math/fraction-5.otf
+  /tests/fonts/math/fraction-6.otf
+  /tests/fonts/math/fraction-7.otf
+  /tests/fonts/math/fraction-8.otf
+  /tests/fonts/math/fraction-9.otf
+  /tests/fonts/math/limits-1.otf
+  /tests/fonts/math/limits-2.otf
+  /tests/fonts/math/limits-3.otf
+  /tests/fonts/math/limits-4.otf
+  /tests/fonts/math/limits-5.otf
+  /tests/fonts/math/radical-1.otf
+  /tests/fonts/math/radical-2.otf
+  /tests/fonts/math/radical-3.otf
+  /tests/fonts/math/radical-4.otf
+  /tests/fonts/math/radical-5.otf
+  /tests/fonts/math/radical-6.otf
+  /tests/fonts/math/radical-7.otf
+  /tests/fonts/math/scripts-1.otf
+  /tests/fonts/math/scripts-2.otf
+  /tests/fonts/math/scripts-3.otf
+  /tests/fonts/math/scripts-4.otf
+  /tests/fonts/math/scripts-5.otf
+  /tests/fonts/math/scripts-6.otf
+  /tests/fonts/math/scripts-7.otf
+  /tests/fonts/math/scripts-8.otf
+  /tests/fonts/math/stack-1.otf
+  /tests/fonts/math/stack-2.otf
+  /tests/fonts/math/stack-3.otf
+  /tests/fonts/math/stack-4.otf
+  /tests/fonts/math/stack-5.otf
+  /tests/fonts/math/stack-6.otf
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..974cc958d322419672b0d7ae7e9e94e354466489
GIT binary patch
literal 1896
zc%02uU1%It6#nka?Bu6m)5fF?G7Z;uEy=^KleJBuM5v@JL5vX$MWwV3n<cxrn^`7X
zXiEYC@pt=HQ2Qk0NkR0b_~e4V2?{NUZ`wBa65k`)Y-!f-&fJZ=R-5$AJA3c<opaAQ
z_uM&m@6684&Ef!7VZxotWaReujU6C12;k>TW^U%~FYc~U-k|Kvyf`;)*v}jXYzq*t
z&%X9t`q0|M2)X3^TiKFVJ~z647cf7k?xlRrn>T{h&p7uj`$V1!`*iFc`6hcJU#eW`
zx<iJp3mke&-jy=US4qV%2Yb;g<!;_{#wf1>#<OLAsnUE8&jXh7mk`Pncy}=V<)!|~
zKXJfRdE)jrNB?L?b0gGu!$8#NBR0h*-i+)y3UoGFG7po?GB;=$qv|6=?c#cb;y%WO
zp$zSwT`v{oY)72$AdfvAtrd=FTS@92#PQXx_5@zhT%ZRZYHkoe(cDA=ziV!xM>v|t
za8OKZZc|^PrLa_PFNa==3k=}0<_4b|nwyx$P0cL~h;Geekm7{qHuY~{3O>rXiU0*H
zAdd?7Fp4b3h-tVO$4RmoT3w?>k&j1Nc?I-Sqeq_t*&;CIm#+qeg?vShX2)dO9X}~&
z{A-0`(UVhtQ1%0_Qt)Y~oaX72B^Ht7A_%<sLe?uLNuysT3|R>=U~0KAp%hb+IK%#E
zj7Wcqe1g4|JTm@bCF2JRIhjtm@{HVFiTqS@BB|2cE2Z;XKERURr(|dqJQbo!2<LOb
z61OH@cRb~~uG}l2u6)#66+fpc6Ur8ApsH?BHq?o0Hr4r3*j)du?Q{zpj~w-Xw!P;6
z2hG^q<gv|+p!p8V{x2IAu=pm0=>59_Lj47k^?uYHQ9o+bN6h*W>w2H4RvXKW<(PvT
z{SI)@!Ka5DbUXNQ0G4v;X4OyQtPZrl1HZd!#{m%HeV9TVJD#l8wpMDQR@=T+Gi!$%
z!&~b+!*=b#*F#$?+qWL9bj9OUOJ%jQ+!b#u4_1e&eZ6Sy^QRZqZY%7#Bh^eV?u!&J
zy~)_GPxv-}&^Wda+mD&X#eLYNBij&Lye&qDzQuKW>VpWy5b*F9l1WzKFfl=F-K`?5
lO}ms}@8kVAjFJD$DzY4;MIvPJFm9x6VcVm=F3}eT_zP;A{R031
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f7ba0ef1e8926316618f657f18ab7616d512c03
GIT binary patch
literal 1896
zc%02uO=uHA6#iy+vrT_YwX|9^Ekljcf{EK$E0hXKB^0q%u!xGNOB$MB(hb`PDlHTQ
zMdMBI2Lz!fz38QQG9aD=g$m+Htrjo!Y^5=x@y+g}CKheIIh&dHy*J-`^Jd@dWN>I`
z5Ve?u3ZpL);f1G#BH(ER@G24+8aQ)*c8c_Q()|N_hx!$L+Z#aF0Csfn@b>V!sqR+7
zoaRqQQ)YT!``j#`-Xq)oc+4DD?8&<{_n3NjoDBLd&wIiP)C2KU=3LcFLZ~`HLruy&
zmxg+XAZw;UA2n04J9DkuNS_3hEoo~kQ@n&7fF}Gon4kg^Yd&|Ks_*@RT2<tUnMW<3
z%B4E**u7BTHu7N$YyrnzK8*~OjhK{&N=Q@ZiRmHJRYmOLnk(4{bTUN{_39-r5oJ$B
zoG0LI8{M^>5oIfJxdR^_ELpeWpu`N-xFWGa@}|Tp0{AGghHB=Q*n_pKUt*o?DPl5B
z<aWUE5}2U@XC+qXxh}Dae%zK=Lj&_l>;Y$6CDzG)41KVW#(CICU<7ewXb<g(qJv}@
z20GD2Xn<H3h>@hnBwcvf<R?axd=i94fj%pJ-cF3fGrT?8!NW#p7ay=LB$7#!_gQw@
zvdv7wBA##>CZ{OLB!aXMY;!mfHIqSt?l0nm%sA4f)M8FTAxep(hx+muu6-xrZbx^M
zN5mS<L@awG#={|l_wc2a2=5Gb2Su7IrF4Xrw=pL7$tko59&)5e2uEV}7;TLkMrX({
z48Br8S$VgYD!xxt#?dvZfvCDhx*|?ou_(@$kj1%oWv83zSa#HZZ!69J2TfU-^4F%i
zqIglf=H(k^(CAGvR`aU@OnidDd_D4hmTyt=t!jRQcCC(OvxV`(xW|v{^?qQjAGg-|
z;q~Kr12o~{rK<139vNtL2YzYQiUYvdWvGm`Z4PF0ixWAP%YB{Bsk!xq=Eb=m&3f+J
z!=}ZFuhZWqs(ikzCbIf5Ugax{H)fl%bu}pM^TqC|86hj~NHJ4`4=hBNUa#lvKfcXp
zQg*C@dxO$Axe8v`<vOy2%VJd6OIS8>r*Aq+>ofu1Uz4Gis<579fMn@zWln9%wE*=x
fx*wa-`p2wXW+O2I4)Qs1U292}Jt7nL9|rgdQsMsr
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..850eee0d1e199446581b96376b0efcb7360ce443
GIT binary patch
literal 1896
zc%02tO=ufO7=5$5TFXDkiLp}?WHY2{un$t!YT`iRLV|-Zp{@fpp)IBDA`44Y@`|+r
zNwC3CXh@Y?piNEzpOQ;*2_c6H3cVCsNFnr=rZKs=cNZ%*jrwMH<VsCjySL7I=6mza
z`@VUjZ#*-zvoq+%3QRbYnT*{2b{jyXpTpx!W_J41J5N_RU*|kNeR_7vu!l|pwgrgy
zX5KxL-oH9NOf0$nNw(yc&y1`+1<c#@oz3UmIm2JM#kH^5$Mba9$0NTGZ?GrwrOL&Q
zABoWMA&0J#d$A1j9HAKGU@y3(+^y&G2<Iz+@kZHOtTaByn}DU_C4`~^7oxG^$GsE3
zq1#kC@#w+OudUWx5ByOW2peO>hS<OdA)li_dn1!NOd`u%Co@9V7lt~;wa|)Z7!!sf
z+MPR5D$A+1Jl{YbIvDO1jA+?O>J!9pcgK4e?`SO0iK`kLv|nj#B7x@`Tj&&VjU(76
zrZl$cFOexMrS0t?N@0OMT+rCycU@x>Q@E+Ig+3A0I07jSYi!g1J|^Lzj7#uQz&!G(
z@C+l!Vw5%w2V*!&G)>lJGK&0M&Q+ApI5oPADG)6HlV16fUzpEV<Vbc@rk$~)a@xCG
zC>C8g>G@^PcPj;tJQXy@pe$_>Np%5ycdn3ii%G)pFB7D!1lFgtTp%b#NfIa6U(FHv
zj}ecvH^n34EmSg|KcAE7lp{~bot=n}CC8IW=5CVCb9*0)`ka!fRq|9|l^~qY`HMW7
zbeyr2<2Z7+gu3!!Z&v(_s!TAqSOZmci*rNWxJE<WFJ&8RKeya&VdIsn{@1qK`v0IA
zyHozPnW1TX#<Ks-fdwr7l0tO-SplK`1(Wq&)Z?N)WYmYv`fJv;9#O4sEp07D;<(-$
z2lmBrV}BgcIKJ<Lr9z^t`f;4niS~BkcXn;N076`WDa4`IlhxYha!u4~FYedO+JUXX
z&9#?<c5VCKz~=Ic``gPMu~^kos$MR2#I~0Ds{_@ZE;P^i!&|G5lx=$>)k+thi4-5b
ziO7@x_-lTr?dTr3UsA?Ld*G!*ZeW|ZB}bcI<L-yya`>imp8??ap9m&cg#)w++UDCT
kg4(ps66`&E9|tk~kE%juKN*Pt#e%${w`p5GrKG9m4+a|j0{{R3
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e199f73ae9ead4e3e9bb0d6552f11c9e4a808566
GIT binary patch
literal 1896
zc%02tO=ufO7=5$5TK~kzj<Hh{6f-!Au@6$#s^dU#Ai+VHQrCeRla$hAk%c89dBs|V
zB-mgmv^2^ske^e*r}olbLQfU+&_khx6hcq=vk3+F?qbDGqP*E%Ia2=Y+&Zh7_vYL0
z`{vDlqnVtVn#3L~L5DS#Ov<OfZ3!UM1>kNnIW=+Nhlk6YuW=rkI5{=0nZpkN(*VSo
z$xja__AZa~l1sinpUT^XQv<6H0sVX0KFXx+8O>e#j_-b9AIZ>Q9t}MrUuTbI^2Liy
zf03c-a}KR}`(gq5X;RU{!JM=6>E(a=5}Ypq+M$9oU#xzO4*^5PO9<r(<i$OCu6^`B
z?9r7@-1+&yzxAlEdG=;#@Ec>qx>(0&zCTBS#zs%-(8&yajh-Qzu4rl(SA7&K7!sOt
zG+VZ#RF)GBd47fL+wZUCji_5m20IAj$8BprJ_)!$3%(7wM!XSl9Z@_ExPcZC33vz{
zVm#m`?Rk0%Luvcii&9*m6JG{g<8v+GI>vD;;08KHbHGE8qCem!?PoCt2L)V$i!5f5
zL6LhHKnjDz1S||;m~4Vxm+6t?V{@*eT*j%<W=xiB4j6L^m)z`ZrYHwegEC<a4a*7V
zayFN<<(T6Z9M>*p9r~%D83v_@ImEaGTze*)vU4#~|CjVq7Cm$+E$s=4Q<B6n_SbXx
z_9NsY>^1R7I&;OO<IbjKB5uiJa(gB6Be9W~lDU(lX)f<#KG>&ZYLz_hp%R4Yv^&qO
zNy{3FTb3nvN*Gk$@3o4bQkC)M25X?IZg8%t6IZRO^QEx5`k?M~3lpy$^;g?Y@Bar)
z+u7xvP4}Vt70dpH4GS3jl0vk;tbkB|!C0jom58Vu&?>!p<pbktn<$kw7d96{5nOAJ
z038wB+#5l21b=kGP$A8%`ca$+67BB5Z?D>L0EGAkx)6N_W2N%OVp){SPi~j>^1jWU
zjn(HpW_jzU?v2GKx3?CX!r_vkR6Sp43U4lSmAXr9t*Gtu&*RH?6gJ$E>P;(FM4Xr2
zXz2cXe$C$l9NdNPb;|f+7k&xf*TWjG%h6y@yzB=DyxZJsq8oVjH_0fgu#Xre*6vo}
k)uw(HWpCsC*n{4;s`5R%=n?f;*vso%YgqRvB{elK0FMX$0ssI2
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bd3351bb4c741bb4cd22153494ff1a97e48dcbd3
GIT binary patch
literal 1896
zc%02tO=ufO7=5$5TK~kzv9S}kC}v2NU>~Hc)!2cMLV|-ZrLF@tAuXlJA`44I@`|+r
zNwC3CXla#OpiNH&Lm<60m(WuMy%Y*9Bv5)w)0iCU++D2LNt8FcBS*?l?cO@8nfK<~
z@B8M>exsS1o}R)kEWv~`o=(drKW`d9qz}OF>GbsE`S0#6bH2)XZ1TkPgkkrb18fTr
zXQn<ll<HX?8zh%}e=bvWODBg`?g8cv+TP7&-5JAQ`j+p0WFO1XU>}M6MZU%!&lSrT
z+wPE|?PCs|MfYL}<|$G!z`>q#i`nac$45C|0*nJCZ@ygr3~vLLikA?|6_|NE*n777
z*gx21DxJ9f!@h^jXs!nKb{Gg7W5k+R!$+Y%M}gKxPwFtqEOV8f5t_a<)Gn@sDDGoK
z7|PM^*osnFj<@9b33C6N;ab6nrj?}LK@{I_Sr6iU%>_E}h2{qFYt2o>@j!D69U`WA
z1iQtA<~Hp`dJ0QvdoPGmT%Z>hG&lHM)!f7czR}!5uV~ji0x1q^ZqxoD#^IraOYo7$
zEOIDw4@1acn3#ft5gaC)q}OG76!^HDt0<pwYIGTsCz}Jtz0xH=KbtGdq0F#MIU|SV
zq<1-AD7bRm^GlxZmh&F{RL~5AGQ<KB;DPYnnS91ABuK+wI!IX#(5JL)ASg*m5=Yrz
z&Jo&2$;a3m;*s{|%4yG^&B|2Lkw@j$O5~%7v4oPjout!T-p9P&r(|lCJQ<)8gwt7n
zo?DZSGm>;1M{bu;S3c~Gil0=K3Fa1SpsH?hZm1JiudDN=u)gwV)9DsAUOMV8w(Z{k
z51O&P%fB`=g!-o}`ztmqVDU=|(fParLj463wQkg6qPEYd4VtyR)|D<%scbB4EJR|s
z+8qOS$8fDDhV~eK?S-X6+FA7@IIa`z?7(lW+HwGd_#CDX``=1bs_TnYQLR3@RW+-7
zHU`#Lo(|a6&71w}i;r$?F1AIZ6-%jly3iKgSm>+tSGqdU*ynHWEZ<hxa!0B+owzTO
zy!4Jm?*7NG`HRNk9r%7l8K3OHFBSR**x*e$TI>z3TX?5)oqpiSA0%(E3VVogV&iTV
kL2a66arQ3Wj{_Kdt*X$oj~?-WMT5MdwSi5KQqoZK3_d6Q0{{R3
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b28a85d700acf6577e4c48e1de2708adf8f65d00
GIT binary patch
literal 1896
zc%02uO=uHA6#iy+lm3!wt+hy6h8jzINZdwkrBqN_LJ?~Pi>QdYq@f8W-LQ?&mKF+v
zfAJs`{5gowQ@!X#JQ?sLf`Woqtrjo!UP)}B@y+feCjPbFoXyPl&71e$yti*MJ2X5z
zgc{63h29qm@%0yLD&T4W@GcY@9=!N)ah~SOH1`f39v)C!t@i=92C!2@C-wxl&UdvC
z=d^wyoG_C8?MsV*x<Ilc(TFjkShEjk?HTp1C<)x%u8+i5sQaRc)I`NwVyHMvLv_NK
zNJ2eMlr_=d9y1b=g)eOfXg&)lyOZX4Dt`rg0ZrI*Frf;Z&1P?%uj~Da8db!JH&2_t
zl%l$9%PXP4X=KAz*b2@#`ZO|>H`1gy=uJRVmr2t_q8p0H;--V_6FQk96x~%tE8*o(
znV;w2tvj8)>=7k9ahZV!kBZVZ9Fv@(3fCo92=7R)!iUe2Yp7yg$z9mO1|)ZrJVBaF
z6R{n&tpsPN$0f-XdgdfoF@SrLYp7?HlDoiJo8)eipGF@{BrypKF^nRL6y?y4Fggf>
z(9wx~#0E)giZtT%7&I4F7TJl>Ae$JmF`&;(PFk_iXo|OoJ9tp<+{XvasaQO2@IKQ@
znwF7@nWQI-M#v~k7>6HSBr--~VI%G*>ij~s%an~4g%+^`3Q$NKJ=A~o;mG&f++PeH
zA#*GhGOf`F4+eDJ!;3o+-|z48i!e6|=_GA$VO-|P$+d7Euu%krlM!p2QscVb8PIi|
zZ{$!`-sy#k_lwHdbB$^ss;<#o5hpI67w1c0e(6KW>1J;Ha@2or8?FBbP1#uGuT6Cz
zf0@eun}iuOdXtP*|EK^He?fn)4mmH&H7mImHMc{%S<BMt)#=q~mltz&USNwCcei>`
z>BXyhXu_nDs@{!5($VG)d~w&Z1Hjl-sEoDl@~1P|nGDNhzCFpPna0(o?9zIZJG1t9
zdv@mAleL)&k0-5(sMe<|Jgd_U>Fw#-Y83K(eQ^Gbz_L41tW@I@3(%$4>w5o>Z}X+Z
zj!o#^rZCQJLNDm(+F0NvKFZ|5l3rrJ?V9AhRE0)DA7SBcWp-^!XFlq+bU!ws<&RN0
Ynhm7kvzf>C>qrY&@`$gC^MwJv1C$N@0{{R3
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4a4fc99c870fdda2252e5ba5a40c59c38570859b
GIT binary patch
literal 1896
zc%02uUuaWT82_DnZ_+=O)Rx+nEtZ3er4<ryV{O58;HZQm)(#A%il~<~G+{|^xQ(FF
zLSeA6#W!Jpo(6r|7;G=Hrv-d-Fu{SZvs!$q_#{*sTQL64y*D+{xz;z&%{kxieCPLl
z=lkw=a_(d@If*@3f(~;mk&xBfTLuv50&p*pNKSn5%gQq6Yn+ECK1+^kfkSy9NRF7E
zJaahSu{_*MEV+IumA48f`d3!~{b%Y<X42M-<}CfhwLjU1GgJge0uPAS*&~^J@k-M_
zL})tCp*3$^DM0_6Q1oyJ&RO~NuTT0v;d}|u4i@bBV)ZK=0Ssj?AruuzK7F)yv3>Lz
z_UI~3-2G$!<9eyDx%y^k@EUEzx>(0KkIzw{v60C*bRt7vBQrqNx0=f0x+ld$3<^yV
zgDu-u%FFQvKer$ceCX}vj;Py7`Wb}q+qSk3r+qBYf^U4RQGV}Z9T7b8v4Iv5_Hh7v
z#kh}y)aS_*hKlW!Yo)M2CocO~<8#BuI>zy%j}3H+W*-M2MW2s@)Stx|Y!q-64zid<
z21Vx3j}!(d<1jIZA)*Pgu91=BV{xvm9NMYTqD_`)4j8iwSDox^rYQSU12S$74#^4o
zS~i!n<e2RgY{x2QZSs`S42@EhIYco+l{J%1S-B{o_e;1gi>`DSTG|aL#*ieAvA^lV
z(;p=sX0HX0ggsYG*v@QP#$%>DCbxGYJ{ld4sxWs7X^PuBnD_IPbgi7nT&V)WRN9$m
zYSJ_ZW2R}!ogDg=_j;}3CsbwJxxpH!svDeZ>cmy6>U=3#UA<p-x<wFg9QD`RPV4VM
z({`r(Z__<d{gP$>kAwvbzDXfkUsXV;zhJb|j!IZm_G^`1z4C!^y-k!#n+ux@fiP~g
zhk?Ce{Lm3ba~OYj!cZp7tojI!`;K;Z;J0^eH~>O?4PA%>A4f~&jm5Gkm!ID(>*emv
zo{iNPJ;CzU@B20upWobCYzl=+hKlONLQ`mSp{um7)Yghxo_9W7zN=)z9jR7Y@leEg
z>5T^deaE-?moEo)!TpY5T-XIK?r~jN!*xCy^zpi0Z_oD8G>1`Ep_?*7S-V?>Tbue>
iguRXTV-I@Y8kNWFA|v9Wkn7je)@0qIzAoMu26zcfi2VZq
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1d70be6130ea7791e28ff2979bb3bf8ebb2e7eda
GIT binary patch
literal 1860
zc%0o;O>9h26#njeZ>G~9Z8dFG47p*HhK|=k6H*JBOuA4d8o>giopdHTeUmpMK~$PZ
z1S1wC#MX)p3xb46ti(dX#!mc%1z}m~AdK(6_oim3w6^Y@bI*6q{m!}PzWd&tfx*E6
z)M5fU%-(2JhP96;0bd<}`_brN|Do$IuhM=@JJ`Q@uut<ZJWu-_Aa)PzToajpusK95
zIe%a%6-#5D{s_>o(YGZLj}8Agd;Biv9#FaybZ7&<SHzQ)P$HE*QuT}oRXrR6so0S;
zwC#kVje~zImWpp#ec}S`2|!z(wldk`DXayIPn?$!iV6(xn3&k#(DNC!`g@h_>7B(N
z%C*-5&^*K#F)1do*X6sOibm#kXM~}@C(}pctfqEx&eh^Ix`d`E{_5$d-?IP@S*3K>
za>jCw^mb5>8`Iu)Z1b={HO_cgqrU869U;8+uz_k3^so<&qR+#A`cq^IL)Es`iBedg
z35Pwbv0wDCjy_!Ruz@BK@UV}yw|m%6{~q+hLK;V5BZ(0tkmVj$VhA175t!)0I--8E
zj*&6S9;2<IY{scE#+W407|?5_kJ`zRL{_dG>W~q$Yn|-3jwMG&W3tz>)0Q2}CN1(Z
zTtF?DW@rYTTm+dRJDJXAItkrh)Jd6jw9V4uPC;RoB(ah5XAalDp17M*Djrd5EE~1#
zk+_V6O}SA{uSC4Qv%6E3Ia^7)xV%ljyHCl~DtXw^svzu&+Zk?6nr2tnG)*~MLhs~V
zDV=zaIvK|{R8EeDW6NUE9gA;D@0IY+^m10V+2;R)rn{<mlE*#6h6M~hK_O~>J$a!%
zy;X$<6c&j>P%A9f3k!^Mbt1>+3*vM`5NHe{H$R9#5VxA3tAG_e<qdOtyQi0`IBfw<
zh^5PN`Kj@|$mhS@&g=QsuWeIrezf`X-)^={jeoiQZM>?!{_FAPTuZL52BrNx*>v@(
z(iL~0nyJBS5$2`V<9qRsPwla*YVXZ~dx>T2n*%T6avfd5WjQMRkuoWZ7cIc|=TP54
r0Ik#^>eAh*dZiVj)bajn!;-&N<uaSe2sx<U$?JMcx~!{z4<$bVwiNCS
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..13f7afcb5011fdb18ec9a7beeae3dc046007759f
GIT binary patch
literal 1860
zc%0o;O-vI(6#iy+Tgs381(1YdCR!0<TDBEPBzRC_gNX=<1kn(+VnZ7#+iYtB1QHSw
zqm-Lb<CT+M^dQlLHt}RQnBc{mQHUNedc;s5Qs3-uu>}>*&UD`U-kbL~KRfN}>FGit
zCLu#@_xpLH@@)#R6#;nZ_xE((c>Hme<av^vohN%bBzwaJlD`0~uj_oHuk2cdi!i78
zs{@fh6#L{ifc%Jbr$WKN_08$=7c}>ZMoWkkQkU%$;T0OLP$WK*_l^+q+K4zJfsrVr
zZi1|uh<!K^37+;$-XnPukPb(+SUi0T#{lI!&2une3iO}pU%pb(_5+3TvWT|uy!LB0
zx0(Zzg~*4kuoYY~?M+QiBg<}sLXnrr(ni9xBvvtFa<&LBlZ1&qf6Hro6yP;g$<15_
z&9>pz3X1V$OIwF?7G}uD9ScjuA6Qt13!g2lAfGucY(pvQu&|x<5wc{8sO_xbB``xd
zZdzEPe%Hb>I`GiK3d)(o!ZxbC&cb%mUqm}JL@^2-VGJUKIIW=`185-bg9<O22z8Rx
z7+DNa50EUpbn+84Kt5qY!$7+h9o55wp*XJ}Xy888+r&GyvGCAPfVXRURMP|Tuts(<
zN+1$O$u$NyB|>aK4@cuMH$n5~H$uh@u2X42qaY8J#L-G)XAD!{Ot{66&EnzLhU0!s
z9}IGzN9C=2D-+>ncZ*w;xm!uSlwK#jxlT@@MR1S7MM3Bd>M>dxS5>b^RaL%QK<nhq
zkvZ`;aWaOih?qnbL+0tUNz+T2d&TU3x}3RfxB35|$tFuriS6CFU<QSDkg<Z_JI}<Y
zcQjRkR1HfxrBtn)+ONzMu>>`n6Sqs8K&canGAA5PJS&GR9FEW_AK%;U-b$5o+6)q7
z2M;BZs}o6<Os>r(<z&@*_3F}QwLQ7<v~qP~ZEj;Cuef-9ydqJVC@Mf^J#SCUE(o6U
z28x*iEHV#0YHhX;|K6mUzHN$mi#P0HhwoDvm-k@jGi?o?!C5hK^uDZ-<<BaCpYI{Q
t0|%;zyNGArPSJBE7mXr%|Eh7|uT`0r6=dNuP_Yr$)Mj{A7ylk&`~q74?hOC{
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4326ead245fc46044c0ab9d42c67ebf1487aca5f
GIT binary patch
literal 1896
zc%02uU1$_n6#nka?BvI=(U@o`Yq-@_l84<+R*fJjD3K+IX$l5uMbu$kvP-j>Wp)LX
z1VRh7y1oh4J{9uRzSI}#lM6ly7AzFs{0n_a!N*9}__O`)%xpTVZ8wkJ*?Z4-&OLv3
z&e=PYQ&W@JgazoZ#?omy@Ot+yAkquqk92x!;;WyZERtU)ADcKlHLjT-Uj|GA5MN9l
z|0K0#ab$p4a{p|mU>A=JE<FMCpC~(;%i8BOci~6w-QgU`QD7d3JSAS?jOPmF3vIs>
zq3slx&VqfR2>o+H(a*)4wF}vC>+7537XWQ{(J7Vd-(oLdD0>N^RDs8@pWivtJ^BKh
zbd@I_{JP_>Fx8hmc{?=tgEnGCtl*@t&sCs#P?LG+M25ah%?L$THFb(>J{8X}EHtHP
zcC1?|FNd1^+=blvksr%j5sD;(6GZXLx^xdd3$Q>3t^`;k{XW1t;`lSb20BD6z!7W~
z;{i4)FHln$Dz{^vmBIo&I3Hk*&-DQ77{?C*Hqay50~~=Adjf1y{w2oXpooibk;gQ0
zDDw=1$Y6*x1q;L2M>IjLOVpU*W0O}_F74E6(<V<e3ye9%i*9~8SC)gBA(^s<_sI$8
zQhsK}mSc`vbX>cfcc@ol02Q!E(-IP@0ZJJ+Uo4jrg#It>xh#9sWolV3p(In1ILP_F
z4`05Yc!aZ&Jkri=IqkU9S(!>&@}OLgM7%#Sl2B>3O6df{yOjIqlyt3}Cq1eX!ilU~
z;?bmK4JR$jlC2yDmG@_(;zv|vJl<dpRMidgn(DZEUG<lu^`*z5?iMEAYxQ?WtNjmP
zXsuQLcj!K;f5Wo>%Yg+9zDXfE|EYjbf5Akp8?~6I?a*oidTqOLtxHrYYjbOJkr=Lb
z$AHZ-+}sjFdkpt`U?`JzR{a1Dx%Rny#-7<&!>>neY5*ZFLl<J_u0*A}I$ssl>dV_z
zy}E6!e|70?zgc~Ct8aDw<?UDVZP94OP+7g5Ym2VU^;Y^SU7cv0^S4hIA1K;%N2;Ap
zJQGP?dZUp?tzY2Q??TMIfDUco&EH@er#GON@^wAhz#$(^@>FPs>_s2&<{|MYtFVnU
rPTIIzg;$#}7w7Ea{n(Fz|IEtQ?4?HBLs8GKFKy7!qrNWw7Y6tnOkDsE
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f807eba4d8d01b05b6396fc65a6dd1ee688d0428
GIT binary patch
literal 1860
zc%0o;O=uHA6#iy+lcu${T3Rg_WzhIjq;V6qpwxpFLc!Jw7Euv3*3bl-?y`xXVnI+u
zjW<CNZ=MuH4;DRWz>|0o>cyM*gB}z;RvHzJ-|TK`;$M4qCU4&N-n{qby_wm`z~JBj
z=HMiBm_3PvjD<d&0s@Ty?k5t1{fBS7xJLOg<#7Mz!Co!6+@kyz5W5C;tclM**cu_0
zoIfy>P1=~NKLYgY)NM(pl83&ZKXH$94@g~UDzt&XOX5jVB%RG4t$Rv@x^51kZ1SiL
zZ9Ac8=MWrCW>Z_^r>{~z324i0E0-^y!CJuh$ax8&Oo6@)dvES<?*4>1`a2bE;_l-2
z)!c6(Xg;Ekm=u%P<Jo(fnnug*?g&GFN6P?(^O~ySg2%-x#Du0yg7wp0zeWKbGE3>L
z<&M=h(yyQix2Cl#u+7H;^*HBajr_8Ybwu#S#|G*}*vA3P6TLnTQlF)zFjQ`Ru9w0B
zEjZ$1js2pJb@bwjj}5elkdFh*eT9#M)bB<QEZ8^(2N?__jXY~ug&}m1$6+FdbwvHN
zI!=ob_9SKH<<L)!N%~}nMu8s7KIUYG(|NgSs6)oh*gDy79nXx6BxR4~*p`#bXDr&~
zxPV&FrfUwJTmrcvCu8SxorK;m;fBn+++k`dH=!s~lGsT4J%*=WPuxYSB#(qOnon5H
za7xCbrrao}S0Y~D+107ioGGQ9T;8GHt5Y(x3LbU2N(ehsPL8EX(~Lz;)08s>^iSTS
z%87TYlW}E3#pGzXvMiUqvHZGnuSD=qm$SCbH2)to-DBlbJnlafEMRa4g=qM>^Fn=k
zt4qx&EfS@$R$8o=78(~CMS(34#@XgDFfWY4{4hdc+-ZTX99Hs_H_YyKPcKz-+5(yo
zOP3XjQ)5L@EPfs@>cs_L+NWNBZx0r~-fo*3`#k=2tgfl)%Zb)PTcNQ5m3p3Rx;CMB
z%^Rp@8t_U)`KWaVp8viv3+;dG+GC%0%wmTxF^zq*u#0=PF0bIK7&ZEM6;=6*HsISc
usP7<z1>_O(%G;@WtrQ_O^8IValD}r<S+>$5;-V%uuBWZ=s;>S$6#W3dtnLi}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..018d270f1c4f9aebf404f7b496152db183f9a812
GIT binary patch
literal 1860
zc%0o;O=uHA6#iy+lcu${T3Rg_Wzbly(zuCjQK<*5gdVIdSVTRjv4$qtbi*csEfxep
z)OZsVFCIMUMGuM|G~h`*2zv1*+M)+VkCjG6<2SpTn)pNO)tS6`-+S}DH*a=!Cj&!6
z16YL9&|&t*VlrCy;SAub2k;;k8|puP^VN0QPiP1GcMSDu{w<qmzXinpfxVleOOG~(
zh$ZKb45#B6EY=?b`VIPaCKK^v-!GiH&$)+`?j#-BfbTW&3?-CI=T6o<CqhjRhd?@h
zG6QXpP_%OJkHyo8J)LK-(LN1mYcp0hS2~N$fbo&@5<*ddU6IXghZ}o7VUhk$WqWpS
z<@-wQwE#2^F-FXY860%^uBWPzIp~Zq^mk<XXk5_LE-t!SOd%pPMe*0pMg5uuc*H8D
zyOuLna-_F|2HcwSwqcKl1!{5L!y5G!59<iwjfV}?ilB#mSR(p7?596XrZ7}(yPYV7
z1)6Ze!y5Y~59{c|RSz3z5&;kUSbLj?{q!F|FDzs*4jU<qAc-9JupYx`r;frz1f4|v
zWKEDU${we!qHM;gG0vD2(HPKcWybB)NHQna54X#x8R?Y$)<kM_G%kBBJ7d}LT*@LZ
z%LUYe8HQ%jfiAj+?Nlb0?I3i2F(+lt(Kbs<I0c1SlEgO3?>St57jZYGTs&gdST1JS
zBMBJ|n{u0+TZy=<qq{?uIbTWpxV%ljyHCl~DtXw^svzu3*ja8(nr0+ynx>pDp?C7G
zlux`zos44}Dkn$7v1O^`j-~1HdnNpTdO54xeDnW7(_K|M!{h$Lh6M~hK_TjXK6#-&
zy^Y026jz91P%Ey~i_49R^&-#a3*ua35LgmKerXVaAnr6lR{`sI%3BxqcF!$Ub=m@&
z5UbbZ3$v32Q7C-AThI&3zO>Fxe{b~{zTR$`o&0?F>tszs!<SRd`IdZr9m@N8y8Zey
zrK|2hHB*Nv5$2`V<9qpU4{bxy1MLeSUuGGH7Ql<TTt}C2MUE<ev_dN4MGNrl1=M#C
qz%uF(b@}d8z1j*<>UsaQV%1-(a+%F!gdEi1<aNDeUD4IQhms%fnC%V#
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..963f26179c7d5fdbb14ac50eea6c3bc94aba917b
GIT binary patch
literal 1860
zc%0o;O=uHA6#iy+lcsHKZRsDF%Am1YC2^bnfF&L@5PGn-VkzoDjWsmErW-a9+R{Ry
zAhqdDP(0d`UR1ECpaD<fL8upRqAdz4daN|I*!X656BDhpUY*Iz``(-Hy?JkEchb|>
z*Mo9QLWUX$26?OV%M@U90(cS(_H|#n^LCE(7o@wokMwm(_P|HdKLG4h&&h+nstYx4
z!kpI655z)oY?Ge@@@=vmjf6uN*Js8b(b`iQ9T74}J+^m*mua{ovE)d}D?%vo)8vSS
zM&giq39<&7?8Bj0_(aF_Ez&0eX-`~BB(qo03MgM`or4J~;BT(Kf3DL14dwDD5pCgN
z<L5$YH3uXMkq=vD%Q$25O-oTDX0I_rkv|dBM#_vNs+ct;TSN<!1jSyO_xe2w@QkwL
z=3d5J$l+E66}X$XHsQF18A@^0!V<|F7M9`0dkZTlWiAWbu$^^T*iQBsF_|KAJ7#zZ
z%utQX7M7@Av#^XV+_bQQYUZ%8jdE|Yu$}Cu5rBp`Mxi5$K}3+G8unoT%_MzL(SkNY
z-NYIr#t`)o>B37VKQV{MCrW4-2x#$9Jvtak@_hr%+^4p*@osG_Iy4mG0Zor<dMFvy
zh?k%Z#D;NlO~8W=G7ad_crxK3X#Rpm$fO~4N-b<8<fW82I%)hF!?d>>*pp8lL2Wo0
z)bznH_jy&`$@4oAZufL}M4FqW)KA;%WH;;N6j}uL8d4;L{;-~)(zvR&cvV&9n+3E^
z-W<6T_luJ;bVbCZSuu2;&6;y|DfeD6`$jKkaocSDKWMTkvQu>28x+i-&=X{=?AMcL
z;?p~jsYGT6%ebUWqnxQ%W}PfW&E~>%r3={ZLaNFIhYJs?Aq$7SbjpXe_IBsDDmrZj
ziLqU~Q|Xn7G)t$y&!^>d-D<<i(t3kEy>_p5W#aq%+C)i3#p-xXsy5{;L$02ehvycA
zEV={5N*NZJmo7EG?ajYEwEY>N{4s&%Es(EM8fUk_^O;;j=5RrbBD=3(6!^1R;Kyr-
t@4$gNl5Uc@yHoUH%}v8e_g@2c{xvI;SwjrBfhvr+rZp!Ey7>1H<0lj{?+gF{
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..98f6634187e7721d4fe56e735be23fcd80b3f6c5
GIT binary patch
literal 1860
zc%0o;O=uHA6#iy+lcu$%T3am`Wz_gnq;VT-{h=PT5PGmyFo=3kV+~ET>4r@N6$^sk
zPvcEcyov|C=t0qg20Td*f?m9dKj=ZxW2I5i_|5L7CR%CF&g9Me-kbN{yf-sD8HmRR
zFb8L#!|aX4WLNOhS-{r_;9)El?>~0y)pg3_ltca7;(eNb*?G$E0kL;r_qyo(!!2QA
z$@xQrnM4+I^(TOSle+DxWa7xrvC|JY_lVS;qCy++y(XR@g;SaQiMr=RsO#Yn$Rti=
zq3t3RZ5;d~iA*xSY3v5&Gk~@-YvuCgb65`;pE)lflqt})Z12&7O+8;QNB^LrJ-ff;
zV>S0$0GfyBBPPTI_Ph43rl!$ymovi9KhV-gVN6q1TynX1gHE9-6My}b*Pl^<$IMc?
zYdK@Jjr1xA;`Wqw6?S@9pdJ@JtdU>!u#Pa^dDuX`2zl6td7{t5e(E!{6o$%ehvTKN
zKr@beSYyBJVI6(A=3xWPBH&>kb6@3QKlS_23kzACgpD+YkV2j{tid4K$)hmQi7ujk
zTAiZBFnfZs^0Mit#sq!RL?b}2l|5;vhf;aDX0TmG&CV{_Z=FgH4<}@=WoIorkxyH+
z%W(m<V3w{qbYLS@gLXQb&vg*GznBv;?{J%`C7pyKOi5x3>F*e>egkngsggWm)<`~P
z*+WSgjhJ$aoLY%^Lq~UqN^_=^_HcQddbdu=&?<Pu;VL2QN!mG<CQY+5Vw$F$DWG@q
zE>%vvN1co#8!9G8!;xjV?2hHPm3t-p(_PNmHq-on&~%rT&+@pZDOkYZ4hqrmd*_Av
z^wyS|P+BZXA+5ATFD)`IHHre8FN6zCAz)qzh4~=_Lb%%uT{*1gDQ}+L?Vehy=ClPg
zA(pQw6emZEqFDTTuc#Lnerub2`?Jko{C=l(a`fxH@1u3W;J4E)h1No211j}A-Fp3*
z;x%uenrXlr5#giO<9j*%<}A4Ik6j!0c>64N_zKfFFblh=YwPd|u8L8kk5*BYzi0)1
vyny-+0$4~MCa=7ms@F<kQX}8LHZ1*TR<30WEy4~8I&ocXg;#a;@1f`y`t9xw
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..eca5ee75caf010968c8238de01e9b9cce1d53433
GIT binary patch
literal 1860
zc%0o;O=weD6#njeFKJpkZ7r=<jB?S~AGGl$+M=Z{#zN@ATEXJaEM|-~G{L4XyhKp3
zAPAzSJ3(>lMrWf7#aYY*Tn#P;oXzaSA9SJUveKxG@w@Nc)Wjd!wfE+n^PO|gIrp4*
z-@6%~m>9<joP`N{B$1E<ZLiM(fo1@ICK3~4$A5o(o%#dn;jy15MvY*shx!XZ92(!h
zHNNs_M}$~%{m5iCnZr-!-++0Ow%zGe^4P~qXa3;YU!=h_4aRuj3GqBBlFk-RHvCJ3
zhGDW$HhD4!V;`aDA`8wWv#Enab2q4;1&mEOCts+X$2P!v!*vOvT!AfX1|q+;4!^|;
z^QFr6@ZP#twNj4|42>8g=EXdI@%?>E-Js__kHa!w(lbEilA*eo^QCx-m@t$}uyHZ!
z%PhcsRw@0xJYMS~bq6iDwP@|eUX2ABaZzJ~@~XxrB6zN`g+>w9IDj@Ws&SC^EIoy#
zYTM&QDJ;;A6B-+wmo+vqifbBMXcr-k1FXGU;~?#aF#-oUoPvuCrjSN~J@jG{eUx$7
zh+#X?7`;x@W12HbT}8Q!Q#{F-4ABfQ;^a=bnW=O^_D=T6xE<Rr$DGrd>FJ~#aon8a
zCJPydetB-7Hq0?JkACc+Y0}N)3i*CQ|CjJm7Ch;)w3Js+lqE?Fk-pC1+XsjTN!8+!
zaApb#$DK;ac+{3da&af(f&RgMRpwG99pLsZ?S7w<sa5i*Csjc>kaF{EP1<%WYTLG4
zDxp4kpQ<N5tWL($EtQkp@^o3L_`LG0`d*3Pw_eWrvDEqxFic-m&hfav(XfEUCn!YI
z=O-`Jr?<J>it<`f4jbilW_h(W*DQ)0fiNz#hJm&)iYvnig>k1HrV8lcDeqj~+r79|
z-DwLLLTuPrEG^8IM5*-dZpkdIdf&D1>|<B3^x<~r!tA@dA7&d`THc@OD0UW`n^5iN
zpIz4<Dp_|2s+A@@6;WPl!+}T3dsrKLHF%(9-!g)(u#8`q;TQLPJz2#yIqK~38mfsG
yoxuP9L45}ytfGuiR_{(V>$M1}nfG58)_=Du-?M`r5f8O^d3|eD)=c&9q39FT)a?!c
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..80721864f9a904b909bec259613d1f699dcc8441
GIT binary patch
literal 1832
zc%0o;&1(}u6#vcc=EGXkTG|>g%Ai48Bykhl9;6<$5<S>fuvAe{*BYA8rW-a9+R{Q%
z6f_kS(LbOk1+|x|7XuzdJP7rm2cc-a>AlieKjNF+NlB!o_3E3vdB6AOea+17rn{%7
z8yhhJ6?#W3#_u0>&j8v2fG4q7Pv^jck5ho_A?bn6gFQzT_nGUYzXsT;?h|{Xn=jM{
z33FOM-<LAd*rdJ!)LUdbl!zM_f8Q8;Mr+TB+Y)3@x?P_Li~PYvDm(0XO9&nj?@bxQ
zX(-1DGCxi3AtM!^4rP`|p8%9iX)}{8Uc)}>?;WjkFyRW^eK}WmuBQDPHmYAlw%MoK
zzLrZ#UMLb#3|n9eIPLg5mI@-z<Ms?q{X(8DQf??>7n6=;^N27-xVSegNBx}zctKrq
zr<OgJ`*67fA097TccDvS1`n=EtdP7dv5Fn|Ah8AytCrY>TGl49o9rjalWC&2V|J9l
zjA~tySfO!KVikvRM`De9eoE}3-s>fH!^e)G118cKfrTXckwBLA(1boTlZ-+~1TBO*
z$!nB625A_iiztiY#B5MZlF$&)VWvl{WPc*doBEo0RFAaqPIELlIB4(=(@L9`kxiQ9
zm!S}YiVPq`1(3-aeFGr^&M#&s%i7YSrs8%hVQPkBKXGNWV{0YcMqFwcF>@#zGp+tO
zkA`)=pUWDAT0?Ci(c0>5^ioNSR-IjON-2_tZ7G^SZ`{hzM!2p=!n&^W)l<nEb~qq!
zvt8VPt!pA1&6=(AV$qq4pG(gVbFcIeR?=GQ{{g9vC|;opUSY!w8l50x-qN`<@q+Cs
z)S$4H6#`0On_AeSO;)oUkt=}9H36VDfUBDW@CNXx4yp*)O?TY7zGqk#D!XR}g|Qtw
zbNR*bJj>_5&*as7<C1^z^KZX9|6{sgas2ztk8zLBw=`CtYsghsm0Blyb6{##$cpcr
zSgFE13)6?I-8J`*C-z#(=CxhBIJI$h9XZ9>-;=V0OZ2xrTE=DZtO5A-9^xJFqLE~f
mWa;}TMx_=cu0|dF*uH94j%Pi21a0KA^E%d&EF0n<Lhv6z9OV@N
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..90814048b082e83af44891680f703f1b20443f34
GIT binary patch
literal 1832
zc%0o;+e;Kt82_D_*-NSG1vR5JPPLR0uH&XYh&`0C`H&eT6%o~Bi@SK4Wn3XeK?-~D
z0!7dt;G56|!mNiD>Lq*#>Y<<@y1do9;hO38otd+;t4a3SIeX6c`|jU&&dh9kM@KvI
zFbWlVOE}DDTHSMiwgBL9INZ_JJ@aWAaNQ%`-*%*<RdMg!L;O6z&b6Pe4HaK04G`v}
zzueht#8IHW1k_t3I~t7`S69b}pOEeut;Q$`ly=u=!Xkbk+MBrMc|!;u;qUD=uEn98
zBFHLebN3m&kw>)yE5wfiN<rN0Po!_+5Y_jV^c+l>0#h$8yuVb~`~!LFHxcdiT;=y{
zDu)+}MC8L3*aFTw_KqZHkmV_Rho*ibOBXTYis)j}q3jFlm?BKv+t$3+M**HwmE6f?
z@7Xq7cHqN<HR*nwl$gPTF^LtTw<T7w7at_n;9>a^yHLa$C3chiELk#5)ON!55|~l0
z0f`lwQxdB<hC32#Wb;d67u8-Wu^T>i94#;r#~>`k(1j=x)I$|IQB5=i9d)QD)J9fA
zWYI&@AYOP`<R^B6d}4(9fEF`8XvMms30~D%%|m)!J#RCIVm&<uZ!xX7X&H%_Np}6@
zVo;K9)KC)iCydVS8UoHQYzIr&)S{vyb}2zBhNFpAuD2s=Alzv4PRR(HeTlGXbwzk6
zsPiT+a}a8%X{-^YZC=J1N@<bS>55ZG5j1F1Q3TFJtbS^Q>v~;K*LA*mD0#!q^2^(7
z7B^t?nutcbX7fCqcJ}nw%=5$Ce|iXW$KUk-!B8ENz99~GW5Wy@ogic0%(*l1f*nj1
zBDIU9{7R})P3_Po^VtLqmmk*){Xmf)W5s@W{kUHORX7}=J8sz8Gb|Hj-7|y2*xr2;
z$;FW*OD30QlWMa3XT{>z)e3iV`C-}O$kOcch{xyqIb1qXHj%$QQ#y@Tho@f)n)96#
zn(g?)g7o2Pc76QE6PuT`dZQ}u=|&m5xP_Ra&%2UlaAvHRhq6|dKPv-P-a)(rUX&9J
n5Y2oa#mwabwDM7c3hdsrD#x;vECM$2*>N3dhGtFi4<XiX`!wYh
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bcd71b827a69d25f0fa34662b1cd19a013063377
GIT binary patch
literal 1832
zc%0o;&1(};5dXd1&4;$8wxk*{%CiP-k;YB5IY>QdC3-MMFsOJ?*BF}6j}4m$RV;{7
z4^}}D`~$oxeq8+M!GI^}L97Qo2;#?0@0F&l8t3i4l%zCRug=T7`OUnUdGp@vZjz}~
z5>2=S6?$Jh&hH;^PXO99fT!_zDlu^H(_O&zfb?KuPwIf;Ubl(#Nq`+s9@!pkJ>w4%
z=Cpn~J!IsuN__>WH_5g)n=#J*zIO3Bt-T<QWyzo<U7rby{Gsenam4eM5IiE@J7kRH
zp&Ta20yMdYjiJob$cWG{0m`bpStwSnVh7dtj*J{kECFMs<8My2^!`AT`b}h;dbZ(v
zt(4@2A`!)~X*P`$j=y86Bl0|K&(PFw<mn>inj%hd-I44IB1{o3?iCABi?aYPsY>qb
zWzV%fT%N#(M+??1I3zKH2V)W|ByUNqq5~f!*5F~y61%XP#Uyr<{TO*NP1JVKjuM#B
zUgsoMXxxxk#Xj7YSR<dG61%8&zr=3%*nafEL>}j1A%}isQKU0;B8@JRQRs+ZC!qv+
zT_BG^8V2bi%Az<i8x)fxGz|2a`SVt;KU?IT=`J4CBRhG*ypS6lG<ctB<xR^d=1lS{
zP>4aB44_*yzfd&N1Kk9iU))Ysw53HwW$aSIR1C*1;`(UE)<ZZ(TrC-KbGR5ct^N#;
zhIPJ+%RLD7bjP|yX^qP`N?TgA>YR#GN|7{dOHl-lW~>4ogzI`Ftm`^&oJw}s;h^kh
zujqiSYa$!XnyvFn#hEK#tIrQ}FZB@C)8E$r15zDPxk3$I;=l|V-5_J$>b*1Zf^93e
zpuC=ygGzaWT3)MNZ)W2}t{^VA1cB8-jI{>g4dP)NR1vV1dfc<TXIO4j(`N>Sv5w8-
zrJ2zZE0t!Sl+@CixxmcV-vM`N{&D-v=<JjEQIF3zchNuIKHj{tS~}6|-FK&itozQ1
zm6iCy!t~+lb$$HD8=I7}tFcSdM9mGJTt-fD_jjbM;wmk+M{Bqyp0xwN-b1_tUaTP*
nB3b=DicznHh?~)d05&$P%JKA*N61D#JFjD{%9<hmAq4*cRe<Cc
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..51bb28a56e0caaff90e1ab153a6bd1792f502b00
GIT binary patch
literal 1832
zc%0o;&1(}u6#vcc=EEA(4_XZvWze84lDJK64y7J65<M6r7*u-EHHId%>4t3tEe6D|
zgHccf{{U~|*TpZyfL^2rp$d8s#E+ZaD~+G=&F-WmVzFMG$(#3kZ+`F1o0;8BDxFSY
zDNaCz9#16r^&ReqfHn)@ZX%IRj$M0u6>!}kJDA*(-l4cho{&8au>Gk$8>5|vx<iCH
z%^%DZj3Sn)PXYBJ`L^b=#^Immj^C%bM<lTvIh2&^9bu6_lq-~udY%)4N5p#z#?c~_
z-2_>H2KR(f$UYdDQpr96D9eiGWT}1@161Ejn&)7G3X~tbIDMdf_%oKOA4RsAd#gS*
zYuUU|B%&BL%Vsg+@EuP}Bj#><gr<HZri+YoirB?@N3-|nXNsV>m&`}~o&|VJRdQ!7
zdu--#xdT6L&3o5jm&6PnoRL@|eMw>!Yw%iP4Ibu`*o6)jlh{rEeZ*v%sBNbmB`~A4
zj!3LfzaX)SZMZD4Mx5^wyQubViQVwC?TEuf5yxO5k5S}MqCNB?gFezx=;+5LLP=sx
z5o4UXLAHppC{Bz9#pDT10CBT;%*v1EO1wAI$D?}xCZ05>^5f$MkDFG}w2V^TB;F*2
z7_`V3!jvA9B_lHyCgA)McCwPKEh;K&mlC03IEF}CqaEKM;TTDyWF*XqQo^)GvpgEn
z`4E?D5E=}}!lJZ=%h*dxS~TnIic?CFG-7K}1omdFN!ke4_5O&i>wMu<@`fD=%G(?k
zH(=YE$VQ`P+q_<P#`=fG^TXVKdI($F-{${=raG#AiZ1vM8)nex1R3)-&Yg)DY(uRb
zwUw+ERBEf#+6wKwk5#C-f;ib81UiB^(;0*}h?`wdMZkKx<H5x}!*ZdfduC7=TeG%O
zohw&awff~wRjn@n8kqa=GvKa%yWKNa{&MGA+2i+rJ>FgEsrcF&rBi#h`Ra_&E#EmY
z(}wpfLLaVS*PDMlv1zIM7Qwv&?Ba{yMIElK8@MS)i$B^VP4TP;`0)zj9q?i~=@9A0
k_fhm#D@5W$7XnzlU{wyYn;0P*`R%-px1pQ5_=gbk3$G^S6#xJL
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..12ea7bcbfc173ebbb851c73fd4b42db798dab3a1
GIT binary patch
literal 1832
zc%0o;%}*0S6#vccc3T0<M*y2x%tRZ780xlC4g?R1sl<pFC4OCW#fCOewpmJ|1QMdr
zgJ7aD@ekl;f_lM^M4Nar9!&6{2NUDR4euBVsP)b6l(Yt-UY+U8`@Q#m@6DT;-ED7Q
zUoR>#2^B_HJkDpk_2+=L2;fmX-q$mD@8b;MnI%2gv%jxf(F12le+979y(jiWYcJG?
z2y^nE?@yZ<Y*t?a>MgPzNG8mSKW~gbAs^*Ldy))FujdnCkw277XD@l*5Q104`_ks6
z43uL8S%4;e*i0v$#m05gCjn)1#u~{Mu46CN_m=z|Oi+Q*N5>DJtM2@UN_9bGn}6K&
zwN%RHgCY^dutm0rvo7DYlr>@=b7pAj0x><L+)%_Wrd`QCBf=Cx(KoF{{hkGQK~-{h
zEoUy}aJd6N9;{h+;;6(7UR;w{A$eP372EM%VhvtaC9wxJtX*QA?5BvyG*R0TCrV&O
zYmG{*P`@d$ii5Z#u|}Nl5__ojdWm)T*&%enLI#&%BZUDZk)=H}qaQ6Kqc9Lb8=)Rz
zjS*vrx=Ff-vMEl?CdH%(4Fg?P=CYj{NM?C+e+!Qqkv86AjirW$Ox|VL8Ot`aDT{a`
z6k^gMgJ?yJ)U4S**h;|t#hqkXN7__W!YL(8#c*`cD35k+F~aRMiX|g%4QJz)J&@qh
zu)#aHT!T=owY^o8ws9FJX-S*B?yfkc6iLI56h+`<!XBZGaKng%4a49Yr;<19j-b5F
zPH_W{u8C|kYmUwf1$QodDLy|;U+*C-Z-4Ut2TgTF;VND5IvZxt=mZ(_70;cC7i@RF
z8u_g(A5`*9YJQ70UB#xTd4jl79RzBExK<m4FNphfP({Ely5rd2J;QRLl6z)Q7~8&M
zDz`L|W4YY&Tu#k3t^}68{0!*1)rSpB6U%d}6JEc6WxRf>VXCU4SUR=W`)1~aEc?z0
zPX#`+Fnzc>Js<w@#9m3+vc9|WX^C?8FLOpEH(G*Ab41tSM9bq@1MuS=#5>?aBgqiS
l;`dSXaxFxo3Uvrz+lE!S%z9#k9OQTMy4IpB>Ea(kj9(4`<Q4z`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a640cd553f18ac755e5d5d7fbad5621acae313ab
GIT binary patch
literal 1832
zc%0o;&1(}u6#vcc=A&O}Ev*JjWze7&N!-S^f>cl|u?K4l2EQ)4*3g7D-LQ?&ij|`1
zp{bw<{sFxSRuSsQ!H6gEAm~94f@piwd!?yg@y+g}B&F4Qbtd!P@4flGH*aQkH$Aaf
z52`Q@6?$hh%BQ>B&j4*6z{6-X);)0N;}qb!OLm}pf2>P!`%jYn5@08Kj_!=CJKGQ>
z%xV5iU&=_MMtuROH^_G&5jW2Lnz;Cw=AP1MPmn|DaeX2z@&^;C%!ua=A$UZ*H)V{Z
zq4W}DeiH5>BNczP`%(qj<A73=Hit8XYuH8gy`^~$Ca6H_!I6EZYdgN8O8qRdy?)g6
zrBuu2g(4Bfuz5C*Qx4zplr>`Z+7g=jnV2pzCKR!YNk_9;v@k_b+!aev%d-H_sY>pw
zWy?|ympky`-ja7Kj!4Yl!BvSB(l;emu^I0r*5F~)61z~x+9h_A|2Q$3CTcruM+wYm
zt@9Eq)UQjd;vjBGtP$sj#4f76L1H(2><~I(B8^d4NTMGJWM~iD(T8Tz5$I?^E1_;;
zT_DCFb%SgXWl@}v2E`-^4FR2IdelnxCo+6{Uo(&BEv>xUypS9mG<c_JrA^DoBu(NC
zQ;0!}3?PJdGBZZsK!||zi`vODwzjCKxLrz^is9HpqdeO2wb?kdR5GIGP$p_x{c#=%
z>wFKFYY=J+wTDD$tCw+%mb7Tr*%hahB5Byxq6i#|Tf?*wuInvfUDx^QspJhiBOq_H
zL)?IEYa$y-&9-@=;K;&U@%dryl^(+K_P6=}ps9{3T%ikIVZ#g>ogic0;<+>Ng6+uH
zBEOO414_P0&2P{qt67$sD}c+j0iZ5`tLp;r1~6R@RRnCKJ8oOsGb|S>xn~B2vCUhu
zxrMPD%jFhla%yh<H~+%iFTXqY{eI)Z*y7ChF^|vp?P5c=F<V_(ES=h`y;HA+F8j`j
znM%yEFnzc>Tp#}N#9m6>{AXI#6B4)Am@^`|krG^N%l(m(Q4-G@fuHXn-T^PxlMa$D
leji0Iw}LdPQ4c>hty-1CY#>I^Mm{^Q<1OlvF8(3J_zmY0<Q4z`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c34269defd247da5cd49e6644156f862b4bd85b
GIT binary patch
literal 75872
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