Bug 114365 - MathML Frame changes to support mathvariant. r=fredw
authorJames Kitchener <jkitch.bug@gmail.com>
Mon, 02 Dec 2013 11:50:10 -0500
changeset 173950 512193946706590e8ab0feb2ea68a7f4e804d444
parent 173949 b95c0c0418696b08c1ef9e5d7c6eb68d4db827d6
child 173951 6a5226495f479d660f51b057b5fefaa0fcbce33f
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfredw
bugs114365
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 114365 - MathML Frame changes to support mathvariant. r=fredw
layout/mathml/nsMathMLTokenFrame.cpp
layout/mathml/nsMathMLTokenFrame.h
layout/mathml/nsMathMLmoFrame.cpp
layout/mathml/nsMathMLmoFrame.h
--- a/layout/mathml/nsMathMLTokenFrame.cpp
+++ b/layout/mathml/nsMathMLTokenFrame.cpp
@@ -23,95 +23,88 @@ nsMathMLTokenFrame::~nsMathMLTokenFrame(
 }
 
 NS_IMETHODIMP
 nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent)
 {
   // let the base class get the default from our parent
   nsMathMLContainerFrame::InheritAutomaticData(aParent);
 
-  ProcessTextData();
-
   return NS_OK;
 }
 
 eMathMLFrameType
 nsMathMLTokenFrame::GetMathMLFrameType()
 {
   // treat everything other than <mi> as ordinary...
   if (mContent->Tag() != nsGkAtoms::mi_) {
     return eMathMLFrameType_Ordinary;
   }
 
-  // for <mi>, distinguish between italic and upright...
-  nsAutoString style;
-  // mathvariant overrides fontstyle
-  // http://www.w3.org/TR/2003/REC-MathML2-20031021/chapter3.html#presm.deprecatt
-  mContent->GetAttr(kNameSpaceID_None,
-                    nsGkAtoms::_moz_math_fontstyle_, style) ||
-    GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::mathvariant_,
-                 style) ||
-    GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::fontstyle_,
-                 style);
-
-  if (style.EqualsLiteral("italic") || style.EqualsLiteral("bold-italic") ||
-      style.EqualsLiteral("script") || style.EqualsLiteral("bold-script") ||
-      style.EqualsLiteral("sans-serif-italic") ||
-      style.EqualsLiteral("sans-serif-bold-italic")) {
+  uint8_t mathVariant = StyleFont()->mMathVariant;
+  if ((mathVariant == NS_MATHML_MATHVARIANT_NONE &&
+       (StyleFont()->mFont.style == NS_STYLE_FONT_STYLE_ITALIC ||
+        HasAnyStateBits(TEXT_IS_IN_SINGLE_CHAR_MI))) ||
+      mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
+      mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
+      mathVariant == NS_MATHML_MATHVARIANT_BOLD_ITALIC ||
+      mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC ||
+      mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) {
     return eMathMLFrameType_ItalicIdentifier;
   }
-  else if(style.EqualsLiteral("invariant")) {
-    nsAutoString data;
-    nsContentUtils::GetNodeTextContent(mContent, false, data);
-    data.CompressWhitespace();
-    eMATHVARIANT variant = nsMathMLOperators::LookupInvariantChar(data);
-
-    switch (variant) {
-    case eMATHVARIANT_italic:
-    case eMATHVARIANT_bold_italic:
-    case eMATHVARIANT_script:
-    case eMATHVARIANT_bold_script:
-    case eMATHVARIANT_sans_serif_italic:
-    case eMATHVARIANT_sans_serif_bold_italic:
-      return eMathMLFrameType_ItalicIdentifier;
-    default:
-      ; // fall through to upright
-    }
-  }
   return eMathMLFrameType_UprightIdentifier;
 }
 
 void
 nsMathMLTokenFrame::MarkTextFramesAsTokenMathML()
 {
-  // Set flags on child text frames to force them to trim their leading and
-  // trailing whitespaces.
+  nsIFrame* child = nullptr;
+  uint32_t childCount = 0;
+
+  // Set flags on child text frames
+  // - to force them to trim their leading and trailing whitespaces.
+  // - Indicate which frames are suitable for mathvariant
+  // - flag single character <mi> frames for special italic treatment
   for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
        childFrame = childFrame->GetNextSibling()) {
     for (nsIFrame* childFrame2 = childFrame->GetFirstPrincipalChild();
          childFrame2; childFrame2 = childFrame2->GetNextSibling()) {
       if (childFrame2->GetType() == nsGkAtoms::textFrame) {
         childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
+        child = childFrame2;
+        childCount++;
       }
     }
   }
