--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -4948,27 +4948,30 @@ nsTextFrame::GetTextDecorations(
nsTextFrame::TextDecorations& aDecorations)
{
const nsCompatibility compatMode = aPresContext->CompatibilityMode();
bool useOverride = false;
nscolor overrideColor = NS_RGBA(0, 0, 0, 0);
bool nearestBlockFound = false;
- WritingMode wm = GetWritingMode();
+ // Use writing mode of parent frame for orthogonal text frame to work.
+ // See comment in nsTextFrame::DrawTextRunAndDecorations.
+ WritingMode wm = GetParent()->GetWritingMode();
bool vertical = wm.IsVertical();
+ nscoord ascent = GetLogicalBaseline(wm);
// physicalBlockStartOffset represents the offset from our baseline
// to f's physical block start, which is top in horizontal writing
// mode, and left in vertical writing modes, in our coordinate space.
// This physical block start is logical block start in most cases,
// but for vertical-rl, it is logical block end, and consequently in
// that case, it starts from the descent instead of ascent.
nscoord physicalBlockStartOffset =
- wm.IsVerticalRL() ? GetSize().width - mAscent : mAscent;
+ wm.IsVerticalRL() ? GetSize().width - ascent : ascent;
// baselineOffset represents the offset from our baseline to f's baseline or
// the nearest block's baseline, in our coordinate space, whichever is closest
// during the particular iteration
nscoord baselineOffset = 0;
for (nsIFrame* f = this, *fChild = nullptr;
f;
fChild = f,
@@ -5211,20 +5214,19 @@ void
nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
nsIFrame* aBlock,
PropertyProvider& aProvider,
nsRect* aVisualOverflowRect,
bool aIncludeTextDecorations)
{
const WritingMode wm = GetWritingMode();
bool verticalRun = mTextRun->IsVertical();
- bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
- bool inverted = wm.IsLineInverted();
if (IsFloatingFirstLetterChild()) {
+ bool inverted = wm.IsLineInverted();
// The underline/overline drawable area must be contained in the overflow
// rect when this is in floating first letter frame at *both* modes.
// In this case, aBlock is the ::first-letter frame.
uint8_t decorationStyle = aBlock->StyleContext()->
StyleTextReset()->GetDecorationStyle();
// If the style is none, let's include decoration line rect as solid style
// since changing the style from none to solid/dotted/dashed doesn't cause
// reflow.
@@ -5260,43 +5262,50 @@ nsTextFrame::UnionAdditionalOverflow(nsP
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, underlineRect);
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, overlineRect);
// XXX If strikeoutSize is much thicker than the underlineSize, it may
// cause overflowing from the overflow rect. However, such case
// isn't realistic, we don't need to compute it now.
}
if (aIncludeTextDecorations) {
+ // Use writing mode of parent frame for orthogonal text frame to
+ // work. See comment in nsTextFrame::DrawTextRunAndDecorations.
+ WritingMode parentWM = GetParent()->GetWritingMode();
+ bool verticalDec = parentWM.IsVertical();
+ bool useVerticalMetrics = verticalDec != verticalRun
+ ? verticalDec : verticalRun && mTextRun->UseCenterBaseline();
+
// Since CSS 2.1 requires that text-decoration defined on ancestors maintain
// style and position, they can be drawn at virtually any y-offset, so
// maxima and minima are required to reliably generate the rectangle for
// them
TextDecorations textDecs;
GetTextDecorations(aPresContext, eResolvedColors, textDecs);
if (textDecs.HasDecorationLines()) {
nscoord inflationMinFontSize =
nsLayoutUtils::InflationMinFontSizeFor(aBlock);
- const nscoord measure = verticalRun ? GetSize().height : GetSize().width;
- const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(),
- gfxWidth = measure / appUnitsPerDevUnit;
- gfxFloat ascent = gfxFloat(mAscent) / appUnitsPerDevUnit;
+ const nscoord measure = verticalDec ? GetSize().height : GetSize().width;
+ const gfxFloat app = aPresContext->AppUnitsPerDevPixel();
+ gfxFloat gfxWidth = measure / app;
+ gfxFloat ascent = gfxFloat(GetLogicalBaseline(parentWM)) / app;
nscoord frameBStart = 0;
- if (wm.IsVerticalRL()) {
+ if (parentWM.IsVerticalRL()) {
frameBStart = GetSize().width;
ascent = -ascent;
}
// The decoration-line offsets need to be reversed for sideways-lr mode,
// so we will multiply the values from metrics by this factor.
gfxFloat decorationOffsetDir = mTextRun->IsSidewaysLeft() ? -1.0 : 1.0;
nsCSSRendering::DecorationRectParams params;
params.lineSize = Size(gfxWidth, 0);
params.ascent = ascent;
- params.vertical = verticalRun;
+ params.vertical = verticalDec;
nscoord topOrLeft(nscoord_MAX), bottomOrRight(nscoord_MIN);
typedef gfxFont::Metrics Metrics;
auto accumulateDecorationRect = [&](const LineDecoration& dec,
gfxFloat Metrics::* lineSize,
gfxFloat Metrics::* lineOffset) {
params.style = dec.mStyle;
// If the style is solid, let's include decoration line rect of solid
@@ -5311,20 +5320,20 @@ nsTextFrame::UnionAdditionalOverflow(nsP
const Metrics metrics =
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
useVerticalMetrics);
params.lineSize.height = metrics.*lineSize;
params.offset = decorationOffsetDir * metrics.*lineOffset;
const nsRect decorationRect =
nsCSSRendering::GetTextDecorationRect(aPresContext, params) +
- (verticalRun ? nsPoint(frameBStart - dec.mBaselineOffset, 0)
+ (verticalDec ? nsPoint(frameBStart - dec.mBaselineOffset, 0)
: nsPoint(0, -dec.mBaselineOffset));
- if (verticalRun) {
+ if (verticalDec) {
topOrLeft = std::min(decorationRect.x, topOrLeft);
bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight);
} else {
topOrLeft = std::min(decorationRect.y, topOrLeft);
bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight);
}
};
@@ -5343,22 +5352,22 @@ nsTextFrame::UnionAdditionalOverflow(nsP
params.decoration = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
for (const LineDecoration& dec : textDecs.mStrikes) {
accumulateDecorationRect(dec, &Metrics::strikeoutSize,
&Metrics::strikeoutOffset);
}
aVisualOverflowRect->UnionRect(
*aVisualOverflowRect,
- verticalRun ? nsRect(topOrLeft, 0, bottomOrRight - topOrLeft, measure)
+ verticalDec ? nsRect(topOrLeft, 0, bottomOrRight - topOrLeft, measure)
: nsRect(0, topOrLeft, measure, bottomOrRight - topOrLeft));
}
aVisualOverflowRect->UnionRect(*aVisualOverflowRect,
- UpdateTextEmphasis(wm, aProvider));
+ UpdateTextEmphasis(parentWM, aProvider));
}
// Text-shadow overflows
nsRect shadowRect =
nsLayoutUtils::GetTextShadowRectsUnion(*aVisualOverflowRect, this);
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, shadowRect);
// When this frame is not selected, the text-decoration area must be in
@@ -6625,44 +6634,52 @@ nsTextFrame::DrawTextRun(Range aRange, c
void
nsTextFrame::DrawTextRunAndDecorations(Range aRange,
const gfxPoint& aTextBaselinePt,
const DrawTextParams& aParams,
const TextDecorations& aDecorations)
{
const gfxFloat app =
aParams.textStyle->PresContext()->AppUnitsPerDevPixel();
+ // Writing mode of parent frame is used because the text frame may
+ // be orthogonal to its parent when text-combine-upright is used or
+ // its parent has "display: contents", and in those cases, we want
+ // to draw the decoration lines according to parents' direction
+ // rather than ours.
+ const WritingMode wm = GetParent()->GetWritingMode();
+ bool verticalDec = wm.IsVertical();
bool verticalRun = mTextRun->IsVertical();
- bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
+ // If the text run and the decoration is orthogonal, we choose the
+ // metrics for decoration so that decoration line won't be broken.
+ bool useVerticalMetrics = verticalDec != verticalRun
+ ? verticalDec : verticalRun && mTextRun->UseCenterBaseline();
// XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
nscoord x = NSToCoordRound(aParams.framePt.x);
nscoord y = NSToCoordRound(aParams.framePt.y);
// 'measure' here is textrun-relative, so for a horizontal run it's the
// width, while for a vertical run it's the height of the decoration
const nsSize frameSize = GetSize();
- nscoord measure = verticalRun ? frameSize.height : frameSize.width;
-
- if (verticalRun) {
+ nscoord measure = verticalDec ? frameSize.height : frameSize.width;
+
+ if (verticalDec) {
aParams.clipEdges->Intersect(&y, &measure);
} else {
aParams.clipEdges->Intersect(&x, &measure);
}
// decSize is a textrun-relative size, so its 'width' field is actually
// the run-relative measure, and 'height' will be the line thickness
- gfxFloat ascent = gfxFloat(mAscent) / app;
-
+ gfxFloat ascent = gfxFloat(GetLogicalBaseline(wm)) / app;
// The starting edge of the frame in block direction
- gfxFloat frameBStart = verticalRun ? aParams.framePt.x : aParams.framePt.y;
-
- // In vertical-rl mode, block coordinates are measured from the right,
- // so we need to adjust here.
- const WritingMode wm = GetWritingMode();
+ gfxFloat frameBStart = verticalDec ? aParams.framePt.x : aParams.framePt.y;
+
+ // In vertical-rl mode, block coordinates are measured from the
+ // right, so we need to adjust here.
if (wm.IsVerticalRL()) {
frameBStart += frameSize.width;
ascent = -ascent;
}
nscoord inflationMinFontSize =
nsLayoutUtils::InflationMinFontSizeFor(this);
@@ -6673,20 +6690,35 @@ nsTextFrame::DrawTextRunAndDecorations(R
PaintDecorationLineParams params;
params.context = aParams.context;
params.dirtyRect = aParams.dirtyRect;
params.overrideColor = aParams.decorationOverrideColor;
params.callbacks = aParams.callbacks;
// pt is the physical point where the decoration is to be drawn,
// relative to the frame; one of its coordinates will be updated below.
params.pt = Point(x / app, y / app);
- Float& bCoord = verticalRun ? params.pt.x : params.pt.y;
+ Float& bCoord = verticalDec ? params.pt.x : params.pt.y;
params.lineSize = Size(measure / app, 0);
params.ascent = ascent;
- params.vertical = verticalRun;
+ params.vertical = verticalDec;
+
+ // The matrix of the context may have been altered for text-combine-
+ // upright. However, we want to draw decoration lines unscaled, thus
+ // we need to revert the scaling here.
+ gfxContextMatrixAutoSaveRestore scaledRestorer;
+ if (StyleContext()->IsTextCombined()) {
+ float scaleFactor = GetTextCombineScaleFactor(this);
+ if (scaleFactor != 1.0f) {
+ scaledRestorer.SetContext(aParams.context);
+ gfxMatrix unscaled = aParams.context->CurrentMatrix();
+ gfxPoint pt(x / app, y / app);
+ unscaled.Translate(pt).Scale(1.0f / scaleFactor, 1.0f).Translate(-pt);
+ aParams.context->SetMatrix(unscaled);
+ }
+ }
typedef gfxFont::Metrics Metrics;
auto paintDecorationLine = [&](const LineDecoration& dec,
gfxFloat Metrics::* lineSize,
gfxFloat Metrics::* lineOffset) {
if (dec.mStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
return;
}
@@ -6713,19 +6745,27 @@ nsTextFrame::DrawTextRunAndDecorations(R
&Metrics::underlineOffset);
}
// Overlines
params.decoration = NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
for (const LineDecoration& dec : Reversed(aDecorations.mOverlines)) {
paintDecorationLine(dec, &Metrics::underlineSize, &Metrics::maxAscent);
}
- // CSS 2.1 mandates that text be painted after over/underlines, and *then*
- // line-throughs
- DrawTextRun(aRange, aTextBaselinePt, aParams);
+ {
+ gfxContextMatrixAutoSaveRestore unscaledRestorer;
+ if (scaledRestorer.HasMatrix()) {
+ unscaledRestorer.SetContext(aParams.context);
+ aParams.context->SetMatrix(scaledRestorer.Matrix());
+ }
+
+ // CSS 2.1 mandates that text be painted after over/underlines,
+ // and *then* line-throughs
+ DrawTextRun(aRange, aTextBaselinePt, aParams);
+ }
// Emphasis marks
DrawEmphasisMarks(aParams.context, wm, aTextBaselinePt, aRange,
aParams.decorationOverrideColor, aParams.provider);
// Line-throughs
params.decoration = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
for (const LineDecoration& dec : Reversed(aDecorations.mStrikes)) {
@@ -9487,19 +9527,33 @@ nsTextFrame::HasSignificantTerminalNewli
bool
nsTextFrame::IsAtEndOfLine() const
{
return (GetStateBits() & TEXT_END_OF_LINE) != 0;
}
nscoord
-nsTextFrame::GetLogicalBaseline(WritingMode aWritingMode ) const
-{
- return mAscent;
+nsTextFrame::GetLogicalBaseline(WritingMode aWM) const
+{
+ if (!aWM.IsOrthogonalTo(GetWritingMode())) {
+ return mAscent;
+ }
+
+ // When the text frame has a writing mode orthogonal to the desired
+ // writing mode, return a baseline coincides its parent frame.
+ nsIFrame* parent = GetParent();
+ nsPoint position = GetNormalPosition();
+ nscoord parentAscent = parent->GetLogicalBaseline(aWM);
+ if (aWM.IsVerticalRL()) {
+ nscoord parentDescent = parent->GetSize().width - parentAscent;
+ nscoord descent = parentDescent - position.x;
+ return GetSize().width - descent;
+ }
+ return parentAscent - (aWM.IsVertical() ? position.x : position.y);
}
bool
nsTextFrame::HasAnyNoncollapsedCharacters()
{
gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated);
int32_t offset = GetContentOffset(),
offsetEnd = GetContentEnd();