Skip to content
Permalink
Browse files

Use presentation hints correctly for the dimensions of `<img>`.

Mostly straightforward; includes some extra fixes to make `<canvas>`
work the same way as `<img>` for reflow.
  • Loading branch information
eefriedman authored and jdm committed Feb 25, 2016
1 parent b188cb5 commit 7b671d13a02a8d26f7d7769a6d2d62b2be8df5ac
Showing with 5,505 additions and 853 deletions.
  1. +48 −55 components/layout/fragment.rs
  2. +5 −0 components/script/dom/element.rs
  3. +49 −5 components/script/dom/htmlimageelement.rs
  4. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-001.htm.ini
  5. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-002.htm.ini
  6. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-003.htm.ini
  7. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-006.htm.ini
  8. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-007.htm.ini
  9. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-008.htm.ini
  10. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-009.htm.ini
  11. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-010.htm.ini
  12. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-014.htm.ini
  13. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-018.htm.ini
  14. +0 −3 tests/wpt/metadata-css/css-backgrounds-3_dev/html4/background-022.htm.ini
  15. +0 −3 tests/wpt/metadata-css/css21_dev/html4/absolute-replaced-width-006.htm.ini
  16. +0 −3 tests/wpt/metadata-css/css21_dev/html4/absolute-replaced-width-020.htm.ini
  17. +0 −3 tests/wpt/metadata-css/css21_dev/html4/absolute-replaced-width-041.htm.ini
  18. +0 −3 tests/wpt/metadata-css/css21_dev/html4/absolute-replaced-width-055.htm.ini
  19. +0 −3 tests/wpt/metadata-css/css21_dev/html4/absolute-replaced-width-069.htm.ini
  20. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-001.htm.ini
  21. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-002.htm.ini
  22. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-003.htm.ini
  23. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-006.htm.ini
  24. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-007.htm.ini
  25. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-008.htm.ini
  26. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-009.htm.ini
  27. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-010.htm.ini
  28. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-014.htm.ini
  29. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-018.htm.ini
  30. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-022.htm.ini
  31. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-087.htm.ini
  32. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-182.htm.ini
  33. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-image-cover-002.htm.ini
  34. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-image-cover-004.htm.ini
  35. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-image-cover-attachment-001.htm.ini
  36. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-image-transparency-001.htm.ini
  37. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-repeat-001.htm.ini
  38. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-repeat-002.htm.ini
  39. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-repeat-003.htm.ini
  40. +0 −3 tests/wpt/metadata-css/css21_dev/html4/background-repeat-005.htm.ini
  41. +0 −3 tests/wpt/metadata-css/css21_dev/html4/block-replaced-width-006.htm.ini
  42. +0 −3 tests/wpt/metadata-css/css21_dev/html4/border-bottom-width-003.htm.ini
  43. +0 −3 tests/wpt/metadata-css/css21_dev/html4/border-bottom-width-025.htm.ini
  44. +0 −3 tests/wpt/metadata-css/css21_dev/html4/border-bottom-width-058.htm.ini
  45. +0 −3 tests/wpt/metadata-css/css21_dev/html4/border-bottom-width-069.htm.ini
  46. +0 −3 tests/wpt/metadata-css/css21_dev/html4/border-top-width-025.htm.ini
  47. +0 −3 tests/wpt/metadata-css/css21_dev/html4/border-top-width-058.htm.ini
  48. +0 −3 tests/wpt/metadata-css/css21_dev/html4/border-top-width-069.htm.ini
  49. +0 −3 tests/wpt/metadata-css/css21_dev/html4/float-replaced-width-011.htm.ini
  50. +0 −3 tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-width-006.htm.ini
  51. +0 −3 tests/wpt/metadata-css/css21_dev/html4/inline-replaced-width-006.htm.ini
  52. +5,380 −1 tests/wpt/metadata/MANIFEST.json
  53. +0 −432 tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-fixed.html.ini
  54. +0 −216 .../wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html.ini
  55. +11 −0 ...ests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-dim-ref.html
  56. +12 −0 ...rm-tests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-dim.html
@@ -34,7 +34,6 @@ use std::cmp::{max, min};
use std::collections::LinkedList;
use std::fmt;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::computed_values::content::ContentItem;
use style::computed_values::{border_collapse, clear, display, mix_blend_mode, overflow_wrap};
use style::computed_values::{overflow_x, position, text_decoration, transform_style};
@@ -312,28 +311,38 @@ pub struct CanvasFragmentInfo {
pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<Arc<Mutex<IpcSender<CanvasMsg>>>>,
pub dom_width: Au,
pub dom_height: Au,
}

