diff options
author | cathiechen <cathiechen@igalia.com> | 2024-03-22 16:02:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-22 15:02:01 +0000 |
commit | cb275e086c215b6da741c7918cd9683a134eb24f (patch) | |
tree | 173f32008068d06f27b3d1a8af1a855dfa6174da /components/script | |
parent | bae77671f85481503ab563c20ed488cf883436fa (diff) | |
download | servo-cb275e086c215b6da741c7918cd9683a134eb24f.tar.gz servo-cb275e086c215b6da741c7918cd9683a134eb24f.zip |
Implement StaticRange (#31809)
* Add DOM interface for AbstractRange
* Add DOM interface for StaticRange
* Update WPT tests for StaticRange-constructor.html
* Fix formatting
* Add AbstractRange & StaticRange in interfaces.html
* rebased the code and fixed the failures
Signed-off-by: Cathie Chen <cathiechen@igalia.com>
* update the expected result in idlharness.window.js.ini file
* Addressed the code review comments
* updae the test result of legacy layout
---------
Signed-off-by: Cathie Chen <cathiechen@igalia.com>
Co-authored-by: Nipun Garg <nipung271@gmail.com>
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/abstractrange.rs | 177 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/Bindings.conf | 8 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/range.rs | 430 | ||||
-rw-r--r-- | components/script/dom/selection.rs | 42 | ||||
-rw-r--r-- | components/script/dom/staticrange.rs | 88 | ||||
-rw-r--r-- | components/script/dom/webidls/AbstractRange.webidl | 21 | ||||
-rw-r--r-- | components/script/dom/webidls/Range.webidl | 12 | ||||
-rw-r--r-- | components/script/dom/webidls/StaticRange.webidl | 19 |
9 files changed, 519 insertions, 280 deletions
diff --git a/components/script/dom/abstractrange.rs b/components/script/dom/abstractrange.rs new file mode 100644 index 00000000000..a39b67b1807 --- /dev/null +++ b/components/script/dom/abstractrange.rs @@ -0,0 +1,177 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::cell::Cell; +use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; + +use deny_public_fields::DenyPublicFields; +use dom_struct::dom_struct; + +use crate::dom::bindings::codegen::Bindings::AbstractRangeBinding::AbstractRangeMethods; +use crate::dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods}; +use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; +use crate::dom::bindings::root::{DomRoot, MutDom}; +use crate::dom::document::Document; +use crate::dom::node::{Node, ShadowIncluding}; + +#[dom_struct] +pub struct AbstractRange { + reflector_: Reflector, + start: BoundaryPoint, + end: BoundaryPoint, +} + +impl AbstractRange { + pub fn new_inherited( + start_container: &Node, + start_offset: u32, + end_container: &Node, + end_offset: u32, + ) -> AbstractRange { + AbstractRange { + reflector_: Reflector::new(), + start: BoundaryPoint::new(start_container, start_offset), + end: BoundaryPoint::new(end_container, end_offset), + } + } + + pub fn new( + document: &Document, + start_container: &Node, + start_offset: u32, + end_container: &Node, + end_offset: u32, + ) -> DomRoot<AbstractRange> { + let abstractrange = reflect_dom_object( + Box::new(AbstractRange::new_inherited( + start_container, + start_offset, + end_container, + end_offset, + )), + document.window(), + ); + abstractrange + } + + pub fn start(&self) -> &BoundaryPoint { + &self.start + } + + pub fn end(&self) -> &BoundaryPoint { + &self.end + } +} + +impl AbstractRangeMethods for AbstractRange { + /// <https://dom.spec.whatwg.org/#dom-range-startcontainer> + fn StartContainer(&self) -> DomRoot<Node> { + self.start.node.get() + } + + /// <https://dom.spec.whatwg.org/#dom-range-startoffset> + fn StartOffset(&self) -> u32 { + self.start.offset.get() + } + + /// <https://dom.spec.whatwg.org/#dom-range-endcontainer> + fn EndContainer(&self) -> DomRoot<Node> { + self.end.node.get() + } + + /// <https://dom.spec.whatwg.org/#dom-range-endoffset> + fn EndOffset(&self) -> u32 { + self.end.offset.get() + } + + /// <https://dom.spec.whatwg.org/#dom-range-collapsed> + fn Collapsed(&self) -> bool { + self.start == self.end + } +} + +#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)] +#[crown::unrooted_must_root_lint::must_root] +pub struct BoundaryPoint { + node: MutDom<Node>, + offset: Cell<u32>, +} + +impl BoundaryPoint { + fn new(node: &Node, offset: u32) -> BoundaryPoint { + debug_assert!(!node.is_doctype()); + BoundaryPoint { + node: MutDom::new(node), + offset: Cell::new(offset), + } + } + + pub fn set(&self, node: &Node, offset: u32) { + self.node.set(node); + self.set_offset(offset); + } + + pub fn set_offset(&self, offset: u32) { + self.offset.set(offset); + } + + pub fn node(&self) -> &MutDom<Node> { + &self.node + } +} + +#[allow(crown::unrooted_must_root)] +impl PartialOrd for BoundaryPoint { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + bp_position( + &self.node.get(), + self.offset.get(), + &other.node.get(), + other.offset.get(), + ) + } +} + +#[allow(crown::unrooted_must_root)] +impl PartialEq for BoundaryPoint { + fn eq(&self, other: &Self) -> bool { + self.node.get() == other.node.get() && self.offset.get() == other.offset.get() + } +} + +/// <https://dom.spec.whatwg.org/#concept-range-bp-position> +pub fn bp_position(a_node: &Node, a_offset: u32, b_node: &Node, b_offset: u32) -> Option<Ordering> { + if a_node as *const Node == b_node as *const Node { + // Step 1. + return Some(a_offset.cmp(&b_offset)); + } + let position = b_node.CompareDocumentPosition(a_node); + if position & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 { + // No order is defined for nodes not in the same tree. + None + } else if position & NodeConstants::DOCUMENT_POSITION_FOLLOWING != 0 { + // Step 2. + match bp_position(b_node, b_offset, a_node, a_offset).unwrap() { + Ordering::Less => Some(Ordering::Greater), + Ordering::Greater => Some(Ordering::Less), + Ordering::Equal => unreachable!(), + } + } else if position & NodeConstants::DOCUMENT_POSITION_CONTAINS != 0 { + // Step 3-1, 3-2. + let mut b_ancestors = b_node.inclusive_ancestors(ShadowIncluding::No); + let child = b_ancestors + .find(|child| &*child.GetParentNode().unwrap() == a_node) + .unwrap(); + // Step 3-3. + if child.index() < a_offset { + Some(Ordering::Greater) + } else { + // Step 4. + Some(Ordering::Less) + } + } else { + // Step 4. + Some(Ordering::Less) + } +} diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 4f8986dea48..b4c5c96b8ff 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -30,6 +30,14 @@ DOMInterfaces = { 'spiderMonkeyInterface': True, }, +'AbstractRange': { + 'weakReferenceable': True, +}, + +'StaticRange': { + 'weakReferenceable': True, +}, + 'Range': { 'weakReferenceable': True, }, diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 2b1e72d0bb7..4df2c0188e6 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -209,6 +209,7 @@ pub mod types { include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs")); } +pub mod abstractrange; pub mod abstractworker; pub mod abstractworkerglobalscope; pub mod activation; @@ -524,6 +525,7 @@ pub mod serviceworkerglobalscope; pub mod serviceworkerregistration; pub mod servoparser; pub mod shadowroot; +pub mod staticrange; pub mod stereopannernode; pub mod storage; pub mod storageevent; diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 227a346ffbd..09f0d8454d0 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -2,26 +2,27 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use std::cell::{Cell, UnsafeCell}; -use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; +use std::cell::UnsafeCell; +use std::cmp::{Ordering, PartialOrd}; -use deny_public_fields::DenyPublicFields; use dom_struct::dom_struct; use js::jsapi::JSTracer; use js::rust::HandleObject; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use crate::dom::abstractrange::{bp_position, AbstractRange, BoundaryPoint}; use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::AbstractRangeBinding::AbstractRangeMethods; use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods; -use crate::dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods}; +use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use crate::dom::bindings::codegen::Bindings::RangeBinding::{RangeConstants, RangeMethods}; use crate::dom::bindings::codegen::Bindings::TextBinding::TextMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::{Castable, CharacterDataTypeId, NodeTypeId}; -use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector}; -use crate::dom::bindings::root::{Dom, DomRoot, MutDom}; +use crate::dom::bindings::reflector::reflect_dom_object_with_proto; +use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::bindings::trace::JSTraceable; use crate::dom::bindings::weakref::{WeakRef, WeakRefVec}; @@ -37,9 +38,7 @@ use crate::dom::window::Window; #[dom_struct] pub struct Range { - reflector_: Reflector, - start: BoundaryPoint, - end: BoundaryPoint, + abstract_range: AbstractRange, // A range that belongs to a Selection needs to know about it // so selectionchange can fire when the range changes. // A range shouldn't belong to more than one Selection at a time, @@ -59,10 +58,15 @@ impl Range { end_container: &Node, end_offset: u32, ) -> Range { + debug_assert!(start_offset <= start_container.len()); + debug_assert!(end_offset <= end_container.len()); Range { - reflector_: Reflector::new(), - start: BoundaryPoint::new(start_container, start_offset), - end: BoundaryPoint::new(end_container, end_offset), + abstract_range: AbstractRange::new_inherited( + start_container, + start_offset, + end_container, + end_offset, + ), associated_selections: DomRefCell::new(vec![]), } } @@ -114,35 +118,35 @@ impl Range { range } - // https://dom.spec.whatwg.org/#dom-range + /// <https://dom.spec.whatwg.org/#dom-range> #[allow(non_snake_case)] pub fn Constructor(window: &Window, proto: Option<HandleObject>) -> Fallible<DomRoot<Range>> { let document = window.Document(); Ok(Range::new_with_doc(&document, proto)) } - // https://dom.spec.whatwg.org/#contained + /// <https://dom.spec.whatwg.org/#contained> fn contains(&self, node: &Node) -> bool { match ( - bp_position(node, 0, &self.StartContainer(), self.StartOffset()), - bp_position(node, node.len(), &self.EndContainer(), self.EndOffset()), + bp_position(node, 0, &self.start_container(), self.start_offset()), + bp_position(node, node.len(), &self.end_container(), self.end_offset()), ) { (Some(Ordering::Greater), Some(Ordering::Less)) => true, _ => false, } } - // https://dom.spec.whatwg.org/#partially-contained + /// <https://dom.spec.whatwg.org/#partially-contained> fn partially_contains(&self, node: &Node) -> bool { - self.StartContainer() + self.start_container() .inclusive_ancestors(ShadowIncluding::No) .any(|n| &*n == node) != - self.EndContainer() + self.end_container() .inclusive_ancestors(ShadowIncluding::No) .any(|n| &*n == node) } - // https://dom.spec.whatwg.org/#concept-range-clone + /// <https://dom.spec.whatwg.org/#concept-range-clone> fn contained_children( &self, ) -> Fallible<( @@ -150,8 +154,8 @@ impl Range { Option<DomRoot<Node>>, Vec<DomRoot<Node>>, )> { - let start_node = self.StartContainer(); - let end_node = self.EndContainer(); + let start_node = self.start_container(); + let end_node = self.end_container(); // Steps 5-6. let common_ancestor = self.CommonAncestorContainer(); @@ -193,45 +197,45 @@ impl Range { )) } - // https://dom.spec.whatwg.org/#concept-range-bp-set + /// <https://dom.spec.whatwg.org/#concept-range-bp-set> fn set_start(&self, node: &Node, offset: u32) { - if &self.start.node != node || self.start.offset.get() != offset { + if self.start().node() != node || self.start_offset() != offset { self.report_change(); } - if &self.start.node != node { - if self.start.node == self.end.node { + if self.start().node() != node { + if self.start().node() == self.end().node() { node.ranges().push(WeakRef::new(self)); - } else if &self.end.node == node { - self.StartContainer().ranges().remove(self); + } else if self.end().node() == node { + self.start_container().ranges().remove(self); } else { node.ranges() - .push(self.StartContainer().ranges().remove(self)); + .push(self.start_container().ranges().remove(self)); } } - self.start.set(node, offset); + self.start().set(node, offset); } - // https://dom.spec.whatwg.org/#concept-range-bp-set + /// <https://dom.spec.whatwg.org/#concept-range-bp-set> fn set_end(&self, node: &Node, offset: u32) { - if &self.end.node != node || self.end.offset.get() != offset { + if self.end().node() != node || self.end_offset() != offset { self.report_change(); } - if &self.end.node != node { - if self.end.node == self.start.node { + if self.end().node() != node { + if self.end().node() == self.start().node() { node.ranges().push(WeakRef::new(self)); - } else if &self.start.node == node { - self.EndContainer().ranges().remove(self); + } else if self.start().node() == node { + self.end_container().ranges().remove(self); } else { node.ranges() - .push(self.EndContainer().ranges().remove(self)); + .push(self.end_container().ranges().remove(self)); } } - self.end.set(node, offset); + self.end().set(node, offset); } - // https://dom.spec.whatwg.org/#dom-range-comparepointnode-offset + /// <https://dom.spec.whatwg.org/#dom-range-comparepointnode-offset> fn compare_point(&self, node: &Node, offset: u32) -> Fallible<Ordering> { - let start_node = self.StartContainer(); + let start_node = self.start_container(); let start_node_root = start_node .inclusive_ancestors(ShadowIncluding::No) .last() @@ -252,13 +256,13 @@ impl Range { // Step 3. return Err(Error::IndexSize); } - if let Ordering::Less = bp_position(node, offset, &start_node, self.StartOffset()).unwrap() + if let Ordering::Less = bp_position(node, offset, &start_node, self.start_offset()).unwrap() { // Step 4. return Ok(Ordering::Less); } if let Ordering::Greater = - bp_position(node, offset, &self.EndContainer(), self.EndOffset()).unwrap() + bp_position(node, offset, &self.end_container(), self.end_offset()).unwrap() { // Step 5. return Ok(Ordering::Greater); @@ -286,42 +290,49 @@ impl Range { .iter() .for_each(|s| s.queue_selectionchange_task()); } -} -impl RangeMethods for Range { - // https://dom.spec.whatwg.org/#dom-range-startcontainer - fn StartContainer(&self) -> DomRoot<Node> { - self.start.node.get() + fn abstract_range(&self) -> &AbstractRange { + &self.abstract_range + } + + fn start(&self) -> &BoundaryPoint { + &self.abstract_range().start() + } + + fn end(&self) -> &BoundaryPoint { + &self.abstract_range().end() + } + + pub fn start_container(&self) -> DomRoot<Node> { + self.abstract_range().StartContainer() } - // https://dom.spec.whatwg.org/#dom-range-startoffset - fn StartOffset(&self) -> u32 { - self.start.offset.get() + pub fn start_offset(&self) -> u32 { + self.abstract_range().StartOffset() } - // https://dom.spec.whatwg.org/#dom-range-endcontainer - fn EndContainer(&self) -> DomRoot<Node> { - self.end.node.get() + pub fn end_container(&self) -> DomRoot<Node> { + self.abstract_range().EndContainer() } - // https://dom.spec.whatwg.org/#dom-range-endoffset - fn EndOffset(&self) -> u32 { - self.end.offset.get() + pub fn end_offset(&self) -> u32 { + self.abstract_range().EndOffset() } - // https://dom.spec.whatwg.org/#dom-range-collapsed - fn Collapsed(&self) -> bool { - self.start == self.end + pub fn collapsed(&self) -> bool { + self.abstract_range().Collapsed() } +} - // https://dom.spec.whatwg.org/#dom-range-commonancestorcontainer +impl RangeMethods for Range { + /// <https://dom.spec.whatwg.org/#dom-range-commonancestorcontainer> fn CommonAncestorContainer(&self) -> DomRoot<Node> { - self.EndContainer() - .common_ancestor(&self.StartContainer(), ShadowIncluding::No) + self.end_container() + .common_ancestor(&self.start_container(), ShadowIncluding::No) .expect("Couldn't find common ancestor container") } - // https://dom.spec.whatwg.org/#dom-range-setstart + /// <https://dom.spec.whatwg.org/#dom-range-setstart> fn SetStart(&self, node: &Node, offset: u32) -> ErrorResult { if node.is_doctype() { // Step 1. @@ -332,7 +343,7 @@ impl RangeMethods for Range { } else { // Step 3. self.set_start(node, offset); - if !(self.start <= self.end) { + if !(self.start() <= self.end()) { // Step 4. self.set_end(node, offset); } @@ -340,7 +351,7 @@ impl RangeMethods for Range { } } - // https://dom.spec.whatwg.org/#dom-range-setend + /// <https://dom.spec.whatwg.org/#dom-range-setend> fn SetEnd(&self, node: &Node, offset: u32) -> ErrorResult { if node.is_doctype() { // Step 1. @@ -351,7 +362,7 @@ impl RangeMethods for Range { } else { // Step 3. self.set_end(node, offset); - if !(self.end >= self.start) { + if !(self.end() >= self.start()) { // Step 4. self.set_start(node, offset); } @@ -359,40 +370,40 @@ impl RangeMethods for Range { } } - // https://dom.spec.whatwg.org/#dom-range-setstartbefore + /// <https://dom.spec.whatwg.org/#dom-range-setstartbefore> fn SetStartBefore(&self, node: &Node) -> ErrorResult { let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?; self.SetStart(&parent, node.index()) } - // https://dom.spec.whatwg.org/#dom-range-setstartafter + /// <https://dom.spec.whatwg.org/#dom-range-setstartafter> fn SetStartAfter(&self, node: &Node) -> ErrorResult { let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?; self.SetStart(&parent, node.index() + 1) } - // https://dom.spec.whatwg.org/#dom-range-setendbefore + /// <https://dom.spec.whatwg.org/#dom-range-setendbefore> fn SetEndBefore(&self, node: &Node) -> ErrorResult { let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?; self.SetEnd(&parent, node.index()) } - // https://dom.spec.whatwg.org/#dom-range-setendafter + /// <https://dom.spec.whatwg.org/#dom-range-setendafter> fn SetEndAfter(&self, node: &Node) -> ErrorResult { let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?; self.SetEnd(&parent, node.index() + 1) } - // https://dom.spec.whatwg.org/#dom-range-collapse + /// <https://dom.spec.whatwg.org/#dom-range-collapse> fn Collapse(&self, to_start: bool) { if to_start { - self.set_end(&self.StartContainer(), self.StartOffset()); + self.set_end(&self.start_container(), self.start_offset()); } else { - self.set_start(&self.EndContainer(), self.EndOffset()); + self.set_start(&self.end_container(), self.end_offset()); } } - // https://dom.spec.whatwg.org/#dom-range-selectnode + /// <https://dom.spec.whatwg.org/#dom-range-selectnode> fn SelectNode(&self, node: &Node) -> ErrorResult { // Steps 1, 2. let parent = node.GetParentNode().ok_or(Error::InvalidNodeType)?; @@ -405,7 +416,7 @@ impl RangeMethods for Range { Ok(()) } - // https://dom.spec.whatwg.org/#dom-range-selectnodecontents + /// <https://dom.spec.whatwg.org/#dom-range-selectnodecontents> fn SelectNodeContents(&self, node: &Node) -> ErrorResult { if node.is_doctype() { // Step 1. @@ -420,19 +431,19 @@ impl RangeMethods for Range { Ok(()) } - // https://dom.spec.whatwg.org/#dom-range-compareboundarypoints + /// <https://dom.spec.whatwg.org/#dom-range-compareboundarypoints> fn CompareBoundaryPoints(&self, how: u16, other: &Range) -> Fallible<i16> { if how > RangeConstants::END_TO_START { // Step 1. return Err(Error::NotSupported); } let this_root = self - .StartContainer() + .start_container() .inclusive_ancestors(ShadowIncluding::No) .last() .unwrap(); let other_root = other - .StartContainer() + .start_container() .inclusive_ancestors(ShadowIncluding::No) .last() .unwrap(); @@ -442,10 +453,10 @@ impl RangeMethods for Range { } // Step 3. let (this_point, other_point) = match how { - RangeConstants::START_TO_START => (&self.start, &other.start), - RangeConstants::START_TO_END => (&self.end, &other.start), - RangeConstants::END_TO_END => (&self.end, &other.end), - RangeConstants::END_TO_START => (&self.start, &other.end), + RangeConstants::START_TO_START => (self.start(), other.start()), + RangeConstants::START_TO_END => (self.end(), other.start()), + RangeConstants::END_TO_END => (self.end(), other.end()), + RangeConstants::END_TO_START => (self.start(), other.end()), _ => unreachable!(), }; // step 4. @@ -456,20 +467,20 @@ impl RangeMethods for Range { } } - // https://dom.spec.whatwg.org/#dom-range-clonerange + /// <https://dom.spec.whatwg.org/#dom-range-clonerange> fn CloneRange(&self) -> DomRoot<Range> { - let start_node = self.StartContainer(); + let start_node = self.start_container(); let owner_doc = start_node.owner_doc(); Range::new( &owner_doc, &start_node, - self.StartOffset(), - &self.EndContainer(), - self.EndOffset(), + self.start_offset(), + &self.end_container(), + self.end_offset(), ) } - // https://dom.spec.whatwg.org/#dom-range-ispointinrange + /// <https://dom.spec.whatwg.org/#dom-range-ispointinrange> fn IsPointInRange(&self, node: &Node, offset: u32) -> Fallible<bool> { match self.compare_point(node, offset) { Ok(Ordering::Less) => Ok(false), @@ -483,7 +494,7 @@ impl RangeMethods for Range { } } - // https://dom.spec.whatwg.org/#dom-range-comparepoint + /// <https://dom.spec.whatwg.org/#dom-range-comparepoint> fn ComparePoint(&self, node: &Node, offset: u32) -> Fallible<i16> { self.compare_point(node, offset).map(|order| match order { Ordering::Less => -1, @@ -492,11 +503,11 @@ impl RangeMethods for Range { }) } - // https://dom.spec.whatwg.org/#dom-range-intersectsnode + /// <https://dom.spec.whatwg.org/#dom-range-intersectsnode> fn IntersectsNode(&self, node: &Node) -> bool { - let start_node = self.StartContainer(); + let start_node = self.start_container(); let start_node_root = self - .StartContainer() + .start_container() .inclusive_ancestors(ShadowIncluding::No) .last() .unwrap(); @@ -519,25 +530,26 @@ impl RangeMethods for Range { let offset = node.index(); // Step 5. Ordering::Greater == - bp_position(&parent, offset + 1, &start_node, self.StartOffset()).unwrap() && + bp_position(&parent, offset + 1, &start_node, self.start_offset()).unwrap() && Ordering::Less == - bp_position(&parent, offset, &self.EndContainer(), self.EndOffset()).unwrap() + bp_position(&parent, offset, &self.end_container(), self.end_offset()) + .unwrap() } - // https://dom.spec.whatwg.org/#dom-range-clonecontents - // https://dom.spec.whatwg.org/#concept-range-clone + /// <https://dom.spec.whatwg.org/#dom-range-clonecontents> + /// <https://dom.spec.whatwg.org/#concept-range-clone> fn CloneContents(&self) -> Fallible<DomRoot<DocumentFragment>> { // Step 3. - let start_node = self.StartContainer(); - let start_offset = self.StartOffset(); - let end_node = self.EndContainer(); - let end_offset = self.EndOffset(); + let start_node = self.start_container(); + let start_offset = self.start_offset(); + let end_node = self.end_container(); + let end_offset = self.end_offset(); // Step 1. let fragment = DocumentFragment::new(&start_node.owner_doc()); // Step 2. - if self.start == self.end { + if self.start() == self.end() { return Ok(fragment); } @@ -625,20 +637,20 @@ impl RangeMethods for Range { Ok(fragment) } - // https://dom.spec.whatwg.org/#dom-range-extractcontents - // https://dom.spec.whatwg.org/#concept-range-extract + /// <https://dom.spec.whatwg.org/#dom-range-extractcontents> + /// <https://dom.spec.whatwg.org/#concept-range-extract> fn ExtractContents(&self) -> Fallible<DomRoot<DocumentFragment>> { // Step 3. - let start_node = self.StartContainer(); - let start_offset = self.StartOffset(); - let end_node = self.EndContainer(); - let end_offset = self.EndOffset(); + let start_node = self.start_container(); + let start_offset = self.start_offset(); + let end_node = self.end_container(); + let end_offset = self.end_offset(); // Step 1. let fragment = DocumentFragment::new(&start_node.owner_doc()); // Step 2. - if self.Collapsed() { + if self.collapsed() { return Ok(fragment); } @@ -763,16 +775,16 @@ impl RangeMethods for Range { Ok(fragment) } - // https://dom.spec.whatwg.org/#dom-range-detach + /// <https://dom.spec.whatwg.org/#dom-range-detach> fn Detach(&self) { // This method intentionally left blank. } - // https://dom.spec.whatwg.org/#dom-range-insertnode - // https://dom.spec.whatwg.org/#concept-range-insert + /// <https://dom.spec.whatwg.org/#dom-range-insertnode> + /// <https://dom.spec.whatwg.org/#concept-range-insert> fn InsertNode(&self, node: &Node) -> ErrorResult { - let start_node = self.StartContainer(); - let start_offset = self.StartOffset(); + let start_node = self.start_container(); + let start_offset = self.start_offset(); // Step 1. if &*start_node == node { @@ -846,25 +858,25 @@ impl RangeMethods for Range { Node::pre_insert(node, &parent, reference_node.as_deref())?; // Step 13. - if self.Collapsed() { + if self.collapsed() { self.set_end(&parent, new_offset); } Ok(()) } - // https://dom.spec.whatwg.org/#dom-range-deletecontents + /// <https://dom.spec.whatwg.org/#dom-range-deletecontents> fn DeleteContents(&self) -> ErrorResult { // Step 1. - if self.Collapsed() { + if self.collapsed() { return Ok(()); } // Step 2. - let start_node = self.StartContainer(); - let end_node = self.EndContainer(); - let start_offset = self.StartOffset(); - let end_offset = self.EndOffset(); + let start_node = self.start_container(); + let end_node = self.end_container(); + let start_offset = self.start_offset(); + let end_offset = self.end_offset(); // Step 3. if start_node == end_node { @@ -937,11 +949,11 @@ impl RangeMethods for Range { Ok(()) } - // https://dom.spec.whatwg.org/#dom-range-surroundcontents + /// <https://dom.spec.whatwg.org/#dom-range-surroundcontents> fn SurroundContents(&self, new_parent: &Node) -> ErrorResult { // Step 1. - let start = self.StartContainer(); - let end = self.EndContainer(); + let start = self.start_container(); + let end = self.end_container(); if start .inclusive_ancestors(ShadowIncluding::No) @@ -978,10 +990,10 @@ impl RangeMethods for Range { self.SelectNode(new_parent) } - // https://dom.spec.whatwg.org/#dom-range-stringifier + /// <https://dom.spec.whatwg.org/#dom-range-stringifier> fn Stringifier(&self) -> DOMString { - let start_node = self.StartContainer(); - let end_node = self.EndContainer(); + let start_node = self.start_container(); + let end_node = self.end_container(); // Step 1. let mut s = DOMString::new(); @@ -992,14 +1004,17 @@ impl RangeMethods for Range { // Step 2. if start_node == end_node { return char_data - .SubstringData(self.StartOffset(), self.EndOffset() - self.StartOffset()) + .SubstringData(self.start_offset(), self.end_offset() - self.start_offset()) .unwrap(); } // Step 3. s.push_str( &*char_data - .SubstringData(self.StartOffset(), char_data.Length() - self.StartOffset()) + .SubstringData( + self.start_offset(), + char_data.Length() - self.start_offset(), + ) .unwrap(), ); } @@ -1019,17 +1034,17 @@ impl RangeMethods for Range { // Step 5. if let Some(text_node) = end_node.downcast::<Text>() { let char_data = text_node.upcast::<CharacterData>(); - s.push_str(&*char_data.SubstringData(0, self.EndOffset()).unwrap()); + s.push_str(&*char_data.SubstringData(0, self.end_offset()).unwrap()); } // Step 6. s } - // https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#extensions-to-the-range-interface + /// <https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#extensions-to-the-range-interface> fn CreateContextualFragment(&self, fragment: DOMString) -> Fallible<DomRoot<DocumentFragment>> { // Step 1. - let node = self.StartContainer(); + let node = self.start_container(); let owner_doc = node.owner_doc(); let element = match node.type_id() { NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) => None, @@ -1063,88 +1078,6 @@ impl RangeMethods for Range { } } -#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)] -#[crown::unrooted_must_root_lint::must_root] -pub struct BoundaryPoint { - node: MutDom<Node>, - offset: Cell<u32>, -} - -impl BoundaryPoint { - fn new(node: &Node, offset: u32) -> BoundaryPoint { - debug_assert!(!node.is_doctype()); - debug_assert!(offset <= node.len()); - BoundaryPoint { - node: MutDom::new(node), - offset: Cell::new(offset), - } - } - - pub fn set(&self, node: &Node, offset: u32) { - self.node.set(node); - self.set_offset(offset); - } - - pub fn set_offset(&self, offset: u32) { - self.offset.set(offset); - } -} - -#[allow(crown::unrooted_must_root)] -impl PartialOrd for BoundaryPoint { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - bp_position( - &self.node.get(), - self.offset.get(), - &other.node.get(), - other.offset.get(), - ) - } -} - -#[allow(crown::unrooted_must_root)] -impl PartialEq for BoundaryPoint { - fn eq(&self, other: &Self) -> bool { - self.node.get() == other.node.get() && self.offset.get() == other.offset.get() - } -} - -// https://dom.spec.whatwg.org/#concept-range-bp-position -fn bp_position(a_node: &Node, a_offset: u32, b_node: &Node, b_offset: u32) -> Option<Ordering> { - if a_node as *const Node == b_node as *const Node { - // Step 1. - return Some(a_offset.cmp(&b_offset)); - } - let position = b_node.CompareDocumentPosition(a_node); - if position & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 { - // No order is defined for nodes not in the same tree. - None - } else if position & NodeConstants::DOCUMENT_POSITION_FOLLOWING != 0 { - // Step 2. - match bp_position(b_node, b_offset, a_node, a_offset).unwrap() { - Ordering::Less => Some(Ordering::Greater), - Ordering::Greater => Some(Ordering::Less), - Ordering::Equal => unreachable!(), - } - } else if position & NodeConstants::DOCUMENT_POSITION_CONTAINS != 0 { - // Step 3-1, 3-2. - let mut b_ancestors = b_node.inclusive_ancestors(ShadowIncluding::No); - let child = b_ancestors - .find(|child| &*child.GetParentNode().unwrap() == a_node) - .unwrap(); - // Step 3-3. - if child.index() < a_offset { - Some(Ordering::Greater) - } else { - // Step 4. - Some(Ordering::Less) - } - } else { - // Step 4. - Some(Ordering::Less) - } -} - pub struct WeakRangeVec { cell: UnsafeCell<WeakRefVec<Range>>, } @@ -1189,16 +1122,16 @@ impl WeakRangeVec { ranges.update(|entry| { let range = entry.root().unwrap(); - if &range.start.node == parent || &range.end.node == parent { + if range.start().node() == parent || range.end().node() == parent { entry.remove(); } - if &range.start.node == child { + if range.start().node() == child { range.report_change(); - range.start.set(context.parent, offset); + range.start().set(context.parent, offset); } - if &range.end.node == child { + if range.end().node() == child { range.report_change(); - range.end.set(context.parent, offset); + range.end().set(context.parent, offset); } }); @@ -1218,16 +1151,16 @@ impl WeakRangeVec { ranges.update(|entry| { let range = entry.root().unwrap(); - if &range.start.node == sibling || &range.end.node == sibling { + if range.start().node() == sibling || range.end().node() == sibling { entry.remove(); } - if &range.start.node == node { + if range.start().node() == node { range.report_change(); - range.start.set(sibling, range.StartOffset() + length); + range.start().set(sibling, range.start_offset() + length); } - if &range.end.node == node { + if range.end().node() == node { range.report_change(); - range.end.set(sibling, range.EndOffset() + length); + range.end().set(sibling, range.end_offset() + length); } }); @@ -1244,17 +1177,17 @@ impl WeakRangeVec { (*self.cell.get()).update(|entry| { let range = entry.root().unwrap(); - let node_is_start = &range.start.node == node; - let node_is_end = &range.end.node == node; + let node_is_start = range.start().node() == node; + let node_is_end = range.end().node() == node; - let move_start = node_is_start && range.StartOffset() == offset; - let move_end = node_is_end && range.EndOffset() == offset; + let move_start = node_is_start && range.start_offset() == offset; + let move_end = node_is_end && range.end_offset() == offset; let remove_from_node = move_start && move_end || move_start && !node_is_end || move_end && !node_is_start; - let already_in_child = &range.start.node == child || &range.end.node == child; + let already_in_child = range.start().node() == child || range.end().node() == child; let push_to_child = !already_in_child && (move_start || move_end); if remove_from_node { @@ -1268,11 +1201,11 @@ impl WeakRangeVec { if move_start { range.report_change(); - range.start.set(child, new_offset); + range.start().set(child, new_offset); } if move_end { range.report_change(); - range.end.set(child, new_offset); + range.end().set(child, new_offset); } }); } @@ -1304,11 +1237,11 @@ impl WeakRangeVec { (*self.cell.get()).update(|entry| { let range = entry.root().unwrap(); - let start_offset = range.StartOffset(); - let end_offset = range.EndOffset(); + let start_offset = range.start_offset(); + let end_offset = range.end_offset(); - let node_is_start = &range.start.node == node; - let node_is_end = &range.end.node == node; + let node_is_start = range.start().node() == node; + let node_is_end = range.end().node() == node; let move_start = node_is_start && start_offset > offset; let move_end = node_is_end && end_offset > offset; @@ -1317,7 +1250,8 @@ impl WeakRangeVec { move_start && !node_is_end || move_end && !node_is_start; - let already_in_sibling = &range.start.node == sibling || &range.end.node == sibling; + let already_in_sibling = + range.start().node() == sibling || range.end().node() == sibling; let push_to_sibling = !already_in_sibling && (move_start || move_end); if remove_from_node { @@ -1331,11 +1265,11 @@ impl WeakRangeVec { if move_start { range.report_change(); - range.start.set(sibling, start_offset - offset); + range.start().set(sibling, start_offset - offset); } if move_end { range.report_change(); - range.end.set(sibling, end_offset - offset); + range.end().set(sibling, end_offset - offset); } }); } @@ -1347,13 +1281,13 @@ impl WeakRangeVec { unsafe { (*self.cell.get()).update(|entry| { let range = entry.root().unwrap(); - if &range.start.node == node && offset == range.StartOffset() { + if range.start().node() == node && offset == range.start_offset() { range.report_change(); - range.start.set_offset(offset + 1); + range.start().set_offset(offset + 1); } - if &range.end.node == node && offset == range.EndOffset() { + if range.end().node() == node && offset == range.end_offset() { range.report_change(); - range.end.set_offset(offset + 1); + range.end().set_offset(offset + 1); } }); } @@ -1363,21 +1297,21 @@ impl WeakRangeVec { unsafe { (*self.cell.get()).update(|entry| { let range = entry.root().unwrap(); - let start_offset = range.StartOffset(); - if &range.start.node == node && start_offset > offset { + let start_offset = range.start_offset(); + if range.start().node() == node && start_offset > offset { range.report_change(); - range.start.set_offset(f(start_offset)); + range.start().set_offset(f(start_offset)); } - let end_offset = range.EndOffset(); - if &range.end.node == node && end_offset > offset { + let end_offset = range.end_offset(); + if range.end().node() == node && end_offset > offset { range.report_change(); - range.end.set_offset(f(end_offset)); + range.end().set_offset(f(end_offset)); } }); } } - fn push(&self, ref_: WeakRef<Range>) { + pub fn push(&self, ref_: WeakRef<Range>) { unsafe { (*self.cell.get()).push(ref_); } diff --git a/components/script/dom/selection.rs b/components/script/dom/selection.rs index 2d5b3cb0474..8d16372e46c 100644 --- a/components/script/dom/selection.rs +++ b/components/script/dom/selection.rs @@ -113,8 +113,8 @@ impl SelectionMethods for Selection { fn GetAnchorNode(&self) -> Option<DomRoot<Node>> { if let Some(range) = self.range.get() { match self.direction.get() { - Direction::Forwards => Some(range.StartContainer()), - _ => Some(range.EndContainer()), + Direction::Forwards => Some(range.start_container()), + _ => Some(range.end_container()), } } else { None @@ -125,8 +125,8 @@ impl SelectionMethods for Selection { fn AnchorOffset(&self) -> u32 { if let Some(range) = self.range.get() { match self.direction.get() { - Direction::Forwards => range.StartOffset(), - _ => range.EndOffset(), + Direction::Forwards => range.start_offset(), + _ => range.end_offset(), } } else { 0 @@ -137,8 +137,8 @@ impl SelectionMethods for Selection { fn GetFocusNode(&self) -> Option<DomRoot<Node>> { if let Some(range) = self.range.get() { match self.direction.get() { - Direction::Forwards => Some(range.EndContainer()), - _ => Some(range.StartContainer()), + Direction::Forwards => Some(range.end_container()), + _ => Some(range.start_container()), } } else { None @@ -149,8 +149,8 @@ impl SelectionMethods for Selection { fn FocusOffset(&self) -> u32 { if let Some(range) = self.range.get() { match self.direction.get() { - Direction::Forwards => range.EndOffset(), - _ => range.StartOffset(), + Direction::Forwards => range.end_offset(), + _ => range.start_offset(), } } else { 0 @@ -160,7 +160,7 @@ impl SelectionMethods for Selection { // https://w3c.github.io/selection-api/#dom-selection-iscollapsed fn IsCollapsed(&self) -> bool { if let Some(range) = self.range.get() { - range.Collapsed() + range.collapsed() } else { true } @@ -178,7 +178,7 @@ impl SelectionMethods for Selection { // https://w3c.github.io/selection-api/#dom-selection-type fn Type(&self) -> DOMString { if let Some(range) = self.range.get() { - if range.Collapsed() { + if range.collapsed() { DOMString::from("Caret") } else { DOMString::from("Range") @@ -202,7 +202,7 @@ impl SelectionMethods for Selection { // https://w3c.github.io/selection-api/#dom-selection-addrange fn AddRange(&self, range: &Range) { // Step 1 - if !self.is_same_root(&*range.StartContainer()) { + if !self.is_same_root(&*range.start_container()) { return; } @@ -283,7 +283,7 @@ impl SelectionMethods for Selection { // https://w3c.github.io/selection-api/#dom-selection-collapsetostart fn CollapseToStart(&self) -> ErrorResult { if let Some(range) = self.range.get() { - self.Collapse(Some(&*range.StartContainer()), range.StartOffset()) + self.Collapse(Some(&*range.start_container()), range.start_offset()) } else { Err(Error::InvalidState) } @@ -292,7 +292,7 @@ impl SelectionMethods for Selection { // https://w3c.github.io/selection-api/#dom-selection-collapsetoend fn CollapseToEnd(&self) -> ErrorResult { if let Some(range) = self.range.get() { - self.Collapse(Some(&*range.EndContainer()), range.EndOffset()) + self.Collapse(Some(&*range.end_container()), range.end_offset()) } else { Err(Error::InvalidState) } @@ -319,7 +319,7 @@ impl SelectionMethods for Selection { } // Step 4 - if !self.is_same_root(&*range.StartContainer()) { + if !self.is_same_root(&*range.start_container()) { // Step 5, and its following 8 and 9 self.set_range(&*Range::new(&self.document, node, offset, node, offset)); self.direction.set(Direction::Forwards); @@ -458,7 +458,7 @@ impl SelectionMethods for Selection { return false; } if let Some(range) = self.range.get() { - let start_node = &*range.StartContainer(); + let start_node = &*range.start_container(); if !self.is_same_root(start_node) { // node can't be contained in a range with a different root return false; @@ -468,30 +468,30 @@ impl SelectionMethods for Selection { if node.is_before(start_node) { return false; } - let end_node = &*range.EndContainer(); + let end_node = &*range.end_container(); if end_node.is_before(node) { return false; } if node == start_node { - return range.StartOffset() < node.len(); + return range.start_offset() < node.len(); } if node == end_node { - return range.EndOffset() > 0; + return range.end_offset() > 0; } true } else { if node.is_before(start_node) { return false; } - let end_node = &*range.EndContainer(); + let end_node = &*range.end_container(); if end_node.is_before(node) { return false; } if node == start_node { - return range.StartOffset() == 0; + return range.start_offset() == 0; } if node == end_node { - return range.EndOffset() == node.len(); + return range.end_offset() == node.len(); } true } diff --git a/components/script/dom/staticrange.rs b/components/script/dom/staticrange.rs new file mode 100644 index 00000000000..84c25e12f47 --- /dev/null +++ b/components/script/dom/staticrange.rs @@ -0,0 +1,88 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use dom_struct::dom_struct; +use js::rust::HandleObject; + +use crate::dom::abstractrange::AbstractRange; +use crate::dom::bindings::codegen::Bindings::StaticRangeBinding::StaticRangeInit; +use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::inheritance::NodeTypeId; +use crate::dom::bindings::reflector::reflect_dom_object_with_proto; +use crate::dom::bindings::root::DomRoot; +use crate::dom::document::Document; +use crate::dom::node::Node; +use crate::dom::window::Window; + +#[dom_struct] +pub struct StaticRange { + abstract_range: AbstractRange, +} + +impl StaticRange { + fn new_inherited( + start_container: &Node, + start_offset: u32, + end_container: &Node, + end_offset: u32, + ) -> StaticRange { + StaticRange { + abstract_range: AbstractRange::new_inherited( + start_container, + start_offset, + end_container, + end_offset, + ), + } + } + pub fn new_with_doc( + document: &Document, + proto: Option<HandleObject>, + init: &StaticRangeInit, + ) -> DomRoot<StaticRange> { + StaticRange::new_with_proto(document, proto, init) + } + + pub fn new_with_proto( + document: &Document, + proto: Option<HandleObject>, + init: &StaticRangeInit, + ) -> DomRoot<StaticRange> { + let staticrange = reflect_dom_object_with_proto( + Box::new(StaticRange::new_inherited( + &init.startContainer, + init.startOffset, + &init.endContainer, + init.endOffset, + )), + document.window(), + proto, + ); + staticrange + } + + /// <https://dom.spec.whatwg.org/#dom-staticrange-staticrange> + #[allow(non_snake_case)] + pub fn Constructor( + window: &Window, + proto: Option<HandleObject>, + init: &StaticRangeInit, + ) -> Fallible<DomRoot<StaticRange>> { + match init.startContainer.type_id() { + NodeTypeId::DocumentType | NodeTypeId::Attr => { + return Err(Error::InvalidNodeType); + }, + _ => (), + } + match init.endContainer.type_id() { + NodeTypeId::DocumentType | NodeTypeId::Attr => { + return Err(Error::InvalidNodeType); + }, + _ => (), + } + let document = window.Document(); + Ok(StaticRange::new_with_doc(&document, proto, init)) + } +} diff --git a/components/script/dom/webidls/AbstractRange.webidl b/components/script/dom/webidls/AbstractRange.webidl new file mode 100644 index 00000000000..4472d27fc20 --- /dev/null +++ b/components/script/dom/webidls/AbstractRange.webidl @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +/* + * The origin of this IDL file is + * https://dom.spec.whatwg.org/#interface-abstractrange + */ + +[Exposed=Window] +interface AbstractRange { + [Pure] + readonly attribute Node startContainer; + [Pure] + readonly attribute unsigned long startOffset; + [Pure] + readonly attribute Node endContainer; + [Pure] + readonly attribute unsigned long endOffset; + [Pure] + readonly attribute boolean collapsed; +}; diff --git a/components/script/dom/webidls/Range.webidl b/components/script/dom/webidls/Range.webidl index 037093a0762..7ba168ddb05 100644 --- a/components/script/dom/webidls/Range.webidl +++ b/components/script/dom/webidls/Range.webidl @@ -9,19 +9,9 @@ */ [Exposed=Window] -interface Range { +interface Range : AbstractRange { [Throws] constructor(); [Pure] - readonly attribute Node startContainer; - [Pure] - readonly attribute unsigned long startOffset; - [Pure] - readonly attribute Node endContainer; - [Pure] - readonly attribute unsigned long endOffset; - [Pure] - readonly attribute boolean collapsed; - [Pure] readonly attribute Node commonAncestorContainer; [Throws] diff --git a/components/script/dom/webidls/StaticRange.webidl b/components/script/dom/webidls/StaticRange.webidl new file mode 100644 index 00000000000..a582afe3d7a --- /dev/null +++ b/components/script/dom/webidls/StaticRange.webidl @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +/* + * The origin of this IDL file is + * https://dom.spec.whatwg.org/#interface-staticrange + */ + +dictionary StaticRangeInit { + required Node startContainer; + required unsigned long startOffset; + required Node endContainer; + required unsigned long endOffset; +}; + +[Exposed=Window] +interface StaticRange : AbstractRange { + [Throws] constructor(StaticRangeInit init); +}; |