From 6d77b2c8933b277522016d66cf9feb5aed99dfa1 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Mon, 4 May 2015 09:52:53 +1200 Subject: [PATCH] Bug 1149009 - Suppress line break inside text frame if it is directly contained by ruby content box. r=dbaron --- layout/base/nsBidiPresUtils.cpp | 3 ++- layout/generic/nsTextFrame.cpp | 14 +++++++------- layout/generic/nsTextFrame.h | 13 +++++++++++++ .../css-ruby/line-break-suppression-4-ref.html | 11 +++++++++++ .../css-ruby/line-break-suppression-4.html | 11 +++++++++++ layout/reftests/css-ruby/reftest.list | 1 + layout/style/nsStyleContext.h | 2 ++ layout/style/nsStyleStruct.h | 3 ++- layout/style/nsStyleStructInlines.h | 5 +++-- 9 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 layout/reftests/css-ruby/line-break-suppression-4-ref.html create mode 100644 layout/reftests/css-ruby/line-break-suppression-4.html diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index ebda564bd5d..3a82eeb60c6 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -1055,7 +1055,8 @@ nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame, if (nsGkAtoms::textFrame == frameType) { if (content != aBpd->mPrevContent) { aBpd->mPrevContent = content; - if (!frame->StyleText()->NewlineIsSignificant(frame)) { + if (!frame->StyleText()->NewlineIsSignificant( + static_cast(frame))) { content->AppendTextTo(aBpd->mBuffer); } else { /* diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 4cd4c6e22e5..79002e8f85f 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -678,7 +678,7 @@ static bool IsSpaceCombiningSequenceTail(const nsTextFragment* aFrag, uint32_t a // Check whether aPos is a space for CSS 'word-spacing' purposes static bool IsCSSWordSpacingSpace(const nsTextFragment* aFrag, uint32_t aPos, - nsIFrame* aFrame, const nsStyleText* aStyleText) + nsTextFrame* aFrame, const nsStyleText* aStyleText) { NS_ASSERTION(aPos < aFrag->GetLength(), "No text for IsSpace!"); @@ -1942,7 +1942,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) textFlags |= GetSpacingFlags(WordSpacing(f)); nsTextFrameUtils::CompressionMode compression = GetCSSWhitespaceToCompressionMode(f, textStyle); - if ((enabledJustification || f->StyleContext()->ShouldSuppressLineBreak()) && + if ((enabledJustification || f->ShouldSuppressLineBreak()) && !textStyle->WhiteSpaceIsSignificant() && !isSVG) { textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING; } @@ -2816,9 +2816,9 @@ static int32_t FindChar(const nsTextFragment* frag, return -1; } -static bool IsChineseOrJapanese(nsIFrame* aFrame) +static bool IsChineseOrJapanese(nsTextFrame* aFrame) { - if (aFrame->StyleContext()->ShouldSuppressLineBreak()) { + if (aFrame->ShouldSuppressLineBreak()) { // Always treat ruby as CJ language so that those characters can // be expanded properly even when surrounded by other language. return true; @@ -8343,7 +8343,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, (GetStateBits() & TEXT_IS_IN_TOKEN_MATHML); gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority(); gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak; - if (StyleContext()->ShouldSuppressLineBreak()) { + if (ShouldSuppressLineBreak()) { suppressBreak = gfxTextRun::eSuppressAllBreaks; } else if (!aLineLayout.LineIsBreakable()) { suppressBreak = gfxTextRun::eSuppressInitialBreak; @@ -8552,7 +8552,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, bool emptyTextAtStartOfLine = atStartOfLine && length == 0; if (!breakAfter && charsFit == length && !emptyTextAtStartOfLine && transformedOffset + transformedLength == mTextRun->GetLength() && - !StyleContext()->ShouldSuppressLineBreak() && + !ShouldSuppressLineBreak() && (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK)) { // We placed all the text in the textrun and we have a break opportunity at // the end of the textrun. We need to record it because the following @@ -8614,7 +8614,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, if (!textStyle->WhiteSpaceIsSignificant() && (lineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY || lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY || - StyleContext()->ShouldSuppressLineBreak()) && + ShouldSuppressLineBreak()) && !lineContainer->IsSVGText()) { AddStateBits(TEXT_JUSTIFICATION_ENABLED); provider.ComputeJustification(offset, charsFit); diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index ef456aa8eee..ce3c972b68a 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -15,6 +15,7 @@ #include "gfxTextRun.h" #include "nsDisplayList.h" #include "JustificationUtils.h" +#include "RubyUtils.h" // Undo the windows.h damage #if defined(XP_WIN) && defined(DrawText) @@ -122,6 +123,18 @@ public: nsIFrame::eLineParticipant)); } + bool ShouldSuppressLineBreak() const + { + // If the parent frame of the text frame is ruby content box, it must + // suppress line break inside. This check is necessary, because when + // a whitespace is only contained by pseudo ruby frames, its style + // context won't have SuppressLineBreak bit set. + if (mozilla::RubyUtils::IsRubyContentBox(GetParent()->GetType())) { + return true; + } + return StyleContext()->ShouldSuppressLineBreak(); + } + virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) override; virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) override; diff --git a/layout/reftests/css-ruby/line-break-suppression-4-ref.html b/layout/reftests/css-ruby/line-break-suppression-4-ref.html new file mode 100644 index 00000000000..5e680a29840 --- /dev/null +++ b/layout/reftests/css-ruby/line-break-suppression-4-ref.html @@ -0,0 +1,11 @@ + + + + + Bug 1149009 - Line break suppression on whitespaces wrapped but not contained in ruby boxes + + + a +b + + diff --git a/layout/reftests/css-ruby/line-break-suppression-4.html b/layout/reftests/css-ruby/line-break-suppression-4.html new file mode 100644 index 00000000000..90d7e73dec6 --- /dev/null +++ b/layout/reftests/css-ruby/line-break-suppression-4.html @@ -0,0 +1,11 @@ + + + + + Bug 1149009 - Line break suppression on whitespaces wrapped but not contained in ruby boxes + + + a +b + + diff --git a/layout/reftests/css-ruby/reftest.list b/layout/reftests/css-ruby/reftest.list index d8a2e8f8b36..abef389dc56 100644 --- a/layout/reftests/css-ruby/reftest.list +++ b/layout/reftests/css-ruby/reftest.list @@ -31,6 +31,7 @@ fuzzy-if(winWidget,255,792) == lang-specific-style-1.html lang-specific-style-1- == line-break-suppression-1.html line-break-suppression-1-ref.html == line-break-suppression-2.html line-break-suppression-2-ref.html == line-break-suppression-3.html line-break-suppression-3-ref.html +== line-break-suppression-4.html line-break-suppression-4-ref.html == line-height-1.html line-height-1-ref.html == line-height-2.html line-height-2-ref.html == line-height-3.html line-height-3-ref.html diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h index e3f73835444..0e4c7d1b033 100644 --- a/layout/style/nsStyleContext.h +++ b/layout/style/nsStyleContext.h @@ -157,6 +157,8 @@ public: // as if nowrap is set,
is suppressed, and blocks are inlinized. // This bit is propogated to all children of line partitipants. It is // currently used by ruby to make its content frames unbreakable. + // NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak() + // instead of this method. bool ShouldSuppressLineBreak() const { return !!(mBits & NS_STYLE_SUPPRESS_LINEBREAK); } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 0a95902d6d3..1391cf51565 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -30,6 +30,7 @@ #include "CounterStyleManager.h" class nsIFrame; +class nsTextFrame; class nsIURI; class imgIContainer; @@ -1666,7 +1667,7 @@ struct nsStyleText { // style struct is for. If the frame is for SVG text or inside ruby, // the return value will be massaged to be something that makes sense // for those cases. - inline bool NewlineIsSignificant(const nsIFrame* aContextFrame) const; + inline bool NewlineIsSignificant(const nsTextFrame* aContextFrame) const; inline bool WhiteSpaceCanWrap(const nsIFrame* aContextFrame) const; inline bool WordCanWrap(const nsIFrame* aContextFrame) const; }; diff --git a/layout/style/nsStyleStructInlines.h b/layout/style/nsStyleStructInlines.h index 8a52f9934ec..3883d7ceb1f 100644 --- a/layout/style/nsStyleStructInlines.h +++ b/layout/style/nsStyleStructInlines.h @@ -14,6 +14,7 @@ #include "nsIFrame.h" #include "nsStyleStruct.h" #include "nsIContent.h" // for GetParent() +#include "nsTextFrame.h" // for nsTextFrame::ShouldSuppressLineBreak inline void nsStyleImage::SetSubImage(uint8_t aIndex, imgIContainer* aSubImage) const @@ -43,11 +44,11 @@ nsStyleText::GetTextShadow() const } bool -nsStyleText::NewlineIsSignificant(const nsIFrame* aContextFrame) const +nsStyleText::NewlineIsSignificant(const nsTextFrame* aContextFrame) const { NS_ASSERTION(aContextFrame->StyleText() == this, "unexpected aContextFrame"); return NewlineIsSignificantStyle() && - !aContextFrame->StyleContext()->ShouldSuppressLineBreak(); + !aContextFrame->ShouldSuppressLineBreak(); } bool