Commit f9a46fa7 authored by Delan Azabani's avatar Delan Azabani Committed by Chromium LUCI CQ

Implement style support for ::spelling-error + ::grammar-error

This implements the style support only, behind a flag, based on the
::target-text counterpart in <https://crrev.com/c/2463563>.

The paint code for querying these selectors and paint invalidation,
as well as the changes needed to limit the acceptable properties (à
la <https://crrev.com/c/2489657>), will be written in another CL.

Bug: 1035708
Change-Id: I77e530fbbb78fb20c05325ef75babde91e5ef831
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2606878
Auto-Submit: Delan Azabani <dazabani@igalia.com>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Reviewed-by: default avatarManuel Rego <rego@igalia.com>
Commit-Queue: Delan Azabani <dazabani@igalia.com>
Cr-Commit-Position: refs/heads/master@{#841443}
parent cd7b7fd2
...@@ -1815,6 +1815,8 @@ domain DOM ...@@ -1815,6 +1815,8 @@ domain DOM
backdrop backdrop
selection selection
target-text target-text
spelling-error
grammar-error
first-line-inherited first-line-inherited
scrollbar scrollbar
scrollbar-thumb scrollbar-thumb
......
...@@ -245,6 +245,10 @@ PseudoId CSSSelector::GetPseudoId(PseudoType type) { ...@@ -245,6 +245,10 @@ PseudoId CSSSelector::GetPseudoId(PseudoType type) {
return kPseudoIdResizer; return kPseudoIdResizer;
case kPseudoTargetText: case kPseudoTargetText:
return kPseudoIdTargetText; return kPseudoIdTargetText;
case kPseudoSpellingError:
return kPseudoIdSpellingError;
case kPseudoGrammarError:
return kPseudoIdGrammarError;
case kPseudoUnknown: case kPseudoUnknown:
case kPseudoEmpty: case kPseudoEmpty:
case kPseudoFirstChild: case kPseudoFirstChild:
...@@ -411,6 +415,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = { ...@@ -411,6 +415,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
{"focus-within", CSSSelector::kPseudoFocusWithin}, {"focus-within", CSSSelector::kPseudoFocusWithin},
{"fullscreen", CSSSelector::kPseudoFullscreen}, {"fullscreen", CSSSelector::kPseudoFullscreen},
{"future", CSSSelector::kPseudoFutureCue}, {"future", CSSSelector::kPseudoFutureCue},
{"grammar-error", CSSSelector::kPseudoGrammarError},
{"horizontal", CSSSelector::kPseudoHorizontal}, {"horizontal", CSSSelector::kPseudoHorizontal},
{"host", CSSSelector::kPseudoHost}, {"host", CSSSelector::kPseudoHost},
{"hover", CSSSelector::kPseudoHover}, {"hover", CSSSelector::kPseudoHover},
...@@ -440,6 +445,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = { ...@@ -440,6 +445,7 @@ const static NameToPseudoStruct kPseudoTypeWithoutArgumentsMap[] = {
{"scope", CSSSelector::kPseudoScope}, {"scope", CSSSelector::kPseudoScope},
{"selection", CSSSelector::kPseudoSelection}, {"selection", CSSSelector::kPseudoSelection},
{"single-button", CSSSelector::kPseudoSingleButton}, {"single-button", CSSSelector::kPseudoSingleButton},
{"spelling-error", CSSSelector::kPseudoSpellingError},
{"start", CSSSelector::kPseudoStart}, {"start", CSSSelector::kPseudoStart},
{"target", CSSSelector::kPseudoTarget}, {"target", CSSSelector::kPseudoTarget},
{"target-text", CSSSelector::kPseudoTargetText}, {"target-text", CSSSelector::kPseudoTargetText},
...@@ -521,6 +527,12 @@ static CSSSelector::PseudoType NameToPseudoType(const AtomicString& name, ...@@ -521,6 +527,12 @@ static CSSSelector::PseudoType NameToPseudoType(const AtomicString& name,
return CSSSelector::kPseudoUnknown; return CSSSelector::kPseudoUnknown;
} }
if ((match->type == CSSSelector::kPseudoSpellingError ||
match->type == CSSSelector::kPseudoGrammarError) &&
!RuntimeEnabledFeatures::CSSSpellingGrammarErrorsEnabled()) {
return CSSSelector::kPseudoUnknown;
}
return static_cast<CSSSelector::PseudoType>(match->type); return static_cast<CSSSelector::PseudoType>(match->type);
} }
...@@ -630,6 +642,8 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value, ...@@ -630,6 +642,8 @@ void CSSSelector::UpdatePseudoType(const AtomicString& value,
case kPseudoWebKitCustomElement: case kPseudoWebKitCustomElement:
case kPseudoSlotted: case kPseudoSlotted:
case kPseudoTargetText: case kPseudoTargetText:
case kPseudoSpellingError:
case kPseudoGrammarError:
if (match_ != kPseudoElement) if (match_ != kPseudoElement)
pseudo_type_ = kPseudoUnknown; pseudo_type_ = kPseudoUnknown;
break; break;
...@@ -1121,6 +1135,8 @@ bool CSSSelector::IsAllowedAfterPart() const { ...@@ -1121,6 +1135,8 @@ bool CSSSelector::IsAllowedAfterPart() const {
case kPseudoFirstLetter: case kPseudoFirstLetter:
case kPseudoSelection: case kPseudoSelection:
case kPseudoTargetText: case kPseudoTargetText:
case kPseudoSpellingError:
case kPseudoGrammarError:
return true; return true;
default: default:
return false; return false;
......
...@@ -285,6 +285,8 @@ class CORE_EXPORT CSSSelector { ...@@ -285,6 +285,8 @@ class CORE_EXPORT CSSSelector {
kPseudoVideoPersistentAncestor, kPseudoVideoPersistentAncestor,
kPseudoTargetText, kPseudoTargetText,
kPseudoDir, kPseudoDir,
kPseudoSpellingError,
kPseudoGrammarError,
}; };
enum class AttributeMatchType { enum class AttributeMatchType {
......
...@@ -180,6 +180,8 @@ bool SupportsInvalidation(CSSSelector::PseudoType type) { ...@@ -180,6 +180,8 @@ bool SupportsInvalidation(CSSSelector::PseudoType type) {
case CSSSelector::kPseudoIs: case CSSSelector::kPseudoIs:
case CSSSelector::kPseudoWhere: case CSSSelector::kPseudoWhere:
case CSSSelector::kPseudoTargetText: case CSSSelector::kPseudoTargetText:
case CSSSelector::kPseudoSpellingError:
case CSSSelector::kPseudoGrammarError:
return true; return true;
case CSSSelector::kPseudoUnknown: case CSSSelector::kPseudoUnknown:
case CSSSelector::kPseudoLeftPage: case CSSSelector::kPseudoLeftPage:
......
...@@ -180,6 +180,10 @@ protocol::DOM::PseudoType InspectorDOMAgent::ProtocolPseudoElementType( ...@@ -180,6 +180,10 @@ protocol::DOM::PseudoType InspectorDOMAgent::ProtocolPseudoElementType(
return protocol::DOM::PseudoTypeEnum::Selection; return protocol::DOM::PseudoTypeEnum::Selection;
case kPseudoIdTargetText: case kPseudoIdTargetText:
return protocol::DOM::PseudoTypeEnum::TargetText; return protocol::DOM::PseudoTypeEnum::TargetText;
case kPseudoIdSpellingError:
return protocol::DOM::PseudoTypeEnum::SpellingError;
case kPseudoIdGrammarError:
return protocol::DOM::PseudoTypeEnum::GrammarError;
case kPseudoIdFirstLineInherited: case kPseudoIdFirstLineInherited:
return protocol::DOM::PseudoTypeEnum::FirstLineInherited; return protocol::DOM::PseudoTypeEnum::FirstLineInherited;
case kPseudoIdScrollbar: case kPseudoIdScrollbar:
......
...@@ -369,6 +369,8 @@ const char* PseudoTypeToString(CSSSelector::PseudoType pseudo_type) { ...@@ -369,6 +369,8 @@ const char* PseudoTypeToString(CSSSelector::PseudoType pseudo_type) {
DEFINE_STRING_MAPPING(PseudoXrOverlay) DEFINE_STRING_MAPPING(PseudoXrOverlay)
DEFINE_STRING_MAPPING(PseudoTargetText) DEFINE_STRING_MAPPING(PseudoTargetText)
DEFINE_STRING_MAPPING(PseudoModal) DEFINE_STRING_MAPPING(PseudoModal)
DEFINE_STRING_MAPPING(PseudoSpellingError)
DEFINE_STRING_MAPPING(PseudoGrammarError)
#undef DEFINE_STRING_MAPPING #undef DEFINE_STRING_MAPPING
} }
......
...@@ -65,6 +65,8 @@ enum PseudoId : uint8_t { ...@@ -65,6 +65,8 @@ enum PseudoId : uint8_t {
kPseudoIdSelection, kPseudoIdSelection,
kPseudoIdScrollbar, kPseudoIdScrollbar,
kPseudoIdTargetText, kPseudoIdTargetText,
kPseudoIdSpellingError,
kPseudoIdGrammarError,
// Internal IDs follow: // Internal IDs follow:
kPseudoIdFirstLineInherited, kPseudoIdFirstLineInherited,
kPseudoIdScrollbarThumb, kPseudoIdScrollbarThumb,
......
...@@ -228,7 +228,7 @@ ...@@ -228,7 +228,7 @@
{ {
name: "PseudoBits", name: "PseudoBits",
field_template: "primitive", field_template: "primitive",
field_size: 9, field_size: 11,
default_value: "kPseudoIdNone", default_value: "kPseudoIdNone",
type_name: "unsigned", type_name: "unsigned",
custom_copy: true, custom_copy: true,
......
...@@ -155,12 +155,12 @@ TEST(ComputedStyleTest, FirstPublicPseudoStyle) { ...@@ -155,12 +155,12 @@ TEST(ComputedStyleTest, FirstPublicPseudoStyle) {
} }
TEST(ComputedStyleTest, LastPublicPseudoElementStyle) { TEST(ComputedStyleTest, LastPublicPseudoElementStyle) {
static_assert(kFirstInternalPseudoId - 1 == kPseudoIdTargetText, static_assert(kFirstInternalPseudoId - 1 == kPseudoIdGrammarError,
"Make sure we are testing the last public pseudo id"); "Make sure we are testing the last public pseudo id");
scoped_refptr<ComputedStyle> style = ComputedStyle::Create(); scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
style->SetHasPseudoElementStyle(kPseudoIdTargetText); style->SetHasPseudoElementStyle(kPseudoIdGrammarError);
EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdTargetText)); EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdGrammarError));
EXPECT_TRUE(style->HasAnyPseudoElementStyles()); EXPECT_TRUE(style->HasAnyPseudoElementStyles());
} }
......
...@@ -614,6 +614,17 @@ ...@@ -614,6 +614,17 @@
name: "CSSSnapSize", name: "CSSSnapSize",
status: "experimental", status: "experimental",
}, },
{
// Support for CSS ::spelling-error, ::grammar-error, and the
// spelling-error and grammar-error values in text-decoration-line.
//
// https://drafts.csswg.org/css-pseudo-4/#selectordef-spelling-error
// https://drafts.csswg.org/css-pseudo-4/#selectordef-grammar-error
// https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-spelling-error
// https://drafts.csswg.org/css-text-decor-4/#valdef-text-decoration-line-grammar-error
name: "CSSSpellingGrammarErrors",
status: "test",
},
// Make system color keywords compute to themselves. // Make system color keywords compute to themselves.
// https://github.com/w3c/csswg-drafts/issues/3847 // https://github.com/w3c/csswg-drafts/issues/3847
{ {
......
<!doctype html>
<meta charset="utf-8">
<title>CSS Pseudo-Elements Test: highlight selectors getComputedStyle</title>
<link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-selectors">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#target::selection,
#target::target-text,
#target::spelling-error,
#target::grammar-error {
background-color: green;
color: lime;
}
</style>
<div id="target"></div>
<script>
for (const pseudo of ["::selection", "::target-text", "::spelling-error", "::grammar-error"]) {
test(() => {
let style = getComputedStyle(target, pseudo);
assert_equals(style.backgroundColor, "rgb(0, 128, 0)", "Background color is green.");
assert_equals(style.color, "rgb(0, 255, 0)", "Color is lime.");
}, `getComputedStyle() for ${pseudo}`);
}
</script>
<!doctype html>
<meta charset="utf-8">
<title>CSS Pseudo-Elements Test: highlight selectors parsing</title>
<link rel="help" href="https://drafts.csswg.org/css-pseudo/#highlight-selectors">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
<script>
for (const pseudo of ["::selection", "::target-text", "::spelling-error", "::grammar-error"]) {
test_valid_selector(`${pseudo}`);
test_valid_selector(`.a${pseudo}`);
test_valid_selector(`div ${pseudo}`);
test_valid_selector(`::part(my-part)${pseudo}`);
test_invalid_selector(`::before${pseudo}`);
test_invalid_selector(`${pseudo}.a`);
test_invalid_selector(`${pseudo} div`);
test_invalid_selector(`${pseudo}::after`);
test_invalid_selector(`${pseudo}:hover`);
test_invalid_selector(`:not(${pseudo})`);
}
</script>
<!doctype html>
<meta charset="utf-8">
<title>CSS Pseudo-Elements Test: ::target-text parsing</title>
<link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-target-text">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
<script>
test_valid_selector("::target-text");
test_valid_selector(".a::target-text");
test_valid_selector("div ::target-text");
test_valid_selector("::part(my-part)::target-text");
test_invalid_selector("::before::target-text");
test_invalid_selector("::target-text.a");
test_invalid_selector("::target-text div");
test_invalid_selector("::target-text::after");
test_invalid_selector("::target-text:hover");
test_invalid_selector(":not(::target-text)");
</script>
<!doctype html>
<meta charset="utf-8">
<title>CSS Pseudo-Elements Test: ::target-text getComputedStyle</title>
<link rel="help" href="https://drafts.csswg.org/css-pseudo/#selectordef-target-text">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#target::target-text {
background-color: green;
}
#target::target-text {
color: lime;
}
</style>
<div id="target"></div>
<script>
test(() => {
let style = getComputedStyle(target, "::target-text");
assert_equals(style.backgroundColor, "rgb(0, 128, 0)", "Background color is green.");
assert_equals(style.color, "rgb(0, 255, 0)", "Color is lime.");
}, "getComputedStyle() for ::target-text");
</script>
...@@ -39,6 +39,11 @@ element.style { () ...@@ -39,6 +39,11 @@ element.style { ()
[$#inspected:after$] { (<style>) [$#inspected:after$] { (<style>)
content: "AFTER"; content: "AFTER";
======== Pseudo ::grammar-error element ========
[expanded]
#inspected::grammar-error { (<style>)
color: teal;
======== Pseudo ::marker element ======== ======== Pseudo ::marker element ========
[expanded] [expanded]
[$#inspected::marker$] { (<style>) [$#inspected::marker$] { (<style>)
...@@ -53,6 +58,11 @@ element.style { () ...@@ -53,6 +58,11 @@ element.style { ()
text-align: start !important; text-align: start !important;
text-align-last: start !important; text-align-last: start !important;
======== Pseudo ::spelling-error element ========
[expanded]
#inspected::spelling-error { (<style>)
color: orange;
======== Pseudo ::target-text element ======== ======== Pseudo ::target-text element ========
[expanded] [expanded]
#inspected::target-text { (<style>) #inspected::target-text { (<style>)
......
...@@ -12,6 +12,14 @@ ...@@ -12,6 +12,14 @@
color: green; color: green;
} }
#inspected::spelling-error {
color: orange;
}
#inspected::grammar-error {
color: teal;
}
#inspected { #inspected {
display: list-item; display: list-item;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment