Backed out 6 changesets (bug 827713) for reftest failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 29 Jul 2013 15:19:34 -0400
changeset 140386 a59ad3157c17f3df0a132979f428c65211e4ce23
parent 140385 014cc3de08fb8156f4f4391732284a2e09639eed
child 140387 5375b4e2b7c24e4b8b6c1e482fb213955c3a9a30
push id31716
push userryanvm@gmail.com
push dateMon, 29 Jul 2013 19:19:35 +0000
treeherdermozilla-inbound@a59ad3157c17 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs827713
milestone25.0a1
backs out014cc3de08fb8156f4f4391732284a2e09639eed
4113172193aaa6d6cfcc42fef0cd3b25b207d038
27a5c8dd5ff757042366bd15904fcccda074dd96
6448c7e05f11ef896eff0f70874743deec772a22
b67a72618c669e643e625ab6dbfddd920d78d95b
1279664e0d41273c4bbee2755d4c8a17bb7c5564
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
Backed out 6 changesets (bug 827713) for reftest failures. Backed out changeset 014cc3de08fb (bug 827713) Backed out changeset 4113172193aa (bug 827713) Backed out changeset 27a5c8dd5ff7 (bug 827713) Backed out changeset 6448c7e05f11 (bug 827713) Backed out changeset b67a72618c66 (bug 827713) Backed out changeset 1279664e0d41 (bug 827713)
dom/locales/en-US/chrome/mathml/mathml.properties
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsFrameIdList.h
layout/mathml/moz.build
layout/mathml/nsMathMLContainerFrame.cpp
layout/mathml/nsMathMLContainerFrame.h
layout/mathml/nsMathMLmmultiscriptsFrame.cpp
layout/mathml/nsMathMLmmultiscriptsFrame.h
layout/mathml/nsMathMLmsubFrame.cpp
layout/mathml/nsMathMLmsubFrame.h
layout/mathml/nsMathMLmsubsupFrame.cpp
layout/mathml/nsMathMLmsubsupFrame.h
layout/mathml/nsMathMLmsupFrame.cpp
layout/mathml/nsMathMLmsupFrame.h
layout/mathml/nsMathMLmunderoverFrame.cpp
layout/mathml/tests/Makefile.in
layout/mathml/tests/test_bug827713-2.html
layout/mathml/tests/test_bug827713.html
layout/reftests/mathml/multiscripts-1-ref.html
layout/reftests/mathml/multiscripts-1.html
layout/reftests/mathml/reftest.list
--- a/dom/locales/en-US/chrome/mathml/mathml.properties
+++ b/dom/locales/en-US/chrome/mathml/mathml.properties
@@ -1,13 +1,12 @@
 # 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/.
 
-InvalidChild=Invalid markup: <%1$S> is not allowed as a child of <%2$S>.
 ChildCountIncorrect=Invalid markup: Incorrect number of children for <%1$S/> tag.
 DuplicateMprescripts=Invalid markup: More than one <mprescripts/> in <mmultiscripts/>.
 # LOCALIZATION NOTE:  The first child of <mmultiscript/> is the base, that is the element to which scripts are attached.
 NoBase=Invalid markup: Expected exactly one Base element in <mmultiscripts/>.  Found none.
 SubSupMismatch=Invalid markup: Incomplete subscript/superscript pair in <mmultiscripts/>.
 
 # LOCALIZATION NOTE:  When localizing the single quotes ('), follow the conventions in css.properties for your target locale.
 AttributeParsingError=Error in parsing the value '%1$S' for '%2$S' attribute of <%3$S/>.  Attribute ignored.
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -4574,19 +4574,19 @@ nsCSSFrameConstructor::FindMathMLData(El
     SIMPLE_MATHML_CREATE(annotation_, NS_NewMathMLTokenFrame),
     SIMPLE_MATHML_CREATE(annotation_xml_, NS_NewMathMLmrowFrame),
     SIMPLE_MATHML_CREATE(mi_, NS_NewMathMLTokenFrame),
     SIMPLE_MATHML_CREATE(mn_, NS_NewMathMLTokenFrame),
     SIMPLE_MATHML_CREATE(ms_, NS_NewMathMLTokenFrame),
     SIMPLE_MATHML_CREATE(mtext_, NS_NewMathMLTokenFrame),
     SIMPLE_MATHML_CREATE(mo_, NS_NewMathMLmoFrame),
     SIMPLE_MATHML_CREATE(mfrac_, NS_NewMathMLmfracFrame),
-    SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmmultiscriptsFrame),
-    SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmmultiscriptsFrame),
-    SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmmultiscriptsFrame),
+    SIMPLE_MATHML_CREATE(msup_, NS_NewMathMLmsupFrame),
+    SIMPLE_MATHML_CREATE(msub_, NS_NewMathMLmsubFrame),
+    SIMPLE_MATHML_CREATE(msubsup_, NS_NewMathMLmsubsupFrame),
     SIMPLE_MATHML_CREATE(munder_, NS_NewMathMLmunderoverFrame),
     SIMPLE_MATHML_CREATE(mover_, NS_NewMathMLmunderoverFrame),
     SIMPLE_MATHML_CREATE(munderover_, NS_NewMathMLmunderoverFrame),
     SIMPLE_MATHML_CREATE(mphantom_, NS_NewMathMLmphantomFrame),
     SIMPLE_MATHML_CREATE(mpadded_, NS_NewMathMLmpaddedFrame),
     SIMPLE_MATHML_CREATE(mspace_, NS_NewMathMLmspaceFrame),
     SIMPLE_MATHML_CREATE(none, NS_NewMathMLmspaceFrame),
     SIMPLE_MATHML_CREATE(mprescripts_, NS_NewMathMLmspaceFrame),
--- a/layout/generic/nsFrameIdList.h
+++ b/layout/generic/nsFrameIdList.h
@@ -85,16 +85,19 @@ FRAME_ID(nsMathMLmoFrame)
 FRAME_ID(nsMathMLmoverFrame)
 FRAME_ID(nsMathMLmpaddedFrame)
 FRAME_ID(nsMathMLmphantomFrame)
 FRAME_ID(nsMathMLmrootFrame)
 FRAME_ID(nsMathMLmrowFrame)
 FRAME_ID(nsMathMLmspaceFrame)
 FRAME_ID(nsMathMLmsqrtFrame)
 FRAME_ID(nsMathMLmstyleFrame)
+FRAME_ID(nsMathMLmsubFrame)
+FRAME_ID(nsMathMLmsubsupFrame)
+FRAME_ID(nsMathMLmsupFrame)
 FRAME_ID(nsMathMLmtableFrame)
 FRAME_ID(nsMathMLmtableOuterFrame)
 FRAME_ID(nsMathMLmtdFrame)
 FRAME_ID(nsMathMLmtdInnerFrame)
 FRAME_ID(nsMathMLmtrFrame)
 FRAME_ID(nsMathMLmunderFrame)
 FRAME_ID(nsMathMLmunderoverFrame)
 FRAME_ID(nsMathMLsemanticsFrame)
--- a/layout/mathml/moz.build
+++ b/layout/mathml/moz.build
@@ -21,13 +21,16 @@ CPP_SOURCES += [
     'nsMathMLmoFrame.cpp',
     'nsMathMLmpaddedFrame.cpp',
     'nsMathMLmphantomFrame.cpp',
     'nsMathMLmrootFrame.cpp',
     'nsMathMLmrowFrame.cpp',
     'nsMathMLmspaceFrame.cpp',
     'nsMathMLmsqrtFrame.cpp',
     'nsMathMLmstyleFrame.cpp',
+    'nsMathMLmsubFrame.cpp',
+    'nsMathMLmsubsupFrame.cpp',
+    'nsMathMLmsupFrame.cpp',
     'nsMathMLmtableFrame.cpp',
     'nsMathMLmunderoverFrame.cpp',
     'nsMathMLsemanticsFrame.cpp',
 ]
 
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -1539,24 +1539,16 @@ nsMathMLContainerFrame::ReportParseError
 
 nsresult
 nsMathMLContainerFrame::ReportChildCountError()
 {
   const PRUnichar* arg = mContent->Tag()->GetUTF16String();
   return ReportErrorToConsole("ChildCountIncorrect", &arg, 1);
 }
 
-nsresult
-nsMathMLContainerFrame::ReportInvalidChildError(nsIAtom* aChildTag)
-{
-  const PRUnichar* argv[] =
-    { aChildTag->GetUTF16String(), mContent->Tag()->GetUTF16String() };
-  return ReportErrorToConsole("InvalidChild", argv, 2);
-}
-
 //==========================
 
 nsIFrame*
 NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
                            uint32_t aFlags)
 {
   nsMathMLmathBlockFrame* it = new (aPresShell) nsMathMLmathBlockFrame(aContext);
   if (it) {
--- a/layout/mathml/nsMathMLContainerFrame.h
+++ b/layout/mathml/nsMathMLContainerFrame.h
@@ -254,24 +254,16 @@ public:
   /*
    * Helper to call ReportErrorToConsole when certain tags
    * have more than the expected amount of children.
    */
   nsresult
   ReportChildCountError();
 
   /*
-   * Helper to call ReportErrorToConsole when certain tags have
-   * invalid child tags
-   * @param aChildTag The tag which is forbidden in this context
-   */
-  nsresult
-  ReportInvalidChildError(nsIAtom* aChildTag);
-
-  /*
    * Helper to call ReportToConsole when an error occurs.
    * @param aParams see nsContentUtils::ReportToConsole
    */
   nsresult
   ReportErrorToConsole(const char*       aErrorMsgId,
                        const PRUnichar** aParams = nullptr,
                        uint32_t          aParamCount = 0);
 
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
@@ -11,19 +11,16 @@
 #include "nsStyleConsts.h"
 #include "nsRenderingContext.h"
 
 #include "nsMathMLmmultiscriptsFrame.h"
 #include <algorithm>
 
 //
 // <mmultiscripts> -- attach prescripts and tensor indices to a base - implementation
-// <msub> -- attach a subscript to a base - implementation
-// <msubsup> -- attach a subscript-superscript pair to a base - implementation
-// <msup> -- attach a superscript to a base - implementation
 //
 
 nsIFrame*
 NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsMathMLmmultiscriptsFrame(aContext);
 }
 
@@ -36,583 +33,431 @@ nsMathMLmmultiscriptsFrame::~nsMathMLmmu
 NS_IMETHODIMP
 nsMathMLmmultiscriptsFrame::TransmitAutomaticData()
 {
   // if our base is an embellished operator, let its state bubble to us
   mPresentationData.baseFrame = mFrames.FirstChild();
   GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
 
   // The REC says:
-  // The script element increments scriptlevel by 1, and sets
+  // The <mmultiscripts> element increments scriptlevel by 1, and sets
   // displaystyle to "false", within each of its arguments except base
   UpdatePresentationDataFromChildAt(1, -1,
     ~NS_MATHML_DISPLAYSTYLE, NS_MATHML_DISPLAYSTYLE);
 
   // The TeXbook (Ch 17. p.141) says the superscript inherits the compression
   // while the subscript is compressed. So here we collect subscripts and set
   // the compression flag in them.
-
-  if (mContent->Tag() == nsGkAtoms::msup_)
-    return NS_OK;
-
   int32_t count = 0;
-  bool isSubScript = true;
-
+  bool isSubScript = false;
   nsAutoTArray<nsIFrame*, 8> subScriptFrames;
   nsIFrame* childFrame = mFrames.FirstChild();
   while (childFrame) {
     if (childFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) {
       // mprescripts frame
-    } else if (0 == count) {
+    }
+    else if (0 == count) {
       // base frame
-    } else {
+    }
+    else {
       // super/subscript block
       if (isSubScript) {
         // subscript
         subScriptFrames.AppendElement(childFrame);
-      } else {
+      }
+      else {
         // superscript
       }
       isSubScript = !isSubScript;
     }
     count++;
     childFrame = childFrame->GetNextSibling();
   }
   for (int32_t i = subScriptFrames.Length() - 1; i >= 0; i--) {
     childFrame = subScriptFrames[i];
     PropagatePresentationDataFor(childFrame,
       NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED);
   }
 
   return NS_OK;
 }
 
-/* virtual */ nsresult
-nsMathMLmmultiscriptsFrame::Place(nsRenderingContext& aRenderingContext,
-                                  bool                 aPlaceOrigin,
-                                  nsHTMLReflowMetrics& aDesiredSize)
+void
+nsMathMLmmultiscriptsFrame::ProcessAttributes()
 {
-  nscoord subScriptShift = 0;
-  nscoord supScriptShift = 0;
-  nsIAtom* tag = mContent->Tag();
+  mSubScriptShift = 0;
+  mSupScriptShift = 0;
 
   // subscriptshift
   //
   // "Specifies the minimum amount to shift the baseline of subscript down; the
   // default is for the rendering agent to use its own positioning rules."
   //
   // values: length
   // default: automatic
   //
   // We use 0 as the default value so unitless values can be ignored.
   // As a minimum, negative values can be ignored.
   //
   nsAutoString value;
-  if (tag != nsGkAtoms::msup_) {
-    GetAttribute(mContent, mPresentationData.mstyle,
-                 nsGkAtoms::subscriptshift_, value);
-    if (!value.IsEmpty()) {
-      ParseNumericValue(value, &subScriptShift, 0, PresContext(),
-                        mStyleContext);
-    }
+  GetAttribute(mContent, mPresentationData.mstyle,
+               nsGkAtoms::subscriptshift_, value);
+  if (!value.IsEmpty()) {
+    ParseNumericValue(value, &mSubScriptShift, 0, PresContext(),
+                      mStyleContext);
   }
   // superscriptshift
   //
   // "Specifies the minimum amount to shift the baseline of superscript up; the
   // default is for the rendering agent to use its own positioning rules."
   //
   // values: length
   // default: automatic
   //
   // We use 0 as the default value so unitless values can be ignored.
   // As a minimum, negative values can be ignored.
   //
-  if (tag != nsGkAtoms::msub_) {
-    GetAttribute(mContent, mPresentationData.mstyle,
-                 nsGkAtoms::superscriptshift_, value);
-    if (!value.IsEmpty()) {
-      ParseNumericValue(value, &supScriptShift, 0, PresContext(),
-                        mStyleContext);
-    }
+  GetAttribute(mContent, mPresentationData.mstyle,
+               nsGkAtoms::superscriptshift_, value);
+  if (!value.IsEmpty()) {
+    ParseNumericValue(value, &mSupScriptShift, 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);
 }
 
-// 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)
+/* virtual */ nsresult
+nsMathMLmmultiscriptsFrame::Place(nsRenderingContext& aRenderingContext,
+                                  bool                 aPlaceOrigin,
+                                  nsHTMLReflowMetrics& aDesiredSize)
 {
-  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_;
-  else if (tag == nsGkAtoms::munder_)
-    tag = nsGkAtoms::msub_;
-  else if (tag  == nsGkAtoms::munderover_)
-    tag = nsGkAtoms::msubsup_;
-
-  nsBoundingMetrics bmFrame;
-  nsHTMLReflowMetrics frameSize;
+  ////////////////////////////////////
+  // Get the children's desired sizes
 
   nscoord minShiftFromXHeight, subDrop, supDrop;
 
   ////////////////////////////////////////
   // Initialize super/sub shifts that
   // depend only on the current font
   ////////////////////////////////////////
 
-  nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
-
-  if (!baseFrame) {
-    if (tag == nsGkAtoms::mmultiscripts_)
-      aFrame->ReportErrorToConsole("NoBase");
-    else
-      aFrame->ReportChildCountError();
-    return aFrame->ReflowError(aRenderingContext, aDesiredSize);
-  }
-
+  ProcessAttributes();
 
   // get x-height (an ex)
-  const nsStyleFont* font = aFrame->StyleFont();
+  const nsStyleFont* font = StyleFont();
   nsRefPtr<nsFontMetrics> fm;
-  nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
+  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   aRenderingContext.SetFont(fm);
 
   nscoord xHeight = fm->XHeight();
 
   nscoord ruleSize;
   GetRuleThickness (aRenderingContext, fm, ruleSize);
 
-  // force the scriptSpace to be at least 1 pixel
+  // scriptspace from TeX for extra spacing after sup/subscript (0.5pt in plain TeX)
+  // forced to be at least 1 pixel here
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
-  aScriptSpace = std::max(onePixel, aScriptSpace);
+  nscoord scriptSpace = std::max(nsPresContext::CSSPointsToAppUnits(0.5f), onePixel);
 
   /////////////////////////////////////
   // 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;
 
   // 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 < mSubScriptShift) {
+    // the user has set the subscriptshift attribute
+    float scaler = ((float) subScriptShift2) / subScriptShift1;
+    subScriptShift1 = std::max(subScriptShift1, mSubScriptShift);
+    subScriptShift2 = NSToCoordRound(scaler * subScriptShift1);
   }
-  if (0 < aUserSubScriptShift) {
-    // the user has set the subscriptshift attribute
-    subScriptShift = std::max(subScriptShift, aUserSubScriptShift);
-  }
+  // the font dependent shift
+  nscoord subScriptShift = std::max(subScriptShift1,subScriptShift2);
 
   /////////////////////////////////////
   // 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);
+  if (0 < mSupScriptShift) {
+    // the user has set the superscriptshift attribute
+    float scaler2 = ((float) supScriptShift2) / supScriptShift1;
+    float scaler3 = ((float) supScriptShift3) / supScriptShift1;
+    supScriptShift1 = std::max(supScriptShift1, mSupScriptShift);
+    supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1);
+    supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1);
+  }
 
   // get sup script shift depending on current script level and display style
   // Rule 18c, App. G, TeXbook
-  nsPresentationData presentationData;
-  aFrame->GetPresentationData(presentationData);
   nscoord supScriptShift;
   if ( font->mScriptLevel == 0 &&
-       NS_MATHML_IS_DISPLAYSTYLE(presentationData.flags) &&
-      !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
+       NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags) &&
+      !NS_MATHML_IS_COMPRESSED(mPresentationData.flags)) {
     // Style D in TeXbook
     supScriptShift = supScriptShift1;
-  } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
+  }
+  else if (NS_MATHML_IS_COMPRESSED(mPresentationData.flags)) {
     // Style C' in TeXbook = D',T',S',SS'
     supScriptShift = supScriptShift3;
-  } else {
+  }
+  else {
     // everything else = T,S,SS
     supScriptShift = supScriptShift2;
   }
 
-  if (0 < aUserSupScriptShift) {
-    // the user has set the supscriptshift attribute
-    supScriptShift = std::max(supScriptShift, aUserSupScriptShift);
-  }
-
   ////////////////////////////////////
   // Get the children's sizes
   ////////////////////////////////////
 
   nscoord width = 0, prescriptsWidth = 0, rightBearing = 0;
+  nsIFrame* mprescriptsFrame = nullptr; // frame of <mprescripts/>, if there.
+  bool isSubScript = false;
   nscoord minSubScriptShift = 0, minSupScriptShift = 0;
   nscoord trySubScriptShift = subScriptShift;
   nscoord trySupScriptShift = supScriptShift;
   nscoord maxSubScriptShift = subScriptShift;
   nscoord maxSupScriptShift = supScriptShift;
+  int32_t count = 0;
   nsHTMLReflowMetrics baseSize;
   nsHTMLReflowMetrics subScriptSize;
   nsHTMLReflowMetrics supScriptSize;
-  nsHTMLReflowMetrics multiSubSize, multiSupSize;
-  baseFrame = nullptr;
+  nsIFrame* baseFrame = nullptr;
   nsIFrame* subScriptFrame = nullptr;
   nsIFrame* supScriptFrame = nullptr;
-  nsIFrame* prescriptsFrame = nullptr; // frame of <mprescripts/>, if there.
 
   bool firstPrescriptsPair = false;
-  nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup;
-  multiSubSize.ascent = multiSupSize.ascent = -0x7FFFFFFF;
-  bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF;
-  bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF;
+  nsBoundingMetrics bmBase, bmSubScript, bmSupScript;
   nscoord italicCorrection = 0;
 
-  nsBoundingMetrics boundingMetrics;
-  boundingMetrics.width = 0;
-  boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF;
+  mBoundingMetrics.width = 0;
+  mBoundingMetrics.ascent = mBoundingMetrics.descent = -0x7FFFFFFF;
+  nscoord ascent = -0x7FFFFFFF, descent = -0x7FFFFFFF;
   aDesiredSize.width = aDesiredSize.height = 0;
 
-  int32_t count = 0;
-  bool foundNoneTag = false;
-
-  // Boolean to determine whether the current child is a subscript.
-  // Note that only msup starts with a superscript.
-  bool isSubScript = (tag != nsGkAtoms::msup_);
-
-  nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
+  nsIFrame* childFrame = mFrames.FirstChild();
   while (childFrame) {
-    nsIAtom* childTag = childFrame->GetContent()->Tag();
-    if (childTag == nsGkAtoms::mprescripts_) {
-      if (tag != nsGkAtoms::mmultiscripts_) {
-        if (aPlaceOrigin) {
-          aFrame->ReportInvalidChildError(childTag);
-        }
-        return aFrame->ReflowError(aRenderingContext, aDesiredSize);
-      }
-      if (prescriptsFrame) {
+    if (childFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) {
+      if (mprescriptsFrame) {
         // duplicate <mprescripts/> found
         // report an error, encourage people to get their markups in order
         if (aPlaceOrigin) {
-          aFrame->ReportErrorToConsole("DuplicateMprescripts");
-        }
-        return aFrame->ReflowError(aRenderingContext, aDesiredSize);
-      }
-      if (!isSubScript) {
-        if (aPlaceOrigin) {
-          aFrame->ReportErrorToConsole("SubSupMismatch");
-        }
-        return aFrame->ReflowError(aRenderingContext, aDesiredSize);
-      }
-
-      prescriptsFrame = childFrame;
-      firstPrescriptsPair = true;
-    } else if (0 == count) {
-      // base
-
-      if (childTag == nsGkAtoms::none) {
-        if (tag == nsGkAtoms::mmultiscripts_) {
-          if (aPlaceOrigin) {
-            aFrame->ReportErrorToConsole("NoBase");
-          }
-          return aFrame->ReflowError(aRenderingContext, aDesiredSize);
-        } else {
-          //A different error message is triggered later for the other tags
-          foundNoneTag = true;
+          ReportErrorToConsole("DuplicateMprescripts");
         }
-      }
-      baseFrame = childFrame;
-      GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
-
-      if (tag != nsGkAtoms::msub_) {
-        // Apply italics correction if there is the potential for a 
-        // postsupscript.
-        GetItalicCorrection(bmBase, italicCorrection);
-        // If italics correction is applied, we always add "a little to spare"
-        // (see TeXbook Ch.11, p.64), as we estimate the italic creation
-        // ourselves and it isn't the same as TeX.
-        italicCorrection += onePixel;
+        return ReflowError(aRenderingContext, aDesiredSize);
       }
-
-      // we update boundingMetrics.{ascent,descent} with that
-      // of the baseFrame only after processing all the sup/sub pairs
-      // XXX need italic correction only *if* there are postscripts ?
-      boundingMetrics.width = bmBase.width + italicCorrection;
-      boundingMetrics.rightBearing = bmBase.rightBearing;
-      boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
-    } else {
-      // super/subscript block
-      if ( childTag == nsGkAtoms::none) {
-        foundNoneTag = true;
-      }
+      mprescriptsFrame = childFrame;
+      firstPrescriptsPair = true;
+    }
+    else {
+      if (0 == count) {
+        // base
+        baseFrame = childFrame;
+        GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
+        GetItalicCorrection(bmBase, italicCorrection);
+        // for the superscript, we always add "a little to spare"
+        italicCorrection += onePixel;
 
-      if (isSubScript) {
-        // subscript
-        subScriptFrame = childFrame;
-        GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
-        // get the subdrop from the subscript font
-        GetSubDropFromChild (subScriptFrame, subDrop);
-        // parameter v, Rule 18a, App. G, TeXbook
-        minSubScriptShift = bmBase.descent + subDrop;
-        trySubScriptShift = std::max(minSubScriptShift,subScriptShift);
-        multiSubSize.ascent = std::max(multiSubSize.ascent,
-                                       subScriptSize.ascent);
-        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.ascent);
-        if (bmSubScript.width)
-          width = bmSubScript.width + aScriptSpace;
-        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);
-          maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);
-
-          maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
-          trySubScriptShift = subScriptShift;
+        // we update mBoundingMetrics.{ascent,descent} with that
+        // of the baseFrame only after processing all the sup/sub pairs
+        // XXX need italic correction only *if* there are postscripts ?
+        mBoundingMetrics.width = bmBase.width + italicCorrection;
+        mBoundingMetrics.rightBearing = bmBase.rightBearing;
+        mBoundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
+      }
+      else {
+        // super/subscript block
+        if (isSubScript) {
+          // subscript
+          subScriptFrame = childFrame;
+          GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
+          // get the subdrop from the subscript font
+          GetSubDropFromChild (subScriptFrame, subDrop);
+          // parameter v, Rule 18a, App. G, TeXbook
+          minSubScriptShift = bmBase.descent + subDrop;
+          trySubScriptShift = std::max(minSubScriptShift,subScriptShift);
+          mBoundingMetrics.descent =
+            std::max(mBoundingMetrics.descent,bmSubScript.descent);
+          descent = std::max(descent,subScriptSize.height - subScriptSize.ascent);
+          width = bmSubScript.width + scriptSpace;
+          rightBearing = bmSubScript.rightBearing;
         }
-      } 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));
-        trySupScriptShift = std::max(minSupScriptShift,
-                                     std::max(minShiftFromXHeight,
-                                              supScriptShift));
-        multiSupSize.ascent = std::max(multiSupSize.ascent,
-                                       supScriptSize.ascent);
-        bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSubScript.ascent);
-        bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
-        multiSupSize.height = 
-          std::max(multiSupSize.height,
-                   supScriptSize.height - supScriptSize.ascent);
+        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));
+          trySupScriptShift =
+            std::max(minSupScriptShift,std::max(minShiftFromXHeight,supScriptShift));
+          mBoundingMetrics.ascent =
+            std::max(mBoundingMetrics.ascent,bmSupScript.ascent);
+          ascent = std::max(ascent,supScriptSize.ascent);
+          width = std::max(width, bmSupScript.width + scriptSpace);
+          rightBearing = std::max(rightBearing, bmSupScript.rightBearing);
 
-        if (bmSupScript.width)
-          width = std::max(width, bmSupScript.width + aScriptSpace);
-        rightBearing = std::max(rightBearing, bmSupScript.rightBearing);
+          if (!mprescriptsFrame) { // we are still looping over base & postscripts
+            mBoundingMetrics.rightBearing = mBoundingMetrics.width + rightBearing;
+            mBoundingMetrics.width += width;
+          }
+          else {
+            prescriptsWidth += width;
+            if (firstPrescriptsPair) {
+              firstPrescriptsPair = false;
+              mBoundingMetrics.leftBearing =
+                std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
+            }
+          }
+          width = rightBearing = 0;
 
-        if (!prescriptsFrame) { // we are still looping over base & postscripts
-          boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
-          boundingMetrics.width += width;
-        } else {
-          prescriptsWidth += width;
-          if (firstPrescriptsPair) {
-            firstPrescriptsPair = false;
-            boundingMetrics.leftBearing =
-              std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
-          }
-        }
-        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_) {
+          // negotiate between the various shifts so that
+          // there is enough gap between the sup and subscripts
+          // Rule 18e, App. G, TeXbook
           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);
           }
 
           // 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));
-          if (gap > 0) {
+          if (gap > 0.0f) {
             trySupScriptShift += gap;
             trySubScriptShift -= gap;
           }
-        }
+          
+          maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
+          maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);
 
-        maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
-        maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);
-
-        trySubScriptShift = subScriptShift;
-        trySupScriptShift = supScriptShift;
+          trySubScriptShift = subScriptShift;
+          trySupScriptShift = supScriptShift;
+        }
       }
 
       isSubScript = !isSubScript;
     }
     count++;
     childFrame = childFrame->GetNextSibling();
   }
-
-  //NoBase error may also have been reported above
-  if ((count != 2 && (tag == nsGkAtoms::msup_ || tag == nsGkAtoms::msub_)) ||
-      (count != 3 && tag == nsGkAtoms::msubsup_) || !baseFrame ||
-      (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) ||
-      (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) {
+  // note: width=0 if all sup-sub pairs match correctly
+  if ((0 != width) || !baseFrame) {
     // report an error, encourage people to get their markups in order
     if (aPlaceOrigin) {
-      if ((count != 2 && (tag == nsGkAtoms::msup_ || 
-          tag == nsGkAtoms::msub_)) ||
-          (count != 3 && tag == nsGkAtoms::msubsup_ )) {
-        aFrame->ReportChildCountError();
-      } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) {
-        aFrame->ReportInvalidChildError(nsGkAtoms::none);
-      } else if (!baseFrame) {
-        aFrame->ReportErrorToConsole("NoBase");
+      if (!baseFrame) {
+        ReportErrorToConsole("NoBase");
       } else {
-        aFrame->ReportErrorToConsole("SubSupMismatch");
+        ReportErrorToConsole("SubSupMismatch");
       }
     }
-    return aFrame->ReflowError(aRenderingContext, aDesiredSize);
+    return ReflowError(aRenderingContext, aDesiredSize);
   }
 
   // we left out the width of prescripts, so ...
-  boundingMetrics.rightBearing += prescriptsWidth;
-  boundingMetrics.width += prescriptsWidth;
-
-  // Zero out the shifts in where a frame isn't present to avoid the potential
-  // for overflow.
-  if (!subScriptFrame)
-    maxSubScriptShift = 0;
-  if (!supScriptFrame)
-    maxSupScriptShift = 0;
+  mBoundingMetrics.rightBearing += prescriptsWidth;
+  mBoundingMetrics.width += prescriptsWidth;
 
   // we left out the base during our bounding box updates, so ...
-  if (tag == nsGkAtoms::msub_) {
-    boundingMetrics.ascent = std::max(bmBase.ascent,
-                                      bmMultiSub.ascent - maxSubScriptShift);
-  } else {
-    boundingMetrics.ascent =
-      std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift));
-  }
-  if (tag == nsGkAtoms::msup_) {
-    boundingMetrics.descent = std::max(bmBase.descent,
-                                       bmMultiSup.descent - maxSupScriptShift);
-  } else {
-    boundingMetrics.descent =
-      std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift));
-  }
-  aFrame->SetBoundingMetrics(boundingMetrics);
+  mBoundingMetrics.ascent =
+    std::max(mBoundingMetrics.ascent+maxSupScriptShift,bmBase.ascent);
+  mBoundingMetrics.descent =
+    std::max(mBoundingMetrics.descent+maxSubScriptShift,bmBase.descent);
 
   // get the reflow metrics ...
-  aDesiredSize.ascent = 
-    std::max(baseSize.ascent, 
-             std::max(multiSubSize.ascent - maxSubScriptShift,
-                      multiSupSize.ascent + maxSupScriptShift));
+  aDesiredSize.ascent =
+    std::max(ascent+maxSupScriptShift,baseSize.ascent);
   aDesiredSize.height = aDesiredSize.ascent +
-    std::max(baseSize.height - baseSize.ascent,
-             std::max(multiSubSize.height + maxSubScriptShift,
-                      multiSupSize.height - maxSupScriptShift));
-  aDesiredSize.width = boundingMetrics.width;
-  aDesiredSize.mBoundingMetrics = boundingMetrics;
+    std::max(descent+maxSubScriptShift,baseSize.height - baseSize.ascent);
+  aDesiredSize.width = mBoundingMetrics.width;
+  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
 
-  aFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
+  mReference.x = 0;
+  mReference.y = aDesiredSize.ascent;
 
   //////////////////
   // Place Children
 
   // Place prescripts, followed by base, and then postscripts.
   // The list of frames is in the order: {base} {postscripts} {prescripts}
   // We go over the list in a circular manner, starting at <prescripts/>
 
   if (aPlaceOrigin) {
     nscoord dx = 0, dy = 0;
 
-    // With msub and msup there is only one element and 
-    // subscriptFrame/supScriptFrame have already been set above where
-    // relevant.  In these cases we skip to the reflow part.
-    if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_)
-      count = 1;
-    else
-      count = 0;
-    childFrame = prescriptsFrame;
+    count = 0;
+    childFrame = mprescriptsFrame;
     do {
       if (!childFrame) { // end of prescripts,
         // place the base ...
         childFrame = baseFrame;
         dy = aDesiredSize.ascent - baseSize.ascent;
-        FinishReflowChild (baseFrame, aPresContext, nullptr, baseSize,
-                           aFrame->MirrorIfRTL(aDesiredSize.width,
-                                               baseSize.width,
-                                               dx),
+        FinishReflowChild (baseFrame, PresContext(), nullptr, baseSize,
+                           MirrorIfRTL(aDesiredSize.width,
+                                       baseSize.width,
+                                       dx),
                            dy, 0);
         dx += bmBase.width + italicCorrection;
-      } else if (prescriptsFrame != childFrame) {
+      }
+      else if (mprescriptsFrame != childFrame) {
         // process each sup/sub pair
         if (0 == count) {
           subScriptFrame = childFrame;
           count = 1;
-        } else if (1 == count) {
-          if (tag != nsGkAtoms::msub_)
-            supScriptFrame = childFrame;
+        }
+        else if (1 == count) {
+          supScriptFrame = childFrame;
           count = 0;
 
           // get the ascent/descent of sup/subscripts stored in their rects
           // rect.x = descent, rect.y = ascent
-          if (subScriptFrame)
-            GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
-          if (supScriptFrame)
-            GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
+          GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
+          GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
 
           // center w.r.t. largest width
           width = std::max(subScriptSize.width, supScriptSize.width);
 
-          if (subScriptFrame) {
-            dy = aDesiredSize.ascent - subScriptSize.ascent +
-              maxSubScriptShift;
-            FinishReflowChild (subScriptFrame, aPresContext, nullptr,
-                               subScriptSize,
-                               aFrame->MirrorIfRTL(aDesiredSize.width,
-                                                   subScriptSize.width,
-                                                   dx + (width-subScriptSize.width)/2),
-                               dy, 0);
-          }
+          dy = aDesiredSize.ascent - subScriptSize.ascent +
+            maxSubScriptShift;
+          FinishReflowChild (subScriptFrame, PresContext(), nullptr,
+                             subScriptSize,
+                             MirrorIfRTL(aDesiredSize.width,
+                                         subScriptSize.width,
+                                         dx + (width-subScriptSize.width)/2),
+                             dy, 0);
 
-          if (supScriptFrame) {
-            dy = aDesiredSize.ascent - supScriptSize.ascent -
-              maxSupScriptShift;
-            FinishReflowChild (supScriptFrame, aPresContext, nullptr,
-                               supScriptSize,
-                               aFrame->MirrorIfRTL(aDesiredSize.width,
-                                                   supScriptSize.width,
-                                                   dx + (width-supScriptSize.width)/2),
-                               dy, 0);
-          }
-          dx += width + aScriptSpace;
+          dy = aDesiredSize.ascent - supScriptSize.ascent -
+            maxSupScriptShift;
+          FinishReflowChild (supScriptFrame, PresContext(), nullptr,
+                             supScriptSize,
+                             MirrorIfRTL(aDesiredSize.width,
+                                         supScriptSize.width,
+                                         dx + (width-supScriptSize.width)/2),
+                             dy, 0);
+
+          dx += width + scriptSpace;
         }
       }
       childFrame = childFrame->GetNextSibling();
-    } while (prescriptsFrame != childFrame);
+    } while (mprescriptsFrame != childFrame);
   }
 
   return NS_OK;
 }
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.h
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.h
@@ -7,45 +7,37 @@
 #define nsMathMLmmultiscriptsFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsCOMPtr.h"
 #include "nsMathMLContainerFrame.h"
 
 //
 // <mmultiscripts> -- attach prescripts and tensor indices to a base 
-// <msub> -- attach a subscript to a base
-// <msubsup> -- attach a subscript-superscript pair to a base
-// <msup> -- attach a superscript to a base
 //
 
 class nsMathMLmmultiscriptsFrame : public nsMathMLContainerFrame {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   NS_IMETHOD
   TransmitAutomaticData() MOZ_OVERRIDE;
 
   virtual nsresult
   Place(nsRenderingContext& aRenderingContext,
         bool                 aPlaceOrigin,
         nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
 
-  static nsresult
-  PlaceMultiScript(nsPresContext*      aPresContext,
-                    nsRenderingContext& aRenderingContext,
-                    bool                 aPlaceOrigin,
-                    nsHTMLReflowMetrics& aDesiredSize,
-                    nsMathMLContainerFrame* aForFrame,
-                    nscoord              aUserSubScriptShift,
-                    nscoord              aUserSupScriptShift,
-                    nscoord              aScriptSpace);
-
 protected:
   nsMathMLmmultiscriptsFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
   virtual ~nsMathMLmmultiscriptsFrame();
   
+private:
+  nscoord mSubScriptShift;
+  nscoord mSupScriptShift;
 
+  void
+  ProcessAttributes();
 };
 
 #endif /* nsMathMLmmultiscriptsFrame_h___ */
new file mode 100644
--- /dev/null
+++ b/layout/mathml/nsMathMLmsubFrame.cpp
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsCOMPtr.h"
+#include "nsFrame.h"
+#include "nsPresContext.h"
+#include "nsStyleContext.h"
+#include "nsStyleConsts.h"
+
+#include "nsMathMLmsubFrame.h"
+#include <algorithm>
+
+//
+// <msub> -- attach a subscript to a base - implementation
+//
+
+nsIFrame*
+NS_NewMathMLmsubFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+  return new (aPresShell) nsMathMLmsubFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmsubFrame)
+
+nsMathMLmsubFrame::~nsMathMLmsubFrame()
+{
+}
+
+NS_IMETHODIMP
+nsMathMLmsubFrame::TransmitAutomaticData()
+{
+  // if our base is an embellished operator, let its state bubble to us
+  mPresentationData.baseFrame = mFrames.FirstChild();
+  GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
+
+  // 1. The REC says:
+  // The <msub> element increments scriptlevel by 1, and sets displaystyle to
+  // "false", within subscript, but leaves both attributes unchanged within base.
+  // 2. The TeXbook (Ch 17. p.141) says the subscript is compressed
+  UpdatePresentationDataFromChildAt(1, -1,
+    ~NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED,
+     NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED);
+
+  return NS_OK;
+}
+
+/* virtual */ nsresult
+nsMathMLmsubFrame::Place (nsRenderingContext& aRenderingContext,
+                          bool                 aPlaceOrigin,
+                          nsHTMLReflowMetrics& aDesiredSize)
+{
+  // extra spacing after sup/subscript
+  nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); // 0.5pt as in plain TeX
+
+  // subscriptshift
+  //
+  // "Specifies the minimum amount to shift the baseline of subscript down; the
+  // default is for the rendering agent to use its own positioning rules."
+  //
+  // values: length
+  // default: automatic
+  //
+  // We use 0 as the default value so unitless values can be ignored.
+  // As a minimum, negative values can be ignored.
+  //
+  nscoord subScriptShift = 0;
+  nsAutoString value;
+  GetAttribute(mContent, mPresentationData.mstyle,
+               nsGkAtoms::subscriptshift_, value);
+  if (!value.IsEmpty()) {
+    ParseNumericValue(value, &subScriptShift, 0, PresContext(), mStyleContext);
+  }
+
+  return nsMathMLmsubFrame::PlaceSubScript(PresContext(), 
+                                           aRenderingContext,
+                                           aPlaceOrigin,
+                                           aDesiredSize,
+                                           this,
+                                           subScriptShift,
+                                           scriptSpace);
+}
+
+// exported routine that both munder and msub share.
+// munder uses this when movablelimits is set.
+nsresult
+nsMathMLmsubFrame::PlaceSubScript (nsPresContext*      aPresContext,
+                                   nsRenderingContext& aRenderingContext,
+                                   bool                 aPlaceOrigin,
+                                   nsHTMLReflowMetrics& aDesiredSize,
+                                   nsMathMLContainerFrame* aFrame,
+                                   nscoord              aUserSubScriptShift,
+                                   nscoord              aScriptSpace)
+{
+  // force the scriptSpace to be atleast 1 pixel 
+  aScriptSpace = std::max(nsPresContext::CSSPixelsToAppUnits(1), aScriptSpace);
+
+  ////////////////////////////////////
+  // Get the children's desired sizes
+
+  nsBoundingMetrics bmBase, bmSubScript;
+  nsHTMLReflowMetrics baseSize;
+  nsHTMLReflowMetrics subScriptSize;
+  nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
+  nsIFrame* subScriptFrame = nullptr;
+  if (baseFrame)
+    subScriptFrame = baseFrame->GetNextSibling();
+  if (!baseFrame || !subScriptFrame || subScriptFrame->GetNextSibling()) {
+    // report an error, encourage people to get their markups in order
+    if (aPlaceOrigin) {
+      aFrame->ReportChildCountError();
+    }
+    return aFrame->ReflowError(aRenderingContext, aDesiredSize);
+  }
+  GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
+  GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
+
+  // get the subdrop from the subscript font
+  nscoord subDrop;
+  GetSubDropFromChild(subScriptFrame, subDrop);
+  // parameter v, Rule 18a, App. G, TeXbook
+  nscoord minSubScriptShift = bmBase.descent + subDrop;
+
+  //////////////////
+  // Place Children
+  
+  // get min subscript shift limit from x-height
+  // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
+  nscoord xHeight = 0;
+  nsRefPtr<nsFontMetrics> fm;
+  nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
+
+  xHeight = fm->XHeight();
+  nscoord minShiftFromXHeight = (nscoord) 
+    (bmSubScript.ascent - (4.0f/5.0f) * xHeight);
+
+  // subScriptShift
+  // = minimum amount to shift the subscript down set by user or from the font
+  // = sub1 in TeX
+  // = subscriptshift attribute * x-height
+  nscoord subScriptShift, dummy;
+  // get subScriptShift default from font
+  GetSubScriptShifts (fm, subScriptShift, dummy);
+
+  subScriptShift = 
+    std::max(subScriptShift, aUserSubScriptShift);
+
+  // get actual subscriptshift to be used
+  // Rule 18b, App. G, TeXbook
+  nscoord actualSubScriptShift = 
+    std::max(minSubScriptShift,std::max(subScriptShift,minShiftFromXHeight));
+  // get bounding box for base + subscript
+  nsBoundingMetrics boundingMetrics;
+  boundingMetrics.ascent = 
+    std::max(bmBase.ascent, bmSubScript.ascent - actualSubScriptShift);
+  boundingMetrics.descent = 
+    std::max(bmBase.descent, bmSubScript.descent + actualSubScriptShift);
+
+  // add aScriptSpace to the subscript's width
+  boundingMetrics.width = bmBase.width + bmSubScript.width + aScriptSpace;
+  boundingMetrics.leftBearing = bmBase.leftBearing;
+  boundingMetrics.rightBearing = std::max(bmBase.rightBearing, bmBase.width +
+    std::max(bmSubScript.width + aScriptSpace, bmSubScript.rightBearing));
+  aFrame->SetBoundingMetrics (boundingMetrics);
+
+  // reflow metrics
+  aDesiredSize.ascent = 
+    std::max(baseSize.ascent, subScriptSize.ascent - actualSubScriptShift);
+  aDesiredSize.height = aDesiredSize.ascent +
+    std::max(baseSize.height - baseSize.ascent,
+           subScriptSize.height - subScriptSize.ascent + actualSubScriptShift);
+  aDesiredSize.width = boundingMetrics.width;
+  aDesiredSize.mBoundingMetrics = boundingMetrics;
+
+  aFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
+
+  if (aPlaceOrigin) {
+    nscoord dx, dy;
+    // now place the base ...
+    dx = aFrame->MirrorIfRTL(aDesiredSize.width, baseSize.width, 0);
+    dy = aDesiredSize.ascent - baseSize.ascent;
+    FinishReflowChild (baseFrame, aPresContext, nullptr, baseSize, dx, dy, 0);
+    // ... and subscript
+    dx = aFrame->MirrorIfRTL(aDesiredSize.width, subScriptSize.width,
+                             bmBase.width);
+    dy = aDesiredSize.ascent - (subScriptSize.ascent - actualSubScriptShift);
+    FinishReflowChild (subScriptFrame, aPresContext, nullptr, subScriptSize, dx, dy, 0);
+  }
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/layout/mathml/nsMathMLmsubFrame.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef nsMathMLmsubFrame_h___
+#define nsMathMLmsubFrame_h___
+
+#include "mozilla/Attributes.h"
+#include "nsCOMPtr.h"
+#include "nsMathMLContainerFrame.h"
+
+//
+// <msub> -- attach a subscript to a base
+//
+
+class nsMathMLmsubFrame : public nsMathMLContainerFrame {
+public:
+  NS_DECL_FRAMEARENA_HELPERS
+
+  friend nsIFrame* NS_NewMathMLmsubFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+
+  NS_IMETHOD
+  TransmitAutomaticData() MOZ_OVERRIDE;
+
+  virtual nsresult
+  Place(nsRenderingContext& aRenderingContext,
+        bool                 aPlaceOrigin,
+        nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
+
+  static nsresult
+  PlaceSubScript (nsPresContext*      aPresContext,
+                  nsRenderingContext& aRenderingContext,
+                  bool                 aPlaceOrigin,
+                  nsHTMLReflowMetrics& aDesiredSize,
+                  nsMathMLContainerFrame* aForFrame,
+                  nscoord              aUserSubScriptShift,
+                  nscoord              aScriptSpace);
+
+ protected:
+  nsMathMLmsubFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
+  virtual ~nsMathMLmsubFrame();
+};
+
+#endif /* nsMathMLmsubFrame_h___ */
new file mode 100644
--- /dev/null
+++ b/layout/mathml/nsMathMLmsubsupFrame.cpp
@@ -0,0 +1,341 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsCOMPtr.h"
+#include "nsFrame.h"
+#include "nsPresContext.h"
+#include "nsStyleContext.h"
+#include "nsStyleConsts.h"
+#include "nsRenderingContext.h"
+
+#include "nsMathMLmsubsupFrame.h"
+#include <algorithm>
+
+//
+// <msubsup> -- attach a subscript-superscript pair to a base - implementation
+//
+
+nsIFrame*
+NS_NewMathMLmsubsupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+  return new (aPresShell) nsMathMLmsubsupFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmsubsupFrame)
+
+nsMathMLmsubsupFrame::~nsMathMLmsubsupFrame()
+{
+}
+
+NS_IMETHODIMP
+nsMathMLmsubsupFrame::TransmitAutomaticData()
+{
+  // if our base is an embellished operator, let its state bubble to us
+  mPresentationData.baseFrame = mFrames.FirstChild();
+  GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
+
+  // 1. The REC says:
+  //    The <msubsup> element increments scriptlevel by 1, and sets displaystyle to
+  //    "false", within subscript and superscript, but leaves both attributes
+  //    unchanged within base.
+  // 2. The TeXbook (Ch 17. p.141) says the superscript inherits the compression
+  //    while the subscript is compressed
+  UpdatePresentationDataFromChildAt(1, -1,
+    ~NS_MATHML_DISPLAYSTYLE,
+     NS_MATHML_DISPLAYSTYLE);
+  UpdatePresentationDataFromChildAt(1,  1,
+     NS_MATHML_COMPRESSED,
+     NS_MATHML_COMPRESSED);
+
+  return NS_OK;
+}
+
+/* virtual */ nsresult
+nsMathMLmsubsupFrame::Place(nsRenderingContext& aRenderingContext,
+                            bool                 aPlaceOrigin,
+                            nsHTMLReflowMetrics& aDesiredSize)
+{
+  // extra spacing between base and sup/subscript
+  nscoord scriptSpace = 0;
+
+  // subscriptshift
+  //
+  // "Specifies the minimum amount to shift the baseline of subscript down; the
+  // default is for the rendering agent to use its own positioning rules."
+  //
+  // values: length
+  // default: automatic
+  //
+  // We use 0 as the default value so unitless values can be ignored.
+  // As a minimum, negative values can be ignored.
+  //
+  nsAutoString value;
+  nscoord subScriptShift = 0;
+  GetAttribute(mContent, mPresentationData.mstyle,
+               nsGkAtoms::subscriptshift_, value);
+  if (!value.IsEmpty()) {
+    ParseNumericValue(value, &subScriptShift, 0, PresContext(), mStyleContext);
+  }
+  // superscriptshift
+  //
+  // "Specifies the minimum amount to shift the baseline of superscript up; the
+  // default is for the rendering agent to use its own positioning rules."
+  //
+  // values: length
+  // default: automatic
+  //
+  // We use 0 as the default value so unitless values can be ignored.
+  // As a minimum, negative values can be ignored.
+  //
+  nscoord supScriptShift = 0;
+  GetAttribute(mContent, mPresentationData.mstyle,
+               nsGkAtoms::superscriptshift_, value);
+  if (!value.IsEmpty()) {
+    ParseNumericValue(value, &supScriptShift, 0, PresContext(), mStyleContext);
+  }
+
+  return nsMathMLmsubsupFrame::PlaceSubSupScript(PresContext(),
+                                                 aRenderingContext,
+                                                 aPlaceOrigin,
+                                                 aDesiredSize,
+                                                 this,
+                                                 subScriptShift,
+                                                 supScriptShift,
+                                                 scriptSpace);
+}
+
+// exported routine that both munderover and msubsup share.
+// munderover uses this when movablelimits is set.
+nsresult
+nsMathMLmsubsupFrame::PlaceSubSupScript(nsPresContext*      aPresContext,
+                                        nsRenderingContext& aRenderingContext,
+                                        bool                 aPlaceOrigin,
+                                        nsHTMLReflowMetrics& aDesiredSize,
+                                        nsMathMLContainerFrame* aFrame,
+                                        nscoord              aUserSubScriptShift,
+                                        nscoord              aUserSupScriptShift,
+                                        nscoord              aScriptSpace)
+{
+  // force the scriptSpace to be atleast 1 pixel
+  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
+  aScriptSpace = std::max(onePixel, aScriptSpace);
+
+  ////////////////////////////////////
+  // Get the children's desired sizes
+
+  nsHTMLReflowMetrics baseSize;
+  nsHTMLReflowMetrics subScriptSize;
+  nsHTMLReflowMetrics supScriptSize;
+  nsBoundingMetrics bmBase, bmSubScript, bmSupScript;
+  nsIFrame* subScriptFrame = nullptr;
+  nsIFrame* supScriptFrame = nullptr;
+  nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
+  if (baseFrame)
+    subScriptFrame = baseFrame->GetNextSibling();
+  if (subScriptFrame)
+    supScriptFrame = subScriptFrame->GetNextSibling();
+  if (!baseFrame || !subScriptFrame || !supScriptFrame ||
+      supScriptFrame->GetNextSibling()) {
+    // report an error, encourage people to get their markups in order
+    if (aPlaceOrigin) {
+      aFrame->ReportChildCountError();
+    }
+    return aFrame->ReflowError(aRenderingContext, aDesiredSize);
+  }
+  GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
+  GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
+  GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
+
+  // get the subdrop from the subscript font
+  nscoord subDrop;
+  GetSubDropFromChild(subScriptFrame, subDrop);
+  // parameter v, Rule 18a, App. G, TeXbook
+  nscoord minSubScriptShift = bmBase.descent + subDrop;
+
+  // get the supdrop from the supscript font
+  nscoord supDrop;
+  GetSupDropFromChild(supScriptFrame, supDrop);
+  // parameter u, Rule 18a, App. G, TeXbook
+  nscoord minSupScriptShift = bmBase.ascent - supDrop;
+
+  //////////////////
+  // Place Children
+  //////////////////
+
+  //////////////////////////////////////////////////
+  // Get subscript shift
+  // slightly different from nsMathMLmsubFrame.cpp
+  //////////////////////////////////////////////////
+
+  // subScriptShift{1,2}
+  // = minimum amount to shift the subscript down
+  // = sub{1,2} in TeXbook
+  // subScriptShift1 = subscriptshift attribute * x-height
+  nscoord subScriptShift1, subScriptShift2;
+
+  nsRefPtr<nsFontMetrics> fm;
+  nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
+  aRenderingContext.SetFont(fm);
+
+  // get x-height (an ex)
+  nscoord xHeight = fm->XHeight();
+
+  nscoord ruleSize;
+  GetRuleThickness (aRenderingContext, fm, ruleSize);
+
+  // Get subScriptShift{1,2} default from font
+  GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
+
+  if (0 < aUserSubScriptShift) {
+    // the user has set the subscriptshift attribute
+    float scaler = ((float) subScriptShift2) / subScriptShift1;
+    subScriptShift1 = std::max(subScriptShift1, aUserSubScriptShift);
+    subScriptShift2 = NSToCoordRound(scaler * subScriptShift1);
+  }
+
+  // get a tentative value for subscriptshift
+  // Rule 18d, App. G, TeXbook
+  nscoord subScriptShift =
+    std::max(minSubScriptShift,std::max(subScriptShift1,subScriptShift2));
+
+  //////////////////////////////////////////////////
+  // Get supscript shift
+  // same code from nsMathMLmsupFrame.cpp
+  //////////////////////////////////////////////////
+
+  // get min supscript shift limit from x-height
+  // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
+  nscoord minShiftFromXHeight = (nscoord)
+    (bmSupScript.descent + (1.0f/4.0f) * xHeight);
+
+  // 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);
+  if (0 < aUserSupScriptShift) {
+    // the user has set the superscriptshift attribute
+    float scaler2 = ((float) supScriptShift2) / supScriptShift1;
+    float scaler3 = ((float) supScriptShift3) / supScriptShift1;
+    supScriptShift1 = std::max(supScriptShift1, aUserSupScriptShift);
+    supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1);
+    supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1);
+  }
+
+  // get sup script shift depending on current script level and display style
+  // Rule 18c, App. G, TeXbook
+  nscoord supScriptShift;
+  nsPresentationData presentationData;
+  aFrame->GetPresentationData(presentationData);
+  if ( aFrame->StyleFont()->mScriptLevel == 0 &&
+       NS_MATHML_IS_DISPLAYSTYLE(presentationData.flags) &&
+      !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;
+  }
+
+  // get tentative value for superscriptshift
+  // Rule 18c, App. G, TeXbook
+  supScriptShift =
+    std::max(minSupScriptShift,std::max(supScriptShift,minShiftFromXHeight));
+
+  //////////////////////////////////////////////////
+  // Negotiate between supScriptShift and subScriptShift
+  // so that there will be enough gap between them
+  // Rule 18e, App. G, TeXbook
+  //////////////////////////////////////////////////
+
+  nscoord gap =
+    (supScriptShift - bmSupScript.descent) -
+    (bmSubScript.ascent - subScriptShift);
+  if (gap < 4.0f * ruleSize) {
+    // adjust subScriptShift to get a gap of (4.0 * ruleSize)
+    subScriptShift += NSToCoordRound ((4.0f * ruleSize) - 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 -
+                        (supScriptShift - bmSupScript.descent));
+  if (gap > 0) {
+    supScriptShift += gap;
+    subScriptShift -= gap;
+  }
+
+  //////////////////////////////////////////////////
+  // Do the Placing
+  //////////////////////////////////////////////////
+
+  // get bounding box for base + subscript + superscript
+  nsBoundingMetrics boundingMetrics;
+  boundingMetrics.ascent =
+    std::max(bmBase.ascent, (bmSupScript.ascent + supScriptShift));
+  boundingMetrics.descent =
+   std::max(bmBase.descent, (bmSubScript.descent + subScriptShift));
+
+  // leave aScriptSpace after both super/subscript
+  // add italicCorrection between base and superscript
+  // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we
+  // estimate the italic creation ourselves and it isn't the same as TeX 
+  nscoord italicCorrection;
+  GetItalicCorrection(bmBase, italicCorrection);
+  italicCorrection += onePixel;
+  boundingMetrics.width = bmBase.width + aScriptSpace +
+    std::max((italicCorrection + bmSupScript.width), bmSubScript.width);
+  boundingMetrics.leftBearing = bmBase.leftBearing;
+  boundingMetrics.rightBearing = bmBase.width +
+    std::max((italicCorrection + bmSupScript.rightBearing), bmSubScript.rightBearing);
+  aFrame->SetBoundingMetrics(boundingMetrics);
+
+  // reflow metrics
+  aDesiredSize.ascent =
+    std::max(baseSize.ascent, 
+       std::max(subScriptSize.ascent - subScriptShift,
+              supScriptSize.ascent + supScriptShift));
+  aDesiredSize.height = aDesiredSize.ascent +
+    std::max(baseSize.height - baseSize.ascent,
+       std::max(subScriptSize.height - subScriptSize.ascent + subScriptShift, 
+              supScriptSize.height - subScriptSize.ascent - supScriptShift));
+  aDesiredSize.width = boundingMetrics.width;
+  aDesiredSize.mBoundingMetrics = boundingMetrics;
+
+  aFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
+
+  if (aPlaceOrigin) {
+    nscoord dx, dy;
+    // now place the base ...
+    dx = aFrame->MirrorIfRTL(aDesiredSize.width, baseSize.width, 0);
+    dy = aDesiredSize.ascent - baseSize.ascent;
+    FinishReflowChild(baseFrame, aPresContext, nullptr,
+                      baseSize, dx, dy, 0);
+    // ... and subscript
+    dx = aFrame->MirrorIfRTL(aDesiredSize.width, subScriptSize.width,
+                             bmBase.width);
+    dy = aDesiredSize.ascent - (subScriptSize.ascent - subScriptShift);
+    FinishReflowChild(subScriptFrame, aPresContext, nullptr,
+                      subScriptSize, dx, dy, 0);
+    // ... and the superscript
+    dx = aFrame->MirrorIfRTL(aDesiredSize.width, supScriptSize.width,
+                             bmBase.width + italicCorrection);
+    dy = aDesiredSize.ascent - (supScriptSize.ascent + supScriptShift);
+    FinishReflowChild(supScriptFrame, aPresContext, nullptr,
+                      supScriptSize, dx, dy, 0);
+  }
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/layout/mathml/nsMathMLmsubsupFrame.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef nsMathMLmsubsupFrame_h___
+#define nsMathMLmsubsupFrame_h___
+
+#include "mozilla/Attributes.h"
+#include "nsCOMPtr.h"
+#include "nsMathMLContainerFrame.h"
+
+//
+// <msubsup> -- attach a subscript-superscript pair to a base
+//
+
+class nsMathMLmsubsupFrame : public nsMathMLContainerFrame {
+public:
+  NS_DECL_FRAMEARENA_HELPERS
+
+  friend nsIFrame* NS_NewMathMLmsubsupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+
+  NS_IMETHOD
+  TransmitAutomaticData() MOZ_OVERRIDE;
+
+  virtual nsresult
+  Place(nsRenderingContext& aRenderingContext,
+        bool                 aPlaceOrigin,
+        nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
+
+  static nsresult
+  PlaceSubSupScript(nsPresContext*      aPresContext,
+                    nsRenderingContext& aRenderingContext,
+                    bool                 aPlaceOrigin,
+                    nsHTMLReflowMetrics& aDesiredSize,
+                    nsMathMLContainerFrame* aForFrame,
+                    nscoord              aUserSubScriptShift,
+                    nscoord              aUserSupScriptShift,
+                    nscoord              aScriptSpace);
+
+protected:
+  nsMathMLmsubsupFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
+  virtual ~nsMathMLmsubsupFrame();
+};
+
+#endif /* nsMathMLmsubsupFrame_h___ */
new file mode 100644
--- /dev/null
+++ b/layout/mathml/nsMathMLmsupFrame.cpp
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsCOMPtr.h"
+#include "nsFrame.h"
+#include "nsPresContext.h"
+#include "nsStyleContext.h"
+#include "nsStyleConsts.h"
+
+#include "nsMathMLmsupFrame.h"
+#include <algorithm>
+
+//
+// <msup> -- attach a superscript to a base - implementation
+//
+
+nsIFrame*
+NS_NewMathMLmsupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+  return new (aPresShell) nsMathMLmsupFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmsupFrame)
+
+nsMathMLmsupFrame::~nsMathMLmsupFrame()
+{
+}
+
+NS_IMETHODIMP
+nsMathMLmsupFrame::TransmitAutomaticData()
+{
+  // if our base is an embellished operator, its flags bubble to us
+  mPresentationData.baseFrame = mFrames.FirstChild();
+  GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
+
+  // 1. The REC says:
+  // The <msup> element increments scriptlevel by 1, and sets displaystyle to
+  // "false", within superscript, but leaves both attributes unchanged within base.
+  // 2. The TeXbook (Ch 17. p.141) says the superscript *inherits* the compression,
+  // so we don't set the compression flag. Our parent will propagate its own.
+  UpdatePresentationDataFromChildAt(1, -1,
+    ~NS_MATHML_DISPLAYSTYLE,
+     NS_MATHML_DISPLAYSTYLE);
+
+  return NS_OK;
+}
+
+/* virtual */ nsresult
+nsMathMLmsupFrame::Place(nsRenderingContext& aRenderingContext,
+                         bool                 aPlaceOrigin,
+                         nsHTMLReflowMetrics& aDesiredSize)
+{
+  // extra spacing after sup/subscript
+  nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); // 0.5pt as in plain TeX
+
+  // superscriptshift
+  //
+  // "Specifies the minimum amount to shift the baseline of superscript up; the
+  // default is for the rendering agent to use its own positioning rules."
+  //
+  // values: length
+  // default: automatic
+  //
+  // We use 0 as the default value so unitless values can be ignored.
+  // As a minimum, negative values can be ignored.
+  //
+  nsAutoString value;
+  nscoord supScriptShift = 0;
+  GetAttribute(mContent, mPresentationData.mstyle,
+               nsGkAtoms::superscriptshift_, value);
+  if (!value.IsEmpty()) {
+    ParseNumericValue(value, &supScriptShift, 0, PresContext(), mStyleContext);
+  }
+
+  return nsMathMLmsupFrame::PlaceSuperScript(PresContext(), 
+                                             aRenderingContext,
+                                             aPlaceOrigin,
+                                             aDesiredSize,
+                                             this,
+                                             supScriptShift,
+                                             scriptSpace);
+}
+
+// exported routine that both mover and msup share.
+// mover uses this when movablelimits is set.
+nsresult
+nsMathMLmsupFrame::PlaceSuperScript(nsPresContext*      aPresContext,
+                                    nsRenderingContext& aRenderingContext,
+                                    bool                 aPlaceOrigin,
+                                    nsHTMLReflowMetrics& aDesiredSize,
+                                    nsMathMLContainerFrame* aFrame,
+                                    nscoord              aUserSupScriptShift,
+                                    nscoord              aScriptSpace)
+{
+  // force the scriptSpace to be at least 1 pixel 
+  nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
+  aScriptSpace = std::max(onePixel, aScriptSpace);
+
+  ////////////////////////////////////
+  // Get the children's desired sizes
+
+  nsHTMLReflowMetrics baseSize;
+  nsHTMLReflowMetrics supScriptSize;
+  nsBoundingMetrics bmBase, bmSupScript;
+  nsIFrame* supScriptFrame = nullptr;
+  nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
+  if (baseFrame)
+    supScriptFrame = baseFrame->GetNextSibling();
+  if (!baseFrame || !supScriptFrame || supScriptFrame->GetNextSibling()) {
+    // report an error, encourage people to get their markups in order
+    if (aPlaceOrigin) {
+      aFrame->ReportChildCountError();
+    }
+    return aFrame->ReflowError(aRenderingContext, aDesiredSize);
+  }
+  GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
+  GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
+
+  // get the supdrop from the supscript font
+  nscoord supDrop;
+  GetSupDropFromChild(supScriptFrame, supDrop);
+  // parameter u, Rule 18a, App. G, TeXbook
+  nscoord minSupScriptShift = bmBase.ascent - supDrop;
+
+  //////////////////
+  // Place Children 
+  
+  // get min supscript shift limit from x-height
+  // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
+  nscoord xHeight = 0;
+  nsRefPtr<nsFontMetrics> fm;
+  nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
+
+  xHeight = fm->XHeight();
+  nscoord minShiftFromXHeight = (nscoord) 
+    (bmSupScript.descent + (1.0f/4.0f) * xHeight);
+  nscoord italicCorrection;
+  GetItalicCorrection(bmBase, italicCorrection);
+
+  // 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);
+
+  if (0 < aUserSupScriptShift) {
+    // the user has set the superscriptshift attribute
+    float scaler2 = ((float) supScriptShift2) / supScriptShift1;
+    float scaler3 = ((float) supScriptShift3) / supScriptShift1;
+    supScriptShift1 = 
+      std::max(supScriptShift1, aUserSupScriptShift);
+    supScriptShift2 = NSToCoordRound(scaler2 * supScriptShift1);
+    supScriptShift3 = NSToCoordRound(scaler3 * supScriptShift1);
+  }
+
+  // get sup script shift depending on current script level and display style
+  // Rule 18c, App. G, TeXbook
+  nscoord supScriptShift;
+  nsPresentationData presentationData;
+  aFrame->GetPresentationData (presentationData);
+  if ( aFrame->StyleFont()->mScriptLevel == 0 && 
+       NS_MATHML_IS_DISPLAYSTYLE(presentationData.flags) &&
+      !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;
+  }
+
+  // get actual supscriptshift to be used
+  // Rule 18c, App. G, TeXbook
+  nscoord actualSupScriptShift = 
+    std::max(minSupScriptShift,std::max(supScriptShift,minShiftFromXHeight));
+
+  // bounding box
+  nsBoundingMetrics boundingMetrics;
+  boundingMetrics.ascent =
+    std::max(bmBase.ascent, (bmSupScript.ascent + actualSupScriptShift));
+  boundingMetrics.descent =
+    std::max(bmBase.descent, (bmSupScript.descent - actualSupScriptShift));
+
+  // leave aScriptSpace after superscript
+  // add italicCorrection between base and superscript
+  // add "a little to spare" as well (see TeXbook Ch.11, p.64), as we
+  // estimate the italic creation ourselves and it isn't the same as TeX 
+  italicCorrection += onePixel;
+  boundingMetrics.width = bmBase.width + italicCorrection +
+                          bmSupScript.width + aScriptSpace;
+  boundingMetrics.leftBearing = bmBase.leftBearing;
+  boundingMetrics.rightBearing = bmBase.width + italicCorrection +
+                                 bmSupScript.rightBearing;
+  aFrame->SetBoundingMetrics(boundingMetrics);
+
+  // reflow metrics
+  aDesiredSize.ascent =
+    std::max(baseSize.ascent, (supScriptSize.ascent + actualSupScriptShift));
+  aDesiredSize.height = aDesiredSize.ascent +
+    std::max(baseSize.height - baseSize.ascent,
+           (supScriptSize.height - supScriptSize.ascent - actualSupScriptShift));
+  aDesiredSize.width = boundingMetrics.width;
+  aDesiredSize.mBoundingMetrics = boundingMetrics;
+
+  aFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
+
+  if (aPlaceOrigin) {
+    nscoord dx, dy;
+    // now place the base ...
+    dx = aFrame->MirrorIfRTL(aDesiredSize.width, baseSize.width, 0);
+    dy = aDesiredSize.ascent - baseSize.ascent;
+    FinishReflowChild (baseFrame, aPresContext, nullptr, baseSize, dx, dy, 0);
+    // ... and supscript
+    dx = aFrame->MirrorIfRTL(aDesiredSize.width, supScriptSize.width,
+                             bmBase.width + italicCorrection);
+    dy = aDesiredSize.ascent - (supScriptSize.ascent + actualSupScriptShift);
+    FinishReflowChild (supScriptFrame, aPresContext, nullptr, supScriptSize, dx, dy, 0);
+  }
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/layout/mathml/nsMathMLmsupFrame.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef nsMathMLmsupFrame_h___
+#define nsMathMLmsupFrame_h___
+
+#include "mozilla/Attributes.h"
+#include "nsCOMPtr.h"
+#include "nsMathMLContainerFrame.h"
+
+//
+// <msup> -- attach a superscript to a base
+//
+
+class nsMathMLmsupFrame : public nsMathMLContainerFrame {
+public:
+  NS_DECL_FRAMEARENA_HELPERS
+
+  friend nsIFrame* NS_NewMathMLmsupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+
+  NS_IMETHOD
+  TransmitAutomaticData() MOZ_OVERRIDE;
+
+  virtual nsresult
+  Place(nsRenderingContext& aRenderingContext,
+        bool                 aPlaceOrigin,
+        nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
+
+  static nsresult
+  PlaceSuperScript (nsPresContext*      aPresContext,
+                    nsRenderingContext& aRenderingContext,
+                    bool                 aPlaceOrigin,
+                    nsHTMLReflowMetrics& aDesiredSize,
+                    nsMathMLContainerFrame* aForFrame,
+                    nscoord              aUserSupScriptShift,
+                    nscoord              aScriptSpace);
+
+protected:
+  nsMathMLmsupFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
+  virtual ~nsMathMLmsupFrame();
+};
+
+#endif /* nsMathMLmsupFrame_h___ */
--- a/layout/mathml/nsMathMLmunderoverFrame.cpp
+++ b/layout/mathml/nsMathMLmunderoverFrame.cpp
@@ -8,17 +8,19 @@
 #include "nsFrame.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "nsStyleConsts.h"
 #include "nsINameSpaceManager.h"
 #include "nsRenderingContext.h"
 
 #include "nsMathMLmunderoverFrame.h"
-#include "nsMathMLmmultiscriptsFrame.h"
+#include "nsMathMLmsubsupFrame.h"
+#include "nsMathMLmsupFrame.h"
+#include "nsMathMLmsubFrame.h"
 #include <algorithm>
 
 //
 // <munderover> -- attach an underscript-overscript pair to a base - implementation
 // <mover> -- attach an overscript to a base - implementation
 // <munder> -- attach an underscript to a base - implementation
 //
 
@@ -303,37 +305,37 @@ nsMathMLmunderoverFrame::Place(nsRenderi
                                nsHTMLReflowMetrics& aDesiredSize)
 {
   nsIAtom* tag = mContent->Tag();
   if ( NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
        !NS_MATHML_IS_DISPLAYSTYLE(mPresentationData.flags)) {
     //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);
+      return nsMathMLmsubsupFrame::PlaceSubSupScript(PresContext(),
+                                                     aRenderingContext,
+                                                     aPlaceOrigin,
+                                                     aDesiredSize,
+                                                     this, 0, 0,
+                                                     scriptSpace);
     } else if (tag == nsGkAtoms::munder_) {
-      return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
-                                                          aRenderingContext,
-                                                          aPlaceOrigin,
-                                                          aDesiredSize,
-                                                          this, 0, 0,
-                                                          scriptSpace);
+      return nsMathMLmsubFrame::PlaceSubScript(PresContext(),
+                                               aRenderingContext,
+                                               aPlaceOrigin,
+                                               aDesiredSize,
+                                               this, 0,
+                                               scriptSpace);
     } else {
       NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized");
-      return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
-                                                          aRenderingContext,
-                                                          aPlaceOrigin,
-                                                          aDesiredSize,
-                                                          this, 0, 0,
-                                                          scriptSpace);
+      return nsMathMLmsupFrame::PlaceSuperScript(PresContext(),
+                                                 aRenderingContext,
+                                                 aPlaceOrigin,
+                                                 aDesiredSize,
+                                                 this, 0,
+                                                 scriptSpace);
     }
     
   }
 
   ////////////////////////////////////
   // Get the children's desired sizes
 
   nsBoundingMetrics bmBase, bmUnder, bmOver;