+  if (mContent->Tag() == nsGkAtoms::mi_ && childCount == 1) {
+    nsAutoString data;
+    nsContentUtils::GetNodeTextContent(mContent, false, data);
+    data.CompressWhitespace();
+    int32_t length = data.Length();
+
+    bool isSingleCharacter = length == 1 ||
+      (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
+
+    if (isSingleCharacter) {
+      child->AddStateBits(TEXT_IS_IN_SINGLE_CHAR_MI);
+    }
+  }
 }
 
 NS_IMETHODIMP
 nsMathMLTokenFrame::SetInitialChildList(ChildListID     aListID,
                                         nsFrameList&    aChildList)
 {
   // First, let the base class do its work
   nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
   if (NS_FAILED(rv))
     return rv;
 
   MarkTextFramesAsTokenMathML();
 
-  ProcessTextData();
   return rv;
 }
 
 NS_IMETHODIMP
 nsMathMLTokenFrame::AppendFrames(ChildListID aListID,
                                  nsFrameList& aChildList)
 {
   nsresult rv = nsMathMLContainerFrame::AppendFrames(aListID, aChildList);
@@ -227,125 +220,8 @@ nsMathMLTokenFrame::Place(nsRenderingCon
     }
   }
 
   SetReference(nsPoint(0, aDesiredSize.ascent));
 
   return NS_OK;
 }
 
-/* virtual */ void
-nsMathMLTokenFrame::MarkIntrinsicWidthsDirty()
-{
-  // this could be called due to changes in the nsTextFrame beneath us
-  // when something changed in the text content. So re-process our text
-  ProcessTextData();
-
-  nsMathMLContainerFrame::MarkIntrinsicWidthsDirty();
-}
-
-void
-nsMathMLTokenFrame::ProcessTextData()
-{
-  // see if the style changes from normal to italic or vice-versa
-  if (!SetTextStyle())
-    return;
-
-  // explicitly request a re-resolve to pick up the change of style
-  PresContext()->RestyleManager()->
-    PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
-}
-
-///////////////////////////////////////////////////////////////////////////
-// For <mi>, if the content is not a single character, turn the font to
-// normal (this function will also query attributes from the mstyle hierarchy)
-// Returns true if there is a style change.
-//
-// http://www.w3.org/TR/2003/REC-MathML2-20031021/chapter3.html#presm.commatt
-//
-//  "It is important to note that only certain combinations of
-//   character data and mathvariant attribute values make sense.
-//   ...
-//   By design, the only cases that have an unambiguous
-//   interpretation are exactly the ones that correspond to SMP Math
-//   Alphanumeric Symbol characters, which are enumerated in Section
-//   6.2.3 Mathematical Alphanumeric Symbols Characters. In all other
-//   cases, it is suggested that renderers ignore the value of the
-//   mathvariant attribute if it is present."
-//
-// There are no corresponding characters for mathvariant=normal, suggesting
-// that this value should be ignored, but this (from the same section of
-// Chapter 3) implies that font-style should not be inherited, but set to
-// normal for mathvariant=normal:
-//
-//  "In particular, inheritance of the mathvariant attribute does not follow
-//   the CSS model. The default value for this attribute is "normal"
-//   (non-slanted) for all tokens except mi. ... (The deprecated fontslant
-//   attribute also behaves this way.)"
-
-bool
-nsMathMLTokenFrame::SetTextStyle()
-{
-  if (mContent->Tag() != nsGkAtoms::mi_)
-    return false;
-
-  if (!mFrames.FirstChild())
-    return false;
-
-  // Get the text content that we enclose and its length
-  nsAutoString data;
-  nsContentUtils::GetNodeTextContent(mContent, false, data);
-  data.CompressWhitespace();
-  int32_t length = data.Length();
-  if (!length)
-    return false;
-
-  nsAutoString fontstyle;
-  bool isSingleCharacter =
-    length == 1 ||
-    (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
-  if (isSingleCharacter &&
-      nsMathMLOperators::LookupInvariantChar(data) != eMATHVARIANT_NONE) {
-    // bug 65951 - a non-stylable character has its own intrinsic appearance
-    fontstyle.AssignLiteral("invariant");
-  }
-  else {
-    // Attributes override the default behavior.
-    nsAutoString value;
-    if (!(GetAttribute(mContent, mPresentationData.mstyle,
-                       nsGkAtoms::mathvariant_, value) ||
-          GetAttribute(mContent, mPresentationData.mstyle,
-                       nsGkAtoms::fontstyle_, value))) {
-      if (!isSingleCharacter) {
-        fontstyle.AssignLiteral("normal");
-      }
-      else if (length == 1 && // BMP
-               !nsMathMLOperators::
-                TransformVariantChar(data[0], eMATHVARIANT_italic).
-                Equals(data)) {
-        // Transformation exists.  Try to make the BMP character look like the
-        // styled character using the style system until bug 114365 is resolved.
-        fontstyle.AssignLiteral("italic");
-      }
-      // else single character but there is no corresponding Math Alphanumeric
-      // Symbol character: "ignore the value of the [default] mathvariant
-      // attribute".
-    }
-  }
-
-  // set the _moz-math-font-style attribute without notifying that we want a reflow
-  if (fontstyle.IsEmpty()) {
-    if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_)) {
-      mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_,
-                          false);
-      return true;
-    }
-  }
-  else if (!mContent->AttrValueIs(kNameSpaceID_None,
-                                  nsGkAtoms::_moz_math_fontstyle_,
-                                  fontstyle, eCaseMatters)) {
-    mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_,
-                      fontstyle, false);
-    return true;
-  }
-
-  return false;
-}
--- a/layout/mathml/nsMathMLTokenFrame.h
+++ b/layout/mathml/nsMathMLTokenFrame.h
@@ -53,32 +53,16 @@ public:
          const nsHTMLReflowState& aReflowState,
          nsReflowStatus&          aStatus) MOZ_OVERRIDE;
 
   virtual nsresult
   Place(nsRenderingContext& aRenderingContext,
         bool                 aPlaceOrigin,
         nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
 
-  virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE;
-
-  virtual nsresult
-  ChildListChanged(int32_t aModType) MOZ_OVERRIDE
-  {
-    ProcessTextData();
-    return nsMathMLContainerFrame::ChildListChanged(aModType);
-  }
-
 protected:
   nsMathMLTokenFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
   virtual ~nsMathMLTokenFrame();
 
-  // hook to perform MathML-specific actions depending on the tag
-  virtual void ProcessTextData();
-
-  // helper to set the style of <mi> which has to be italic or normal
-  // depending on its textual content
-  bool SetTextStyle();
-
   void MarkTextFramesAsTokenMathML();
 };
 
 #endif /* nsMathMLTokentFrame_h___ */
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -911,32 +911,46 @@ nsMathMLmoFrame::Stretch(nsRenderingCont
 }
 
 NS_IMETHODIMP
 nsMathMLmoFrame::InheritAutomaticData(nsIFrame* aParent)
 {
   // retain our native direction, it only changes if our text content changes
   nsStretchDirection direction = mEmbellishData.direction;
   nsMathMLTokenFrame::InheritAutomaticData(aParent);
+  ProcessTextData();
   mEmbellishData.direction = direction;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMathMLmoFrame::TransmitAutomaticData()
 {
   // this will cause us to re-sync our flags from scratch
   // but our returned 'form' is still not final (bug 133429), it will
   // be recomputed to its final value during the next call in Reflow()
   mEmbellishData.coreFrame = nullptr;
   ProcessOperatorData();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsMathMLmoFrame::SetInitialChildList(ChildListID     aListID,
+                                     nsFrameList&    aChildList)
+{
+  // First, let the parent class do its work
+  nsresult rv = nsMathMLTokenFrame::SetInitialChildList(aListID, aChildList);
+  if (NS_FAILED(rv))
+    return rv;
+
+  ProcessTextData();
+  return rv;
+}
+
+NS_IMETHODIMP
 nsMathMLmoFrame::Reflow(nsPresContext*          aPresContext,
                         nsHTMLReflowMetrics&     aDesiredSize,
                         const nsHTMLReflowState& aReflowState,
                         nsReflowStatus&          aStatus)
 {
   // certain values use units that depend on our style context, so
   // it is safer to just process the whole lot here
   ProcessOperatorData();
--- a/layout/mathml/nsMathMLmoFrame.h
+++ b/layout/mathml/nsMathMLmoFrame.h
@@ -34,16 +34,20 @@ public:
 
   NS_IMETHOD
   InheritAutomaticData(nsIFrame* aParent) MOZ_OVERRIDE;
 
   NS_IMETHOD
   TransmitAutomaticData() MOZ_OVERRIDE;
 
   NS_IMETHOD
+  SetInitialChildList(ChildListID     aListID,
+                      nsFrameList&    aChildList) MOZ_OVERRIDE;
+
+  NS_IMETHOD
   Reflow(nsPresContext*          aPresContext,
          nsHTMLReflowMetrics&     aDesiredSize,
          const nsHTMLReflowState& aReflowState,
          nsReflowStatus&          aStatus) MOZ_OVERRIDE;
 
   virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE;
 
   virtual void
@@ -58,29 +62,36 @@ public:
   // This method is called by the parent frame to ask <mo> 
   // to stretch itself.
   NS_IMETHOD
   Stretch(nsRenderingContext& aRenderingContext,
           nsStretchDirection   aStretchDirection,
           nsBoundingMetrics&   aContainerSize,
           nsHTMLReflowMetrics& aDesiredStretchSize) MOZ_OVERRIDE;
 
+  virtual nsresult
+  ChildListChanged(int32_t aModType) MOZ_OVERRIDE
+  {
+    ProcessTextData();
+    return nsMathMLContainerFrame::ChildListChanged(aModType);
+  }
+
 protected:
   nsMathMLmoFrame(nsStyleContext* aContext) : nsMathMLTokenFrame(aContext) {}
   virtual ~nsMathMLmoFrame();
   
   nsMathMLChar     mMathMLChar; // Here is the MathMLChar that will deal with the operator.
   nsOperatorFlags  mFlags;
   float            mMinSize;
   float            mMaxSize;
 
   bool UseMathMLChar();
 
   // overload the base method so that we can setup our nsMathMLChar
-  virtual void ProcessTextData() MOZ_OVERRIDE;
+  void ProcessTextData();
 
   // helper to get our 'form' and lookup in the Operator Dictionary to fetch 
   // our default data that may come from there, and to complete the setup
   // using attributes that we may have
   void
   ProcessOperatorData();
 
   // helper to double check thar our char should be rendered as a selected char