Bug 1868316 - Prototype a user-find css property to control findability of text. r=jfkthame

Nightly-only for now waiting on CSSWG discussion.

Differential Revision: https://phabricator.services.mozilla.com/D199727
This commit is contained in:
Emilio Cobos Álvarez 2024-02-02 09:45:45 +00:00
parent 3bc607893d
commit b59c93386c
16 changed files with 208 additions and 8 deletions

View file

@ -192,6 +192,12 @@ let runTests = t.step_func_done(function() {
`, "ZWSP should be ignored");
testFindable(2, " ", "a b c", "Collapsed whitespace");
// TODO(emilio): This might be worth discussing in the spec. For now
// hard-coding our implementation.
testFindable(false, "find me", `
Do you find <span style="user-find: none">not findable</span> me?
`, "boundary-crossing user-find: none");
});
window.onload = function() {

View file

@ -131,7 +131,7 @@ use.counter.error:
send_in_pings:
- use-counters
# Total of 2309 use counter metrics (excludes denominators).
# Total of 2311 use counter metrics (excludes denominators).
# Total of 358 'page' use counters.
use.counter.page:
svgsvgelement_getelementbyid:
@ -15735,7 +15735,7 @@ use.counter.deprecated_ops.doc:
send_in_pings:
- use-counters
# Total of 696 'CSS (page)' use counters.
# Total of 697 'CSS (page)' use counters.
use.counter.css.page:
css_align_content:
type: counter
@ -17794,6 +17794,23 @@ use.counter.css.page:
send_in_pings:
- use-counters
css_user_find:
type: counter
description: >
Whether a page used the CSS property user-find.
Compare against `use.counter.top_level_content_documents_destroyed`
to calculate the rate.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
notification_emails:
- dom-core@mozilla.com
- emilio@mozilla.com
expires: never
send_in_pings:
- use-counters
css_user_select:
type: counter
description: >
@ -27569,7 +27586,7 @@ use.counter.css.page:
send_in_pings:
- use-counters
# Total of 696 'CSS (document)' use counters.
# Total of 697 'CSS (document)' use counters.
use.counter.css.doc:
css_align_content:
type: counter
@ -29628,6 +29645,23 @@ use.counter.css.doc:
send_in_pings:
- use-counters
css_user_find:
type: counter
description: >
Whether a document used the CSS property user-find.
Compare against `use.counter.content_documents_destroyed`
to calculate the rate.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1852098
notification_emails:
- dom-core@mozilla.com
- emilio@mozilla.com
expires: never
send_in_pings:
- use-counters
css_user_select:
type: counter
description: >

View file

@ -105,6 +105,7 @@ rusty-enums = [
"mozilla::StyleInert",
"mozilla::StyleUserModify",
"mozilla::StyleUserInput",
"mozilla::StyleUserFind",
"mozilla::StyleBoxDirection",
"mozilla::StyleRubyAlign",
"mozilla::StyleTextSecurity",

View file

@ -153,6 +153,12 @@ enum class StyleUserInput : uint8_t {
Auto,
};
// user-find
enum class StyleUserFind : uint8_t {
Auto,
None,
};
// user-modify
enum class StyleUserModify : uint8_t {
ReadOnly,

View file

@ -2969,6 +2969,7 @@ nsStyleUI::nsStyleUI()
: mInert(StyleInert::None),
mMozTheme(StyleMozTheme::Auto),
mUserInput(StyleUserInput::Auto),
mUserFind(StyleUserFind::Auto),
mUserModify(StyleUserModify::ReadOnly),
mUserFocus(StyleUserFocus::Normal),
mPointerEvents(StylePointerEvents::Auto),
@ -2984,6 +2985,7 @@ nsStyleUI::nsStyleUI(const nsStyleUI& aSource)
: mInert(aSource.mInert),
mMozTheme(aSource.mMozTheme),
mUserInput(aSource.mUserInput),
mUserFind(aSource.mUserFind),
mUserModify(aSource.mUserModify),
mUserFocus(aSource.mUserFocus),
mPointerEvents(aSource.mPointerEvents),
@ -3041,7 +3043,8 @@ nsChangeHint nsStyleUI::CalcDifference(const nsStyleUI& aNewData) const {
hint |= NS_STYLE_HINT_VISUAL | kPointerEventsHint;
}
if (mUserFocus != aNewData.mUserFocus || mUserInput != aNewData.mUserInput) {
if (mUserFocus != aNewData.mUserFocus || mUserInput != aNewData.mUserInput ||
mUserFind != aNewData.mUserFind) {
hint |= nsChangeHint_NeutralChange;
}

View file

@ -1734,6 +1734,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI {
private:
mozilla::StyleUserInput mUserInput;
mozilla::StyleUserFind mUserFind;
mozilla::StyleUserModify mUserModify;
mozilla::StyleUserFocus mUserFocus;
mozilla::StylePointerEvents mPointerEvents;
@ -1746,6 +1747,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI {
return IsInert() ? mozilla::StyleUserInput::None : mUserInput;
}
mozilla::StyleUserFind UserFind() const { return mUserFind; }
mozilla::StyleUserModify UserModify() const {
return IsInert() ? mozilla::StyleUserModify::ReadOnly : mUserModify;
}

View file

@ -19,6 +19,7 @@ prefs = [
"layout.css.basic-shape-rect.enabled=true",
"layout.css.basic-shape-xywh.enabled=true",
"layout.css.transform-box-content-stroke.enabled=true",
"layout.css.user-find.enabled=true",
]
support-files = [
"animation_utils.js",

View file

@ -3928,6 +3928,14 @@ var gCSSProperties = {
alias_for: "user-select",
subproperties: ["user-select"],
},
"user-find": {
domProp: "userFind",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: ["auto"],
other_values: ["none"],
invalid_values: [],
},
"user-select": {
domProp: "userSelect",
inherited: false,

View file

@ -8793,6 +8793,13 @@
mirror: always
rust: true
# Whether user-find CSS property is enabled.
- name: layout.css.user-find.enabled
type: RelaxedAtomicBool
value: @IS_NIGHTLY_BUILD@
mirror: always
rust: true
# Should the :visited selector ever match (otherwise :link matches instead)?
- name: layout.css.visited_links_enabled
type: bool

View file

@ -78,6 +78,19 @@ ${helpers.single_keyword(
affects="",
)}
${helpers.single_keyword(
"user-find",
"auto none",
engines="gecko",
gecko_ffi_name="mUserFind",
gecko_enum_prefix="StyleUserFind",
animation_value_type="discrete",
gecko_pref="layout.css.user-find.enabled",
spec="Prototype of solution proposed in https://github.com/w3c/csswg-drafts/issues/3460",
has_effect_on_gecko_scrollbars=False,
affects="",
)}
${helpers.predefined_type(
"caret-color",
"color::CaretColor",

View file

@ -37,6 +37,9 @@ assert_not_inherited('appearance', 'none', 'auto');
assert_inherited('caret-color', currentColor, 'rgba(42, 53, 64, 0.75)');
assert_inherited('caret-shape', 'auto', 'bar');
assert_inherited('cursor', 'auto', 'pointer');
if (CSS.supports('user-find', 'auto')) {
assert_inherited('user-find', 'auto', 'none');
}
assert_not_inherited('nav-down', 'auto', '#foo');
assert_not_inherited('nav-left', 'auto', '#foo');
assert_not_inherited('nav-right', 'auto', '#foo');

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS UI Level 4: getComputedStyle().userFind</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3460">
<meta name="assert" content="user-find computed value is as specified.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/computed-testcommon.js"></script>
</head>
<body>
<div id="target"></div>
<script>
test_computed_value("user-find", "auto");
test_computed_value("user-find", "none");
</script>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS UI Level 4: parsing user-find with invalid values</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3460">
<meta name="assert" content="user-find supports only the grammar 'auto | none'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("user-find", "visible");
test_invalid_value("user-find", "never");
test_invalid_value("user-find", "10px");
test_invalid_value("user-find", "'none'");
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS UI Level 4: parsing user-find with valid values</title>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3460">
<meta name="assert" content="user-find supports the grammar 'auto | none'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("user-find", "auto");
test_valid_value("user-find", "none");
</script>
</body>
</html>

View file

@ -0,0 +1,57 @@
<!doctype html>
<meta charset="utf-8">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3460">
<title>Basic test for the user-find property</title>
<body>
<script>
const t = async_test("Basic test for the user-find property");
function testFindable(findCount, textToFind, buildDoc, description) {
if (typeof findCount == "boolean")
findCount = findCount ? 1 : 0;
try {
const iframe = document.querySelector("iframe")
iframe.contentDocument.documentElement.innerHTML =
(typeof buildDoc == "string") ? buildDoc : "";
if (typeof buildDoc == "function")
buildDoc(iframe.contentDocument);
iframe.contentWindow.getSelection().removeAllRanges();
for (let i = findCount; i >= 0; --i) {
const expectFindable = i != 0;
assert_equals(
iframe.contentWindow.find(textToFind),
expectFindable,
"Should be " + (expectFindable ? "" : "not ") + "findable: " + description + ", text: " + textToFind + ", iter: " + (findCount - i + 1)
);
}
} catch (ex) {
assert_unreached(ex);
}
}
let runTests = t.step_func_done(function() {
testFindable(true, "me", `
Find me please
`, "sanity test");
testFindable(false, "me", `
<div style="user-find: none">Do not find me please</div>
`, "Basic use case");
testFindable(true, "me", `
<div style="user-find: none">Do not find me, but <span style="user-find: auto">find me please</span></div>
`, "nested");
});
window.onload = function() {
let iframe = document.createElement("iframe");
iframe.onload = runTests;
iframe.srcdoc = "<!doctype html><html></html>";
document.body.appendChild(iframe);
};
</script>
</body>

View file

@ -140,7 +140,7 @@ static bool IsRubyAnnotationNode(const nsINode* aNode) {
StyleDisplay::RubyTextContainer == display;
}
static bool IsVisibleNode(const nsINode* aNode) {
static bool IsFindableNode(const nsINode* aNode) {
if (!IsDisplayedNode(aNode)) {
return false;
}
@ -151,7 +151,8 @@ static bool IsVisibleNode(const nsINode* aNode) {
return true;
}
if (frame->HidesContent(nsIFrame::IncludeContentVisibility::Hidden) ||
if (frame->StyleUI()->UserFind() == StyleUserFind::None ||
frame->HidesContent(nsIFrame::IncludeContentVisibility::Hidden) ||
frame->IsHiddenByContentVisibilityOnAnyAncestor(
nsIFrame::IncludeContentVisibility::Hidden)) {
return false;
@ -953,8 +954,8 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange,
}
RefPtr<nsRange> range = nsRange::Create(current);
if (startParent && endParent && IsVisibleNode(startParent) &&
IsVisibleNode(endParent)) {
if (startParent && endParent && IsFindableNode(startParent) &&
IsFindableNode(endParent)) {
IgnoredErrorResult rv;
range->SetStart(*startParent, matchStartOffset, rv);
if (!rv.Failed()) {