servo: Merge #9743 - Use presentation hints correctly for the dimensions of `<img>` (from jdm:image-preshint-rebase); r=pcwalton

Mostly straightforward; includes some extra fixes to make `<canvas>`
work the same way as `<img>` for reflow.

Rebase of #8531.

Source-Repo: https://github.com/servo/servo
Source-Revision: 8c23cbb78b36ac143bbea3b2e64961bfc46d8e0d
This commit is contained in:
Eli Friedman 2016-02-26 00:40:32 +05:01
Родитель f20750fbd6
Коммит d54fe3d15b
3 изменённых файлов: 102 добавлений и 60 удалений

Просмотреть файл

@ -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,17 +1322,13 @@ 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,
@ -1360,11 +1336,18 @@ impl Fragment {
});
}
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);
}