Bug 1120313 - Fix nested ruby inside ruby annotation. r=dbaron

--HG--
extra : source : ea44dcc7bf0e008d6669a00d107529a97ab1c84d
This commit is contained in:
Xidorn Quan 2015-01-13 15:14:46 +11:00
parent fccbdc4b77
commit 59a6f1fedb
4 changed files with 72 additions and 25 deletions

View File

@ -58,7 +58,7 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
: mPresContext(aPresContext),
mFloatManager(aFloatManager),
mBlockReflowState(aOuterReflowState),
mBaseLineLayout(aBaseLineLayout ? aBaseLineLayout->mBaseLineLayout : this),
mBaseLineLayout(aBaseLineLayout),
mLastOptionalBreakFrame(nullptr),
mForceBreakFrame(nullptr),
mBlockRS(nullptr),/* XXX temporary */
@ -87,6 +87,11 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
NS_ASSERTION(aFloatManager || aOuterReflowState->frame->GetType() ==
nsGkAtoms::letterFrame,
"float manager should be present");
MOZ_ASSERT((!!mBaseLineLayout) ==
(aOuterReflowState->frame->GetType() ==
nsGkAtoms::rubyTextContainerFrame),
"Only ruby text container frames have "
"a different base line layout");
MOZ_COUNT_CTOR(nsLineLayout);
// Stash away some style data that we need
@ -182,7 +187,7 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
mIsTopOfPage = aIsTopOfPage;
mImpactedByFloats = aImpactedByFloats;
mTotalPlacedFrames = 0;
if (mBaseLineLayout == this) {
if (!mBaseLineLayout) {
mLineIsEmpty = true;
mLineAtStart = true;
} else {
@ -263,7 +268,7 @@ nsLineLayout::EndLineReflow()
printf(": EndLineReflow: width=%d\n", mRootSpan->mICoord - mRootSpan->mIStart);
#endif
NS_ASSERTION(mBaseLineLayout == this ||
NS_ASSERTION(!mBaseLineLayout ||
(!mSpansAllocated && !mSpansFreed && !mSpanFreeList &&
!mFramesAllocated && !mFramesFreed && !mFrameFreeList),
"Allocated frames or spans on non-base line layout?");
@ -386,18 +391,19 @@ nsLineLayout::UpdateBand(WritingMode aWM,
nsLineLayout::PerSpanData*
nsLineLayout::NewPerSpanData()
{
PerSpanData* psd = mBaseLineLayout->mSpanFreeList;
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
PerSpanData* psd = outerLineLayout->mSpanFreeList;
if (!psd) {
void *mem;
size_t sz = sizeof(PerSpanData);
PL_ARENA_ALLOCATE(mem, &mBaseLineLayout->mArena, sz);
PL_ARENA_ALLOCATE(mem, &outerLineLayout->mArena, sz);
if (!mem) {
NS_ABORT_OOM(sz);
}
psd = reinterpret_cast<PerSpanData*>(mem);
}
else {
mBaseLineLayout->mSpanFreeList = psd->mNextFreeSpan;
outerLineLayout->mSpanFreeList = psd->mNextFreeSpan;
}
psd->mParent = nullptr;
psd->mFrame = nullptr;
@ -408,7 +414,7 @@ nsLineLayout::NewPerSpanData()
psd->mHasNonemptyContent = false;
#ifdef DEBUG
mBaseLineLayout->mSpansAllocated++;
outerLineLayout->mSpansAllocated++;
#endif
return psd;
}
@ -473,13 +479,21 @@ nsLineLayout::EndSpan(nsIFrame* aFrame)
void
nsLineLayout::AttachFrameToBaseLineLayout(PerFrameData* aFrame)
{
NS_PRECONDITION(this != mBaseLineLayout,
NS_PRECONDITION(mBaseLineLayout,
"This method must not be called in a base line layout.");
PerFrameData* baseFrame = mBaseLineLayout->LastFrame();
MOZ_ASSERT(aFrame && baseFrame);
MOZ_ASSERT(!aFrame->mIsLinkedToBase,
"The frame must not have been linked with the base");
#ifdef DEBUG
nsIAtom* baseType = baseFrame->mFrame->GetType();
nsIAtom* annotationType = aFrame->mFrame->GetType();
MOZ_ASSERT((baseType == nsGkAtoms::rubyBaseContainerFrame &&
annotationType == nsGkAtoms::rubyTextContainerFrame) ||
(baseType == nsGkAtoms::rubyBaseFrame &&
annotationType == nsGkAtoms::rubyTextFrame));
#endif
aFrame->mNextAnnotation = baseFrame->mNextAnnotation;
baseFrame->mNextAnnotation = aFrame;
@ -603,10 +617,11 @@ nsLineLayout::FreeFrame(PerFrameData* pfd)
if (nullptr != pfd->mSpan) {
FreeSpan(pfd->mSpan);
}
pfd->mNext = mBaseLineLayout->mFrameFreeList;
mBaseLineLayout->mFrameFreeList = pfd;
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
pfd->mNext = outerLineLayout->mFrameFreeList;
outerLineLayout->mFrameFreeList = pfd;
#ifdef DEBUG
mBaseLineLayout->mFramesFreed++;
outerLineLayout->mFramesFreed++;
#endif
}
@ -616,11 +631,12 @@ nsLineLayout::FreeSpan(PerSpanData* psd)
// Unlink its frames
UnlinkFrame(psd->mFirstFrame);
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
// Now put the span on the free list since it's free too
psd->mNextFreeSpan = mBaseLineLayout->mSpanFreeList;
mBaseLineLayout->mSpanFreeList = psd;
psd->mNextFreeSpan = outerLineLayout->mSpanFreeList;
outerLineLayout->mSpanFreeList = psd;
#ifdef DEBUG
mBaseLineLayout->mSpansFreed++;
outerLineLayout->mSpansFreed++;
#endif
}
@ -641,18 +657,19 @@ nsLineLayout::IsZeroBSize()
nsLineLayout::PerFrameData*
nsLineLayout::NewPerFrameData(nsIFrame* aFrame)
{
PerFrameData* pfd = mBaseLineLayout->mFrameFreeList;
nsLineLayout* outerLineLayout = GetOutermostLineLayout();
PerFrameData* pfd = outerLineLayout->mFrameFreeList;
if (!pfd) {
void *mem;
size_t sz = sizeof(PerFrameData);
PL_ARENA_ALLOCATE(mem, &mBaseLineLayout->mArena, sz);
PL_ARENA_ALLOCATE(mem, &outerLineLayout->mArena, sz);
if (!mem) {
NS_ABORT_OOM(sz);
}
pfd = reinterpret_cast<PerFrameData*>(mem);
}
else {
mBaseLineLayout->mFrameFreeList = pfd->mNext;
outerLineLayout->mFrameFreeList = pfd->mNext;
}
pfd->mSpan = nullptr;
pfd->mNext = nullptr;
@ -684,7 +701,7 @@ nsLineLayout::NewPerFrameData(nsIFrame* aFrame)
#ifdef DEBUG
pfd->mBlockDirAlign = 0xFF;
mBaseLineLayout->mFramesAllocated++;
outerLineLayout->mFramesAllocated++;
#endif
return pfd;
}
@ -970,7 +987,8 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
// We might as well allow zero-width floats to be placed, though.
availableISize = 0;
}
placedFloat = mBaseLineLayout->AddFloat(outOfFlowFrame, availableISize);
placedFloat = GetOutermostLineLayout()->
AddFloat(outOfFlowFrame, availableISize);
NS_ASSERTION(!(outOfFlowFrame->GetType() == nsGkAtoms::letterFrame &&
GetFirstLetterStyleOK()),
"FirstLetterStyle set on line with floating first letter");

View File

@ -385,14 +385,23 @@ protected:
const nsStyleText* mStyleText; // for the block
const nsHTMLReflowState* mBlockReflowState;
// The line layout for the base text. It is usually same as |this|.
// It becomes different when the current line layout is for ruby
// annotations. All line layouts share the same base line layout
// when they are associated. The base line layout is responsible
// for managing the life cycle of per-frame data and per-span data,
// and handling floats.
// The line layout for the base text. It is usually nullptr.
// It becomes not null when the current line layout is for ruby
// annotations. When there is nested ruby inside annotation, it
// forms a linked list from the inner annotation to the outermost
// line layout. The outermost line layout, which has this member
// being nullptr, is responsible for managing the life cycle of
// per-frame data and per-span data, and handling floats.
nsLineLayout* const mBaseLineLayout;
nsLineLayout* GetOutermostLineLayout() {
nsLineLayout* lineLayout = this;
while (lineLayout->mBaseLineLayout) {
lineLayout = lineLayout->mBaseLineLayout;
}
return lineLayout;
}
nsIFrame* mLastOptionalBreakFrame;
nsIFrame* mForceBreakFrame;

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bug 1120313 - Nested ruby inside ruby annotation</title>
<link rel="stylesheet" href="common.css">
</head>
<body>
<ruby>
<rb>base1</rb>
<rt>
<ruby>
<rb>base2</rb>
<rt>text</rt>
</ruby>
</rt>
</ruby>
</body>
</html>

View File

@ -27,6 +27,7 @@ fuzzy-if(winWidget,35,1) == dynamic-removal-3.html dynamic-removal-3-ref.html #
== justification-2.html justification-2-ref.html
== line-height-1.html line-height-1-ref.html
== line-height-2.html line-height-2-ref.html
load nested-ruby-1.html
== line-height-3.html line-height-3-ref.html
== ruby-span-1.html ruby-span-1-ref.html
== ruby-whitespace-1.html ruby-whitespace-1-ref.html