Bug 1099807 part 4 - Fix line breaking around ruby intra-level whitespaces. r=dholbert
authorXidorn Quan <quanxunzhen@gmail.com>
Thu, 08 Jan 2015 18:28:09 +1100
changeset 222602 2cc185fba3dac89dbc9c83ff6be5c5235c3f152d
parent 222601 fb6b0a95a55509375ba5718ee5245fe85790dd01
child 222603 2238390e5de42b8fb3e0b1227882f6c2d9e52cdb
push id28068
push usercbook@mozilla.com
push dateThu, 08 Jan 2015 13:16:34 +0000
treeherdermozilla-central@2880e05d5e32 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1099807
milestone37.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 1099807 part 4 - Fix line breaking around ruby intra-level whitespaces. r=dholbert
layout/generic/nsRubyBaseContainerFrame.cpp
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -9,16 +9,18 @@
 #include "nsRubyBaseContainerFrame.h"
 #include "nsContentUtils.h"
 #include "nsLineLayout.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "nsStyleStructInlines.h"
 #include "WritingModes.h"
 #include "RubyUtils.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/DebugOnly.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
@@ -59,17 +61,18 @@ nsRubyBaseContainerFrame::GetFrameName(n
  * Ruby column is a unit consists of one ruby base and all ruby
  * annotations paired with it.
  * See http://dev.w3.org/csswg/css-ruby/#ruby-pairing
  */
 struct MOZ_STACK_CLASS mozilla::RubyColumn
 {
   nsRubyBaseFrame* mBaseFrame;
   nsAutoTArray<nsRubyTextFrame*, RTC_ARRAY_SIZE> mTextFrames;
-  RubyColumn() : mBaseFrame(nullptr) { }
+  bool mIsIntraLevelWhitespace;
+  RubyColumn() : mBaseFrame(nullptr), mIsIntraLevelWhitespace(false) { }
 };
 
 class MOZ_STACK_CLASS RubyColumnEnumerator
 {
 public:
   RubyColumnEnumerator(nsRubyBaseContainerFrame* aRBCFrame,
                        const nsTArray<nsRubyTextContainerFrame*>& aRTCFrames);
 
@@ -188,16 +191,17 @@ RubyColumnEnumerator::GetColumn(RubyColu
   MOZ_ASSERT(!rbFrame || rbFrame->GetType() == nsGkAtoms::rubyBaseFrame);
   aColumn.mBaseFrame = static_cast<nsRubyBaseFrame*>(rbFrame);
   aColumn.mTextFrames.ClearAndRetainStorage();
   for (uint32_t i = 1, iend = mFrames.Length(); i < iend; i++) {
     nsRubyContentFrame* rtFrame = GetFrameAtLevel(i);
     MOZ_ASSERT(!rtFrame || rtFrame->GetType() == nsGkAtoms::rubyTextFrame);
     aColumn.mTextFrames.AppendElement(static_cast<nsRubyTextFrame*>(rtFrame));
   }
+  aColumn.mIsIntraLevelWhitespace = mAtIntraLevelWhitespace;
 }
 
 static nscoord
 CalculateColumnPrefISize(nsRenderingContext* aRenderingContext,
                          const RubyColumnEnumerator& aEnumerator)
 {
   nscoord max = 0;
   uint32_t levelCount = aEnumerator.GetLevelCount();
@@ -576,21 +580,40 @@ nsRubyBaseContainerFrame::ReflowColumns(
       // If no column has been placed yet, or we have any span,
       // the whole container should be in the next line.
       aStatus = NS_INLINE_LINE_BREAK_BEFORE();
       return 0;
     }
     aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
     MOZ_ASSERT(NS_FRAME_IS_COMPLETE(aStatus) || aReflowState.mAllowLineBreak);
 
-    if (column.mBaseFrame) {
-      PushChildren(column.mBaseFrame, column.mBaseFrame->GetPrevSibling());
+    // If we are on an intra-level whitespace column, null values in
+    // column.mBaseFrame and column.mTextFrames don't represent the
+    // end of the frame-sibling-chain at that level -- instead, they
+    // represent an anonymous empty intra-level whitespace box. It is
+    // likely that there are frames in the next column (which can't be
+    // intra-level whitespace). Those frames should be pushed as well.
+    Maybe<RubyColumn> nextColumn;
+    if (column.mIsIntraLevelWhitespace && !e.AtEnd()) {
+      e.Next();
+      nextColumn.emplace();
+      e.GetColumn(nextColumn.ref());
+    }
+    nsIFrame* baseFrame = column.mBaseFrame;
+    if (!baseFrame & nextColumn.isSome()) {
+      baseFrame = nextColumn->mBaseFrame;
+    }
+    if (baseFrame) {
+      PushChildren(baseFrame, baseFrame->GetPrevSibling());
     }
     for (uint32_t i = 0; i < rtcCount; i++) {
       nsRubyTextFrame* textFrame = column.mTextFrames[i];
+      if (!textFrame && nextColumn.isSome()) {
+        textFrame = nextColumn->mTextFrames[i];
+      }
       if (textFrame) {
         aReflowState.mTextContainers[i]->PushChildren(
           textFrame, textFrame->GetPrevSibling());
       }
     }
   } else if (NS_INLINE_IS_BREAK_AFTER(reflowStatus)) {
     // |reflowStatus| being break after here may only happen when
     // there is a break after the column just pulled, or the whole
@@ -735,30 +758,65 @@ void
 nsRubyBaseContainerFrame::PullOneColumn(nsLineLayout* aLineLayout,
                                         PullFrameState& aPullFrameState,
                                         RubyColumn& aColumn,
                                         bool& aIsComplete)
 {
   const TextContainerArray& textContainers = aPullFrameState.mTextContainers;
   const uint32_t rtcCount = textContainers.Length();
 
-  nsIFrame* nextBase = PullNextInFlowChild(aPullFrameState.mBase);
+  nsIFrame* nextBase = GetNextInFlowChild(aPullFrameState.mBase);
   MOZ_ASSERT(!nextBase || nextBase->GetType() == nsGkAtoms::rubyBaseFrame);
   aColumn.mBaseFrame = static_cast<nsRubyBaseFrame*>(nextBase);
   aIsComplete = !aColumn.mBaseFrame;
+  bool pullingIntraLevelWhitespace =
+    aColumn.mBaseFrame && aColumn.mBaseFrame->IsIntraLevelWhitespace();
 
   aColumn.mTextFrames.ClearAndRetainStorage();
   for (uint32_t i = 0; i < rtcCount; i++) {
     nsIFrame* nextText =
-      textContainers[i]->PullNextInFlowChild(aPullFrameState.mTexts[i]);
+      textContainers[i]->GetNextInFlowChild(aPullFrameState.mTexts[i]);
     MOZ_ASSERT(!nextText || nextText->GetType() == nsGkAtoms::rubyTextFrame);
-    aColumn.mTextFrames.AppendElement(static_cast<nsRubyTextFrame*>(nextText));
+    nsRubyTextFrame* textFrame = static_cast<nsRubyTextFrame*>(nextText);
+    aColumn.mTextFrames.AppendElement(textFrame);
     // If there exists any frame in continations, we haven't
     // completed the reflow process.
     aIsComplete = aIsComplete && !nextText;
+    if (nextText && !pullingIntraLevelWhitespace) {
+      pullingIntraLevelWhitespace = textFrame->IsIntraLevelWhitespace();
+    }
+  }
+
+  aColumn.mIsIntraLevelWhitespace = pullingIntraLevelWhitespace;
+  if (pullingIntraLevelWhitespace) {
+    // We are pulling an intra-level whitespace. Drop all frames which
+    // are not part of this intra-level whitespace column. (Those frames
+    // are really part of the *next* column, after the pulled one.)
+    if (aColumn.mBaseFrame && !aColumn.mBaseFrame->IsIntraLevelWhitespace()) {
+      aColumn.mBaseFrame = nullptr;
+    }
+    for (uint32_t i = 0; i < rtcCount; i++) {
+      nsRubyTextFrame*& textFrame = aColumn.mTextFrames[i];
+      if (textFrame && !textFrame->IsIntraLevelWhitespace()) {
+        textFrame = nullptr;
+      }
+    }
+  }
+
+  // Pull the frames of this column.
+  if (aColumn.mBaseFrame) {
+    DebugOnly<nsIFrame*> pulled = PullNextInFlowChild(aPullFrameState.mBase);
+    MOZ_ASSERT(pulled == aColumn.mBaseFrame, "pulled a wrong frame?");
+  }
+  for (uint32_t i = 0; i < rtcCount; i++) {
+    if (aColumn.mTextFrames[i]) {
+      DebugOnly<nsIFrame*> pulled =
+        textContainers[i]->PullNextInFlowChild(aPullFrameState.mTexts[i]);
+      MOZ_ASSERT(pulled == aColumn.mTextFrames[i], "pulled a wrong frame?");
+    }
   }
 
   if (!aIsComplete) {
     // We pulled frames from the next line, hence mark it dirty.
     aLineLayout->SetDirtyNextLine();
   }
 }