Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Range.getClientRects and Range.getBoudingClientRect (Work in progress) #10828

Closed
@@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::DOMRectListBinding::DOMRectListMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeConstants;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
@@ -21,7 +23,11 @@ use dom::bindings::weakref::{WeakRef, WeakRefVec};
use dom::characterdata::CharacterData;
use dom::document::Document;
use dom::documentfragment::DocumentFragment;
use dom::domrect::DOMRect;
use dom::domrectlist::DOMRectList;
use dom::element::Element;
use dom::node::{Node, UnbindContext};
use dom::node::{window_from_node};
use dom::text::Text;
use heapsize::HeapSizeOf;
use js::jsapi::JSTracer;
@@ -893,6 +899,87 @@ impl RangeMethods for Range {
// Step 6.
s
}

// https://drafts.csswg.org/cssom-view/#dom-range-getclientrects
fn GetClientRects(&self) -> Option<Root<DOMRectList>> {
let start_node = self.StartContainer();
let end_node = self.EndContainer();
let win = window_from_node(start_node.r());

fn push_rects(node: Option<Root<Node>>, rects: &mut Vec<Root<DOMRect>>, range: &Range) {
let node = match node {
Some(node) => node,
None => return
};

if let Some(element) = node.downcast::<Element>() {
let element_rects = element.GetClientRects();

for i in 0..element_rects.r().Length() {
match element_rects.r().Item(i) {
Some(rect) => rects.push(rect),
None => ()
}
}
}

if let Some(text) = node.downcast::<Text>() {
let start_node = range.StartContainer();
let end_node = range.EndContainer();
let win = window_from_node(start_node.r());

let cut_text = if node == start_node {
let text = start_node.downcast::<Text>().unwrap();
text.SplitText(range.StartOffset()).unwrap()
} else if node == end_node {
let text = end_node.downcast::<Text>().unwrap();
text.SplitText(range.EndOffset()).unwrap()
} else {
Root::from_ref(text)
};

let node = cut_text.upcast::<Node>();
let node_rects = node.content_boxes();
for rect in &node_rects {
rects.push(DOMRect::new(GlobalRef::Window(win.r()),
rect.origin.x.to_f64_px(),
rect.origin.y.to_f64_px(),
rect.size.width.to_f64_px(),
rect.size.height.to_f64_px()))
}

debug!("Some text received {:?}", text.WholeText());
}
}

let mut rects = Vec::new();

if start_node == end_node {
push_rects(Some(start_node), &mut rects, &self);
return Some(DOMRectList::new(win.r(), rects.into_iter()))
}

let (first, last, children) = self.contained_children().unwrap();

push_rects(first, &mut rects, &self);
for node in children {
push_rects(Some(node), &mut rects, &self);
}
push_rects(last, &mut rects, &self);

Some(DOMRectList::new(win.r(), rects.into_iter()))
}

// https://drafts.csswg.org/cssom-view/#dom-range-getboundingclientrect
fn GetBoundingClientRect(&self) -> Root<DOMRect> {
let node = self.StartContainer();
let win = window_from_node(node.r());

match self.GetClientRects() {
Some(rv) => rv.r().Item(0).unwrap(),
None => DOMRect::new(GlobalRef::Window(win.r()), 0.0, 0.0, 0.0, 0.0)
}
}
}

#[derive(JSTraceable)]
@@ -82,6 +82,6 @@ partial interface Range {

// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-range-interface
partial interface Range {
// DOMRectList? getClientRects();
// DOMRect getBoundingClientRect();
DOMRectList? getClientRects();
DOMRect getBoundingClientRect();
};
"path": "dom/ranges/Range-constructor.html",
"url": "/dom/ranges/Range-constructor.html"
},
{
"path": "dom/ranges/Range-getClientRects.html",
"url": "/dom/ranges/Range-getClientRects.html"
},
{
"path": "dom/ranges/Range-getBoundingClientRect.html",
"url": "/dom/ranges/Range-getBoundingClientRect.html"
},
{
"path": "dom/ranges/Range-stringifier.html",
"url": "/dom/ranges/Range-stringifier.html"
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<title>Range getBoundingClientRect</title>
<meta name=timeout content=long>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div id=log></div>
<div id=data>Testing data
<p>Paragraph</p>
</div>
<div id=data2>Data 2
<p id=data3>Data 3</p>
</div>
<script>
test(function() {
var values = {x: 8, y: 28.800003051757812, width: 1280,
height: 123.19999694824219, top: 28.800003051757812, right: 1288,
bottom: 152, left: 8};

var r = document.createRange();
r.setStart(document.getElementById('data'), 0);
r.setEnd(document.getElementById('data3'), 0);

var rect = r.getBoundingClientRect();
for (var property in values) {
assert_equals(values[property], rect[property]);
}
})
</script>
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<title>Range getClientRects</title>
<meta name=timeout content=long>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div id=log></div>
<div id=data>Testing data
<p>Paragraph</p>
</div>
<div id=data2>Data 2
<p id=data3>Data 3</p>
</div>
<script>
test(function() {
var values = [
{top: 26, right: 85.515625, bottom: 44, left: 8, width: 77.515625},
{top: 60, right: 1432, bottom: 78, left: 8, width: 1424},
{top: 60, right: 72.859375, bottom: 78, left: 8, width: 64.859375},
{top: 94, right: 1432, bottom: 146, left: 8, width: 1424},
{top: 94, right: 50.203125, bottom: 112, left: 8, width: 42.203125}
]
var r = document.createRange();
r.setStart(document.getElementById('data'), 0);
r.setEnd(document.getElementById('data3'), 0);
var clientRects = r.getClientRects();
assert_equals(clientRects.length, 5);
for (var i = 0; i < values.length; i++) {
for (var property in values[i]) {
assert_equals(clientRects[i][property], values[i][property]);
}
}
})
</script>
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.