Bug 655877 - Part 11: Ignore vertical-align and map dominant-baseline to vertical-align in SVG text frames. r=roc
authorCameron McCormack <cam@mcc.id.au>
Thu, 02 Aug 2012 21:38:48 +1000
changeset 101214 19cd8d99dfbea29f513fa7b4b97e99fe92a7d45e
parent 101213 ddf80ca678337e26b87cf768e8fac4e2f09186e5
child 101215 58c16e8cfdc7b39c64ee5917392f6ff37e54b2de
push id12898
push usercmccormack@mozilla.com
push dateThu, 02 Aug 2012 11:40:52 +0000
treeherdermozilla-inbound@d7749fadb594 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs655877
milestone17.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 655877 - Part 11: Ignore vertical-align and map dominant-baseline to vertical-align in SVG text frames. r=roc
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsLineLayout.cpp
layout/generic/nsTextFrameThebes.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -7405,16 +7405,62 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex
  * should return false if this is not a text frame.
  */
 bool
 nsIFrame::HasTerminalNewline() const
 {
   return false;
 }
 
+static PRUint8
+ConvertSVGDominantBaselineToVerticalAlign(PRUint8 aDominantBaseline)
+{
+  switch (aDominantBaseline) {
+  case NS_STYLE_DOMINANT_BASELINE_HANGING:
+  case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
+    return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
+  case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
+  case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
+    return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
+  case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
+  case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
+    return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
+  case NS_STYLE_DOMINANT_BASELINE_AUTO:
+  case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
+    return NS_STYLE_VERTICAL_ALIGN_BASELINE;
+  default:
+    NS_NOTREACHED("unexpected aDominantBaseline value");
+    return NS_STYLE_VERTICAL_ALIGN_BASELINE;
+  }
+}
+
+PRUint8
+nsIFrame::VerticalAlignEnum() const
+{
+  if (mState & NS_FRAME_IS_SVG_TEXT) {
+    PRUint8 dominantBaseline;
+    for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
+      dominantBaseline = frame->GetStyleSVGReset()->mDominantBaseline;
+      if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
+          frame->GetType() == nsGkAtoms::svgTextFrame) {
+        break;
+      }
+    }
+    return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline);
+  }
+
+  const nsStyleCoord& verticalAlign =
+    GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
+  if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
+    return verticalAlign.GetIntValue();
+  }
+
+  return eInvalidVerticalAlign;
+}
+
 /* static */
 void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
                                              nsIFrame::Cursor& aCursor)
 {
   aCursor.mCursor = ui->mCursor;
   aCursor.mHaveHotspot = false;
   aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2833,16 +2833,26 @@ NS_PTR_TO_INT32(frame->Properties().Get(
   // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
   // ignore the chrome/content boundary, otherwise we stop looking when we
   // reach it.
   enum {
     VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01
   };
   bool IsVisibleConsideringAncestors(PRUint32 aFlags = 0) const;
 
+  /**
+   * Returns the vertical-align value to be used for layout, if it is one
+   * of the enumerated values.  If this is an SVG text frame, it returns a value
+   * that corresponds to the value of dominant-baseline.  If the
+   * vertical-align property has length or percentage value, this returns
+   * eInvalidVerticalAlign.
+   */
+  PRUint8 VerticalAlignEnum() const;
+  enum { eInvalidVerticalAlign = 0xFF };
+
   bool IsSVGText() const { return mState & NS_FRAME_IS_SVG_TEXT; }
 
 protected:
   // Members
   nsRect           mRect;
   nsIContent*      mContent;
   nsStyleContext*  mStyleContext;
   nsIFrame*        mParent;
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -1447,21 +1447,17 @@ nsLineLayout::VerticalAlignLine()
   // If the frame being reflowed has text decorations, we simulate the
   // propagation of those decorations to a line-level element by storing the
   // offset in a frame property on any child frames that are vertically-aligned
   // somewhere other than the baseline. This property is then used by
   // nsTextFrame::GetTextDecorations when the same conditions are met.
   if (rootPFD.mFrame->GetStyleContext()->HasTextDecorationLines()) {
     for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
       const nsIFrame *const f = pfd->mFrame;
-      const nsStyleCoord& vAlign =
-          f->GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
-
-      if (vAlign.GetUnit() != eStyleUnit_Enumerated ||
-          vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
+      if (f->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
         const nscoord offset = baselineY - pfd->mBounds.y;
         f->Properties().Set(nsIFrame::LineBaselineOffset(),
                             NS_INT32_TO_PTR(offset));
       }
     }
   }
 
   // Fill in returned line-box and max-element-width data
@@ -1771,28 +1767,34 @@ nsLineLayout::VerticalAlignFrames(PerSpa
       // frames height plus its margins.
       logicalHeight = pfd->mBounds.height + pfd->mMargin.top +
         pfd->mMargin.bottom;
     }
 
     // Get vertical-align property
     const nsStyleCoord& verticalAlign =
       frame->GetStyleTextReset()->mVerticalAlign;
+    PRUint8 verticalAlignEnum = frame->VerticalAlignEnum();
 #ifdef NOISY_VERTICAL_ALIGN
     printf("  [frame]");
     nsFrame::ListTag(stdout, frame);
-    printf(": verticalAlignUnit=%d (enum == %d)\n",
+    printf(": verticalAlignUnit=%d (enum == %d",
            verticalAlign.GetUnit(),
            ((eStyleUnit_Enumerated == verticalAlign.GetUnit())
             ? verticalAlign.GetIntValue()
             : -1));
+    if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) {
+      printf(", after SVG dominant-baseline conversion == %d",
+             verticalAlignEnum);
+    }
+    printf(")\n");
 #endif
 
-    if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
-      switch (verticalAlign.GetIntValue()) {
+    if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) {
+      switch (verticalAlignEnum) {
         default:
         case NS_STYLE_VERTICAL_ALIGN_BASELINE:
         {
           // The element's baseline is aligned with the baseline of
           // the parent.
           pfd->mBounds.y = baselineY - pfd->mAscent;
           pfd->mVerticalAlign = VALIGN_OTHER;
           break;
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -4561,21 +4561,17 @@ nsTextFrame::GetTextDecorations(nsPresCo
     // Not updating positions once we hit a parent block is equivalent to
     // the CSS 2.1 spec that blocks should propagate decorations down to their
     // children (albeit the style should be preserved)
     // However, if we're vertically aligned within a block, then we need to
     // recover the right baseline from the line by querying the FrameProperty
     // that should be set (see nsLineLayout::VerticalAlignLine).
     if (firstBlock) {
       // At this point, fChild can't be null since TextFrames can't be blocks
-      const nsStyleCoord& vAlign =
-        fChild->GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
-      if (vAlign.GetUnit() != eStyleUnit_Enumerated ||
-          vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE)
-      {
+      if (fChild->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
         // Since offset is the offset in the child's coordinate space, we have
         // to undo the accumulation to bring the transform out of the block's
         // coordinate space
         baselineOffset =
           frameTopOffset - (fChild->GetRect().y - fChild->GetRelativeOffset().y)
           - NS_PTR_TO_INT32(
               fChild->Properties().Get(nsIFrame::LineBaselineOffset()));
       }