Bug 1089431 part 2 - Break between ruby bases according to line-breaking rules. r=jfkthame

--HG--
extra : rebase_source : dae94948a18c860fd5e86b3754c21fd856d5cc47
extra : source : bdcf6f831f5d0241de8b4a0de617902e23b29e8c
This commit is contained in:
Xidorn Quan 2015-02-11 10:26:56 +11:00
Родитель 0005151f66
Коммит 46d0d217a9
1 изменённых файлов: 84 добавлений и 29 удалений

Просмотреть файл

@ -14,6 +14,7 @@
#include "nsStyleStructInlines.h"
#include "WritingModes.h"
#include "RubyUtils.h"
#include "nsTextFrame.h"
#include "mozilla/Maybe.h"
#include "mozilla/DebugOnly.h"
@ -310,6 +311,7 @@ nsRubyBaseContainerFrame::GetLogicalBaseline(WritingMode aWritingMode) const
struct nsRubyBaseContainerFrame::ReflowState
{
bool mAllowInitialLineBreak;
bool mAllowLineBreak;
const TextContainerArray& mTextContainers;
const nsHTMLReflowState& mBaseReflowState;
@ -418,21 +420,17 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
allowInitialLineBreak = !inNestedRuby &&
parent->StyleText()->WhiteSpaceCanWrap(parent);
}
if (allowInitialLineBreak && aReflowState.mLineLayout->LineIsBreakable() &&
aReflowState.mLineLayout->NotifyOptionalBreakPosition(
this, 0, 0 <= aReflowState.AvailableISize(),
gfxBreakPriority::eNormalBreak)) {
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
if (!aReflowState.mLineLayout->LineIsBreakable()) {
allowInitialLineBreak = false;
}
nscoord isize = 0;
if (aStatus == NS_FRAME_COMPLETE) {
// Reflow columns excluding any span
ReflowState reflowState = {
allowLineBreak && !hasSpan, textContainers, aReflowState, reflowStates
};
isize = ReflowColumns(reflowState, aStatus);
}
// Reflow columns excluding any span
ReflowState reflowState = {
allowInitialLineBreak, allowLineBreak && !hasSpan,
textContainers, aReflowState, reflowStates
};
isize = ReflowColumns(reflowState, aStatus);
DebugOnly<nscoord> lineSpanSize = aReflowState.mLineLayout->EndSpan(this);
aDesiredSize.ISize(lineWM) = isize;
// When there are no frames inside the ruby base container, EndSpan
@ -449,7 +447,7 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
NS_FRAME_IS_COMPLETE(aStatus) && hasSpan) {
// Reflow spans
ReflowState reflowState = {
false, textContainers, aReflowState, reflowStates
false, false, textContainers, aReflowState, reflowStates
};
nscoord spanISize = ReflowSpans(reflowState);
nscoord deltaISize = spanISize - isize;
@ -460,15 +458,6 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
isize = spanISize;
}
}
// When there are spans, ReflowColumns and ReflowOneColumn won't
// record any optional break position. We have to record one
// at the end of this segment.
if (!NS_INLINE_IS_BREAK(aStatus) && allowLineBreak &&
aReflowState.mLineLayout->NotifyOptionalBreakPosition(
this, INT32_MAX, isize <= aReflowState.AvailableISize(),
gfxBreakPriority::eNormalBreak)) {
aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
}
}
for (uint32_t i = 0; i < rtcCount; i++) {
@ -627,6 +616,45 @@ nsRubyBaseContainerFrame::ReflowColumns(const ReflowState& aReflowState,
return icoord;
}
static gfxBreakPriority
LineBreakBefore(const nsHTMLReflowState& aReflowState, nsRubyBaseFrame* aFrame)
{
for (nsIFrame* child = aFrame; child;
child = child->GetFirstPrincipalChild()) {
if (!child->CanContinueTextRun()) {
// It is not an inline element. We can break before it.
return gfxBreakPriority::eNormalBreak;
}
if (child->GetType() != nsGkAtoms::textFrame) {
continue;
}
auto textFrame = static_cast<nsTextFrame*>(child);
gfxSkipCharsIterator iter =
textFrame->EnsureTextRun(nsTextFrame::eInflated,
aReflowState.rendContext->ThebesContext(),
aReflowState.mLineLayout->LineContainerFrame(),
aReflowState.mLineLayout->GetLine());
iter.SetOriginalOffset(textFrame->GetContentOffset());
uint32_t pos = iter.GetSkippedOffset();
gfxTextRun* textRun = textFrame->GetTextRun(nsTextFrame::eInflated);
// Return whether we can break before the first character.
if (textRun->CanBreakLineBefore(pos)) {
return gfxBreakPriority::eNormalBreak;
}
// Check whether we can wrap word here.
const nsStyleText* textStyle = textFrame->StyleText();
if (textStyle->WordCanWrap(textFrame) && textRun->IsClusterStart(pos)) {
return gfxBreakPriority::eWordWrapBreak;
}
// We cannot break before.
return gfxBreakPriority::eNoBreak;
}
// Neither block, nor text frame is found as a leaf. We won't break
// before this base frame. It is the behavior of empty spans.
return gfxBreakPriority::eNoBreak;
}
nscoord
nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
uint32_t aColumnIndex,
@ -636,6 +664,17 @@ nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
const nsHTMLReflowState& baseReflowState = aReflowState.mBaseReflowState;
const auto& textReflowStates = aReflowState.mTextReflowStates;
if (aColumn.mBaseFrame) {
int32_t pos = baseReflowState.mLineLayout->
GetForcedBreakPosition(aColumn.mBaseFrame);
MOZ_ASSERT(pos == -1 || pos == 0,
"It should either break before, or not break at all.");
if (pos >= 0) {
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
return 0;
}
}
const uint32_t rtcCount = aReflowState.mTextContainers.Length();
MOZ_ASSERT(aColumn.mTextFrames.Length() == rtcCount);
MOZ_ASSERT(textReflowStates.Length() == rtcCount);
@ -705,6 +744,29 @@ nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
"Any line break inside ruby box should has been suppressed");
nscoord baseISize = lineLayout->GetCurrentICoord() - baseIStart;
columnISize = std::max(columnISize, baseISize);
bool allowBreakBefore = aColumnIndex ?
aReflowState.mAllowLineBreak : aReflowState.mAllowInitialLineBreak;
if (allowBreakBefore) {
bool shouldBreakBefore = false;
gfxBreakPriority breakPriority =
LineBreakBefore(baseReflowState, aColumn.mBaseFrame);
if (breakPriority != gfxBreakPriority::eNoBreak) {
int32_t offset;
gfxBreakPriority lastBreakPriority;
baseReflowState.mLineLayout->
GetLastOptionalBreakPosition(&offset, &lastBreakPriority);
shouldBreakBefore = breakPriority >= lastBreakPriority;
}
if (shouldBreakBefore) {
bool fits = istart <= baseReflowState.AvailableISize();
DebugOnly<bool> breakBefore =
baseReflowState.mLineLayout->NotifyOptionalBreakPosition(
aColumn.mBaseFrame, 0, fits, breakPriority);
MOZ_ASSERT(!breakBefore, "The break notified here should have "
"triggered at the start of this method.");
}
}
}
// Align all the line layout to the new coordinate.
@ -734,13 +796,6 @@ nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
}
}
if (aReflowState.mAllowLineBreak &&
baseReflowState.mLineLayout->NotifyOptionalBreakPosition(
this, aColumnIndex + 1, icoord <= baseReflowState.AvailableISize(),
gfxBreakPriority::eNormalBreak)) {
aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus);
}
return columnISize;
}