tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 23243178a3de23a51a8e29d2daeaa741fc02c429
parent c0fd7b0dc9b51afb62e702bd7d721d2428663c66
Author: Mason Freed <masonf@chromium.org>
Date:   Thu,  8 Jan 2026 17:35:14 +0000

Bug 2008832 [wpt PR 57027] - Remove extra parentElement loop for interest invokers, a=testonly

Automatic update from web-platform-tests
Remove extra parentElement loop for interest invokers

The HandleInterestForHoverOrFocus() code already (correctly)
iterates through the flat tree ancestors of the provided node,
so the extra parentElement loop in HandlePointerEventsForInterestFor
was unnecessary. In addition, it missed two cases: SVG <use> and
broken images, due to the shadow DOM and/or parentElement logic.

Fixed: 470478215
Change-Id: I111303c5f29a760b02fc40ed76f8938259e7e9fc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7403039
Auto-Submit: Mason Freed <masonf@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1565249}

--

wpt-commits: 2c8a95ec89583dc745d9d371659c439573a2aa10
wpt-pr: 57027

Diffstat:
Atesting/web-platform/tests/html/semantics/interestfor/interestfor-basic-behavior.tentative.html | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dtesting/web-platform/tests/html/semantics/interestfor/interestfor-input-modalities.tentative.html | 131-------------------------------------------------------------------------------
2 files changed, 147 insertions(+), 131 deletions(-)

