Skip to content

Commit 2c13d49

Browse files
stephanieyzhangChromium LUCI CQ
authored andcommitted
Add OpaqueRange disconnect() method
Implement disconnect() per WHATWG DOM spec PR #1404 [0]. Detaches the range from its element, stopping live offset updates and zeroing offsets. Calling it multiple times is safe and has no additional effect. Adds WPT tests covering disconnect behavior. Automatic disconnection when the element is removed from the tree or changes type will be handled in a follow-up CL. [0] whatwg/dom#1404 (comment) Low-Coverage-Reason: COVERAGE_UNDERREPORTED Bug: 421421332 Change-Id: I6f0bb55d57f1eb1876779faad018a19d23b1d665 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7595177 Reviewed-by: Dan Clark <daniec@microsoft.com> Commit-Queue: Stephanie Zhang <stephanie.zhang@microsoft.com> Reviewed-by: Ana Sollano Kim <ansollan@microsoft.com> Reviewed-by: Mason Freed <masonf@chromium.org> Cr-Commit-Position: refs/heads/main@{#1588113}
1 parent cb13bf9 commit 2c13d49

6 files changed

Lines changed: 91 additions & 0 deletions

File tree

android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6919,6 +6919,7 @@ interface OffscreenCanvasRenderingContext2D
69196919
interface OpaqueRange : AbstractRange
69206920
attribute @@toStringTag
69216921
method constructor
6922+
method disconnect
69226923
method getBoundingClientRect
69236924
method getClientRects
69246925
interface Option

third_party/blink/renderer/core/dom/opaque_range.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ void OpaqueRange::UpdateOffsetsForTextChange(unsigned change_offset,
133133
end_offset_in_value_ = new_end;
134134
}
135135

136+
void OpaqueRange::disconnect() {
137+
if (element_) {
138+
element_->UnregisterOpaqueRange(this);
139+
element_ = nullptr;
140+
}
141+
start_offset_in_value_ = 0;
142+
end_offset_in_value_ = 0;
143+
}
144+
136145
DOMRectList* OpaqueRange::getClientRects() const {
137146
Range* range = BuildValueGeometryContext();
138147
if (!range || range->collapsed()) {

third_party/blink/renderer/core/dom/opaque_range.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ class CORE_EXPORT OpaqueRange final : public AbstractRange {
6161
unsigned deleted_count,
6262
unsigned inserted_count);
6363

64+
// Detaches this range from its element, stopping live offset updates.
65+
// After calling disconnect(), startOffset/endOffset return 0 and
66+
// getClientRects()/getBoundingClientRect() return empty results.
67+
void disconnect();
68+
6469
DOMRectList* getClientRects() const;
6570
DOMRect* getBoundingClientRect() const;
6671

third_party/blink/renderer/core/dom/opaque_range.idl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
Exposed=Window,
77
RuntimeEnabled=OpaqueRange
88
] interface OpaqueRange : AbstractRange {
9+
undefined disconnect();
910
DOMRectList getClientRects();
1011
DOMRect getBoundingClientRect();
1112
};
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<!DOCTYPE html>
2+
<script src="/resources/testharness.js"></script>
3+
<script src="/resources/testharnessreport.js"></script>
4+
<body></body>
5+
<script>
6+
test(() => {
7+
document.body.innerHTML = '<textarea>Hello</textarea>';
8+
const textarea = document.body.firstElementChild;
9+
const range = textarea.getValueRange(1, 4);
10+
11+
range.disconnect();
12+
13+
assert_equals(range.startOffset, 0, "startOffset resets to 0");
14+
assert_equals(range.endOffset, 0, "endOffset resets to 0");
15+
assert_true(range.collapsed, "range is collapsed");
16+
assert_equals(range.startContainer, null, "startContainer remains null");
17+
assert_equals(range.endContainer, null, "endContainer remains null");
18+
assert_equals(range.getClientRects().length, 0, "no client rects");
19+
assert_equals(range.getBoundingClientRect().width, 0, "bounding rect width is 0");
20+
assert_equals(range.getBoundingClientRect().height, 0, "bounding rect height is 0");
21+
}, "disconnect() resets range state and geometry.");
22+
23+
test(() => {
24+
document.body.innerHTML = '<textarea>Hello</textarea>';
25+
const textarea = document.body.firstElementChild;
26+
const range = textarea.getValueRange(1, 4);
27+
28+
range.disconnect();
29+
range.disconnect();
30+
31+
assert_equals(range.startOffset, 0);
32+
assert_equals(range.endOffset, 0);
33+
}, "disconnect() is idempotent.");
34+
35+
test(() => {
36+
document.body.innerHTML = '<textarea>Hello</textarea>';
37+
const textarea = document.body.firstElementChild;
38+
const range = textarea.getValueRange(1, 4);
39+
40+
range.disconnect();
41+
textarea.value = "World!";
42+
43+
assert_equals(range.startOffset, 0, "disconnected range ignores value change");
44+
assert_equals(range.endOffset, 0);
45+
}, "disconnect() stops live offset updates.");
46+
47+
test(() => {
48+
document.body.innerHTML = '<textarea>Hello</textarea>';
49+
const textarea = document.body.firstElementChild;
50+
const range1 = textarea.getValueRange(0, 3);
51+
const range2 = textarea.getValueRange(2, 5);
52+
53+
range1.disconnect();
54+
55+
assert_equals(range2.startOffset, 2, "sibling range unaffected by disconnect");
56+
assert_equals(range2.endOffset, 5);
57+
58+
textarea.value = "Modified";
59+
assert_equals(range1.startOffset, 0, "disconnected range stays at 0");
60+
assert_equals(range2.startOffset, 0, "sibling range still receives updates");
61+
}, "disconnect() only affects the target range.");
62+
63+
test(() => {
64+
document.body.innerHTML = '<textarea>Hello</textarea>';
65+
const textarea = document.body.firstElementChild;
66+
const range = textarea.getValueRange(1, 4);
67+
range.disconnect();
68+
69+
const newRange = textarea.getValueRange(0, 5);
70+
assert_equals(newRange.startOffset, 0);
71+
assert_equals(newRange.endOffset, 5);
72+
assert_false(newRange.collapsed);
73+
}, "Element accepts new ranges after a prior range is disconnected.");
74+
</script>

third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7292,6 +7292,7 @@ interface OffscreenCanvasRenderingContext2D
72927292
interface OpaqueRange : AbstractRange
72937293
attribute @@toStringTag
72947294
method constructor
7295+
method disconnect
72957296
method getBoundingClientRect
72967297
method getClientRects
72977298
interface Option

0 commit comments

Comments
 (0)