Bug 1440014: Part 1: Implemented rendering for text-decoration-width CSS property r=jfkthame

reftests will be added later

Differential Revision: https://phabricator.services.mozilla.com/D34238

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Charlie Marlow 2019-06-26 21:21:57 +00:00
Родитель 6686b244bd
Коммит b695380455
4 изменённых файлов: 73 добавлений и 24 удалений

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

@ -5118,15 +5118,18 @@ void nsTextFrame::GetTextDecorations(
if (textDecorations & kUnderline) {
aDecorations.mUnderlines.AppendElement(nsTextFrame::LineDecoration(
f, baselineOffset, styleText->mTextUnderlineOffset, color, style));
f, baselineOffset, styleText->mTextUnderlineOffset,
styleTextReset->mTextDecorationWidth, color, style));
}
if (textDecorations & kOverline) {
aDecorations.mOverlines.AppendElement(nsTextFrame::LineDecoration(
f, baselineOffset, styleText->mTextUnderlineOffset, color, style));
f, baselineOffset, styleText->mTextUnderlineOffset,
styleTextReset->mTextDecorationWidth, color, style));
}
if (textDecorations & StyleTextDecorationLine_LINE_THROUGH) {
aDecorations.mStrikes.AppendElement(nsTextFrame::LineDecoration(
f, baselineOffset, styleText->mTextUnderlineOffset, color, style));
f, baselineOffset, styleText->mTextUnderlineOffset,
styleTextReset->mTextDecorationWidth, color, style));
}
}
@ -5274,11 +5277,10 @@ nsRect nsTextFrame::UpdateTextEmphasis(WritingMode aWM,
return overflowRect.GetPhysicalRect(aWM, frameSize.GetPhysicalSize(aWM));
}
static void SetParamIfLength(const LengthOrAuto& aTextOffset,
Float* aParamOffset,
static void SetParamIfLength(const LengthOrAuto& aLengthOrAuto, Float* aParam,
const gfxFloat aAppUnitsPerDevPixel) {
if (aTextOffset.IsLength()) {
*aParamOffset = aTextOffset.AsLength().ToAppUnits() / aAppUnitsPerDevPixel;
if (aLengthOrAuto.IsLength()) {
*aParam = aLengthOrAuto.AsLength().ToAppUnits() / aAppUnitsPerDevPixel;
}
}
@ -5305,6 +5307,7 @@ void nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
if (decorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
decorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
}
nsCSSRendering::DecorationRectParams params;
nsFontMetrics* fontMetrics = aProvider.GetFontMetrics();
nscoord underlineOffset, underlineSize;
fontMetrics->GetUnderline(underlineOffset, underlineSize);
@ -5312,14 +5315,21 @@ void nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
const LengthOrAuto& textUnderlineOffset =
aBlock->Style()->StyleText()->mTextUnderlineOffset;
const LengthOrAuto& textDecorationWidth =
aBlock->Style()->StyleTextReset()->mTextDecorationWidth;
if (textUnderlineOffset.IsLength()) {
underlineOffset = textUnderlineOffset.AsLength().ToAppUnits();
}
params.defaultLineThickness = underlineSize;
if (textDecorationWidth.IsLength()) {
underlineSize = textDecorationWidth.AsLength().ToAppUnits();
}
nscoord maxAscent =
inverted ? fontMetrics->MaxDescent() : fontMetrics->MaxAscent();
nsCSSRendering::DecorationRectParams params;
Float gfxWidth = (verticalRun ? aVisualOverflowRect->height
: aVisualOverflowRect->width) /
appUnitsPerDevUnit;
@ -5406,9 +5416,13 @@ void nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
if (lineType == StyleTextDecorationLine_UNDERLINE) {
SetParamIfLength(dec.mTextUnderlineOffset, &params.offset,
aPresContext->AppUnitsPerDevPixel());
appUnitsPerDevUnit);
}
params.defaultLineThickness = params.lineSize.height;
SetParamIfLength(dec.mTextDecorationWidth, &params.lineSize.height,
appUnitsPerDevUnit);
const nsRect decorationRect =
nsCSSRendering::GetTextDecorationRect(aPresContext, params) +
(verticalDec ? nsPoint(frameBStart - dec.mBaselineOffset, 0)
@ -5589,7 +5603,7 @@ void nsTextFrame::DrawSelectionDecorations(
if (aDecoration == StyleTextDecorationLine_UNDERLINE) {
params.offset = aFontMetrics.underlineOffset;
SetParamIfLength(StyleText()->mTextUnderlineOffset, &params.offset,
PresContext()->AppUnitsPerDevPixel());
aTextPaintStyle.PresContext()->AppUnitsPerDevPixel());
} else {
params.offset = aFontMetrics.maxAscent;
}
@ -5603,6 +5617,9 @@ void nsTextFrame::DrawSelectionDecorations(
aTextPaintStyle.PresContext(), aFontMetrics);
float relativeSize;
const LengthOrAuto& decWidth = StyleTextReset()->mTextDecorationWidth;
const gfxFloat appUnitsPerDevPixel =
aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
switch (aSelectionType) {
case SelectionType::eIMERawClause:
@ -5615,8 +5632,11 @@ void nsTextFrame::DrawSelectionDecorations(
bool weDefineSelectionUnderline =
aTextPaintStyle.GetSelectionUnderlineForPaint(
index, &params.color, &relativeSize, &params.style);
params.lineSize.height = ComputeSelectionUnderlineHeight(
params.defaultLineThickness = ComputeSelectionUnderlineHeight(
aTextPaintStyle.PresContext(), aFontMetrics, aSelectionType);
params.lineSize.height = params.defaultLineThickness;
SetParamIfLength(decWidth, &params.lineSize.height, appUnitsPerDevPixel);
bool isIMEType = aSelectionType != SelectionType::eSpellCheck;
if (isIMEType) {
@ -5688,6 +5708,8 @@ void nsTextFrame::DrawSelectionDecorations(
aTextPaintStyle.GetURLSecondaryColor(&params.color);
params.style = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
params.lineSize.height = metrics.strikeoutSize;
params.defaultLineThickness = params.lineSize.height;
SetParamIfLength(decWidth, &params.lineSize.height, appUnitsPerDevPixel);
params.offset = metrics.strikeoutOffset + 0.5;
params.decoration = StyleTextDecorationLine_LINE_THROUGH;
break;
@ -5697,6 +5719,7 @@ void nsTextFrame::DrawSelectionDecorations(
return;
}
params.lineSize.height *= relativeSize;
params.defaultLineThickness *= relativeSize;
params.icoordInFrame =
(aVertical ? params.pt.y - aPt.y : params.pt.x - aPt.x) + aICoordInFrame;
PaintDecorationLine(params);
@ -6881,7 +6904,9 @@ void nsTextFrame::DrawTextRunAndDecorations(
SetParamIfLength(dec.mTextUnderlineOffset, &params.offset,
PresContext()->AppUnitsPerDevPixel());
}
params.defaultLineThickness = params.lineSize.height;
SetParamIfLength(dec.mTextDecorationWidth, &params.lineSize.height,
PresContext()->AppUnitsPerDevPixel());
params.style = dec.mStyle;
PaintDecorationLine(params);
};
@ -7225,11 +7250,16 @@ bool nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
}
nsRect decorationArea;
params.lineSize = Size(aPresContext->AppUnitsToGfxUnits(aRect.width),
ComputeSelectionUnderlineHeight(
aPresContext, metrics, sd->mSelectionType));
const LengthOrAuto& decWidth = StyleTextReset()->mTextDecorationWidth;
params.lineSize.width = aPresContext->AppUnitsToGfxUnits(aRect.width);
params.defaultLineThickness = ComputeSelectionUnderlineHeight(
aPresContext, metrics, sd->mSelectionType);
SetParamIfLength(decWidth, &params.lineSize.height,
aPresContext->AppUnitsPerDevPixel());
relativeSize = std::max(relativeSize, 1.0f);
params.lineSize.height *= relativeSize;
params.defaultLineThickness *= relativeSize;
decorationArea =
nsCSSRendering::GetTextDecorationRect(aPresContext, params);
aRect.UnionRect(aRect, decorationArea);

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

@ -699,15 +699,20 @@ class nsTextFrame : public nsFrame {
// This represents the offset from the initial position of the underline
const mozilla::LengthOrAuto mTextUnderlineOffset;
// for CSS property text-decoration-width, the width refers to the thickness
// of the decoration line
const mozilla::LengthOrAuto mTextDecorationWidth;
nscolor mColor;
uint8_t mStyle;
LineDecoration(nsIFrame* const aFrame, const nscoord aOff,
const mozilla::LengthOrAuto& aUnderline,
const nscolor aColor, const uint8_t aStyle)
const mozilla::LengthOrAuto& aDecWidth, const nscolor aColor,
const uint8_t aStyle)
: mFrame(aFrame),
mBaselineOffset(aOff),
mTextUnderlineOffset(aUnderline),
mTextDecorationWidth(aDecWidth),
mColor(aColor),
mStyle(aStyle) {}
@ -715,6 +720,7 @@ class nsTextFrame : public nsFrame {
: mFrame(aOther.mFrame),
mBaselineOffset(aOther.mBaselineOffset),
mTextUnderlineOffset(aOther.mTextUnderlineOffset),
mTextDecorationWidth(aOther.mTextDecorationWidth),
mColor(aOther.mColor),
mStyle(aOther.mStyle) {}
@ -722,7 +728,8 @@ class nsTextFrame : public nsFrame {
return mFrame == aOther.mFrame && mStyle == aOther.mStyle &&
mColor == aOther.mColor &&
mBaselineOffset == aOther.mBaselineOffset &&
mTextUnderlineOffset == aOther.mTextUnderlineOffset;
mTextUnderlineOffset == aOther.mTextUnderlineOffset &&
mTextDecorationWidth == aOther.mTextDecorationWidth;
}
bool operator!=(const LineDecoration& aOther) const {

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

@ -4062,6 +4062,8 @@ gfxRect nsCSSRendering::GetTextDecorationRectInternal(
gfxFloat lineThickness = NS_round(aParams.lineSize.height);
lineThickness = std::max(lineThickness, 1.0);
gfxFloat defaultLineThickness = NS_round(aParams.defaultLineThickness);
defaultLineThickness = std::max(defaultLineThickness, 1.0);
gfxFloat ascent = NS_round(aParams.ascent);
gfxFloat descentLimit = floor(aParams.descentLimit);
@ -4154,18 +4156,22 @@ gfxRect nsCSSRendering::GetTextDecorationRectInternal(
}
}
} else if (aParams.decoration == StyleTextDecorationLine_OVERLINE) {
// For overline, we adjust the offset by lineThickness (the thickness of
// a single decoration line) because empirically it looks better to draw
// the overline just inside rather than outside the font's ascent, which
// is what nsTextFrame passes as aParams.offset (as fonts don't provide
// an explicit overline-offset).
offset = aParams.offset - lineThickness + r.Height();
// For overline, we adjust the offset by defaultlineThickness (the default
// thickness of a single decoration line) because empirically it looks
// better to draw the overline just inside rather than outside the font's
// ascent, which is what nsTextFrame passes as aParams.offset (as fonts
// don't provide an explicit overline-offset).
offset = aParams.offset - defaultLineThickness + r.Height();
} else if (aParams.decoration == StyleTextDecorationLine_LINE_THROUGH) {
// To maintain a consistent mid-point for line-through decorations,
// we adjust the offset by half of the decoration rect's height.
gfxFloat extra = floor(r.Height() / 2.0 + 0.5);
extra = std::max(extra, lineThickness);
offset = aParams.offset - lineThickness + extra;
// computes offset for when user specifies a decoration width since
// aParams.offset is derived from the font metric's line height
gfxFloat decorationWidthOffset =
(lineThickness - defaultLineThickness) / 2.0;
offset = aParams.offset - lineThickness + extra + decorationWidthOffset;
} else {
MOZ_ASSERT_UNREACHABLE("Invalid text decoration value");
}

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

@ -559,6 +559,12 @@ struct nsCSSRendering {
// for a vertical textrun, width will actually be a physical height;
// and conversely, height will be a physical width.
Size lineSize;
// The default height [thickness] of the line given by the font metrics.
// This is used for obtaining the correct offset for the decoration line
// when CSS specifies a unique thickness for a text-decoration,
// since the offset given by the font is derived from the font metric's
// assumed line height
Float defaultLineThickness = 0.0f;
// The ascent of the text.
Float ascent = 0.0f;
// The offset of the decoration line from the baseline of the text