author | Xidorn Quan <quanxunzhen@gmail.com> |
Wed, 26 Nov 2014 15:52:49 +1100 | |
changeset 217538 | d52caef15e10b32a7e9c48ab7ef5a79c8a1e2dec |
parent 217537 | fab3d1117a6a539611813a4050a692bdbdae5af3 |
child 217539 | 002f76d56d0f1d7d81d5f88ac3b690ca62de7876 |
push id | 52308 |
push user | xquan@mozilla.com |
push date | Wed, 26 Nov 2014 04:53:51 +0000 |
treeherder | mozilla-inbound@b657497010c2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dbaron |
bugs | 1052924, 1055676 |
milestone | 36.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
|
--- a/layout/generic/nsRubyBaseContainerFrame.cpp +++ b/layout/generic/nsRubyBaseContainerFrame.cpp @@ -215,102 +215,144 @@ nsRubyBaseContainerFrame::Reflow(nsPresC NS_ASSERTION( aReflowState.mLineLayout, "No line layout provided to RubyBaseContainerFrame reflow method."); aStatus = NS_FRAME_COMPLETE; return; } aStatus = NS_FRAME_COMPLETE; - nscoord isize = 0; - nscoord leftoverSpace = 0; - nscoord spaceApart = 0; WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); WritingMode frameWM = aReflowState.GetWritingMode(); - LogicalMargin borderPadding = - aReflowState.ComputedLogicalBorderPadding(); - nscoord baseStart = 0; LogicalSize availSize(lineWM, aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); const uint32_t rtcCount = mTextContainers.Length(); + 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. + 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); + // Begin the line layout for each ruby text container in advance. - for (uint32_t i = 0; i < rtcCount; i++) { - nsRubyTextContainerFrame* rtcFrame = mTextContainers.ElementAt(i); - nsHTMLReflowState rtcReflowState(aPresContext, - *aReflowState.parentReflowState, - rtcFrame, availSize); - rtcReflowState.mLineLayout = aReflowState.mLineLayout; - // FIXME: Avoid using/needing the rtcReflowState argument - rtcFrame->BeginRTCLineLayout(aPresContext, rtcReflowState); + 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; + } + nsHTMLReflowState* reflowState = new nsHTMLReflowState( + aPresContext, *aReflowState.parentReflowState, textContainer, availSize); + reflowStates.AppendElement(reflowState); + reflowStateArray->AppendElement(reflowState); + nsLineLayout* lineLayout = new nsLineLayout( + aPresContext, reflowState->mFloatManager, reflowState, nullptr); + lineLayouts.AppendElement(lineLayout); + + // Line number is useless for ruby text + // XXX nullptr here may cause problem, see comments for + // nsLineLayout::mBlockRS and nsLineLayout::AddFloat + lineLayout->Init(nullptr, reflowState->CalcLineHeight(), -1); + reflowState->mLineLayout = lineLayout; + + LogicalMargin borderPadding = reflowState->ComputedLogicalBorderPadding(); + nscoord containerWidth = + reflowState->ComputedWidth() + borderPadding.LeftRight(lineWM); + + lineLayout->BeginLineReflow(borderPadding.IStart(lineWM), + borderPadding.BStart(lineWM), + reflowState->ComputedISize(), + NS_UNCONSTRAINEDSIZE, + false, false, lineWM, containerWidth); } + nscoord istart = aReflowState.mLineLayout->GetCurrentICoord(); + nscoord icoord = istart; + + // Reflow non-span annotations and bases for (PairEnumerator e(this, mTextContainers); !e.AtEnd(); e.Next()) { - // Determine if we need more spacing between bases in the inline direction - // depending on the inline size of the corresponding annotations - // FIXME: The use of GetPrefISize here and below is easier but not ideal. It - // would be better to use metrics from reflow. - nscoord textWidth = 0; + nscoord pairISize = 0; + for (uint32_t i = 0; i < rtcCount; i++) { nsRubyTextFrame* rtFrame = do_QueryFrame(e.GetTextFrame(i)); if (rtFrame) { - int newWidth = rtFrame->GetPrefISize(aReflowState.rendContext); - if (newWidth > textWidth) { - textWidth = newWidth; - } + nsReflowStatus reflowStatus; + nsHTMLReflowMetrics metrics(*rtcReflowStates[i]); + + bool pushedFrame; + rtcReflowStates[i]->mLineLayout->ReflowFrame(rtFrame, reflowStatus, + &metrics, pushedFrame); + NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented"); + pairISize = std::max(pairISize, metrics.ISize(lineWM)); } } nsIFrame* rbFrame = e.GetBaseFrame(); - NS_ASSERTION(!rbFrame || rbFrame->GetType() == nsGkAtoms::rubyBaseFrame, - "Unrecognized child type for ruby base container"); if (rbFrame) { - nsReflowStatus frameReflowStatus; - nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags); - nscoord prefWidth = rbFrame->GetPrefISize(aReflowState.rendContext); - - if (textWidth > prefWidth) { - spaceApart = std::max((textWidth - prefWidth) / 2, spaceApart); - leftoverSpace = spaceApart; - } else { - spaceApart = leftoverSpace; - leftoverSpace = 0; - } - if (spaceApart > 0) { - aReflowState.mLineLayout->AdvanceICoord(spaceApart); - } - baseStart = aReflowState.mLineLayout->GetCurrentICoord(); + MOZ_ASSERT(rbFrame->GetType() == nsGkAtoms::rubyBaseFrame); + nsReflowStatus reflowStatus; + nsHTMLReflowMetrics metrics(aReflowState); bool pushedFrame; - aReflowState.mLineLayout->ReflowFrame(rbFrame, frameReflowStatus, + aReflowState.mLineLayout->ReflowFrame(rbFrame, reflowStatus, &metrics, pushedFrame); NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented"); - - isize += metrics.ISize(lineWM); - rbFrame->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM), - metrics.BSize(lineWM))); - FinishReflowChild(rbFrame, aPresContext, metrics, &aReflowState, 0, 0, - NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW); + pairISize = std::max(pairISize, metrics.ISize(lineWM)); } - // Now reflow the ruby text boxes that correspond to this ruby base box. + // Align all the line layout to the new coordinate. + icoord += pairISize; + aReflowState.mLineLayout->AdvanceICoord( + icoord - aReflowState.mLineLayout->GetCurrentICoord()); for (uint32_t i = 0; i < rtcCount; i++) { - nsRubyTextFrame* rtFrame = do_QueryFrame(e.GetTextFrame(i)); - nsRubyTextContainerFrame* rtcFrame = mTextContainers[i]; - if (rtFrame) { - nsHTMLReflowMetrics rtcMetrics(*aReflowState.parentReflowState, - aDesiredSize.mFlags); - nsHTMLReflowState rtcReflowState(aPresContext, - *aReflowState.parentReflowState, - rtcFrame, availSize); - rtcReflowState.mLineLayout = rtcFrame->GetLineLayout(); - rtcFrame->ReflowRubyTextFrame(rtFrame, rbFrame, baseStart, - aPresContext, rtcMetrics, - rtcReflowState); - } + nsLineLayout* lineLayout = rtcReflowStates[i]->mLineLayout; + lineLayout->AdvanceICoord(icoord - lineLayout->GetCurrentICoord()); } } + // Reflow spans + nscoord spanISize = 0; + for (uint32_t i = 0; i < spanCount; i++) { + nsRubyTextContainerFrame* container = mSpanContainers[i]; + nsIFrame* rtFrame = container->GetFirstPrincipalChild(); + nsReflowStatus reflowStatus; + nsHTMLReflowMetrics metrics(*spanReflowStates[i]); + bool pushedFrame; + spanReflowStates[i]->mLineLayout->ReflowFrame(rtFrame, reflowStatus, + &metrics, pushedFrame); + NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented"); + spanISize = std::max(spanISize, metrics.ISize(lineWM)); + } + + nscoord isize = icoord - istart; + if (isize < spanISize) { + aReflowState.mLineLayout->AdvanceICoord(spanISize - isize); + isize = spanISize; + } + for (uint32_t i = 0; i < totalCount; 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]; + textContainer->SetISize(isize); + lineLayouts[i]->EndLineReflow(); + } + + LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding(); aDesiredSize.ISize(lineWM) = isize; nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState, borderPadding, lineWM, frameWM); }
--- a/layout/generic/nsRubyBaseContainerFrame.h +++ b/layout/generic/nsRubyBaseContainerFrame.h @@ -4,16 +4,17 @@ * version 2.0 (the "License"). You can obtain a copy of the License at * http://mozilla.org/MPL/2.0/. */ /* rendering object for CSS "display: ruby-base-container" */ #ifndef nsRubyBaseContainerFrame_h___ #define nsRubyBaseContainerFrame_h___ +#include "mozilla/UniquePtr.h" #include "nsContainerFrame.h" #include "nsRubyTextContainerFrame.h" #include "nsRubyBaseFrame.h" #include "nsRubyTextFrame.h" /** * Factory function. * @return a newly allocated nsRubyBaseContainerFrame (infallible)
--- a/layout/generic/nsRubyTextContainerFrame.cpp +++ b/layout/generic/nsRubyTextContainerFrame.cpp @@ -7,24 +7,26 @@ /* rendering object for CSS "display: ruby-text-container" */ #include "nsRubyTextContainerFrame.h" #include "nsPresContext.h" #include "nsStyleContext.h" #include "WritingModes.h" #include "mozilla/UniquePtr.h" +using namespace mozilla; + //---------------------------------------------------------------------- // Frame class boilerplate // ======================= NS_QUERYFRAME_HEAD(nsRubyTextContainerFrame) NS_QUERYFRAME_ENTRY(nsRubyTextContainerFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame) +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextContainerFrame) nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { return new (aPresShell) nsRubyTextContainerFrame(aContext); @@ -45,135 +47,29 @@ nsRubyTextContainerFrame::GetType() cons #ifdef DEBUG_FRAME_DUMP nsresult nsRubyTextContainerFrame::GetFrameName(nsAString& aResult) const { return MakeFrameName(NS_LITERAL_STRING("RubyTextContainer"), aResult); } #endif -void -nsRubyTextContainerFrame::BeginRTCLineLayout(nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState) -{ - // Construct block reflow state and line layout - nscoord consumedBSize = GetConsumedBSize(); - - ClearLineCursor(); - - mISize = 0; - - nsBlockReflowState state(aReflowState, aPresContext, this, true, true, - false, consumedBSize); - - NS_ASSERTION(!mLines.empty(), - "There should be at least one line in the ruby text container"); - line_iterator firstLine = begin_lines(); - mLineLayout = mozilla::MakeUnique<nsLineLayout>( - state.mPresContext, - state.mReflowState.mFloatManager, - &state.mReflowState, &firstLine); - mLineLayout->Init(&state, state.mMinLineHeight, state.mLineNumber); - - mozilla::WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); - mozilla::LogicalRect lineRect(state.mContentArea); - nscoord iStart = lineRect.IStart(lineWM); - nscoord availISize = lineRect.ISize(lineWM); - nscoord availBSize = NS_UNCONSTRAINEDSIZE; - - mLineLayout->BeginLineReflow(iStart, state.mBCoord, - availISize, availBSize, - false, - false, - lineWM, state.mContainerWidth); -} - -void -nsRubyTextContainerFrame::ReflowRubyTextFrame( - nsRubyTextFrame* rtFrame, - nsIFrame* rbFrame, - nscoord baseStart, - nsPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState) -{ - nsReflowStatus frameReflowStatus; - nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags); - mozilla::WritingMode lineWM = mLineLayout->GetWritingMode(); - mozilla::LogicalSize availSize(lineWM, aReflowState.AvailableWidth(), - aReflowState.AvailableHeight()); - nsHTMLReflowState childReflowState(aPresContext, aReflowState, rtFrame, availSize); - - // Determine the inline coordinate for the text frame by centering over - // the corresponding base frame - int baseWidth; - if (rbFrame) { - baseWidth = rbFrame->ISize(); - - // If this is the last ruby annotation, it gets paired with ALL remaining - // ruby bases - if (!rtFrame->GetNextSibling()) { - rbFrame = rbFrame->GetNextSibling(); - while (rbFrame) { - baseWidth += rbFrame->ISize(); - rbFrame = rbFrame->GetNextSibling(); - } - } - } else { - baseWidth = 0; - } - - int baseCenter = baseStart + baseWidth / 2; - // FIXME: Find a way to avoid using GetPrefISize here, potentially by moving - // the frame after it has reflowed. - nscoord ICoord = baseCenter - rtFrame->GetPrefISize(aReflowState.rendContext) / 2; - if (ICoord > mLineLayout->GetCurrentICoord()) { - mLineLayout->AdvanceICoord(ICoord - mLineLayout->GetCurrentICoord()); - } - - bool pushedFrame; - mLineLayout->ReflowFrame(rtFrame, frameReflowStatus, - &metrics, pushedFrame); - - NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented"); - - mISize += metrics.ISize(lineWM); - rtFrame->SetSize(nsSize(metrics.ISize(lineWM), metrics.BSize(lineWM))); - FinishReflowChild(rtFrame, aPresContext, metrics, &childReflowState, 0, 0, - NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW); -} - /* virtual */ void nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); // All rt children have already been reflowed. All we need to do is clean up // the line layout. aStatus = NS_FRAME_COMPLETE; - mozilla::WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); - mozilla::WritingMode frameWM = aReflowState.GetWritingMode(); - mozilla::LogicalMargin borderPadding = - aReflowState.ComputedLogicalBorderPadding(); + WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode(); + WritingMode frameWM = aReflowState.GetWritingMode(); + LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding(); aDesiredSize.ISize(lineWM) = mISize; nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState, borderPadding, lineWM, frameWM); - - nscoord bsize = aDesiredSize.BSize(lineWM); - if (!mLines.empty()) { - // Okay to use BlockStartAscent because it has just been correctly set by - // nsLayoutUtils::SetBSizeFromFontMetrics. - mLines.begin()->SetLogicalAscent(aDesiredSize.BlockStartAscent()); - mLines.begin()->SetBounds(aReflowState.GetWritingMode(), 0, 0, mISize, - bsize, mISize); - } - - if (mLineLayout) { - mLineLayout->EndLineReflow(); - mLineLayout = nullptr; - } }
--- a/layout/generic/nsRubyTextContainerFrame.h +++ b/layout/generic/nsRubyTextContainerFrame.h @@ -16,53 +16,41 @@ /** * Factory function. * @return a newly allocated nsRubyTextContainerFrame (infallible) */ nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -// If this is ever changed to be inline again, the code in -// nsFrame::IsFontSizeInflationContainer should be updated to stop excluding -// this from being considered inline. -class nsRubyTextContainerFrame MOZ_FINAL : public nsBlockFrame +class nsRubyTextContainerFrame MOZ_FINAL : public nsContainerFrame { public: NS_DECL_FRAMEARENA_HELPERS NS_DECL_QUERYFRAME_TARGET(nsRubyTextContainerFrame) NS_DECL_QUERYFRAME // nsIFrame overrides virtual nsIAtom* GetType() const MOZ_OVERRIDE; virtual void Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) MOZ_OVERRIDE; #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; #endif - - void ReflowRubyTextFrame(nsRubyTextFrame* rtFrame, nsIFrame* rbFrame, - nscoord baseStart, nsPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState); - void BeginRTCLineLayout(nsPresContext* aPresContext, - const nsHTMLReflowState& aReflowState); - nsLineLayout* GetLineLayout() { return mLineLayout.get(); }; + void SetISize(nscoord aISize) { mISize = aISize; } protected: friend nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); - explicit nsRubyTextContainerFrame(nsStyleContext* aContext) : nsBlockFrame(aContext) {} - // This pointer is active only during reflow of the ruby structure. It gets - // created when the corresponding ruby base container is reflowed, and it is - // destroyed when the ruby text container itself is reflowed. - mozilla::UniquePtr<nsLineLayout> mLineLayout; + explicit nsRubyTextContainerFrame(nsStyleContext* aContext) + : nsContainerFrame(aContext) {} + // The intended dimensions of the ruby text container. These are modified // whenever a ruby text box is reflowed and used when the ruby text container // is reflowed. nscoord mISize; }; #endif /* nsRubyTextContainerFrame_h___ */