diff --git a/testing/web-platform/tests/html/semantics/interestfor/interestfor-basic-behavior.tentative.html b/testing/web-platform/tests/html/semantics/interestfor/interestfor-basic-behavior.tentative.html @@ -0,0 +1,147 @@ +<!DOCTYPE html> +<meta charset="utf-8" /> +<meta name="timeout" content="long"> +<link rel="author" href="mailto:masonf@chromium.org"> +<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" /> +<link rel="help" href="https://github.com/whatwg/html/pull/11006" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/invoker-utils.js"></script> + +<meta name=variant content=?method=hover> +<meta name=variant content=?method=focus> + +<button data-testcase="<button>" interestfor=target>Button</button> + +<a data-testcase="<a>" href="#" interestfor=target>Link</a> + +<img src="/images/blue.png" usemap="#map" id=areatarget> +<map id=map> + <area data-testcase="<area>" data-hover="areatarget" interestfor=target href="/" shape=default> +</map> + +<svg viewBox="0 0 100 100" style="width: 100px" xmlns="http://www.w3.org/2000/svg"> + <a data-testcase="SVG <a>" href="#" interestfor=target> + <text x=50 y=90>SVG A</text> + </a> +</svg> + +<a data-testcase="Broken img" href="#" interestfor=target> + <img src="broken" width="50" height="50"> +</a> + +<a data-testcase="SVG <use>" href="#" interestfor=target> + <svg width="50" height="50" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> + <use xlink:href="#thick-star"></use> + </svg> +</a> +<svg style="display: none;"> + <symbol id="thick-star" viewBox="0 0 24 24"> + <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" + fill="yellow" stroke="black" stroke-width="2" stroke-linejoin="round"/> + </symbol> +</svg> + +<div id=target>Target</div> +<button id=otherbutton>Other button</button> + +<style> + [interestfor] { + interest-delay: 0s; + } +</style> + +<script> +const allInterestForElements = document.querySelectorAll('[data-testcase]'); +assert_true(allInterestForElements.length > 0); +function verifyInterest(onlyElements,description) { + if (!(onlyElements instanceof Array)) { + onlyElements = [onlyElements]; + } + [...allInterestForElements, another].forEach(el => { + const expectInterest = onlyElements.includes(el); + assert_equals(el.matches(':interest-source'),expectInterest,`${description}, element ${el.dataset.testcase} should ${expectInterest ? "" : "NOT "}have interest`); + }) +} +function reinsert(element) { + const parent = element.parentElement; + const nextSibling = element.nextSibling; + element.remove(); + parent.insertBefore(element,nextSibling); +} +function preventEvent(shouldCancel,el,type) { + if (shouldCancel) { + assert_not_equals(type,'focusin','focusin can\'t be cancelled'); + assert_not_equals(type,'focusout','focusout can\'t be cancelled'); + el.addEventListener(type, (e) => e.preventDefault(), {once:true}); + } +} + +const urlParams = new URLSearchParams(window.location.search); +method = urlParams.get('method'); +['none','cancel-trigger','cancel-lose'].forEach(cancelEvent => { + allInterestForElements.forEach(el => { + const description = `${el.dataset.testcase}, ${cancelEvent}, ${method}`; + promise_test(async function (t) { + t.add_cleanup(() => { + reinsert(el); + reinsert(target); + }); + assert_false(el.matches(':interest-source'),'setup'); + assert_false(target.matches(':interest-target'),'setup'); + const signal = t.get_signal(); + let interestCount = 0; + let loseInterestCount = 0; + target.addEventListener('interest', (e) => (++interestCount), {signal}); + target.addEventListener('loseinterest', () => (++loseInterestCount), {signal}); + const cancelTrigger = cancelEvent === 'cancel-trigger'; + const cancelLose = cancelEvent === 'cancel-lose'; + assert_true(cancelTrigger || cancelLose || cancelEvent === 'none'); + + switch (method) { + case 'hover': + preventEvent(cancelTrigger,el,'mouseover'); + hovertarget = el; + if (el.dataset.hover) { + hovertarget = document.getElementById(el.dataset.hover); + } + await hoverOver(hovertarget) + break; + case 'focus': + if (cancelTrigger) { + return; // focusin cannot be cancelled, nothing to test + } + await focusOn(el); + break; + default: + assert_unreached(); + } + assert_equals(loseInterestCount, 0, 'Lose interest should not be fired yet'); + assert_equals(interestCount, 1, 'Interest should be fired (cancelling the trigger event shouldn\'t cancel interest)'); + assert_true(el.matches(':interest-source'),':interest-source should match'); + interestCount = 0; + + switch (method) { + case 'hover': + preventEvent(cancelLose,el,'mouseout'); + await hoverOver(otherbutton); + break; + case 'focus': + if (cancelLose) { + return; // focusout cannot be cancelled, nothing to test + } + await focusOn(otherbutton); + break; + default: + assert_unreached(); + } + assert_equals(interestCount, 0, 'No new interest event should be fired'); + assert_equals(loseInterestCount, 1, 'Lose interest event should be fired (cancelling the trigger event shouldn\'t cancel loseinterest)' ); + assert_false(el.matches(':interest-source'),':interest-source should not match'); + },`Basic behavior, ${description}`); + }); +}); +</script> diff --git a/testing/web-platform/tests/html/semantics/interestfor/interestfor-input-modalities.tentative.html b/testing/web-platform/tests/html/semantics/interestfor/interestfor-input-modalities.tentative.html @@ -1,131 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8" /> -<meta name="timeout" content="long"> -<link rel="author" href="mailto:masonf@chromium.org"> -<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" /> -<link rel="help" href="https://github.com/whatwg/html/pull/11006" /> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="/resources/testdriver.js"></script> -<script src="/resources/testdriver-actions.js"></script> -<script src="/resources/testdriver-vendor.js"></script> -<script src="resources/invoker-utils.js"></script> - -<meta name=variant content=?method=hover> -<meta name=variant content=?method=focus> - -<button data-testcase="<button>" interestfor=target>Button</button> - -<a data-testcase="<a>" href=foo interestfor=target>Link</a> - -<img src="/images/blue.png" usemap="#map" id=areatarget> -<map id=map> - <area data-testcase="<area>" data-hover="areatarget" interestfor=target href="/" shape=default> -</map> - -<svg viewBox="0 0 100 100" style="width: 100px" xmlns="http://www.w3.org/2000/svg"> - <a data-testcase="SVG <a>" href=foo interestfor=target> - <text x=50 y=90>SVG A</text> - </a> -</svg> - -<div id=target>Target</div> -<button id=otherbutton>Other button</button> - -<style> - [interestfor] { - interest-delay: 0s; - } -</style> - -<script> -const allInterestForElements = document.querySelectorAll('[data-testcase]'); -assert_true(allInterestForElements.length > 0); -function verifyInterest(onlyElements,description) { - if (!(onlyElements instanceof Array)) { - onlyElements = [onlyElements]; - } - [...allInterestForElements, another].forEach(el => { - const expectInterest = onlyElements.includes(el); - assert_equals(el.matches(':interest-source'),expectInterest,`${description}, element ${el.dataset.testcase} should ${expectInterest ? "" : "NOT "}have interest`); - }) -} -function reinsert(element) { - const parent = element.parentElement; - const nextSibling = element.nextSibling; - element.remove(); - parent.insertBefore(element,nextSibling); -} -function preventEvent(shouldCancel,el,type) { - if (shouldCancel) { - assert_not_equals(type,'focusin','focusin can\'t be cancelled'); - assert_not_equals(type,'focusout','focusout can\'t be cancelled'); - el.addEventListener(type, (e) => e.preventDefault(), {once:true}); - } -} - -const urlParams = new URLSearchParams(window.location.search); -method = urlParams.get('method'); -['none','cancel-trigger','cancel-lose'].forEach(cancelEvent => { - allInterestForElements.forEach(el => { - const description = `${el.dataset.testcase}, ${cancelEvent}, ${method}`; - promise_test(async function (t) { - t.add_cleanup(() => { - reinsert(el); - reinsert(target); - }); - assert_false(el.matches(':interest-source'),'setup'); - assert_false(target.matches(':interest-target'),'setup'); - const signal = t.get_signal(); - let interestCount = 0; - let loseInterestCount = 0; - target.addEventListener('interest', (e) => (++interestCount), {signal}); - target.addEventListener('loseinterest', () => (++loseInterestCount), {signal}); - const cancelTrigger = cancelEvent === 'cancel-trigger'; - const cancelLose = cancelEvent === 'cancel-lose'; - assert_true(cancelTrigger || cancelLose || cancelEvent === 'none'); - - switch (method) { - case 'hover': - preventEvent(cancelTrigger,el,'mouseover'); - hovertarget = el; - if (el.dataset.hover) { - hovertarget = document.getElementById(el.dataset.hover); - } - await hoverOver(hovertarget) - break; - case 'focus': - if (cancelTrigger) { - return; // focusin cannot be cancelled, nothing to test - } - await focusOn(el); - break; - default: - assert_unreached(); - } - assert_equals(loseInterestCount, 0, 'Lose interest should not be fired yet'); - assert_equals(interestCount, 1, 'Interest should be fired (cancelling the trigger event shouldn\'t cancel interest)'); - assert_true(el.matches(':interest-source'),':interest-source should match'); - interestCount = 0; - - switch (method) { - case 'hover': - preventEvent(cancelLose,el,'mouseout'); - await hoverOver(otherbutton); - break; - case 'focus': - if (cancelLose) { - return; // focusout cannot be cancelled, nothing to test - } - await focusOn(otherbutton); - break; - default: - assert_unreached(); - } - assert_equals(interestCount, 0, 'No new interest event should be fired'); - assert_equals(loseInterestCount, 1, 'Lose interest event should be fired (cancelling the trigger event shouldn\'t cancel loseinterest)' ); - assert_false(el.matches(':interest-source'),':interest-source should not match'); - },`Basic behavior, ${description}`); - }); -}); -</script>