mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Auto merge of #15053 - emilio:image-width, r=jdm
Return the intrinsic image dimension when the image is not rendered See individual commits for details. r? @jdm <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15053) <!-- Reviewable:end -->
This commit is contained in:
commit
ba59ee6627
11 changed files with 58 additions and 23 deletions
|
@ -54,7 +54,7 @@ pub struct LayoutThreadData {
|
||||||
pub stylist: Arc<Stylist>,
|
pub stylist: Arc<Stylist>,
|
||||||
|
|
||||||
/// A queued response for the union of the content boxes of a node.
|
/// A queued response for the union of the content boxes of a node.
|
||||||
pub content_box_response: Rect<Au>,
|
pub content_box_response: Option<Rect<Au>>,
|
||||||
|
|
||||||
/// A queued response for the content boxes of a node.
|
/// A queued response for the content boxes of a node.
|
||||||
pub content_boxes_response: Vec<Rect<Au>>,
|
pub content_boxes_response: Vec<Rect<Au>>,
|
||||||
|
@ -384,15 +384,12 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_content_box_request<N: LayoutNode>(
|
pub fn process_content_box_request<N: LayoutNode>(
|
||||||
requested_node: N, layout_root: &mut Flow) -> Rect<Au> {
|
requested_node: N, layout_root: &mut Flow) -> Option<Rect<Au>> {
|
||||||
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
// FIXME(pcwalton): This has not been updated to handle the stacking context relative
|
||||||
// stuff. So the position is wrong in most cases.
|
// stuff. So the position is wrong in most cases.
|
||||||
let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque());
|
let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque());
|
||||||
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
|
||||||
match iterator.rect {
|
iterator.rect
|
||||||
Some(rect) => rect,
|
|
||||||
None => Rect::zero()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_content_boxes_request<N: LayoutNode>(requested_node: N, layout_root: &mut Flow)
|
pub fn process_content_boxes_request<N: LayoutNode>(requested_node: N, layout_root: &mut Flow)
|
||||||
|
|
|
@ -464,7 +464,7 @@ impl LayoutThread {
|
||||||
constellation_chan: constellation_chan,
|
constellation_chan: constellation_chan,
|
||||||
display_list: None,
|
display_list: None,
|
||||||
stylist: stylist,
|
stylist: stylist,
|
||||||
content_box_response: Rect::zero(),
|
content_box_response: None,
|
||||||
content_boxes_response: Vec::new(),
|
content_boxes_response: Vec::new(),
|
||||||
client_rect_response: Rect::zero(),
|
client_rect_response: Rect::zero(),
|
||||||
hit_test_response: (None, false),
|
hit_test_response: (None, false),
|
||||||
|
@ -1012,7 +1012,7 @@ impl LayoutThread {
|
||||||
debug!("layout: No root node: bailing");
|
debug!("layout: No root node: bailing");
|
||||||
match data.query_type {
|
match data.query_type {
|
||||||
ReflowQueryType::ContentBoxQuery(_) => {
|
ReflowQueryType::ContentBoxQuery(_) => {
|
||||||
rw_data.content_box_response = Rect::zero();
|
rw_data.content_box_response = None;
|
||||||
},
|
},
|
||||||
ReflowQueryType::ContentBoxesQuery(_) => {
|
ReflowQueryType::ContentBoxesQuery(_) => {
|
||||||
rw_data.content_boxes_response = Vec::new();
|
rw_data.content_boxes_response = Vec::new();
|
||||||
|
|
|
@ -625,7 +625,7 @@ impl Document {
|
||||||
// Really what needs to happen is that this needs to go through layout to ask which
|
// Really what needs to happen is that this needs to go through layout to ask which
|
||||||
// layer the element belongs to, and have it send the scroll message to the
|
// layer the element belongs to, and have it send the scroll message to the
|
||||||
// compositor.
|
// compositor.
|
||||||
let rect = element.upcast::<Node>().bounding_content_box();
|
let rect = element.upcast::<Node>().bounding_content_box_or_zero();
|
||||||
|
|
||||||
// In order to align with element edges, we snap to unscaled pixel boundaries, since
|
// In order to align with element edges, we snap to unscaled pixel boundaries, since
|
||||||
// the paint thread currently does the same for drawing elements. This is important
|
// the paint thread currently does the same for drawing elements. This is important
|
||||||
|
|
|
@ -1604,7 +1604,7 @@ impl ElementMethods for Element {
|
||||||
// https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect
|
// https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect
|
||||||
fn GetBoundingClientRect(&self) -> Root<DOMRect> {
|
fn GetBoundingClientRect(&self) -> Root<DOMRect> {
|
||||||
let win = window_from_node(self);
|
let win = window_from_node(self);
|
||||||
let rect = self.upcast::<Node>().bounding_content_box();
|
let rect = self.upcast::<Node>().bounding_content_box_or_zero();
|
||||||
DOMRect::new(win.upcast(),
|
DOMRect::new(win.upcast(),
|
||||||
rect.origin.x.to_f64_px(),
|
rect.origin.x.to_f64_px(),
|
||||||
rect.origin.y.to_f64_px(),
|
rect.origin.y.to_f64_px(),
|
||||||
|
|
|
@ -21,7 +21,7 @@ use dom::eventtarget::EventTarget;
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmlimageelement::HTMLImageElement;
|
use dom::htmlimageelement::HTMLImageElement;
|
||||||
use dom::mouseevent::MouseEvent;
|
use dom::mouseevent::MouseEvent;
|
||||||
use dom::node::{Node, document_from_node, window_from_node};
|
use dom::node::{Node, document_from_node};
|
||||||
use dom::urlhelper::UrlHelper;
|
use dom::urlhelper::UrlHelper;
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use html5ever_atoms::LocalName;
|
use html5ever_atoms::LocalName;
|
||||||
|
@ -544,8 +544,7 @@ impl Activatable for HTMLAnchorElement {
|
||||||
if let Some(element) = target.downcast::<Element>() {
|
if let Some(element) = target.downcast::<Element>() {
|
||||||
if target.is::<HTMLImageElement>() && element.has_attribute(&local_name!("ismap")) {
|
if target.is::<HTMLImageElement>() && element.has_attribute(&local_name!("ismap")) {
|
||||||
let target_node = element.upcast::<Node>();
|
let target_node = element.upcast::<Node>();
|
||||||
let rect = window_from_node(target_node).content_box_query(
|
let rect = target_node.bounding_content_box_or_zero();
|
||||||
target_node.to_trusted_node_address());
|
|
||||||
ismap_suffix = Some(
|
ismap_suffix = Some(
|
||||||
format!("?{},{}", mouse_event.ClientX().to_f32().unwrap() - rect.origin.x.to_f32_px(),
|
format!("?{},{}", mouse_event.ClientX().to_f32().unwrap() - rect.origin.x.to_f32_px(),
|
||||||
mouse_event.ClientY().to_f32().unwrap() - rect.origin.y.to_f32_px())
|
mouse_event.ClientY().to_f32().unwrap() - rect.origin.y.to_f32_px())
|
||||||
|
|
|
@ -358,8 +358,10 @@ impl HTMLImageElementMethods for HTMLImageElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-img-width
|
// https://html.spec.whatwg.org/multipage/#dom-img-width
|
||||||
fn Width(&self) -> u32 {
|
fn Width(&self) -> u32 {
|
||||||
let node = self.upcast::<Node>();
|
let node = self.upcast::<Node>();
|
||||||
let rect = node.bounding_content_box();
|
match node.bounding_content_box() {
|
||||||
rect.size.width.to_px() as u32
|
Some(rect) => rect.size.width.to_px() as u32,
|
||||||
|
None => self.NaturalWidth(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-img-width
|
// https://html.spec.whatwg.org/multipage/#dom-img-width
|
||||||
|
@ -370,8 +372,10 @@ impl HTMLImageElementMethods for HTMLImageElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-img-height
|
// https://html.spec.whatwg.org/multipage/#dom-img-height
|
||||||
fn Height(&self) -> u32 {
|
fn Height(&self) -> u32 {
|
||||||
let node = self.upcast::<Node>();
|
let node = self.upcast::<Node>();
|
||||||
let rect = node.bounding_content_box();
|
match node.bounding_content_box() {
|
||||||
rect.size.height.to_px() as u32
|
Some(rect) => rect.size.height.to_px() as u32,
|
||||||
|
None => self.NaturalHeight(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-img-height
|
// https://html.spec.whatwg.org/multipage/#dom-img-height
|
||||||
|
|
|
@ -524,8 +524,15 @@ impl Node {
|
||||||
TrustedNodeAddress(&*self as *const Node as *const libc::c_void)
|
TrustedNodeAddress(&*self as *const Node as *const libc::c_void)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bounding_content_box(&self) -> Rect<Au> {
|
/// Returns the rendered bounding content box if the element is rendered,
|
||||||
window_from_node(self).content_box_query(self.to_trusted_node_address())
|
/// and none otherwise.
|
||||||
|
pub fn bounding_content_box(&self) -> Option<Rect<Au>> {
|
||||||
|
window_from_node(self)
|
||||||
|
.content_box_query(self.to_trusted_node_address())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bounding_content_box_or_zero(&self) -> Rect<Au> {
|
||||||
|
self.bounding_content_box().unwrap_or_else(Rect::zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content_boxes(&self) -> Vec<Rect<Au>> {
|
pub fn content_boxes(&self) -> Vec<Rect<Au>> {
|
||||||
|
|
|
@ -970,7 +970,7 @@ impl Window {
|
||||||
let body = self.Document().GetBody();
|
let body = self.Document().GetBody();
|
||||||
let (x, y) = match body {
|
let (x, y) = match body {
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
let content_size = e.upcast::<Node>().bounding_content_box();
|
let content_size = e.upcast::<Node>().bounding_content_box_or_zero();
|
||||||
let content_height = content_size.size.height.to_f64_px();
|
let content_height = content_size.size.height.to_f64_px();
|
||||||
let content_width = content_size.size.width.to_f64_px();
|
let content_width = content_size.size.width.to_f64_px();
|
||||||
(xfinite.max(0.0f64).min(content_width - width),
|
(xfinite.max(0.0f64).min(content_width - width),
|
||||||
|
@ -1216,11 +1216,11 @@ impl Window {
|
||||||
&*self.layout_rpc
|
&*self.layout_rpc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content_box_query(&self, content_box_request: TrustedNodeAddress) -> Rect<Au> {
|
pub fn content_box_query(&self, content_box_request: TrustedNodeAddress) -> Option<Rect<Au>> {
|
||||||
if !self.reflow(ReflowGoal::ForScriptQuery,
|
if !self.reflow(ReflowGoal::ForScriptQuery,
|
||||||
ReflowQueryType::ContentBoxQuery(content_box_request),
|
ReflowQueryType::ContentBoxQuery(content_box_request),
|
||||||
ReflowReason::Query) {
|
ReflowReason::Query) {
|
||||||
return Rect::zero();
|
return None;
|
||||||
}
|
}
|
||||||
let ContentBoxResponse(rect) = self.layout_rpc.content_box();
|
let ContentBoxResponse(rect) = self.layout_rpc.content_box();
|
||||||
rect
|
rect
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub trait LayoutRPC {
|
||||||
fn text_index(&self) -> TextIndexResponse;
|
fn text_index(&self) -> TextIndexResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContentBoxResponse(pub Rect<Au>);
|
pub struct ContentBoxResponse(pub Option<Rect<Au>>);
|
||||||
|
|
||||||
pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
|
pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
|
||||||
|
|
||||||
|
|
|
@ -45872,6 +45872,12 @@
|
||||||
"path": "html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html",
|
"path": "html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html",
|
||||||
"url": "/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html"
|
"url": "/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html": [
|
||||||
|
{
|
||||||
|
"path": "html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html",
|
||||||
|
"url": "/html/semantics/embedded-content/the-img-element/not-rendered-dimension-getter.html"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Image intrinsic dimensions are returned if the image isn't rendered</title>
|
||||||
|
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||||
|
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-img-width">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="container" style="display: none">
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
async_test(function(t) {
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.onload = t.step_func_done(function() {
|
||||||
|
assert_equals(img.width, 389, "intrinsic width should've been returned")
|
||||||
|
assert_equals(img.height, 590, "intrinsic height should've been returned")
|
||||||
|
document.getElementById('container').appendChild(img);
|
||||||
|
assert_equals(img.width, 389, "intrinsic width should've been returned");
|
||||||
|
assert_equals(img.height, 590, "intrinsic height should've been returned");
|
||||||
|
});
|
||||||
|
img.src = "image-1.jpg";
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue