зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
f20750fbd6
Коммит
d54fe3d15b
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче