/* 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 { 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 { /// fn StartContainer(&self) -> DomRoot { self.start.node.get() } /// fn StartOffset(&self) -> u32 { self.start.offset.get() } /// fn EndContainer(&self) -> DomRoot { self.end.node.get() } /// fn EndOffset(&self) -> u32 { self.end.offset.get() } /// fn Collapsed(&self) -> bool { self.start == self.end } } #[derive(DenyPublicFields, JSTraceable, MallocSizeOf)] #[crown::unrooted_must_root_lint::must_root] pub struct BoundaryPoint { node: MutDom, offset: Cell, } 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 { &self.node } } #[allow(crown::unrooted_must_root)] impl PartialOrd for BoundaryPoint { fn partial_cmp(&self, other: &Self) -> Option { 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() } } /// pub fn bp_position(a_node: &Node, a_offset: u32, b_node: &Node, b_offset: u32) -> Option { if std::ptr::eq(a_node, b_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) } }