impl CanvasFragmentInfo {
pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, data: HTMLCanvasData) -> CanvasFragmentInfo {
CanvasFragmentInfo {
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
Some(Au::from_px(data.width as i32)),
Some(Au::from_px(data.height as i32))),
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node),
renderer_id: data.renderer_id,
ipc_renderer: data.ipc_renderer
.map(|renderer| Arc::new(Mutex::new(renderer))),
dom_width: Au::from_px(data.width as i32),
dom_height: Au::from_px(data.height as i32),
}
}

/// Returns the original inline-size of the canvas.
pub fn canvas_inline_size(&self) -> Au {
self.replaced_image_fragment_info.dom_inline_size.unwrap_or(Au(0))
if self.replaced_image_fragment_info.writing_mode_is_vertical {
self.dom_height
} else {
self.dom_width
}
}

/// Returns the original block-size of the canvas.
pub fn canvas_block_size(&self) -> Au {
self.replaced_image_fragment_info.dom_block_size.unwrap_or(Au(0))
if self.replaced_image_fragment_info.writing_mode_is_vertical {
self.dom_width
} else {
self.dom_height
}
}
}

@@ -354,14 +363,6 @@ impl ImageFragmentInfo {
/// sense to me.
pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, url: Option<Url>,
layout_context: &LayoutContext) -> ImageFragmentInfo {
fn convert_length<'ln, N>(node: &N, name: &Atom) -> Option<Au>
where N: ThreadSafeLayoutNode<'ln> {
let element = node.as_element();
element.get_attr(&ns!(), name)
.and_then(|string| string.parse().ok())
.map(Au::from_px)
}

let image_or_metadata = url.and_then(|url| {
layout_context.get_or_request_image_or_meta(url, UsePlaceholder::Yes)
});
@@ -379,9 +380,7 @@ impl ImageFragmentInfo {
};

ImageFragmentInfo {
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
convert_length(node, &atom!("width")),
convert_length(node, &atom!("height"))),
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node),
image: image,
metadata: metadata,
}
@@ -436,30 +435,16 @@ impl ImageFragmentInfo {
pub struct ReplacedImageFragmentInfo {
pub computed_inline_size: Option<Au>,
pub computed_block_size: Option<Au>,
pub dom_inline_size: Option<Au>,
pub dom_block_size: Option<Au>,
pub writing_mode_is_vertical: bool,
}

impl ReplacedImageFragmentInfo {
pub fn new<'ln, N>(node: &N,
dom_width: Option<Au>,
dom_height: Option<Au>) -> ReplacedImageFragmentInfo
pub fn new<'ln, N>(node: &N) -> ReplacedImageFragmentInfo
where N: ThreadSafeLayoutNode<'ln> {
let is_vertical = node.style().writing_mode.is_vertical();
ReplacedImageFragmentInfo {
computed_inline_size: None,
computed_block_size: None,
dom_inline_size: if is_vertical {
dom_height
} else {
dom_width
},
dom_block_size: if is_vertical {
dom_width
} else {
dom_height
},
writing_mode_is_vertical: is_vertical,
}
}
@@ -479,20 +464,18 @@ impl ReplacedImageFragmentInfo {
// `dom_length`: inline-size or block-size as specified in the `img` tag.
// `style_length`: inline-size as given in the CSS
pub fn style_length(style_length: LengthOrPercentageOrAuto,
dom_length: Option<Au>,
container_size: Option<Au>) -> MaybeAuto {
match (style_length, dom_length, container_size) {
(LengthOrPercentageOrAuto::Length(length), _, _) => MaybeAuto::Specified(length),
(LengthOrPercentageOrAuto::Percentage(pc), _, Some(container_size)) => {
match (style_length, container_size) {
(LengthOrPercentageOrAuto::Length(length), _) => MaybeAuto::Specified(length),
(LengthOrPercentageOrAuto::Percentage(pc), Some(container_size)) => {
MaybeAuto::Specified(container_size.scale_by(pc))
}
(LengthOrPercentageOrAuto::Percentage(_), _, None) => MaybeAuto::Auto,
(LengthOrPercentageOrAuto::Calc(calc), _, Some(container_size)) => {
(LengthOrPercentageOrAuto::Percentage(_), None) => MaybeAuto::Auto,
(LengthOrPercentageOrAuto::Calc(calc), Some(container_size)) => {
MaybeAuto::Specified(calc.length() + container_size.scale_by(calc.percentage()))
}
(LengthOrPercentageOrAuto::Calc(_), _, None) => MaybeAuto::Auto,
(LengthOrPercentageOrAuto::Auto, Some(dom_length), _) => MaybeAuto::Specified(dom_length),
(LengthOrPercentageOrAuto::Auto, None, _) => MaybeAuto::Auto,
(LengthOrPercentageOrAuto::Calc(_), None) => MaybeAuto::Auto,
(LengthOrPercentageOrAuto::Auto, _) => MaybeAuto::Auto,
}
}

@@ -513,7 +496,6 @@ impl ReplacedImageFragmentInfo {
// TODO(ksh8281): compute border,margin
let inline_size = ReplacedImageFragmentInfo::style_length(
style_inline_size,
self.dom_inline_size,
Some(container_inline_size));

let inline_size = match inline_size {
@@ -528,7 +510,6 @@ impl ReplacedImageFragmentInfo {

let specified_height = ReplacedImageFragmentInfo::style_length(
style_block_size,
self.dom_block_size,
None);
let specified_height = match specified_height {
MaybeAuto::Auto => intrinsic_height,
@@ -568,7 +549,6 @@ impl ReplacedImageFragmentInfo {
let inline_size = self.computed_inline_size();
let block_size = ReplacedImageFragmentInfo::style_length(
style_block_size,
self.dom_block_size,
containing_block_block_size);

let block_size = match block_size {
@@ -1342,29 +1322,32 @@ impl Fragment {
result.union_block(&block_flow.base.intrinsic_inline_sizes)
}
SpecificFragmentInfo::Image(ref mut image_fragment_info) => {
// FIXME(pcwalton): Shouldn't `width` and `height` be preshints?
let image_inline_size = match (image_fragment_info.replaced_image_fragment_info
.dom_inline_size,
self.style.content_inline_size()) {
(None, LengthOrPercentageOrAuto::Auto) |
(None, LengthOrPercentageOrAuto::Percentage(_)) => {
let image_inline_size = match self.style.content_inline_size() {
LengthOrPercentageOrAuto::Auto |
LengthOrPercentageOrAuto::Percentage(_) => {
image_fragment_info.image_inline_size()
}
(Some(dom_inline_size), _) => dom_inline_size,
(None, LengthOrPercentageOrAuto::Length(length)) => length,
(None, LengthOrPercentageOrAuto::Calc(calc)) => calc.length(),
LengthOrPercentageOrAuto::Length(length) => length,
LengthOrPercentageOrAuto::Calc(calc) => calc.length(),
};
result.union_block(&IntrinsicISizes {
minimum_inline_size: image_inline_size,
preferred_inline_size: image_inline_size,
});
}
SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => {
let canvas_inline_size = canvas_fragment_info.canvas_inline_size();
let canvas_inline_size = match self.style.content_inline_size() {
LengthOrPercentageOrAuto::Auto |
LengthOrPercentageOrAuto::Percentage(_) => {
canvas_fragment_info.canvas_inline_size()
}
LengthOrPercentageOrAuto::Length(length) => length,
LengthOrPercentageOrAuto::Calc(calc) => calc.length(),
};
result.union_block(&IntrinsicISizes {
minimum_inline_size: canvas_inline_size,
preferred_inline_size: canvas_inline_size,
})
});
}
SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
let range = &text_fragment_info.range;
@@ -1876,6 +1859,16 @@ impl Fragment {
ascent: computed_block_size + self.border_padding.block_start,
}
}
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
let computed_block_size = canvas_fragment_info.replaced_image_fragment_info
.computed_block_size();
InlineMetrics {
block_size_above_baseline: computed_block_size +
self.border_padding.block_start,
depth_below_baseline: self.border_padding.block_end,
ascent: computed_block_size + self.border_padding.block_start,
}
}
SpecificFragmentInfo::ScannedText(ref text_fragment) => {
// See CSS 2.1 § 10.8.1.
let line_height = self.calculate_line_height(layout_context);
@@ -43,6 +43,7 @@ use dom::htmlfieldsetelement::HTMLFieldSetElement;
use dom::htmlfontelement::{HTMLFontElement, HTMLFontElementLayoutHelpers};
use dom::htmlhrelement::{HTMLHRElement, HTMLHRLayoutHelpers};
use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
use dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use dom::htmllabelelement::HTMLLabelElement;
use dom::htmllegendelement::HTMLLegendElement;
@@ -392,6 +393,8 @@ impl LayoutElementHelpers for LayoutJS<Element> {

let width = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
this.get_width()
} else if let Some(this) = self.downcast::<HTMLImageElement>() {
this.get_width()
} else if let Some(this) = self.downcast::<HTMLTableElement>() {
this.get_width()
} else if let Some(this) = self.downcast::<HTMLTableCellElement>() {
@@ -422,6 +425,8 @@ impl LayoutElementHelpers for LayoutJS<Element> {

let height = if let Some(this) = self.downcast::<HTMLIFrameElement>() {
this.get_height()
} else if let Some(this) = self.downcast::<HTMLImageElement>() {
this.get_height()
} else {
LengthOrPercentageOrAuto::Auto
};
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use dom::attr::Attr;
use dom::attr::AttrValue;
use dom::bindings::cell::DOMRefCell;
@@ -14,10 +15,11 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{LayoutJS, Root};
use dom::bindings::refcounted::Trusted;
use dom::document::Document;
use dom::element::AttributeMutation;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::eventtarget::EventTarget;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeDamage, document_from_node, window_from_node};
use dom::values::UNSIGNED_LONG_MAX;
use dom::virtualmethods::VirtualMethods;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
@@ -28,7 +30,7 @@ use script_thread::{CommonScriptMsg, Runnable, ScriptChan};
use std::sync::Arc;
use string_cache::Atom;
use url::Url;
use util::str::DOMString;
use util::str::{DOMString, LengthOrPercentageOrAuto};

#[dom_struct]
pub struct HTMLImageElement {
@@ -171,6 +173,9 @@ pub trait LayoutHTMLImageElementHelpers {

#[allow(unsafe_code)]
unsafe fn image_url(&self) -> Option<Url>;

fn get_width(&self) -> LengthOrPercentageOrAuto;
fn get_height(&self) -> LengthOrPercentageOrAuto;
}

impl LayoutHTMLImageElementHelpers for LayoutJS<HTMLImageElement> {
@@ -183,6 +188,28 @@ impl LayoutHTMLImageElementHelpers for LayoutJS<HTMLImageElement> {
unsafe fn image_url(&self) -> Option<Url> {
(*self.unsafe_get()).url.borrow_for_layout().clone()
}

#[allow(unsafe_code)]
fn get_width(&self) -> LengthOrPercentageOrAuto {
unsafe {
(*self.upcast::<Element>().unsafe_get())
.get_attr_for_layout(&ns!(), &atom!("width"))
.map(AttrValue::as_dimension)
.cloned()
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
}

#[allow(unsafe_code)]
fn get_height(&self) -> LengthOrPercentageOrAuto {
unsafe {
(*self.upcast::<Element>().unsafe_get())
.get_attr_for_layout(&ns!(), &atom!("height"))
.map(AttrValue::as_dimension)
.cloned()
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
}
}

impl HTMLImageElementMethods for HTMLImageElement {
@@ -214,7 +241,9 @@ impl HTMLImageElementMethods for HTMLImageElement {
}

// https://html.spec.whatwg.org/multipage/#dom-img-width
make_uint_setter!(SetWidth, "width");
fn SetWidth(&self, value: u32) {
image_dimension_setter(self.upcast(), atom!("width"), value);
}

// https://html.spec.whatwg.org/multipage/#dom-img-height
fn Height(&self) -> u32 {
@@ -224,7 +253,9 @@ impl HTMLImageElementMethods for HTMLImageElement {
}

// https://html.spec.whatwg.org/multipage/#dom-img-height
make_uint_setter!(SetHeight, "height");
fn SetHeight(&self, value: u32) {
image_dimension_setter(self.upcast(), atom!("height"), value);
}

// https://html.spec.whatwg.org/multipage/#dom-img-naturalwidth
fn NaturalWidth(&self) -> u32 {
@@ -310,9 +341,22 @@ impl VirtualMethods for HTMLImageElement {
fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
match name {
&atom!("name") => AttrValue::from_atomic(value),
&atom!("width") | &atom!("height") |
&atom!("width") | &atom!("height") => AttrValue::from_dimension(value),
&atom!("hspace") | &atom!("vspace") => AttrValue::from_u32(value, 0),
_ => self.super_type().unwrap().parse_plain_attribute(name, value),
}
}
}

fn image_dimension_setter(element: &Element, attr: Atom, value: u32) {
// This setter is a bit weird: the IDL type is unsigned long, but it's parsed as
// a dimension for rendering.
let value = if value > UNSIGNED_LONG_MAX {
0
} else {
value
};
let dim = LengthOrPercentageOrAuto::Length(Au::from_px(value as i32));
let value = AttrValue::Dimension(DOMString::from(value.to_string()), dim);
element.set_attribute(&attr, value);
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit 7b671d1

Please sign in to comment.
You can’t perform that action at this time.