mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
script: Implement Range::getClientRects
and Range::getBoundingClientRect
(#35993)
* Add doc comments to boundary point Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Allow querying content box of text fragments Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Implement Range::getBoundingClientRect Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update WPT expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
parent
07e06f5635
commit
6be7612d16
8 changed files with 73 additions and 29 deletions
|
@ -155,6 +155,7 @@ impl FragmentTree {
|
|||
}
|
||||
},
|
||||
Fragment::Positioning(fragment) => fragment.borrow().rect.cast_unit(),
|
||||
Fragment::Text(text_fragment) => text_fragment.borrow().rect,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
|
|
@ -94,10 +94,13 @@ impl AbstractRangeMethods<crate::DomTypeHolder> for AbstractRange {
|
|||
}
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#concept-range-bp>
|
||||
#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)]
|
||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||
pub(crate) struct BoundaryPoint {
|
||||
/// <https://dom.spec.whatwg.org/#boundary-point-node>
|
||||
node: MutDom<Node>,
|
||||
/// <https://dom.spec.whatwg.org/#concept-range-bp-offset>
|
||||
offset: Cell<u32>,
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
use std::iter;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::JSTracer;
|
||||
|
@ -29,9 +30,11 @@ use crate::dom::bindings::weakref::{WeakRef, WeakRefVec};
|
|||
use crate::dom::characterdata::CharacterData;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::documentfragment::DocumentFragment;
|
||||
use crate::dom::domrect::DOMRect;
|
||||
use crate::dom::domrectlist::DOMRectList;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::htmlscriptelement::HTMLScriptElement;
|
||||
use crate::dom::node::{Node, ShadowIncluding, UnbindContext};
|
||||
use crate::dom::node::{Node, NodeTraits, ShadowIncluding, UnbindContext};
|
||||
use crate::dom::selection::Selection;
|
||||
use crate::dom::text::Text;
|
||||
use crate::dom::window::Window;
|
||||
|
@ -324,6 +327,23 @@ impl Range {
|
|||
pub(crate) fn collapsed(&self) -> bool {
|
||||
self.abstract_range().Collapsed()
|
||||
}
|
||||
|
||||
fn client_rects(
|
||||
&self,
|
||||
can_gc: CanGc,
|
||||
) -> impl Iterator<Item = euclid::Rect<app_units::Au, euclid::UnknownUnit>> {
|
||||
// FIXME: For text nodes that are only partially selected, this should return the client
|
||||
// rect of the selected part, not the whole text node.
|
||||
let start = self.start_container();
|
||||
let end = self.end_container();
|
||||
let document = start.owner_doc();
|
||||
let end_clone = end.clone();
|
||||
start
|
||||
.following_nodes(document.upcast::<Node>())
|
||||
.take_while(move |node| node != &end)
|
||||
.chain(iter::once(end_clone))
|
||||
.flat_map(move |node| node.content_boxes(can_gc))
|
||||
}
|
||||
}
|
||||
|
||||
impl RangeMethods<crate::DomTypeHolder> for Range {
|
||||
|
@ -1105,6 +1125,51 @@ impl RangeMethods<crate::DomTypeHolder> for Range {
|
|||
// Step 5.
|
||||
Ok(fragment_node)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom-view/#dom-range-getclientrects>
|
||||
fn GetClientRects(&self, can_gc: CanGc) -> DomRoot<DOMRectList> {
|
||||
let start = self.start_container();
|
||||
let window = start.owner_window();
|
||||
|
||||
let client_rects = self
|
||||
.client_rects(can_gc)
|
||||
.map(|rect| {
|
||||
DOMRect::new(
|
||||
window.upcast(),
|
||||
rect.origin.x.to_f64_px(),
|
||||
rect.origin.y.to_f64_px(),
|
||||
rect.size.width.to_f64_px(),
|
||||
rect.size.height.to_f64_px(),
|
||||
can_gc,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
DOMRectList::new(&window, client_rects, can_gc)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom-view/#dom-range-getboundingclientrect>
|
||||
fn GetBoundingClientRect(&self, can_gc: CanGc) -> DomRoot<DOMRect> {
|
||||
let window = self.start_container().owner_window();
|
||||
|
||||
// Step 1. Let list be the result of invoking getClientRects() on the same range this method was invoked on.
|
||||
let list = self.client_rects(can_gc);
|
||||
|
||||
// Step 2. If list is empty return a DOMRect object whose x, y, width and height members are zero.
|
||||
// Step 3. If all rectangles in list have zero width or height, return the first rectangle in list.
|
||||
// Step 4. Otherwise, return a DOMRect object describing the smallest rectangle that includes all
|
||||
// of the rectangles in list of which the height or width is not zero.
|
||||
let bounding_rect = list.fold(euclid::Rect::zero(), |acc, rect| acc.union(&rect));
|
||||
|
||||
DOMRect::new(
|
||||
window.upcast(),
|
||||
bounding_rect.origin.x.to_f64_px(),
|
||||
bounding_rect.origin.y.to_f64_px(),
|
||||
bounding_rect.size.width.to_f64_px(),
|
||||
bounding_rect.size.height.to_f64_px(),
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WeakRangeVec {
|
||||
|
|
|
@ -469,7 +469,7 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'Range': {
|
||||
'canGc': ['CloneContents', 'CloneRange', 'CreateContextualFragment', 'ExtractContents', 'SurroundContents', 'InsertNode'],
|
||||
'canGc': ['CloneContents', 'CloneRange', 'CreateContextualFragment', 'ExtractContents', 'SurroundContents', 'InsertNode', 'GetClientRects', 'GetBoundingClientRect'],
|
||||
'weakReferenceable': True,
|
||||
},
|
||||
|
||||
|
|
|
@ -73,7 +73,6 @@ partial interface Range {
|
|||
|
||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-range-interface
|
||||
partial interface Range {
|
||||
// sequence<DOMRect> getClientRects();
|
||||
// [NewObject]
|
||||
// DOMRect getBoundingClientRect();
|
||||
DOMRectList getClientRects();
|
||||
[NewObject] DOMRect getBoundingClientRect();
|
||||
};
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[DOMRectList.html]
|
||||
[Range getClientRects()]
|
||||
expected: FAIL
|
|
@ -1,9 +0,0 @@
|
|||
[getBoundingClientRect-svg.html]
|
||||
[Element.getBoundingClientRect() and Range.getBoudingClientRect() should match for an SVG <text>]
|
||||
expected: FAIL
|
||||
|
||||
[Element.getBoundingClientRect() and Range.getBoudingClientRect() should match for an SVG <text> with a transform]
|
||||
expected: FAIL
|
||||
|
||||
[Element.getBoundingClientRect() and Range.getBoudingClientRect() should match for an SVG <text> with a rotate]
|
||||
expected: FAIL
|
|
@ -26,9 +26,6 @@
|
|||
[Element interface: document.createElement("div") must inherit property "getBoxQuads(BoxQuadOptions)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Range interface: new Range() must inherit property "getBoundingClientRect()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: calling convertRectFromNode(DOMRectReadOnly, GeometryNode, ConvertCoordinateOptions) on document.createElementNS("x", "y") with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -62,9 +59,6 @@
|
|||
[CaretPosition interface: attribute offset]
|
||||
expected: FAIL
|
||||
|
||||
[Range interface: operation getBoundingClientRect()]
|
||||
expected: FAIL
|
||||
|
||||
[Partial dictionary MouseEventInit: member names are unique]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -98,9 +92,6 @@
|
|||
[CaretPosition interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[Range interface: operation getClientRects()]
|
||||
expected: FAIL
|
||||
|
||||
[Element interface: document.createElementNS("x", "y") must inherit property "convertRectFromNode(DOMRectReadOnly, GeometryNode, ConvertCoordinateOptions)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -272,9 +263,6 @@
|
|||
[Element interface: document.createElement("img") must inherit property "convertPointFromNode(DOMPointInit, GeometryNode, ConvertCoordinateOptions)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Range interface: new Range() must inherit property "getClientRects()" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Window interface: window must inherit property "screenLeft" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue