Bug 1669996 - Do not expose chromeonly nodes via Selection API r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D93258
This commit is contained in:
Kagami Sascha Rosylight 2020-10-15 20:49:47 +00:00
Родитель a22b90ec8c
Коммит 5a12264fb1
4 изменённых файлов: 66 добавлений и 7 удалений

Просмотреть файл

@ -248,22 +248,42 @@ class Selection final : public nsSupportsWeakReference,
JS::Handle<JSObject*> aGivenProto) override;
// WebIDL methods
nsINode* GetAnchorNode() const {
nsINode* GetAnchorNode(CallerType aCallerType = CallerType::System) const {
const RangeBoundary& anchor = AnchorRef();
return anchor.IsSet() ? anchor.Container() : nullptr;
nsINode* anchorNode = anchor.IsSet() ? anchor.Container() : nullptr;
if (!anchorNode || aCallerType == CallerType::System ||
!anchorNode->ChromeOnlyAccess()) {
return anchorNode;
}
// anchor is nsIContent as ChromeOnlyAccess is nsIContent-only
return anchorNode->AsContent()->FindFirstNonChromeOnlyAccessContent();
}
uint32_t AnchorOffset() const {
uint32_t AnchorOffset(CallerType aCallerType = CallerType::System) const {
const RangeBoundary& anchor = AnchorRef();
if (aCallerType != CallerType::System && anchor.IsSet() &&
anchor.Container()->ChromeOnlyAccess()) {
return 0;
}
const Maybe<uint32_t> offset =
anchor.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
return offset ? *offset : 0;
}
nsINode* GetFocusNode() const {
nsINode* GetFocusNode(CallerType aCallerType = CallerType::System) const {
const RangeBoundary& focus = FocusRef();
return focus.IsSet() ? focus.Container() : nullptr;
nsINode* focusNode = focus.IsSet() ? focus.Container() : nullptr;
if (!focusNode || aCallerType == CallerType::System ||
!focusNode->ChromeOnlyAccess()) {
return focusNode;
}
// focus is nsIContent as ChromeOnlyAccess is nsIContent-only
return focusNode->AsContent()->FindFirstNonChromeOnlyAccessContent();
}
uint32_t FocusOffset() const {
uint32_t FocusOffset(CallerType aCallerType = CallerType::System) const {
const RangeBoundary& focus = FocusRef();
if (aCallerType != CallerType::System && focus.IsSet() &&
focus.Container()->ChromeOnlyAccess()) {
return 0;
}
const Maybe<uint32_t> offset =
focus.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
return offset ? *offset : 0;

Просмотреть файл

@ -1363,6 +1363,7 @@ class nsINode : public mozilla::dom::EventTarget {
bool HasBeenInUAWidget() const { return HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET); }
// True for native anonymous content and for content in UA widgets.
// Only nsIContent can fulfill this condition.
bool ChromeOnlyAccess() const {
return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
NODE_HAS_BEEN_IN_UA_WIDGET);

Просмотреть файл

@ -12,9 +12,13 @@
[Exposed=Window]
interface Selection {
[NeedsCallerType]
readonly attribute Node? anchorNode;
[NeedsCallerType]
readonly attribute unsigned long anchorOffset;
[NeedsCallerType]
readonly attribute Node? focusNode;
[NeedsCallerType]
readonly attribute unsigned long focusOffset;
readonly attribute boolean isCollapsed;
/**
@ -102,7 +106,7 @@ partial interface Selection {
/**
* Return array of ranges intersecting with the given DOM interval.
*/
*/
[ChromeOnly,Throws,Pref="dom.testing.selection.GetRangesForInterval"]
sequence<Range> GetRangesForInterval(Node beginNode, long beginOffset, Node endNode, long endOffset,
boolean allowAdjacent);

Просмотреть файл

@ -0,0 +1,34 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Selecting internal node</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<link rel="stylesheet" href="/fonts/ahem.css">
<style>
details {
font: 16px/1 Ahem;
}
</style>
<details id="details"></details>
<script>
promise_test(async () => {
await new test_driver.Actions()
.pointerMove(5, 5, {origin: details})
.pointerDown()
.pointerMove(50, 50)
.pointerUp()
.send();
const selection = getSelection();
// Gecko throws when accessing any property from DOM-invisible node
// so check we can access something
assert_equals(selection.anchorNode.constructor.name, "HTMLDetailsElement");
assert_equals(selection.anchorOffset, 0);
// Gecko limits the selection inside <details> while Blink does not
// so check something general
assert_equals(selection.focusNode.nodeType, Node.ELEMENT_NODE);
assert_equals(selection.focusOffset, 0);
}, "Selecting the default summary of <details> should report a DOM-visible ancestor");
</script>