--- a/layout/mathml/tests/Makefile.in
+++ b/layout/mathml/tests/Makefile.in
@@ -9,13 +9,11 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES =\
 	test_bug706406.html \
 	test_bug553917.html \
-	test_bug827713-2.html \
-	test_bug827713.html \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/layout/mathml/tests/test_bug827713-2.html
+++ /dev/null
@@ -1,157 +0,0 @@
-<!DOCTYPE HTML>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=553917
--->
-<html>
-  <head>
-    <title>Test for error handling aspect of Bug 827713</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" />
-    <script type="application/javascript">
-      if (navigator.platform.indexOf("Win") == 0) {
-        SimpleTest.expectAssertions(20, 22);
-      } else {
-        SimpleTest.expectAssertions(22);
-      }
-
-      var stringBundleService = 
-        SpecialPowers.Cc["@mozilla.org/intl/stringbundle;1"]
-                    .getService(SpecialPowers.Ci.nsIStringBundleService);
-      var g_bundl =
-        stringBundleService.createBundle("chrome://global/locale/mathml/mathml.properties");
-      
-      var g_errorInfo = {
-        InvalidChild: {
-          status : [false, false, false, false, false, false],
-          args : [["mprescripts", "msubsup"], ["mprescripts", "msubsup"],
-                 ["mprescripts", "msub"], ["none", "msub"], ["none","msup"],
-                 ["none","msubsup"]]
-        },
-
-        MMultiscriptsErrors: {
-          status: [false, false],
-          args: ["NoBase", "SubSupMismatch"]
-        }
-    };
-      
-      var g_errorTypes = ["InvalidChild", "MMultiscriptsErrors"];
-      
-      function getErrorMessage(name,idx)
-      {
-        if (name != "MMultiscriptsErrors") {
-          return g_bundl.formatStringFromName(name,g_errorInfo[name].args[idx], 
-                                            g_errorInfo[name].args[idx].length);
-        }
-        else {
-          return g_bundl.formatStringFromName(g_errorInfo[name].args[idx],[],0);
-        }
-      }
-    
-    /** Checks the roll call to see if all expected error messages were present. */
-    function processRollCall()
-    {
-      for (var i=0; i<g_errorTypes.length;i++) {
-        for (var j = 0; j < g_errorInfo[g_errorTypes[i]].status.length; j++) {
-          ok(g_errorInfo[g_errorTypes[i]].status[j],
-             "\"" + getErrorMessage(g_errorTypes[i], j)
-                  + "\" was expected to be in the error console.");
-        }
-      }
-    }
-    
-    /** Tests a candidate to see if it is one of the expected messages and updates the 
-        g_errorInfo structure if it is. */
-    function doRollCall(msg)
-    {
-      for (var i = 0; i < g_errorTypes.length; i++) {
-        for (var j = 0; j < g_errorInfo[g_errorTypes[i]].status.length; j++) {
-          if (msg == getErrorMessage(g_errorTypes[i], j))
-          {
-            g_errorInfo[g_errorTypes[i]].status[j] = true;
-          }
-        }
-      }
-    }
-    
-    SpecialPowers.registerConsoleListener(
-      function (msg) {
-        if (msg.message == "SENTINEL") {
-          processRollCall();
-          SimpleTest.finish();
-        } else if (msg.isScriptError) {
-          doRollCall(msg.errorMessage);
-        }
-      });
-      
-    SimpleTest.waitForExplicitFinish();
-  </script>
-  </head>
-  <body onload="SpecialPowers.postConsoleSentinel();">
-    <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827713">Mozilla Bug 827713</a>
-    
-    <!-- InvalidChild -->
-    <math>
-      <msubsup>
-        <mprescripts/>
-      </msubsup>
-    </math>
-
-    <math>
-      <msubsup>
-        <mprescripts/>
-        <mprescripts/>
-      </msubsup>
-    </math>
-
-    <math>
-      <msub>
-        <mtext>a</mtext>
-        <mprescripts/>
-        <mtext>a</mtext>
-        <mprescripts/>
-      </msub>
-    </math>
-
-    <math>
-      <msub>
-        <mtext>a</mtext>
-        <none/>
-      </msub>
-    </math>
-
-    <math>
-      <msup>
-        <mtext>a</mtext>
-        <none/>
-      </msup>
-    </math>
-
-    <math>
-      <msubsup>
-        <mtext>a</mtext>
-        <mtext>b</mtext>
-        <none/>
-      </msubsup>
-    </math>
-
-    <!-- NoBase -->
-    <math>
-      <mmultiscripts>
-        <none/>
-        <mtext>b</mtext>
-        <mtext>c</mtext>
-      </mmultiscripts>
-    </math>
-
-    <!-- SubSupMismatch -->
-    <math>
-      <mmultiscripts>
-        <mtext>b</mtext>
-        <mtext>c</mtext>
-        <mprescripts/>
-        <mtext>a</mtext>
-      </mmultiscripts>
-    </math>
-  </body>
-</html>
deleted file mode 100644
--- a/layout/mathml/tests/test_bug827713.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=706406
--->
-<head>
-  <title>Test for Bug 706406</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827713">Mozilla Bug 827713</a>
-<p id="display"></p>
-  <p><math>
-    <msub subscriptshift="50px">
-      <mspace width="50px" height="25px" depth="25px" mathbackground="blue" id ="subbase"></mspace>
-      <mspace width="50px" height="25px" depth="25px" mathbackground="red" id="subsub"></mspace>
-    </msub>
-  </math></p>
-
-  <p><math>
-    <msup superscriptshift="50px">
-      <mspace width="50px" height="25px" depth="25px" mathbackground="blue" id="supbase"></mspace>
-      <mspace width="50px" height="25px" depth="25px" mathbackground="green" id="supsup"></mspace>
-    </msup>
-  </math></p>
-
-  <p><math>
-    <msubsup subscriptshift="50px" superscriptshift="50px">
-      <mspace width="50px" height="25px" depth="25px" mathbackground="blue" id="ssbase"></mspace>
-      <mspace width="50px" height="25px" depth="25px" mathbackground="red" id="sssub"></mspace>
-      <mspace width="50px" height="25px" depth="25px" mathbackground="green" id="sssup"></mspace>
-    </msubsup>
-  </math></p>
-<pre id="test">
-<script type="application/javascript">
-
-    /** Test for the scriptshift aspect of bug 827713 **/
-    SimpleTest.waitForExplicitFinish();
-
-    subBaseRect = $("subbase").getBoundingClientRect();
-    subSubRect = $("subsub").getBoundingClientRect();
-    is(subBaseRect.bottom, subSubRect.top, "Bad subscript shift for msub");
-
-    supBaseRect = $("supbase").getBoundingClientRect();
-    supSupRect = $("supsup").getBoundingClientRect();
-    is(supBaseRect.top, supSupRect.bottom, "Bad superscript shift for msup");
-
-    ssBaseRect = $("ssbase").getBoundingClientRect();
-    ssSubRect = $("sssub").getBoundingClientRect();
-    ssSupRect = $("sssup").getBoundingClientRect();
-    is(ssBaseRect.bottom, ssSubRect.top, "Bad subscript shift for msubusp");
-    is(ssBaseRect.top, ssSupRect.bottom, "Bad superscript shift for msubusp");
-
-
-    SimpleTest.finish();
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/layout/reftests/mathml/multiscripts-1-ref.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<html><head>
-<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Comparison of script elements</title></head>
-  <body>
-    msubsup:
-    <math>
-      <mmultiscripts style="background: red;">
-	<mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-	<mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-	<mtext style="background-color: rgba(0, 255, 0, 0.4);">ccc</mtext>
-      </mmultiscripts>
-    </math>
-
-    <br><br>
-
-    msubsup:
-    <math>
-      <mmultiscripts style="background: red;">
-	<mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-	<mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-        <none/>
-      </mmultiscripts>
-    </math>
-
-    <br><br>
-
-    msup / msubsup:
-    <math>
-      <mmultiscripts style="background: red;">
-	<mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <none/>
-	<mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-      </mmultiscripts>
-    </math>
-
-    <math>
-      <mmultiscripts style="background: red;">
-	<mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <none/>
-	<mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-      </mmultiscripts>
-    </math>
-
-    <br><br>
-
-
-    mrow / msub:
-    <math>
-      <mrow style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-      </mrow>
-    </math>
-
-    <math>
-      <mrow style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-      </mrow>
-    </math>
-
-    <br><br>
-
-    msup / msupsub:
-    <math>
-      <mmultiscripts style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-      </mmultiscripts>
-    </math>
-
-    <math>
-      <mmultiscripts style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-      </mmultiscripts>
-    </math>
-
-</body></html>
deleted file mode 100644
--- a/layout/reftests/mathml/multiscripts-1.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<html><head>
-<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Comparison of script elements</title></head>
-  <body>
-    msubsup:
-    <math>
-      <msubsup style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-        <mtext style="background-color: rgba(0, 255, 0, 0.4);">ccc</mtext>
-      </msubsup>
-    </math>
-
-    <br><br>
-
-    <!-- Different rules apply to msub, so it won't provide equivalent output -->
-    msubsup:
-    <math>
-      <msubsup style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-        <mrow></mrow>
-      </msubsup>
-    </math>
-
-    <br><br>
-
-    msup / msubsup:
-    <math>
-      <msup style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-      </msup>
-    </math>
-
-    <math>
-      <msubsup style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mrow></mrow>
-        <mtext style="background-color: rgba(0, 255, 0, 0.4);">bbb</mtext>
-      </msubsup>
-    </math>
-
-    <br><br>
-
-    mrow / msub:
-    <math>
-      <mrow style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-      </mrow>
-    </math>
-
-    <math>
-      <msub style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mrow></mrow>
-      </msub>
-    </math>
-
-    <br><br>
-
-    msup / msupsub:
-    <math>
-      <msup style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mrow></mrow>
-      </msup>
-    </math>
-
-    <math>
-      <msubsup style="background: red;">
-        <mtext style="background-color: rgba(0, 0, 255, 0.4);">AAA</mtext>
-        <mrow></mrow>
-        <mrow></mrow>
-      </msubsup>
-    </math>
-
-</body></html>
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -117,12 +117,11 @@ skip-if(B2G) == maction-dynamic-3.html m
 == whitespace-trim-1.html whitespace-trim-1-ref.html
 == whitespace-trim-2.html whitespace-trim-2-ref.html
 == whitespace-trim-3.html whitespace-trim-3-ref.html
 fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 787215
 == whitespace-trim-5.html whitespace-trim-5-ref.html
 == operator-1.xhtml operator-1-ref.xhtml
 == scriptshift-1.xhtml scriptshift-1-ref.xhtml
 == number-size-1.xhtml number-size-1-ref.xhtml
-== multiscripts-1.html multiscripts-1-ref.html
 == mathml-mmultiscript-base.html mathml-mmultiscript-base-ref.html
 == mathml-mmultiscript-mprescript.html mathml-mmultiscript-mprescript-ref.html
 != menclose-1.html menclose-1-ref.html