--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -184,16 +184,17 @@ nsFirstLetterFrame::Reflow(nsPresContext
"should no longer use unconstrained inline size");
availSize.ISize(wm) -= bp.IStartEnd(wm);
if (NS_UNCONSTRAINEDSIZE != availSize.BSize(wm)) {
availSize.BSize(wm) -= bp.BStartEnd(wm);
}
WritingMode lineWM = aMetrics.GetWritingMode();
ReflowOutput kidMetrics(lineWM);
+ const nsStyleTextReset* styleTR = mStyleContext->StyleTextReset();
// Reflow the child
if (!aReflowInput.mLineLayout) {
// When there is no lineLayout provided, we provide our own. The
// only time that the first-letter-frame is not reflowing in a
// line context is when its floating.
WritingMode kidWritingMode = GetWritingMode(kid);
LogicalSize kidAvailSize = availSize.ConvertTo(kidWritingMode, wm);
@@ -209,32 +210,72 @@ nsFirstLetterFrame::Reflow(nsPresContext
ll.SetInFirstLetter(true);
ll.SetFirstLetterStyleOK(true);
kid->Reflow(aPresContext, kidMetrics, rs, aReflowStatus);
ll.EndLineReflow();
ll.SetInFirstLetter(false);
+ // CSS Inline Layout Level 3 - 3.3 Creating Initial Letters
+ // According to the specification, the initial letter's baseline should
+ // sink to the Nth line, where N is the sink value of the initial-letter
+ // property. To achieve the alignment, we can either adjust the initial
+ // letter's baseline, or move the rest lines of texts. The point is that we
+ // should align the top of the block container with, either the top of the
+ // initial letter, or the top of the first line. So, if moving the rest
+ // lines of texts would break this rule, we should adjust the initial
+ // letter's baseline instead.
+ // Here, the initial letter's baseline, i.e., initialBaseline, and the Nth
+ // line's baseline, i.e., targetBaseline, are both evaluated. If
+ // targetBaseline > initialBaseline, we should adjust initialBaseline
+ // downwards to be aligned with targetBaseline. As to the logic for moving
+ // the rest lines of texts, please see nsLineLayout::ReflowFrame().
+ nscoord offset = 0;
+ if (styleTR->mInitialLetterSink != 0) {
+ nsStyleContext* containerSC = mStyleContext->GetParent();
+ const nsStyleDisplay* containerDisp = containerSC->StyleDisplay();
+ while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
+ if (!containerSC->GetParent()) {
+ break;
+ }
+ containerSC = containerSC->GetParent();
+ containerDisp = containerSC->StyleDisplay();
+ }
+ nscoord containerLH =
+ ReflowInput::CalcLineHeight(nullptr, containerSC, NS_AUTOHEIGHT, 1.0f);
+ RefPtr<nsFontMetrics> containerFM =
+ nsLayoutUtils::GetFontMetricsForStyleContext(containerSC);
+ MOZ_ASSERT(containerFM, "Should have fontMetrics!!");
+ nscoord topLeading = (containerLH - containerFM->MaxHeight()) / 2;
+ nscoord lineAscent = topLeading + containerFM->MaxAscent();
+
+ nscoord targetBaseline =
+ (styleTR->mInitialLetterSink - 1) * containerLH + lineAscent;
+ nscoord initialBaseline = kidMetrics.BlockStartAscent();
+ if (targetBaseline > initialBaseline) {
+ offset = targetBaseline - initialBaseline;
+ }
+ }
// In the floating first-letter case, we need to set this ourselves;
// nsLineLayout::BeginSpan will set it in the other case
- mBaseline = kidMetrics.BlockStartAscent();
+ mBaseline = kidMetrics.BlockStartAscent() + offset;
// Place and size the child and update the output metrics
LogicalSize convertedSize = kidMetrics.Size(lineWM).ConvertTo(wm, lineWM);
- kid->SetRect(nsRect(bp.IStart(wm), bp.BStart(wm),
+ kid->SetRect(nsRect(bp.IStart(wm), bp.BStart(wm) + offset,
convertedSize.ISize(wm), convertedSize.BSize(wm)));
kid->FinishAndStoreOverflow(&kidMetrics);
kid->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
convertedSize.ISize(wm) += bp.IStartEnd(wm);
- convertedSize.BSize(wm) += bp.BStartEnd(wm);
+ convertedSize.BSize(wm) += bp.BStartEnd(wm) + offset;
aMetrics.SetSize(wm, convertedSize);
aMetrics.SetBlockStartAscent(kidMetrics.BlockStartAscent() +
- bp.BStart(wm));
+ bp.BStart(wm) + offset);
// Ensure that the overflow rect contains the child textframe's
// overflow rect.
// Note that if this is floating, the overline/underline drawable
// area is in the overflow rect of the child textframe.
aMetrics.UnionOverflowAreasWithDesiredBounds();
ConsiderChildOverflow(aMetrics.mOverflowAreas, kid);
@@ -251,17 +292,17 @@ nsFirstLetterFrame::Reflow(nsPresContext
ll->ReflowFrame(kid, aReflowStatus, &kidMetrics, pushedFrame);
NS_ASSERTION(lineWM.IsVertical() == wm.IsVertical(),
"we're assuming we can mix sizes between lineWM and wm "
"since we shouldn't have orthogonal writing modes within "
"a line.");
aMetrics.ISize(lineWM) = ll->EndSpan(this) + bp.IStartEnd(wm);
ll->SetInFirstLetter(false);
- if (mStyleContext->StyleTextReset()->mInitialLetterSize != 0.0f) {
+ if (styleTR->mInitialLetterSize != 0.0f) {
aMetrics.SetBlockStartAscent(kidMetrics.BlockStartAscent() +
bp.BStart(wm));
aMetrics.BSize(lineWM) = kidMetrics.BSize(lineWM) + bp.BStartEnd(wm);
} else {
nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics, bp, lineWM, wm);
}
}