Bug 1116037 part 8 - Merge two ruby text container arrays. r=dbaron
authorXidorn Quan <quanxunzhen@gmail.com>
Tue, 30 Dec 2014 09:44:12 +1100
changeset 247657 769f499c51abc35ffe1b5882beba56658efc9f06
parent 247656 80663d48d58fee5af3baa8acd60e4ee1aa848ddc
child 247658 fb2cec3732eaea0ac606db50761b74cec0606707
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1116037
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 1116037 part 8 - Merge two ruby text container arrays. r=dbaron
layout/generic/nsRubyBaseContainerFrame.cpp
layout/generic/nsRubyBaseContainerFrame.h
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -89,17 +89,21 @@ private:
 RubyColumnEnumerator::RubyColumnEnumerator(
   nsRubyBaseContainerFrame* aBaseContainer,
   const nsTArray<nsRubyTextContainerFrame*>& aTextContainers)
 {
   const uint32_t rtcCount = aTextContainers.Length();
   mFrames.SetCapacity(rtcCount + 1);
   mFrames.AppendElement(aBaseContainer->GetFirstPrincipalChild());
   for (uint32_t i = 0; i < rtcCount; i++) {
-    nsIFrame* rtFrame = aTextContainers[i]->GetFirstPrincipalChild();
+    nsRubyTextContainerFrame* container = aTextContainers[i];
+    // If the container is for span, leave a nullptr here.
+    // Spans do not take part in pairing.
+    nsIFrame* rtFrame = !container->IsSpanContainer() ?
+      aTextContainers[i]->GetFirstPrincipalChild() : nullptr;
     mFrames.AppendElement(rtFrame);
   }
 }
 
 void
 RubyColumnEnumerator::Next()
 {
   for (uint32_t i = 0, iend = mFrames.Length(); i < iend; i++) {
@@ -125,30 +129,16 @@ RubyColumnEnumerator::GetColumn(RubyColu
 {
   aColumn.mBaseFrame = mFrames[0];
   aColumn.mTextFrames.ClearAndRetainStorage();
   for (uint32_t i = 1, iend = mFrames.Length(); i < iend; i++) {
     aColumn.mTextFrames.AppendElement(mFrames[i]);
   }
 }
 
-nscoord
-nsRubyBaseContainerFrame::CalculateMaxSpanISize(
-    nsRenderingContext* aRenderingContext)
-{
-  nscoord max = 0;
-  uint32_t spanCount = mSpanContainers.Length();
-  for (uint32_t i = 0; i < spanCount; i++) {
-    nsIFrame* frame = mSpanContainers[i]->GetFirstPrincipalChild();
-    nscoord isize = frame->GetPrefISize(aRenderingContext);
-    max = std::max(max, isize);
-  }
-  return max;
-}
-
 static nscoord
 CalculateColumnPrefISize(nsRenderingContext* aRenderingContext,
                          const RubyColumnEnumerator& aEnumerator)
 {
   nscoord max = 0;
   uint32_t levelCount = aEnumerator.GetLevelCount();
   for (uint32_t i = 0; i < levelCount; i++) {
     nsIFrame* frame = aEnumerator.GetFrame(i);
@@ -158,21 +148,23 @@ CalculateColumnPrefISize(nsRenderingCont
   }
   return max;
 }
 
 /* virtual */ void
 nsRubyBaseContainerFrame::AddInlineMinISize(
     nsRenderingContext *aRenderingContext, nsIFrame::InlineMinISizeData *aData)
 {
-  if (!mSpanContainers.IsEmpty()) {
-    // Since spans are not breakable internally, use our pref isize
-    // directly if there is any span.
-    aData->currentLine += GetPrefISize(aRenderingContext);
-    return;
+  for (uint32_t i = 0, iend = mTextContainers.Length(); i < iend; i++) {
+    if (mTextContainers[i]->IsSpanContainer()) {
+      // Since spans are not breakable internally, use our pref isize
+      // directly if there is any span.
+      aData->currentLine += GetPrefISize(aRenderingContext);
+      return;
+    }
   }
 
   nscoord max = 0;
   RubyColumnEnumerator enumerator(this, mTextContainers);
   for (; !enumerator.AtEnd(); enumerator.Next()) {
     // We use *pref* isize for computing the min isize of columns
     // because ruby bases and texts are unbreakable internally.
     max = std::max(max, CalculateColumnPrefISize(aRenderingContext,
@@ -185,41 +177,40 @@ nsRubyBaseContainerFrame::AddInlineMinIS
 nsRubyBaseContainerFrame::AddInlinePrefISize(
     nsRenderingContext *aRenderingContext, nsIFrame::InlinePrefISizeData *aData)
 {
   nscoord sum = 0;
   RubyColumnEnumerator enumerator(this, mTextContainers);
   for (; !enumerator.AtEnd(); enumerator.Next()) {
     sum += CalculateColumnPrefISize(aRenderingContext, enumerator);
   }
-  sum = std::max(sum, CalculateMaxSpanISize(aRenderingContext));
+  for (uint32_t i = 0, iend = mTextContainers.Length(); i < iend; i++) {
+    if (mTextContainers[i]->IsSpanContainer()) {
+      nsIFrame* frame = mTextContainers[i]->GetFirstPrincipalChild();
+      sum = std::max(sum, frame->GetPrefISize(aRenderingContext));
+    }
+  }
   aData->currentLine += sum;
 }
 
 /* virtual */ bool 
 nsRubyBaseContainerFrame::IsFrameOfType(uint32_t aFlags) const 
 {
   return nsContainerFrame::IsFrameOfType(aFlags & 
          ~(nsIFrame::eLineParticipant));
 }
 
 void nsRubyBaseContainerFrame::AppendTextContainer(nsIFrame* aFrame)
 {
   nsRubyTextContainerFrame* rtcFrame = do_QueryFrame(aFrame);
   MOZ_ASSERT(rtcFrame, "Must provide a ruby text container.");
-
-  nsTArray<nsRubyTextContainerFrame*>* containers = &mTextContainers;
-  if (rtcFrame->IsSpanContainer()) {
-    containers = &mSpanContainers;
-  }
-  containers->AppendElement(rtcFrame);
+  mTextContainers.AppendElement(rtcFrame);
 }
 
 void nsRubyBaseContainerFrame::ClearTextContainers() {
-  mSpanContainers.Clear();
   mTextContainers.Clear();
 }
 
 /* virtual */ bool
 nsRubyBaseContainerFrame::CanContinueTextRun() const
 {
   return true;
 }
@@ -244,17 +235,17 @@ nsRubyBaseContainerFrame::GetLogicalBase
 {
   return mBaseline;
 }
 
 struct nsRubyBaseContainerFrame::ReflowState
 {
   bool mAllowLineBreak;
   const nsHTMLReflowState& mBaseReflowState;
-  const nsTArray<nsHTMLReflowState*>& mTextReflowStates;
+  const nsTArray<UniquePtr<nsHTMLReflowState>>& mTextReflowStates;
 };
 
 // Check whether the given extra isize can fit in the line in base level.
 static bool
 ShouldBreakBefore(const nsHTMLReflowState& aReflowState, nscoord aExtraISize)
 {
   nsLineLayout* lineLayout = aReflowState.mLineLayout;
   int32_t offset;
@@ -287,50 +278,39 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
   for (uint32_t i = 0; i < rtcCount; i++) {
     mTextContainers[i]->MoveOverflowToChildList();
   }
 
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
   LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
                         aReflowState.AvailableHeight());
 
-  const uint32_t spanCount = mSpanContainers.Length();
-  const uint32_t totalCount = rtcCount + spanCount;
   // We have a reflow state and a line layout for each RTC.
   // They are conceptually the state of the RTCs, but we don't actually
   // reflow those RTCs in this code. These two arrays are holders of
   // the reflow states and line layouts.
   // Since there are pointers refer to reflow states and line layouts,
   // it is necessary to guarantee that they won't be moved. For this
   // reason, they are wrapped in UniquePtr here.
   nsAutoTArray<UniquePtr<nsHTMLReflowState>, RTC_ARRAY_SIZE> reflowStates;
   nsAutoTArray<UniquePtr<nsLineLayout>, RTC_ARRAY_SIZE> lineLayouts;
-  reflowStates.SetCapacity(totalCount);
-  lineLayouts.SetCapacity(totalCount);
-
-  nsAutoTArray<nsHTMLReflowState*, RTC_ARRAY_SIZE> rtcReflowStates;
-  nsAutoTArray<nsHTMLReflowState*, RTC_ARRAY_SIZE> spanReflowStates;
-  rtcReflowStates.SetCapacity(rtcCount);
-  spanReflowStates.SetCapacity(spanCount);
+  reflowStates.SetCapacity(rtcCount);
+  lineLayouts.SetCapacity(rtcCount);
 
   // Begin the line layout for each ruby text container in advance.
-  for (uint32_t i = 0; i < totalCount; i++) {
-    nsIFrame* textContainer;
-    nsTArray<nsHTMLReflowState*>* reflowStateArray;
-    if (i < rtcCount) {
-      textContainer = mTextContainers[i];
-      reflowStateArray = &rtcReflowStates;
-    } else {
-      textContainer = mSpanContainers[i - rtcCount];
-      reflowStateArray = &spanReflowStates;
+  bool hasSpan = false;
+  for (uint32_t i = 0; i < rtcCount; i++) {
+    nsRubyTextContainerFrame* textContainer = mTextContainers[i];
+    if (textContainer->IsSpanContainer()) {
+      hasSpan = true;
     }
+
     nsHTMLReflowState* reflowState = new nsHTMLReflowState(
       aPresContext, *aReflowState.parentReflowState, textContainer, availSize);
     reflowStates.AppendElement(reflowState);
-    reflowStateArray->AppendElement(reflowState);
     nsLineLayout* lineLayout = new nsLineLayout(aPresContext,
                                                 reflowState->mFloatManager,
                                                 reflowState, nullptr,
                                                 aReflowState.mLineLayout);
     lineLayouts.AppendElement(lineLayout);
 
     // Line number is useless for ruby text
     // XXX nullptr here may cause problem, see comments for
@@ -373,31 +353,30 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
         gfxBreakPriority::eNormalBreak)) {
     aStatus = NS_INLINE_LINE_BREAK_BEFORE();
   }
 
   nscoord isize = 0;
   if (aStatus == NS_FRAME_COMPLETE) {
     // Reflow columns excluding any span
     ReflowState reflowState = {
-      allowLineBreak && mSpanContainers.IsEmpty(),
-      aReflowState, rtcReflowStates
+      allowLineBreak && !hasSpan, aReflowState, reflowStates
     };
     isize = ReflowColumns(reflowState, aStatus);
   }
 
   // If there exists any span, the columns must either be completely
   // reflowed, or be not reflowed at all.
   MOZ_ASSERT(NS_INLINE_IS_BREAK_BEFORE(aStatus) ||
-             NS_FRAME_IS_COMPLETE(aStatus) || mSpanContainers.IsEmpty());
+             NS_FRAME_IS_COMPLETE(aStatus) || !hasSpan);
   if (!NS_INLINE_IS_BREAK_BEFORE(aStatus) &&
-      NS_FRAME_IS_COMPLETE(aStatus) && !mSpanContainers.IsEmpty()) {
+      NS_FRAME_IS_COMPLETE(aStatus) && hasSpan) {
     // Reflow spans
     ReflowState reflowState = {
-      false, aReflowState, spanReflowStates
+      false, aReflowState, reflowStates
     };
     nscoord spanISize = ReflowSpans(reflowState);
     nscoord deltaISize = spanISize - isize;
     if (deltaISize <= 0) {
       RubyUtils::ClearReservedISize(this);
     } else if (allowLineBreak && ShouldBreakBefore(aReflowState, deltaISize)) {
       aStatus = NS_INLINE_LINE_BREAK_BEFORE();
     } else {
@@ -417,30 +396,29 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
   }
 
   DebugOnly<nscoord> lineSpanSize = aReflowState.mLineLayout->EndSpan(this);
   // When there are no frames inside the ruby base container, EndSpan
   // will return 0. However, in this case, the actual width of the
   // container could be non-zero because of non-empty ruby annotations.
   MOZ_ASSERT(NS_INLINE_IS_BREAK_BEFORE(aStatus) ||
              isize == lineSpanSize || mFrames.IsEmpty());
-  for (uint32_t i = 0; i < totalCount; i++) {
+  for (uint32_t i = 0; i < rtcCount; i++) {
     // It happens before the ruby text container is reflowed, and that
     // when it is reflowed, it will just use this size.
-    nsRubyTextContainerFrame* textContainer = i < rtcCount ?
-      mTextContainers[i] : mSpanContainers[i - rtcCount];
+    nsRubyTextContainerFrame* textContainer = mTextContainers[i];
     nsLineLayout* lineLayout = lineLayouts[i].get();
 
     RubyUtils::ClearReservedISize(textContainer);
     nscoord rtcISize = lineLayout->GetCurrentICoord();
     // Only span containers and containers with collapsed annotations
     // need reserving isize. For normal ruby text containers, their
     // children will be expanded properly. We only need to expand their
     // own size.
-    if (i < rtcCount) {
+    if (!textContainer->IsSpanContainer()) {
       rtcISize = isize;
     } else if (isize > rtcISize) {
       RubyUtils::SetReservedISize(textContainer, isize - rtcISize);
     }
 
     lineLayout->VerticalAlignLine();
     LogicalSize lineSize(lineWM, isize, lineLayout->GetFinalLineBSize());
     textContainer->SetLineSize(lineSize);
@@ -634,16 +612,19 @@ nsRubyBaseContainerFrame::ReflowOneColum
   nscoord deltaISize = icoord - baseReflowState.mLineLayout->GetCurrentICoord();
   if (deltaISize > 0) {
     baseReflowState.mLineLayout->AdvanceICoord(deltaISize);
     if (aColumn.mBaseFrame) {
       RubyUtils::SetReservedISize(aColumn.mBaseFrame, deltaISize);
     }
   }
   for (uint32_t i = 0; i < rtcCount; i++) {
+    if (mTextContainers[i]->IsSpanContainer()) {
+      continue;
+    }
     nsLineLayout* lineLayout = textReflowStates[i]->mLineLayout;
     nsIFrame* textFrame = aColumn.mTextFrames[i];
     nscoord deltaISize = icoord - lineLayout->GetCurrentICoord();
     if (deltaISize > 0) {
       lineLayout->AdvanceICoord(deltaISize);
       if (textFrame) {
         RubyUtils::SetReservedISize(textFrame, deltaISize);
       }
@@ -701,21 +682,24 @@ nsRubyBaseContainerFrame::PullOneColumn(
   }
 }
 
 nscoord
 nsRubyBaseContainerFrame::ReflowSpans(const ReflowState& aReflowState)
 {
   WritingMode lineWM =
     aReflowState.mBaseReflowState.mLineLayout->GetWritingMode();
-  const uint32_t spanCount = mSpanContainers.Length();
   nscoord spanISize = 0;
 
-  for (uint32_t i = 0; i < spanCount; i++) {
-    nsRubyTextContainerFrame* container = mSpanContainers[i];
+  for (uint32_t i = 0, iend = mTextContainers.Length(); i < iend; i++) {
+    nsRubyTextContainerFrame* container = mTextContainers[i];
+    if (!container->IsSpanContainer()) {
+      continue;
+    }
+
     nsIFrame* rtFrame = container->GetFirstPrincipalChild();
     nsReflowStatus reflowStatus;
     nsHTMLReflowMetrics metrics(*aReflowState.mTextReflowStates[i]);
     bool pushedFrame;
     aReflowState.mTextReflowStates[i]->mLineLayout->
       ReflowFrame(rtFrame, reflowStatus, &metrics, pushedFrame);
     MOZ_ASSERT(!NS_INLINE_IS_BREAK(reflowStatus) && !pushedFrame,
                "Any line break inside ruby box should has been suppressed");
--- a/layout/generic/nsRubyBaseContainerFrame.h
+++ b/layout/generic/nsRubyBaseContainerFrame.h
@@ -61,32 +61,29 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 #ifdef DEBUG
   void AssertTextContainersEmpty()
   {
-    MOZ_ASSERT(mSpanContainers.IsEmpty());
     MOZ_ASSERT(mTextContainers.IsEmpty());
   }
 #endif
 
   void AppendTextContainer(nsIFrame* aFrame);
   void ClearTextContainers();
 
 protected:
   friend nsContainerFrame*
     NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   explicit nsRubyBaseContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
 
-  nscoord CalculateMaxSpanISize(nsRenderingContext* aRenderingContext);
-
   struct ReflowState;
   nscoord ReflowColumns(const ReflowState& aReflowState,
                         nsReflowStatus& aStatus);
   nscoord ReflowOneColumn(const ReflowState& aReflowState,
                           const mozilla::RubyColumn& aColumn,
                           nsReflowStatus& aStatus);
   nscoord ReflowSpans(const ReflowState& aReflowState);
 
@@ -95,24 +92,19 @@ protected:
   // Pull ruby base and corresponding ruby text frames from
   // continuations after them.
   void PullOneColumn(nsLineLayout* aLineLayout,
                      PullFrameState& aPullFrameState,
                      mozilla::RubyColumn& aColumn,
                      bool& aIsComplete);
 
   /**
-   * The arrays of ruby text containers below are filled before the ruby
+   * The array of ruby text containers below is filled before the ruby
    * frame (parent) starts reflowing this ruby segment, and cleared when
    * the reflow finishes.
    */
-
-  // The text containers that contain a span, which spans all ruby
-  // columns in the ruby segment.
-  nsTArray<nsRubyTextContainerFrame*> mSpanContainers;
-  // Normal text containers that do not contain spans.
   nsTArray<nsRubyTextContainerFrame*> mTextContainers;
 
   nscoord mBaseline;
   uint32_t mColumnCount;
 };
 
 #endif /* nsRubyBaseContainerFrame_h___ */