Bug 1950844 - Support spelling-error and grammar-error values of text-decoration-line. r=tlouw
Differential Revision: https://phabricator.services.mozilla.com/D239913
This commit is contained in:
@@ -4912,8 +4912,29 @@ void nsTextFrame::GetTextDecorations(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nsStyleTextReset* const styleTextReset = context->StyleTextReset();
|
const nsStyleTextReset* const styleTextReset = context->StyleTextReset();
|
||||||
const StyleTextDecorationLine textDecorations =
|
StyleTextDecorationLine textDecorations =
|
||||||
styleTextReset->mTextDecorationLine;
|
styleTextReset->mTextDecorationLine;
|
||||||
|
bool ignoreSubproperties = false;
|
||||||
|
|
||||||
|
auto lineStyle = styleTextReset->mTextDecorationStyle;
|
||||||
|
if (textDecorations == StyleTextDecorationLine::SPELLING_ERROR ||
|
||||||
|
textDecorations == StyleTextDecorationLine::GRAMMAR_ERROR) {
|
||||||
|
nscolor lineColor;
|
||||||
|
float relativeSize;
|
||||||
|
useOverride = nsTextPaintStyle::GetSelectionUnderline(
|
||||||
|
this, nsTextPaintStyle::SelectionStyleIndex::SpellChecker, &lineColor,
|
||||||
|
&relativeSize, &lineStyle);
|
||||||
|
if (useOverride) {
|
||||||
|
// We don't currently have a SelectionStyleIndex::GrammarChecker; for
|
||||||
|
// now just use SpellChecker and change its color to green.
|
||||||
|
overrideColor =
|
||||||
|
textDecorations == StyleTextDecorationLine::SPELLING_ERROR
|
||||||
|
? lineColor
|
||||||
|
: NS_RGBA(0, 128, 0, 255);
|
||||||
|
textDecorations = StyleTextDecorationLine::UNDERLINE;
|
||||||
|
ignoreSubproperties = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!useOverride &&
|
if (!useOverride &&
|
||||||
(StyleTextDecorationLine::COLOR_OVERRIDE & textDecorations)) {
|
(StyleTextDecorationLine::COLOR_OVERRIDE & textDecorations)) {
|
||||||
@@ -4961,7 +4982,6 @@ void nsTextFrame::GetTextDecorations(
|
|||||||
physicalBlockStartOffset +=
|
physicalBlockStartOffset +=
|
||||||
vertical ? f->GetNormalPosition().x : f->GetNormalPosition().y;
|
vertical ? f->GetNormalPosition().x : f->GetNormalPosition().y;
|
||||||
|
|
||||||
const auto style = styleTextReset->mTextDecorationStyle;
|
|
||||||
if (textDecorations) {
|
if (textDecorations) {
|
||||||
nscolor color;
|
nscolor color;
|
||||||
if (useOverride) {
|
if (useOverride) {
|
||||||
@@ -4992,23 +5012,29 @@ void nsTextFrame::GetTextDecorations(
|
|||||||
: StyleTextDecorationLine::OVERLINE;
|
: StyleTextDecorationLine::OVERLINE;
|
||||||
|
|
||||||
const nsStyleText* const styleText = context->StyleText();
|
const nsStyleText* const styleText = context->StyleText();
|
||||||
|
const auto position = ignoreSubproperties
|
||||||
|
? StyleTextUnderlinePosition::AUTO
|
||||||
|
: styleText->mTextUnderlinePosition;
|
||||||
|
const auto offset = ignoreSubproperties ? LengthPercentageOrAuto::Auto()
|
||||||
|
: styleText->mTextUnderlineOffset;
|
||||||
|
const auto thickness = ignoreSubproperties
|
||||||
|
? StyleTextDecorationLength::Auto()
|
||||||
|
: styleTextReset->mTextDecorationThickness;
|
||||||
|
|
||||||
if (textDecorations & kUnderline) {
|
if (textDecorations & kUnderline) {
|
||||||
aDecorations.mUnderlines.AppendElement(nsTextFrame::LineDecoration(
|
aDecorations.mUnderlines.AppendElement(nsTextFrame::LineDecoration(
|
||||||
f, baselineOffset, styleText->mTextUnderlinePosition,
|
f, baselineOffset, position, offset, thickness, color, lineStyle,
|
||||||
styleText->mTextUnderlineOffset,
|
!ignoreSubproperties));
|
||||||
styleTextReset->mTextDecorationThickness, color, style));
|
|
||||||
}
|
}
|
||||||
if (textDecorations & kOverline) {
|
if (textDecorations & kOverline) {
|
||||||
aDecorations.mOverlines.AppendElement(nsTextFrame::LineDecoration(
|
aDecorations.mOverlines.AppendElement(nsTextFrame::LineDecoration(
|
||||||
f, baselineOffset, styleText->mTextUnderlinePosition,
|
f, baselineOffset, position, offset, thickness, color, lineStyle,
|
||||||
styleText->mTextUnderlineOffset,
|
!ignoreSubproperties));
|
||||||
styleTextReset->mTextDecorationThickness, color, style));
|
|
||||||
}
|
}
|
||||||
if (textDecorations & StyleTextDecorationLine::LINE_THROUGH) {
|
if (textDecorations & StyleTextDecorationLine::LINE_THROUGH) {
|
||||||
aDecorations.mStrikes.AppendElement(nsTextFrame::LineDecoration(
|
aDecorations.mStrikes.AppendElement(nsTextFrame::LineDecoration(
|
||||||
f, baselineOffset, styleText->mTextUnderlinePosition,
|
f, baselineOffset, position, offset, thickness, color, lineStyle,
|
||||||
styleText->mTextUnderlineOffset,
|
!ignoreSubproperties));
|
||||||
styleTextReset->mTextDecorationThickness, color, style));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5568,6 +5594,7 @@ struct nsTextFrame::PaintDecorationLineParams
|
|||||||
DecorationType decorationType = DecorationType::Normal;
|
DecorationType decorationType = DecorationType::Normal;
|
||||||
DrawPathCallbacks* callbacks = nullptr;
|
DrawPathCallbacks* callbacks = nullptr;
|
||||||
bool paintingShadows = false;
|
bool paintingShadows = false;
|
||||||
|
bool allowInkSkipping = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void nsTextFrame::PaintDecorationLine(
|
void nsTextFrame::PaintDecorationLine(
|
||||||
@@ -5579,6 +5606,7 @@ void nsTextFrame::PaintDecorationLine(
|
|||||||
params.color = aParams.overrideColor ? *aParams.overrideColor : aParams.color;
|
params.color = aParams.overrideColor ? *aParams.overrideColor : aParams.color;
|
||||||
params.icoordInFrame = Float(aParams.icoordInFrame);
|
params.icoordInFrame = Float(aParams.icoordInFrame);
|
||||||
params.baselineOffset = Float(aParams.baselineOffset);
|
params.baselineOffset = Float(aParams.baselineOffset);
|
||||||
|
params.allowInkSkipping = aParams.allowInkSkipping;
|
||||||
if (aParams.callbacks) {
|
if (aParams.callbacks) {
|
||||||
Rect path = nsCSSRendering::DecorationLineToPath(params);
|
Rect path = nsCSSRendering::DecorationLineToPath(params);
|
||||||
if (aParams.decorationType == DecorationType::Normal) {
|
if (aParams.decorationType == DecorationType::Normal) {
|
||||||
@@ -7172,6 +7200,7 @@ void nsTextFrame::DrawTextRunAndDecorations(
|
|||||||
app, dec.mFrame, wm.IsCentralBaseline(), swapUnderline);
|
app, dec.mFrame, wm.IsCentralBaseline(), swapUnderline);
|
||||||
|
|
||||||
params.style = dec.mStyle;
|
params.style = dec.mStyle;
|
||||||
|
params.allowInkSkipping = dec.mAllowInkSkipping;
|
||||||
PaintDecorationLine(params);
|
PaintDecorationLine(params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -860,11 +860,11 @@ class nsTextFrame : public nsIFrame {
|
|||||||
const PaintShadowParams& aParams);
|
const PaintShadowParams& aParams);
|
||||||
|
|
||||||
struct LineDecoration {
|
struct LineDecoration {
|
||||||
nsIFrame* mFrame;
|
nsIFrame* const mFrame;
|
||||||
|
|
||||||
// This is represents the offset from our baseline to mFrame's baseline;
|
// This is represents the offset from our baseline to mFrame's baseline;
|
||||||
// positive offsets are *above* the baseline and negative offsets below
|
// positive offsets are *above* the baseline and negative offsets below
|
||||||
nscoord mBaselineOffset;
|
const nscoord mBaselineOffset;
|
||||||
|
|
||||||
// This represents the offset from the initial position of the underline
|
// This represents the offset from the initial position of the underline
|
||||||
const mozilla::LengthPercentageOrAuto mTextUnderlineOffset;
|
const mozilla::LengthPercentageOrAuto mTextUnderlineOffset;
|
||||||
@@ -872,26 +872,30 @@ class nsTextFrame : public nsIFrame {
|
|||||||
// for CSS property text-decoration-thickness, the width refers to the
|
// for CSS property text-decoration-thickness, the width refers to the
|
||||||
// thickness of the decoration line
|
// thickness of the decoration line
|
||||||
const mozilla::StyleTextDecorationLength mTextDecorationThickness;
|
const mozilla::StyleTextDecorationLength mTextDecorationThickness;
|
||||||
nscolor mColor;
|
const nscolor mColor;
|
||||||
mozilla::StyleTextDecorationStyle mStyle;
|
const mozilla::StyleTextDecorationStyle mStyle;
|
||||||
|
|
||||||
// The text-underline-position property; affects the underline offset only
|
// The text-underline-position property; affects the underline offset only
|
||||||
// if mTextUnderlineOffset is auto.
|
// if mTextUnderlineOffset is auto.
|
||||||
const mozilla::StyleTextUnderlinePosition mTextUnderlinePosition;
|
const mozilla::StyleTextUnderlinePosition mTextUnderlinePosition;
|
||||||
|
|
||||||
|
const bool mAllowInkSkipping;
|
||||||
|
|
||||||
LineDecoration(nsIFrame* const aFrame, const nscoord aOff,
|
LineDecoration(nsIFrame* const aFrame, const nscoord aOff,
|
||||||
mozilla::StyleTextUnderlinePosition aUnderlinePosition,
|
const mozilla::StyleTextUnderlinePosition aUnderlinePosition,
|
||||||
const mozilla::LengthPercentageOrAuto& aUnderlineOffset,
|
const mozilla::LengthPercentageOrAuto& aUnderlineOffset,
|
||||||
const mozilla::StyleTextDecorationLength& aDecThickness,
|
const mozilla::StyleTextDecorationLength& aDecThickness,
|
||||||
const nscolor aColor,
|
const nscolor aColor,
|
||||||
const mozilla::StyleTextDecorationStyle aStyle)
|
const mozilla::StyleTextDecorationStyle aStyle,
|
||||||
|
const bool aAllowInkSkipping)
|
||||||
: mFrame(aFrame),
|
: mFrame(aFrame),
|
||||||
mBaselineOffset(aOff),
|
mBaselineOffset(aOff),
|
||||||
mTextUnderlineOffset(aUnderlineOffset),
|
mTextUnderlineOffset(aUnderlineOffset),
|
||||||
mTextDecorationThickness(aDecThickness),
|
mTextDecorationThickness(aDecThickness),
|
||||||
mColor(aColor),
|
mColor(aColor),
|
||||||
mStyle(aStyle),
|
mStyle(aStyle),
|
||||||
mTextUnderlinePosition(aUnderlinePosition) {}
|
mTextUnderlinePosition(aUnderlinePosition),
|
||||||
|
mAllowInkSkipping(aAllowInkSkipping) {}
|
||||||
|
|
||||||
LineDecoration(const LineDecoration& aOther) = default;
|
LineDecoration(const LineDecoration& aOther) = default;
|
||||||
|
|
||||||
@@ -901,7 +905,8 @@ class nsTextFrame : public nsIFrame {
|
|||||||
mBaselineOffset == aOther.mBaselineOffset &&
|
mBaselineOffset == aOther.mBaselineOffset &&
|
||||||
mTextUnderlinePosition == aOther.mTextUnderlinePosition &&
|
mTextUnderlinePosition == aOther.mTextUnderlinePosition &&
|
||||||
mTextUnderlineOffset == aOther.mTextUnderlineOffset &&
|
mTextUnderlineOffset == aOther.mTextUnderlineOffset &&
|
||||||
mTextDecorationThickness == aOther.mTextDecorationThickness;
|
mTextDecorationThickness == aOther.mTextDecorationThickness &&
|
||||||
|
mAllowInkSkipping == aOther.mAllowInkSkipping;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const LineDecoration& aOther) const {
|
bool operator!=(const LineDecoration& aOther) const {
|
||||||
|
|||||||
@@ -1153,9 +1153,10 @@ static nsIFrame* GetPageSequenceForCanvas(const nsIFrame* aCanvasFrame) {
|
|||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nsCSSRendering::FindEffectiveBackgroundColor(
|
auto nsCSSRendering::FindEffectiveBackgroundColor(nsIFrame* aFrame,
|
||||||
nsIFrame* aFrame, bool aStopAtThemed,
|
bool aStopAtThemed,
|
||||||
bool aPreferBodyToCanvas) -> EffectiveBackgroundColor {
|
bool aPreferBodyToCanvas)
|
||||||
|
-> EffectiveBackgroundColor {
|
||||||
MOZ_ASSERT(aFrame);
|
MOZ_ASSERT(aFrame);
|
||||||
nsPresContext* pc = aFrame->PresContext();
|
nsPresContext* pc = aFrame->PresContext();
|
||||||
auto BgColorIfNotTransparent = [&](nsIFrame* aFrame) -> Maybe<nscolor> {
|
auto BgColorIfNotTransparent = [&](nsIFrame* aFrame) -> Maybe<nscolor> {
|
||||||
@@ -4095,21 +4096,16 @@ void nsCSSRendering::PaintDecorationLine(
|
|||||||
aFrame->StyleText()->mTextDecorationSkipInk;
|
aFrame->StyleText()->mTextDecorationSkipInk;
|
||||||
bool skipInkEnabled =
|
bool skipInkEnabled =
|
||||||
skipInk != mozilla::StyleTextDecorationSkipInk::None &&
|
skipInk != mozilla::StyleTextDecorationSkipInk::None &&
|
||||||
aParams.decoration != StyleTextDecorationLine::LINE_THROUGH;
|
aParams.decoration != StyleTextDecorationLine::LINE_THROUGH &&
|
||||||
|
aParams.allowInkSkipping && aFrame->IsTextFrame();
|
||||||
|
|
||||||
if (!skipInkEnabled || aParams.glyphRange.Length() == 0) {
|
if (!skipInkEnabled || aParams.glyphRange.Length() == 0) {
|
||||||
PaintDecorationLineInternal(aFrame, aDrawTarget, aParams, rect);
|
PaintDecorationLineInternal(aFrame, aDrawTarget, aParams, rect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the frame is a text frame or not
|
// Must be a text frame, otherwise skipInkEnabled (above) would be false.
|
||||||
nsTextFrame* textFrame = nullptr;
|
nsTextFrame* textFrame = static_cast<nsTextFrame*>(aFrame);
|
||||||
if (aFrame->IsTextFrame()) {
|
|
||||||
textFrame = static_cast<nsTextFrame*>(aFrame);
|
|
||||||
} else {
|
|
||||||
PaintDecorationLineInternal(aFrame, aDrawTarget, aParams, rect);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get text run and current text offset (for line wrapping)
|
// get text run and current text offset (for line wrapping)
|
||||||
gfxTextRun* textRun =
|
gfxTextRun* textRun =
|
||||||
|
|||||||
@@ -610,6 +610,8 @@ struct nsCSSRendering {
|
|||||||
// Baseline offset being applied to this text (block-direction adjustment
|
// Baseline offset being applied to this text (block-direction adjustment
|
||||||
// applied to glyph positions when computing skip-ink intercepts).
|
// applied to glyph positions when computing skip-ink intercepts).
|
||||||
Float baselineOffset = 0.0f;
|
Float baselineOffset = 0.0f;
|
||||||
|
// Whether text-decoration-skip-ink behavior is to be supported.
|
||||||
|
bool allowInkSkipping = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ impl ToCss for TextOverflow {
|
|||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[css(bitflags(single = "none", mixed = "underline,overline,line-through,blink"))]
|
#[css(bitflags(single = "none,spelling-error,grammar-error", mixed = "underline,overline,line-through,blink"))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
/// Specified keyword values for the text-decoration-line property.
|
/// Specified keyword values for the text-decoration-line property.
|
||||||
pub struct TextDecorationLine(u8);
|
pub struct TextDecorationLine(u8);
|
||||||
@@ -290,6 +290,10 @@ bitflags! {
|
|||||||
const LINE_THROUGH = 1 << 2;
|
const LINE_THROUGH = 1 << 2;
|
||||||
/// blink
|
/// blink
|
||||||
const BLINK = 1 << 3;
|
const BLINK = 1 << 3;
|
||||||
|
/// spelling-error
|
||||||
|
const SPELLING_ERROR = 1 << 4;
|
||||||
|
/// grammar-error
|
||||||
|
const GRAMMAR_ERROR = 1 << 5;
|
||||||
/// Only set by presentation attributes
|
/// Only set by presentation attributes
|
||||||
///
|
///
|
||||||
/// Setting this will mean that text-decorations use the color
|
/// Setting this will mean that text-decorations use the color
|
||||||
@@ -298,7 +302,7 @@ bitflags! {
|
|||||||
/// For example, this gives <a href=foo><font color="red">text</font></a>
|
/// For example, this gives <a href=foo><font color="red">text</font></a>
|
||||||
/// a red text decoration
|
/// a red text decoration
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
const COLOR_OVERRIDE = 0x10;
|
const COLOR_OVERRIDE = 1 << 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
[text-decoration-line-computed.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and fission: [TIMEOUT, OK]
|
|
||||||
[Property text-decoration-line value 'spelling-error']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Property text-decoration-line value 'grammar-error']
|
|
||||||
expected: FAIL
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
[text-decoration-line-valid.html]
|
|
||||||
expected:
|
|
||||||
if (os == "android") and fission: [OK, TIMEOUT]
|
|
||||||
[e.style['text-decoration-line'\] = "spelling-error" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[e.style['text-decoration-line'\] = "grammar-error" should set the property value]
|
|
||||||
expected: FAIL
|
|
||||||
Reference in New Issue
Block a user