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.
This commit is contained in:
Eli Friedman 2015-11-14 16:56:42 -08:00 committed by Josh Matthews
parent b188cb542e
commit 7b671d13a0
56 changed files with 5505 additions and 853 deletions

View file

@ -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);