aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/block.rs53
-rw-r--r--components/layout/construct.rs13
-rw-r--r--components/layout/display_list_builder.rs94
-rw-r--r--components/layout/flex.rs6
-rw-r--r--components/layout/fragment.rs759
-rw-r--r--components/layout/inline.rs4
-rw-r--r--components/layout/list_item.rs4
-rw-r--r--components/layout/model.rs101
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-004.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-005.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-007.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/c43-rpl-bbx-002.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/c44-ln-box-003.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-004.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-005.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-007.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-004.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-005.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-007.htm.ini3
-rw-r--r--tests/wpt/metadata-css/css21_dev/html4/max-height-percentage-003.htm.ini3
20 files changed, 401 insertions, 669 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 45de8786778..6db30de9bec 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -42,12 +42,11 @@ use flow::IS_ABSOLUTELY_POSITIONED;
use flow_list::FlowList;
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
use fragment::{IS_INLINE_FLEX_ITEM, IS_BLOCK_FLEX_ITEM};
-use fragment::SpecificFragmentInfo;
use gfx::display_list::{ClippingRegion, StackingContext};
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree;
use layout_debug;
-use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto};
+use model::{AdjoiningMargins, CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto};
use model::{specified, specified_or_none};
use sequential;
use serde::{Serialize, Serializer};
@@ -555,7 +554,7 @@ impl BlockFlow {
/// relevant margins for this Block.
pub fn block_type(&self) -> BlockType {
if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
- if self.is_replaced_content() {
+ if self.fragment.is_replaced() {
BlockType::AbsoluteReplaced
} else {
BlockType::AbsoluteNonReplaced
@@ -563,19 +562,19 @@ impl BlockFlow {
} else if self.is_inline_flex_item() {
BlockType::InlineFlexItem
} else if self.base.flags.is_float() {
- if self.is_replaced_content() {
+ if self.fragment.is_replaced() {
BlockType::FloatReplaced
} else {
BlockType::FloatNonReplaced
}
} else if self.is_inline_block() {
- if self.is_replaced_content() {
+ if self.fragment.is_replaced() {
BlockType::InlineBlockReplaced
} else {
BlockType::InlineBlockNonReplaced
}
} else {
- if self.is_replaced_content() {
+ if self.fragment.is_replaced() {
BlockType::Replaced
} else {
BlockType::NonReplaced
@@ -668,22 +667,6 @@ impl BlockFlow {
}
}
- /// Return true if this has a replaced fragment.
- ///
- /// Text, Images, Inline Block and Canvas
- /// (https://html.spec.whatwg.org/multipage/#replaced-elements) fragments are considered as
- /// replaced fragments.
- fn is_replaced_content(&self) -> bool {
- match self.fragment.specific {
- SpecificFragmentInfo::ScannedText(_) |
- SpecificFragmentInfo::Svg(_) |
- SpecificFragmentInfo::Image(_) |
- SpecificFragmentInfo::Canvas(_) |
- SpecificFragmentInfo::InlineBlock(_) => true,
- _ => false,
- }
- }
-
/// Return shrink-to-fit inline-size.
///
/// This is where we use the preferred inline-sizes and minimum inline-sizes
@@ -1267,11 +1250,11 @@ impl BlockFlow {
let available_block_size = containing_block_block_size -
self.fragment.border_padding.block_start_end();
- if self.is_replaced_content() {
+ if self.fragment.is_replaced() {
// Calculate used value of block-size just like we do for inline replaced elements.
// TODO: Pass in the containing block block-size when Fragment's
// assign-block-size can handle it correctly.
- self.fragment.assign_replaced_block_size_if_necessary(Some(containing_block_block_size));
+ self.fragment.assign_replaced_block_size_if_necessary();
// TODO: Right now, this content block-size value includes the
// margin because of erroneous block-size calculation in fragment.
// Check this when that has been fixed.
@@ -1896,16 +1879,22 @@ impl Flow for BlockFlow {
fn fragment(&mut self, layout_context: &LayoutContext,
fragmentation_context: Option<FragmentationContext>)
-> Option<Arc<Flow>> {
- if self.is_replaced_content() {
+ if self.fragment.is_replaced() {
let _scope = layout_debug_scope!("assign_replaced_block_size_if_necessary {:x}",
self.base.debug_id());
// Assign block-size for fragment if it is an image fragment.
- let containing_block_block_size =
- self.base.block_container_explicit_block_size;
- self.fragment.assign_replaced_block_size_if_necessary(containing_block_block_size);
+ self.fragment.assign_replaced_block_size_if_necessary();
if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
self.base.position.size.block = self.fragment.border_box.size.block;
+ let mut block_start = AdjoiningMargins::from_margin(self.fragment.margin.block_start);
+ let block_end = AdjoiningMargins::from_margin(self.fragment.margin.block_end);
+ if self.fragment.border_box.size.block == Au(0) {
+ block_start.union(block_end);
+ self.base.collapsible_margins = CollapsibleMargins::CollapseThrough(block_start);
+ } else {
+ self.base.collapsible_margins = CollapsibleMargins::Collapse(block_start, block_end);
+ }
self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
self.fragment.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
}
@@ -2870,7 +2859,7 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size, container_block_size);
// For replaced absolute flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
- MaybeAuto::Specified(fragment.content_inline_size())
+ MaybeAuto::Specified(fragment.content_box().size.inline)
}
fn containing_block_inline_size(&self,
@@ -2929,7 +2918,7 @@ impl ISizeAndMarginsComputer for BlockReplaced {
fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size, container_block_size);
// For replaced block flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
- MaybeAuto::Specified(fragment.content_inline_size())
+ MaybeAuto::Specified(fragment.content_box().size.inline)
}
}
@@ -2987,7 +2976,7 @@ impl ISizeAndMarginsComputer for FloatReplaced {
fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size, container_block_size);
// For replaced block flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
- MaybeAuto::Specified(fragment.content_inline_size())
+ MaybeAuto::Specified(fragment.content_box().size.inline)
}
}
@@ -3075,7 +3064,7 @@ impl ISizeAndMarginsComputer for InlineBlockReplaced {
fragment.assign_replaced_inline_size_if_necessary(parent_flow_inline_size, container_block_size);
// For replaced block flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
- MaybeAuto::Specified(fragment.content_inline_size())
+ MaybeAuto::Specified(fragment.content_box().size.inline)
}
}
diff --git a/components/layout/construct.rs b/components/layout/construct.rs
index f3309b97b75..b25923d19c2 100644
--- a/components/layout/construct.rs
+++ b/components/layout/construct.rs
@@ -346,14 +346,12 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
SpecificFragmentInfo::Iframe(IframeFragmentInfo::new(node))
}
Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) => {
- let image_info = box ImageFragmentInfo::new(node,
- node.image_url(),
+ let image_info = box ImageFragmentInfo::new(node.image_url(),
&self.layout_context.shared);
SpecificFragmentInfo::Image(image_info)
}
Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => {
- let image_info = box ImageFragmentInfo::new(node,
- node.object_data(),
+ let image_info = box ImageFragmentInfo::new(node.object_data(),
&self.layout_context.shared);
SpecificFragmentInfo::Image(image_info)
}
@@ -372,11 +370,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) => {
let data = node.canvas_data().unwrap();
- SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node, data, self.style_context()))
+ SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(data))
}
Some(LayoutNodeType::Element(LayoutElementType::SVGSVGElement)) => {
let data = node.svg_data().unwrap();
- SpecificFragmentInfo::Svg(box SvgFragmentInfo::new(node, data, self.style_context()))
+ SpecificFragmentInfo::Svg(box SvgFragmentInfo::new(data))
}
_ => {
// This includes pseudo-elements.
@@ -1207,8 +1205,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let flotation = FloatKind::from_property(flotation);
let marker_fragments = match node.style(self.style_context()).get_list().list_style_image {
Either::First(ref url_value) => {
- let image_info = box ImageFragmentInfo::new(node,
- url_value.url().map(|u| u.clone()),
+ let image_info = box ImageFragmentInfo::new(url_value.url().map(|u| u.clone()),
&self.layout_context.shared);
vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info), self.layout_context)]
}
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 0c34a147655..60b1ecedc19 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -1489,57 +1489,51 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
- let width = canvas_fragment_info.replaced_image_fragment_info
- .computed_inline_size.map_or(0, |w| w.to_px() as usize);
- let height = canvas_fragment_info.replaced_image_fragment_info
- .computed_block_size.map_or(0, |h| h.to_px() as usize);
- if width > 0 && height > 0 {
- let computed_width = canvas_fragment_info.canvas_inline_size().to_px();
- let computed_height = canvas_fragment_info.canvas_block_size().to_px();
-
- let canvas_data = match canvas_fragment_info.ipc_renderer {
- Some(ref ipc_renderer) => {
- let ipc_renderer = ipc_renderer.lock().unwrap();
- let (sender, receiver) = ipc::channel().unwrap();
- ipc_renderer.send(CanvasMsg::FromLayout(
- FromLayoutMsg::SendData(sender))).unwrap();
- receiver.recv().unwrap()
- },
- None => return,
- };
+ let computed_width = canvas_fragment_info.dom_width.to_px();
+ let computed_height = canvas_fragment_info.dom_height.to_px();
+
+ let canvas_data = match canvas_fragment_info.ipc_renderer {
+ Some(ref ipc_renderer) => {
+ let ipc_renderer = ipc_renderer.lock().unwrap();
+ let (sender, receiver) = ipc::channel().unwrap();
+ ipc_renderer.send(CanvasMsg::FromLayout(
+ FromLayoutMsg::SendData(sender))).unwrap();
+ receiver.recv().unwrap()
+ },
+ None => return,
+ };
+
+ let base = state.create_base_display_item(
+ &stacking_relative_content_box,
+ clip,
+ self.node,
+ self.style.get_cursor(Cursor::Default),
+ DisplayListSection::Content);
+ let display_item = match canvas_data {
+ CanvasData::Image(canvas_data) => {
+ DisplayItem::Image(box ImageDisplayItem {
+ base: base,
+ webrender_image: WebRenderImageInfo {
+ width: computed_width as u32,
+ height: computed_height as u32,
+ format: PixelFormat::RGBA8,
+ key: Some(canvas_data.image_key),
+ },
+ image_data: None,
+ stretch_size: stacking_relative_content_box.size,
+ tile_spacing: Size2D::zero(),
+ image_rendering: image_rendering::T::auto,
+ })
+ }
+ CanvasData::WebGL(context_id) => {
+ DisplayItem::WebGL(box WebGLDisplayItem {
+ base: base,
+ context_id: context_id,
+ })
+ }
+ };
- let base = state.create_base_display_item(
- &stacking_relative_content_box,
- clip,
- self.node,
- self.style.get_cursor(Cursor::Default),
- DisplayListSection::Content);
- let display_item = match canvas_data {
- CanvasData::Image(canvas_data) => {
- DisplayItem::Image(box ImageDisplayItem {
- base: base,
- webrender_image: WebRenderImageInfo {
- width: computed_width as u32,
- height: computed_height as u32,
- format: PixelFormat::RGBA8,
- key: Some(canvas_data.image_key),
- },
- image_data: None,
- stretch_size: stacking_relative_content_box.size,
- tile_spacing: Size2D::zero(),
- image_rendering: image_rendering::T::auto,
- })
- }
- CanvasData::WebGL(context_id) => {
- DisplayItem::WebGL(box WebGLDisplayItem {
- base: base,
- context_id: context_id,
- })
- }
- };
-
- state.add_display_item(display_item);
- }
+ state.add_display_item(display_item);
}
SpecificFragmentInfo::UnscannedText(_) => {
panic!("Shouldn't see unscanned fragments here.")
diff --git a/components/layout/flex.rs b/components/layout/flex.rs
index d84373a7c21..7b169674363 100644
--- a/components/layout/flex.rs
+++ b/components/layout/flex.rs
@@ -19,7 +19,7 @@ use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use layout_debug;
-use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint};
+use model::{IntrinsicISizes, MaybeAuto, SizeConstraint};
use model::{specified, specified_or_none};
use std::cmp::{max, min};
use std::ops::Range;
@@ -38,7 +38,7 @@ use style::values::computed::{LengthOrPercentageOrAutoOrContent, LengthOrPercent
#[derive(Debug)]
enum AxisSize {
Definite(Au),
- MinMax(MinMaxConstraint),
+ MinMax(SizeConstraint),
Infinite,
}
@@ -62,7 +62,7 @@ impl AxisSize {
}
}
LengthOrPercentageOrAuto::Auto => {
- AxisSize::MinMax(MinMaxConstraint::new(content_size, min, max))
+ AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None))
}
}
}
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index f2ba5e83916..e5d86e78ed5 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -23,7 +23,8 @@ use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT, LineMetrics};
use ipc_channel::ipc::IpcSender;
#[cfg(debug_assertions)]
use layout_debug;
-use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
+use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeConstraint};
+use model::style_length;
use msg::constellation_msg::PipelineId;
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
@@ -34,7 +35,7 @@ use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayou
use serde::{Serialize, Serializer};
use servo_url::ServoUrl;
use std::borrow::ToOwned;
-use std::cmp::{max, min};
+use std::cmp::{Ordering, max, min};
use std::collections::LinkedList;
use std::fmt;
use std::sync::{Arc, Mutex};
@@ -43,7 +44,6 @@ use style::computed_values::{border_collapse, box_sizing, clear, color, display,
use style::computed_values::{overflow_wrap, overflow_x, position, text_decoration};
use style::computed_values::{transform_style, vertical_align, white_space, word_break, z_index};
use style::computed_values::content::ContentItem;
-use style::context::SharedStyleContext;
use style::logical_geometry::{Direction, LogicalMargin, LogicalRect, LogicalSize, WritingMode};
use style::properties::ServoComputedValues;
use style::selector_parser::RestyleDamage;
@@ -51,7 +51,6 @@ use style::servo::restyle_damage::RECONSTRUCT_FLOW;
use style::str::char_is_whitespace;
use style::values::Either;
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
-use style::values::computed::LengthOrPercentageOrNone;
use text;
use text::TextRunScanner;
@@ -59,6 +58,10 @@ use text::TextRunScanner;
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
static FONT_SUPERSCRIPT_OFFSET_RATIO: f32 = 0.34;
+// https://drafts.csswg.org/css-images/#default-object-size
+static DEFAULT_REPLACED_WIDTH: i32 = 300;
+static DEFAULT_REPLACED_HEIGHT: i32 = 150;
+
/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
/// specification:
@@ -247,21 +250,6 @@ impl fmt::Debug for SpecificFragmentInfo {
}
}
-/// Clamp a value obtained from style_length, based on min / max lengths.
-fn clamp_size(size: Au,
- min_size: LengthOrPercentage,
- max_size: LengthOrPercentageOrNone,
- container_size: Au)
- -> Au {
- let min_size = model::specified(min_size, container_size);
- let max_size = model::specified_or_none(max_size, container_size);
-
- max(min_size, match max_size {
- None => size,
- Some(max_size) => min(size, max_size),
- })
-}
-
/// Information for generated content.
#[derive(Clone)]
pub enum GeneratedContentInfo {
@@ -326,89 +314,41 @@ impl InlineAbsoluteFragmentInfo {
#[derive(Clone)]
pub struct CanvasFragmentInfo {
- pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub ipc_renderer: Option<Arc<Mutex<IpcSender<CanvasMsg>>>>,
pub dom_width: Au,
pub dom_height: Au,
}
impl CanvasFragmentInfo {
- pub fn new<N: ThreadSafeLayoutNode>(node: &N,
- data: HTMLCanvasData,
- ctx: &SharedStyleContext)
- -> CanvasFragmentInfo {
+ pub fn new(data: HTMLCanvasData) -> CanvasFragmentInfo {
CanvasFragmentInfo {
- replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, ctx),
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 {
- 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 {
- if self.replaced_image_fragment_info.writing_mode_is_vertical {
- self.dom_width
- } else {
- self.dom_height
- }
- }
}
#[derive(Clone)]
pub struct SvgFragmentInfo {
- pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub dom_width: Au,
pub dom_height: Au,
}
impl SvgFragmentInfo {
- pub fn new<N: ThreadSafeLayoutNode>(node: &N,
- data: SVGSVGData,
- ctx: &SharedStyleContext)
- -> SvgFragmentInfo {
+ pub fn new(data: SVGSVGData) -> SvgFragmentInfo {
SvgFragmentInfo {
- replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, ctx),
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 SVG element.
- pub fn svg_inline_size(&self) -> Au {
- if self.replaced_image_fragment_info.writing_mode_is_vertical {
- self.dom_height
- } else {
- self.dom_width
- }
- }
-
- /// Returns the original block-size of the SVG element.
- pub fn svg_block_size(&self) -> Au {
- if self.replaced_image_fragment_info.writing_mode_is_vertical {
- self.dom_width
- } else {
- self.dom_height
- }
- }
}
/// A fragment that represents a replaced content image and its accompanying borders, shadows, etc.
#[derive(Clone)]
pub struct ImageFragmentInfo {
- /// The image held within this fragment.
- pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub image: Option<Arc<Image>>,
pub metadata: Option<ImageMetadata>,
}
@@ -418,9 +358,9 @@ impl ImageFragmentInfo {
///
/// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little
/// sense to me.
- pub fn new<N: ThreadSafeLayoutNode>(node: &N, url: Option<ServoUrl>,
- shared_layout_context: &SharedLayoutContext)
- -> ImageFragmentInfo {
+ pub fn new(url: Option<ServoUrl>,
+ shared_layout_context: &SharedLayoutContext)
+ -> ImageFragmentInfo {
let image_or_metadata = url.and_then(|url| {
shared_layout_context.get_or_request_image_or_meta(url, UsePlaceholder::Yes)
});
@@ -438,40 +378,11 @@ impl ImageFragmentInfo {
};
ImageFragmentInfo {
- replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, &shared_layout_context.style_context),
image: image,
metadata: metadata,
}
}
- /// Returns the original inline-size of the image.
- pub fn image_inline_size(&mut self) -> Au {
- match self.metadata {
- Some(ref metadata) => {
- Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
- metadata.height
- } else {
- metadata.width
- } as i32)
- }
- None => Au(0)
- }
- }
-
- /// Returns the original block-size of the image.
- pub fn image_block_size(&mut self) -> Au {
- match self.metadata {
- Some(ref metadata) => {
- Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
- metadata.width
- } else {
- metadata.height
- } as i32)
- }
- None => Au(0)
- }
- }
-
pub fn tile_image_round(position: &mut Au,
size: &mut Au,
absolute_anchor_origin: Au,
@@ -544,149 +455,6 @@ impl ImageFragmentInfo {
}
}
-#[derive(Clone)]
-pub struct ReplacedImageFragmentInfo {
- pub computed_inline_size: Option<Au>,
- pub computed_block_size: Option<Au>,
- pub writing_mode_is_vertical: bool,
-}
-
-impl ReplacedImageFragmentInfo {
- pub fn new<N>(node: &N, ctx: &SharedStyleContext) -> ReplacedImageFragmentInfo
- where N: ThreadSafeLayoutNode {
- let is_vertical = node.style(ctx).writing_mode.is_vertical();
- ReplacedImageFragmentInfo {
- computed_inline_size: None,
- computed_block_size: None,
- writing_mode_is_vertical: is_vertical,
- }
- }
-
- /// Returns the calculated inline-size of the image, accounting for the inline-size attribute.
- pub fn computed_inline_size(&self) -> Au {
- self.computed_inline_size.expect("image inline_size is not computed yet!")
- }
-
- /// Returns the calculated block-size of the image, accounting for the block-size attribute.
- pub fn computed_block_size(&self) -> Au {
- self.computed_block_size.expect("image block_size is not computed yet!")
- }
-
- // Return used value for inline-size or block-size.
- //
- // `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,
- container_size: Option<Au>) -> MaybeAuto {
- 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)) => {
- MaybeAuto::Specified(calc.length() + container_size.scale_by(calc.percentage()))
- }
- (LengthOrPercentageOrAuto::Calc(_), None) => MaybeAuto::Auto,
- (LengthOrPercentageOrAuto::Auto, _) => MaybeAuto::Auto,
- }
- }
-
- pub fn calculate_replaced_inline_size(&mut self,
- style: &ServoComputedValues,
- noncontent_inline_size: Au,
- container_inline_size: Au,
- container_block_size: Option<Au>,
- fragment_inline_size: Au,
- fragment_block_size: Au)
- -> Au {
- let style_inline_size = style.content_inline_size();
- let style_block_size = style.content_block_size();
- let style_min_inline_size = style.min_inline_size();
- let style_max_inline_size = style.max_inline_size();
- let style_min_block_size = style.min_block_size();
- let style_max_block_size = style.max_block_size();
-
- // TODO(ksh8281): compute border,margin
- let inline_size = ReplacedImageFragmentInfo::style_length(
- style_inline_size,
- Some(container_inline_size));
-
- let inline_size = match inline_size {
- MaybeAuto::Auto => {
- let intrinsic_width = fragment_inline_size;
- let intrinsic_height = fragment_block_size;
- if intrinsic_height == Au(0) {
- intrinsic_width
- } else {
- let ratio = intrinsic_width.to_f32_px() /
- intrinsic_height.to_f32_px();
-
- let specified_height = ReplacedImageFragmentInfo::style_length(
- style_block_size,
- container_block_size);
- let specified_height = match specified_height {
- MaybeAuto::Auto => intrinsic_height,
- MaybeAuto::Specified(h) => h,
- };
- let specified_height = clamp_size(specified_height,
- style_min_block_size,
- style_max_block_size,
- Au(0));
- Au::from_f32_px(specified_height.to_f32_px() * ratio)
- }
- },
- MaybeAuto::Specified(w) => w,
- };
-
- let inline_size = clamp_size(inline_size,
- style_min_inline_size,
- style_max_inline_size,
- container_inline_size);
-
- self.computed_inline_size = Some(inline_size);
- inline_size + noncontent_inline_size
- }
-
- /// Here, `noncontent_block_size` represents the sum of border and padding, but not margin.
- pub fn calculate_replaced_block_size(&mut self,
- style: &ServoComputedValues,
- noncontent_block_size: Au,
- containing_block_block_size: Option<Au>,
- fragment_inline_size: Au,
- fragment_block_size: Au)
- -> Au {
- let style_block_size = style.content_block_size();
- let style_min_block_size = style.min_block_size();
- let style_max_block_size = style.max_block_size();
-
- let inline_size = self.computed_inline_size();
- let block_size = ReplacedImageFragmentInfo::style_length(
- style_block_size,
- containing_block_block_size);
-
- let block_size = match block_size {
- MaybeAuto::Auto => {
- let intrinsic_width = fragment_inline_size;
- let intrinsic_height = fragment_block_size;
- let scale = intrinsic_width.to_f32_px() / inline_size.to_f32_px();
- Au::from_f32_px(intrinsic_height.to_f32_px() / scale)
- },
- MaybeAuto::Specified(h) => {
- h
- }
- };
-
- let block_size = clamp_size(block_size,
- style_min_block_size,
- style_max_block_size,
- Au(0));
-
- self.computed_block_size = Some(block_size);
- block_size + noncontent_block_size
- }
-}
-
/// A fragment that represents an inline frame (iframe). This stores the pipeline ID so that the
/// size of this iframe can be communicated via the constellation to the iframe's own layout thread.
#[derive(Clone)]
@@ -703,52 +471,6 @@ impl IframeFragmentInfo {
pipeline_id: pipeline_id,
}
}
-
- #[inline]
- pub fn calculate_replaced_inline_size(&self, style: &ServoComputedValues, containing_size: Au)
- -> Au {
- // Calculate the replaced inline size (or default) as per CSS 2.1 § 10.3.2
- IframeFragmentInfo::calculate_replaced_size(style.content_inline_size(),
- style.min_inline_size(),
- style.max_inline_size(),
- Some(containing_size),
- Au::from_px(300))
- }
-
- #[inline]
- pub fn calculate_replaced_block_size(&self, style: &ServoComputedValues, containing_size: Option<Au>)
- -> Au {
- // Calculate the replaced block size (or default) as per CSS 2.1 § 10.3.2
- IframeFragmentInfo::calculate_replaced_size(style.content_block_size(),
- style.min_block_size(),
- style.max_block_size(),
- containing_size,
- Au::from_px(150))
-
- }
-
- fn calculate_replaced_size(content_size: LengthOrPercentageOrAuto,
- style_min_size: LengthOrPercentage,
- style_max_size: LengthOrPercentageOrNone,
- containing_size: Option<Au>,
- default_size: Au) -> Au {
- let computed_size = match (content_size, containing_size) {
- (LengthOrPercentageOrAuto::Length(length), _) => length,
- (LengthOrPercentageOrAuto::Percentage(pc), Some(container_size)) => container_size.scale_by(pc),
- (LengthOrPercentageOrAuto::Calc(calc), Some(container_size)) => {
- container_size.scale_by(calc.percentage()) + calc.length()
- },
- (LengthOrPercentageOrAuto::Calc(calc), None) => calc.length(),
- (LengthOrPercentageOrAuto::Percentage(_), None) => default_size,
- (LengthOrPercentageOrAuto::Auto, _) => default_size,
- };
-
- let containing_size = containing_size.unwrap_or(Au(0));
- clamp_size(computed_size,
- style_min_size,
- style_max_size,
- containing_size)
- }
}
/// A scanned text fragment represents a single run of text with a distinct style. A `TextFragment`
@@ -1202,6 +924,198 @@ impl Fragment {
}
}
+ /// intrinsic width of this replaced element.
+ #[inline]
+ pub fn intrinsic_width(&self) -> Au {
+ match self.specific {
+ SpecificFragmentInfo::Image(ref info) => {
+ if let Some(ref data) = info.metadata {
+ Au::from_px(data.width as i32)
+ } else {
+ Au(0)
+ }
+ }
+ SpecificFragmentInfo::Canvas(ref info) => info.dom_width,
+ SpecificFragmentInfo::Svg(ref info) => info.dom_width,
+ // Note: Currently for replaced element with no intrinsic size,
+ // this function simply returns the default object size. As long as
+ // these elements do not have intrinsic aspect ratio this should be
+ // sufficient, but we may need to investigate if this is enough for
+ // use cases like SVG.
+ SpecificFragmentInfo::Iframe(_) => Au::from_px(DEFAULT_REPLACED_WIDTH),
+ _ => panic!("Trying to get intrinsic width on non-replaced element!")
+ }
+ }
+
+ /// intrinsic width of this replaced element.
+ #[inline]
+ pub fn intrinsic_height(&self) -> Au {
+ match self.specific {
+ SpecificFragmentInfo::Image(ref info) => {
+ if let Some(ref data) = info.metadata {
+ Au::from_px(data.height as i32)
+ } else {
+ Au(0)
+ }
+ }
+ SpecificFragmentInfo::Canvas(ref info) => info.dom_height,
+ SpecificFragmentInfo::Svg(ref info) => info.dom_height,
+ SpecificFragmentInfo::Iframe(_) => Au::from_px(DEFAULT_REPLACED_HEIGHT),
+ _ => panic!("Trying to get intrinsic height on non-replaced element!")
+ }
+ }
+
+ /// Whether this replace element has intrinsic aspect ratio.
+ pub fn has_intrinsic_ratio(&self) -> bool {
+ match self.specific {
+ SpecificFragmentInfo::Image(_) |
+ SpecificFragmentInfo::Canvas(_) |
+ // TODO(stshine): According to the SVG spec, whether a SVG element has intrinsic
+ // aspect ratio is determined by the `preserveAspectRatio` attribute. Since for
+ // now SVG is far from implemented, we simply choose the default behavior that
+ // the intrinsic aspect ratio is preserved.
+ // https://svgwg.org/svg2-draft/coords.html#PreserveAspectRatioAttribute
+ SpecificFragmentInfo::Svg(_) =>
+ self.intrinsic_width() != Au(0) && self.intrinsic_height() != Au(0),
+ _ => false
+ }
+ }
+
+ /// CSS 2.1 § 10.3.2 & 10.6.2 Calculate the used width and height of a replaced element.
+ /// When a parameter is `None` it means the specified size in certain direction
+ /// is unconstrained. The inline containing size can also be `None` since this
+ /// method is also used for calculating intrinsic inline size contribution.
+ pub fn calculate_replaced_sizes(&self,
+ containing_inline_size: Option<Au>,
+ containing_block_size: Option<Au>)
+ -> (Au, Au) {
+ let (intrinsic_inline_size, intrinsic_block_size) = if self.style.writing_mode.is_vertical() {
+ (self.intrinsic_height(), self.intrinsic_width())
+ } else {
+ (self.intrinsic_width(), self.intrinsic_height())
+ };
+
+ // Make sure the size we used here is for content box since they may be
+ // transferred by the intrinsic aspect ratio.
+ let inline_size = style_length(self.style.content_inline_size(), containing_inline_size)
+ .map(|x| x - self.box_sizing_boundary(Direction::Inline));
+ let block_size = style_length(self.style.content_block_size(), containing_block_size)
+ .map(|x| x - self.box_sizing_boundary(Direction::Block));
+ let inline_constraint = self.size_constraint(containing_inline_size, Direction::Inline);
+ let block_constraint = self.size_constraint(containing_block_size, Direction::Block);
+
+ // https://drafts.csswg.org/css-images-3/#default-sizing
+ match (inline_size, block_size) {
+ // If the specified size is a definite width and height, the concrete
+ // object size is given that width and height.
+ (MaybeAuto::Specified(inline_size), MaybeAuto::Specified(block_size)) =>
+ (inline_constraint.clamp(inline_size), block_constraint.clamp(block_size)),
+
+ // If the specified size is only a width or height (but not both)
+ // then the concrete object size is given that specified width or
+ // height. The other dimension is calculated as follows:
+ //
+ // If the object has an intrinsic aspect ratio, the missing dimension
+ // of the concrete object size is calculated using the intrinsic
+ // aspect ratio and the present dimension.
+ //
+ // Otherwise, if the missing dimension is present in the object’s intrinsic
+ // dimensions, the missing dimension is taken from the object’s intrinsic
+ // dimensions. Otherwise it is taken from the default object size.
+ (MaybeAuto::Specified(inline_size), MaybeAuto::Auto) => {
+ let inline_size = inline_constraint.clamp(inline_size);
+ let block_size = if self.has_intrinsic_ratio() {
+ // Note: We can not precompute the ratio and store it as a float, because
+ // doing so may result one pixel difference in calculation for certain
+ // images, thus make some tests fail.
+ inline_size * intrinsic_block_size.0 / intrinsic_inline_size.0
+ } else {
+ intrinsic_block_size
+ };
+ (inline_size, block_constraint.clamp(block_size))
+ }
+ (MaybeAuto::Auto, MaybeAuto::Specified(block_size)) => {
+ let block_size = block_constraint.clamp(block_size);
+ let inline_size = if self.has_intrinsic_ratio() {
+ block_size * intrinsic_inline_size.0 / intrinsic_block_size.0
+ } else {
+ intrinsic_inline_size
+ };
+ (inline_constraint.clamp(inline_size), block_size)
+ }
+ // https://drafts.csswg.org/css2/visudet.html#min-max-widths
+ (MaybeAuto::Auto, MaybeAuto::Auto) => {
+ if self.has_intrinsic_ratio() {
+ // This approch follows the spirit of cover and contain constraint.
+ // https://drafts.csswg.org/css-images-3/#cover-contain
+
+ // First, create two rectangles that keep aspect ratio while may be clamped
+ // by the contraints;
+ let first_isize = inline_constraint.clamp(intrinsic_inline_size);
+ let first_bsize = first_isize * intrinsic_block_size.0 / intrinsic_inline_size.0;
+ let second_bsize = block_constraint.clamp(intrinsic_block_size);
+ let second_isize = second_bsize * intrinsic_inline_size.0 / intrinsic_block_size.0;
+
+ let (inline_size, block_size) = match (first_isize.cmp(&intrinsic_inline_size) ,
+ second_isize.cmp(&intrinsic_inline_size)) {
+ (Ordering::Equal, Ordering::Equal) =>
+ (first_isize, first_bsize),
+ // When only one rectangle is clamped, use it;
+ (Ordering::Equal, _) =>
+ (second_isize, second_bsize),
+ (_, Ordering::Equal) =>
+ (first_isize, first_bsize),
+ // When both rectangles grow (smaller than min sizes),
+ // Choose the larger one;
+ (Ordering::Greater, Ordering::Greater) =>
+ if first_isize > second_isize {
+ (first_isize, first_bsize)
+ } else {
+ (second_isize, second_bsize)
+ },
+ // When both rectangles shrink (larger than max sizes),
+ // Choose the smaller one;
+ (Ordering::Less, Ordering::Less) =>
+ if first_isize > second_isize {
+ (second_isize, second_bsize)
+ } else {
+ (first_isize, first_bsize)
+ },
+ // It does not matter which we choose here, because both sizes
+ // will be clamped to constraint;
+ (Ordering::Less, Ordering::Greater) | (Ordering::Greater, Ordering::Less) =>
+ (first_isize, first_bsize)
+ };
+ // Clamp the result and we are done :-)
+ (inline_constraint.clamp(inline_size), block_constraint.clamp(block_size))
+ } else {
+ (inline_constraint.clamp(intrinsic_inline_size),
+ block_constraint.clamp(intrinsic_block_size))
+ }
+ }
+ }
+ }
+
+ /// Return a size constraint that can be used the clamp size in given direction.
+ /// To take `box-sizing: border-box` into account, the `border_padding` field
+ /// must be initialized first.
+ ///
+ /// TODO(stshine): Maybe there is a more convenient way.
+ pub fn size_constraint(&self, containing_size: Option<Au>, direction: Direction) -> SizeConstraint {
+ let (style_min_size, style_max_size) = match direction {
+ Direction::Inline => (self.style.min_inline_size(), self.style.max_inline_size()),
+ Direction::Block => (self.style.min_block_size(), self.style.max_block_size())
+ };
+
+ let border = if self.style().get_position().box_sizing == box_sizing::T::border_box {
+ Some(self.border_padding.start_end(direction))
+ } else {
+ None
+ };
+
+ SizeConstraint::new(containing_size, style_min_size, style_max_size, border)
+ }
+
/// Returns a guess as to the distances from the margin edge of this fragment to its content
/// in the inline direction. This will generally be correct unless percentages are involved.
///
@@ -1254,7 +1168,7 @@ impl Fragment {
}
/// Returns the border width in given direction if this fragment has property
- /// 'box-sizing: border-box'. The `border_padding` field should have been initialized.
+ /// 'box-sizing: border-box'. The `border_padding` field must have been initialized.
pub fn box_sizing_boundary(&self, direction: Direction) -> Au {
match (self.style().get_position().box_sizing, direction) {
(box_sizing::T::border_box, Direction::Inline) => {
@@ -1531,7 +1445,6 @@ impl Fragment {
match self.specific {
SpecificFragmentInfo::Generic |
SpecificFragmentInfo::GeneratedContent(_) |
- SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Table |
SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableColumn(_) |
@@ -1548,66 +1461,42 @@ impl Fragment {
let block_flow = info.flow_ref.as_block();
result.union_block(&block_flow.base.intrinsic_inline_sizes)
}
- SpecificFragmentInfo::Image(ref mut image_fragment_info) => {
- let mut image_inline_size = match self.style.content_inline_size() {
- LengthOrPercentageOrAuto::Auto |
- LengthOrPercentageOrAuto::Percentage(_) => {
- image_fragment_info.image_inline_size()
- }
- LengthOrPercentageOrAuto::Length(length) => length,
- LengthOrPercentageOrAuto::Calc(calc) => calc.length(),
- };
-
- image_inline_size = max(model::specified(self.style.min_inline_size(), Au(0)), image_inline_size);
- if let Some(max) = model::specified_or_none(self.style.max_inline_size(), Au(0)) {
- image_inline_size = min(image_inline_size, max)
- }
-
- result.union_block(&IntrinsicISizes {
- minimum_inline_size: image_inline_size,
- preferred_inline_size: image_inline_size,
- });
- }
- SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => {
- let mut canvas_inline_size = match self.style.content_inline_size() {
+ SpecificFragmentInfo::Image(_) |
+ SpecificFragmentInfo::Canvas(_) |
+ SpecificFragmentInfo::Iframe(_) |
+ SpecificFragmentInfo::Svg(_) => {
+ let mut inline_size = match self.style.content_inline_size() {
LengthOrPercentageOrAuto::Auto |
LengthOrPercentageOrAuto::Percentage(_) => {
- canvas_fragment_info.canvas_inline_size()
+ // We have to initialize the `border_padding` field first to make
+ // the size constraints work properly.
+ // TODO(stshine): Find a cleaner way to do this.
+ let padding = self.style.logical_padding();
+ self.border_padding.inline_start = model::specified(padding.inline_start, Au(0));
+ self.border_padding.inline_end = model::specified(padding.inline_end, Au(0));
+ self.border_padding.block_start = model::specified(padding.block_start, Au(0));
+ self.border_padding.block_end = model::specified(padding.block_end, Au(0));
+ let border = self.border_width();
+ self.border_padding.inline_start += border.inline_start;
+ self.border_padding.inline_end += border.inline_end;
+ self.border_padding.block_start += border.block_start;
+ self.border_padding.block_end += border.block_end;
+ let (result_inline, _) = self.calculate_replaced_sizes(None, None);
+ result_inline
}
LengthOrPercentageOrAuto::Length(length) => length,
LengthOrPercentageOrAuto::Calc(calc) => calc.length(),
};
- canvas_inline_size = max(model::specified(self.style.min_inline_size(), Au(0)), canvas_inline_size);
- if let Some(max) = model::specified_or_none(self.style.max_inline_size(), Au(0)) {
- canvas_inline_size = min(canvas_inline_size, max)
- }
+ let size_constraint = self.size_constraint(None, Direction::Inline);
+ inline_size = size_constraint.clamp(inline_size);
result.union_block(&IntrinsicISizes {
- minimum_inline_size: canvas_inline_size,
- preferred_inline_size: canvas_inline_size,
+ minimum_inline_size: inline_size,
+ preferred_inline_size: inline_size,
});
}
- SpecificFragmentInfo::Svg(ref mut svg_fragment_info) => {
- let mut svg_inline_size = match self.style.content_inline_size() {
- LengthOrPercentageOrAuto::Auto |
- LengthOrPercentageOrAuto::Percentage(_) => {
- svg_fragment_info.svg_inline_size()
- }
- LengthOrPercentageOrAuto::Length(length) => length,
- LengthOrPercentageOrAuto::Calc(calc) => calc.length(),
- };
-
- svg_inline_size = max(model::specified(self.style.min_inline_size(), Au(0)), svg_inline_size);
- if let Some(max) = model::specified_or_none(self.style.max_inline_size(), Au(0)) {
- svg_inline_size = min(svg_inline_size, max)
- }
- result.union_block(&IntrinsicISizes {
- minimum_inline_size: svg_inline_size,
- preferred_inline_size: svg_inline_size,
- });
- }
SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
let range = &text_fragment_info.range;
@@ -1676,45 +1565,6 @@ impl Fragment {
}
}
- /// TODO: What exactly does this function return? Why is it Au(0) for
- /// `SpecificFragmentInfo::Generic`?
- pub fn content_inline_size(&self) -> Au {
- match self.specific {
- SpecificFragmentInfo::Generic |
- SpecificFragmentInfo::GeneratedContent(_) |
- SpecificFragmentInfo::Iframe(_) |
- SpecificFragmentInfo::Table |
- SpecificFragmentInfo::TableCell |
- SpecificFragmentInfo::TableRow |
- SpecificFragmentInfo::TableWrapper |
- SpecificFragmentInfo::Multicol |
- SpecificFragmentInfo::MulticolColumn |
- SpecificFragmentInfo::InlineBlock(_) |
- SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
- SpecificFragmentInfo::InlineAbsolute(_) => Au(0),
- SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
- canvas_fragment_info.replaced_image_fragment_info.computed_inline_size()
- }
- SpecificFragmentInfo::Svg(ref svg_fragment_info) => {
- svg_fragment_info.replaced_image_fragment_info.computed_inline_size()
- }
- SpecificFragmentInfo::Image(ref image_fragment_info) => {
- image_fragment_info.replaced_image_fragment_info.computed_inline_size()
- }
- SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
- let (range, run) = (&text_fragment_info.range, &text_fragment_info.run);
- let text_bounds = run.metrics_for_range(range).bounding_box;
- text_bounds.size.width
- }
- SpecificFragmentInfo::TableColumn(_) => {
- panic!("Table column fragments do not have inline_size")
- }
- SpecificFragmentInfo::UnscannedText(_) => {
- panic!("Unscanned text fragments should have been scanned by now!")
- }
- }
- }
-
/// Returns the dimensions of the content box.
///
/// This is marked `#[inline]` because it is frequently called when only one or two of the
@@ -1991,10 +1841,8 @@ impl Fragment {
SpecificFragmentInfo::Svg(_) => {}
};
- let style = &*self.style;
- let noncontent_inline_size = self.border_padding.inline_start_end();
-
match self.specific {
+ // Inline blocks
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
let block_flow = FlowRef::deref_mut(&mut info.flow_ref).as_mut_block();
block_flow.base.position.size.inline =
@@ -2019,54 +1867,24 @@ impl Fragment {
block_flow.base.block_container_inline_size = self.border_box.size.inline;
block_flow.base.block_container_writing_mode = self.style.writing_mode;
}
+
+ // Text
SpecificFragmentInfo::ScannedText(ref info) => {
// Scanned text fragments will have already had their content inline-sizes assigned
// by this point.
- self.border_box.size.inline = info.content_size.inline + noncontent_inline_size
+ self.border_box.size.inline = info.content_size.inline +
+ self.border_padding.inline_start_end();
}
- SpecificFragmentInfo::Image(ref mut image_fragment_info) => {
- let fragment_inline_size = image_fragment_info.image_inline_size();
- let fragment_block_size = image_fragment_info.image_block_size();
- self.border_box.size.inline =
- image_fragment_info.replaced_image_fragment_info
- .calculate_replaced_inline_size(style,
- noncontent_inline_size,
- container_inline_size,
- container_block_size,
- fragment_inline_size,
- fragment_block_size);
- }
- SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => {
- let fragment_inline_size = canvas_fragment_info.canvas_inline_size();
- let fragment_block_size = canvas_fragment_info.canvas_block_size();
- self.border_box.size.inline =
- canvas_fragment_info.replaced_image_fragment_info
- .calculate_replaced_inline_size(style,
- noncontent_inline_size,
- container_inline_size,
- container_block_size,
- fragment_inline_size,
- fragment_block_size);
- }
- SpecificFragmentInfo::Svg(ref mut svg_fragment_info) => {
- let fragment_inline_size = svg_fragment_info.svg_inline_size();
- let fragment_block_size = svg_fragment_info.svg_block_size();
- self.border_box.size.inline =
- svg_fragment_info.replaced_image_fragment_info
- .calculate_replaced_inline_size(style,
- noncontent_inline_size,
- container_inline_size,
- container_block_size,
- fragment_inline_size,
- fragment_block_size);
- }
- SpecificFragmentInfo::Iframe(ref iframe_fragment_info) => {
- self.border_box.size.inline =
- iframe_fragment_info.calculate_replaced_inline_size(style,
- container_inline_size) +
- noncontent_inline_size;
+
+ // Replaced elements
+ _ if self.is_replaced() => {
+ let (inline_size, block_size) =
+ self.calculate_replaced_sizes(Some(container_inline_size), container_block_size);
+ self.border_box.size.inline = inline_size + self.border_padding.inline_start_end();
+ self.border_box.size.block = block_size + self.border_padding.block_start_end();
}
- _ => panic!("this case should have been handled above"),
+
+ ref unhandled @ _ => panic!("this case should have been handled above: {:?}", unhandled),
}
}
@@ -2074,7 +1892,7 @@ impl Fragment {
/// been assigned first.
///
/// Ideally, this should follow CSS 2.1 § 10.6.2.
- pub fn assign_replaced_block_size_if_necessary(&mut self, containing_block_block_size: Option<Au>) {
+ pub fn assign_replaced_block_size_if_necessary(&mut self) {
match self.specific {
SpecificFragmentInfo::Generic |
SpecificFragmentInfo::GeneratedContent(_) |
@@ -2100,48 +1918,16 @@ impl Fragment {
SpecificFragmentInfo::Svg(_) => {}
}
- let style = &*self.style;
- let noncontent_block_size = self.border_padding.block_start_end();
-
match self.specific {
- SpecificFragmentInfo::Image(ref mut image_fragment_info) => {
- let fragment_inline_size = image_fragment_info.image_inline_size();
- let fragment_block_size = image_fragment_info.image_block_size();
- self.border_box.size.block =
- image_fragment_info.replaced_image_fragment_info
- .calculate_replaced_block_size(style,
- noncontent_block_size,
- containing_block_block_size,
- fragment_inline_size,
- fragment_block_size);
- }
- SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => {
- let fragment_inline_size = canvas_fragment_info.canvas_inline_size();
- let fragment_block_size = canvas_fragment_info.canvas_block_size();
- self.border_box.size.block =
- canvas_fragment_info.replaced_image_fragment_info
- .calculate_replaced_block_size(style,
- noncontent_block_size,
- containing_block_block_size,
- fragment_inline_size,
- fragment_block_size);
- }
- SpecificFragmentInfo::Svg(ref mut svg_fragment_info) => {
- let fragment_inline_size = svg_fragment_info.svg_inline_size();
- let fragment_block_size = svg_fragment_info.svg_block_size();
- self.border_box.size.block =
- svg_fragment_info.replaced_image_fragment_info
- .calculate_replaced_block_size(style,
- noncontent_block_size,
- containing_block_block_size,
- fragment_inline_size,
- fragment_block_size);
- }
+ // Text
SpecificFragmentInfo::ScannedText(ref info) => {
// Scanned text fragments' content block-sizes are calculated by the text run
// scanner during flow construction.
- self.border_box.size.block = info.content_size.block + noncontent_block_size
+ self.border_box.size.block = info.content_size.block +
+ self.border_padding.block_start_end();
}
+
+ // Inline blocks
SpecificFragmentInfo::InlineBlock(ref mut info) => {
// Not the primary fragment, so we do not take the noncontent size into account.
let block_flow = FlowRef::deref_mut(&mut info.flow_ref).as_block();
@@ -2159,36 +1945,31 @@ impl Fragment {
self.border_box.size.block = block_flow.base.position.size.block +
block_flow.fragment.margin.block_start_end()
}
- SpecificFragmentInfo::Iframe(ref info) => {
- self.border_box.size.block =
- info.calculate_replaced_block_size(style, containing_block_block_size) +
- noncontent_block_size;
- }
- _ => panic!("should have been handled above"),
+
+ // Replaced elements
+ _ if self.is_replaced() => {},
+
+ ref unhandled @ _ => panic!("should have been handled above: {:?}", unhandled),
}
}
- /// Returns true if this fragment is replaced content or an inline-block or false otherwise.
- pub fn is_replaced_or_inline_block(&self) -> bool {
+ /// Returns true if this fragment is replaced content.
+ pub fn is_replaced(&self) -> bool {
match self.specific {
- SpecificFragmentInfo::Canvas(_) |
SpecificFragmentInfo::Iframe(_) |
+ SpecificFragmentInfo::Canvas(_) |
SpecificFragmentInfo::Image(_) |
- SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
- SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::Svg(_) => true,
- SpecificFragmentInfo::Generic |
- SpecificFragmentInfo::GeneratedContent(_) |
- SpecificFragmentInfo::InlineAbsolute(_) |
- SpecificFragmentInfo::Table |
- SpecificFragmentInfo::TableCell |
- SpecificFragmentInfo::TableColumn(_) |
- SpecificFragmentInfo::TableRow |
- SpecificFragmentInfo::TableWrapper |
- SpecificFragmentInfo::Multicol |
- SpecificFragmentInfo::MulticolColumn |
- SpecificFragmentInfo::ScannedText(_) |
- SpecificFragmentInfo::UnscannedText(_) => false,
+ _ => false
+ }
+ }
+
+ /// Returns true if this fragment is replaced content or an inline-block or false otherwise.
+ pub fn is_replaced_or_inline_block(&self) -> bool {
+ match self.specific {
+ SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
+ SpecificFragmentInfo::InlineBlock(_) => true,
+ _ => self.is_replaced(),
}
}
@@ -2209,10 +1990,10 @@ impl Fragment {
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Svg(_) |
SpecificFragmentInfo::Generic | SpecificFragmentInfo::GeneratedContent(_) => {
- let ascent = self.border_box.size.block + self.margin.block_start;
+ let ascent = self.border_box.size.block + self.margin.block_end;
InlineMetrics {
- space_above_baseline: ascent,
- space_below_baseline: self.margin.block_end,
+ space_above_baseline: ascent + self.margin.block_start,
+ space_below_baseline: Au(0),
ascent: ascent,
}
}
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index 57eb16f1b84..cefb77bb592 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -1394,11 +1394,9 @@ impl Flow for InlineFlow {
debug!("assign_block_size_inline: floats in: {:?}", self.base.floats);
// Assign the block-size and late-computed inline-sizes for the inline fragments.
- let containing_block_block_size =
- self.base.block_container_explicit_block_size;
for fragment in &mut self.fragments.fragments {
fragment.update_late_computed_replaced_inline_size_if_necessary();
- fragment.assign_replaced_block_size_if_necessary(containing_block_block_size);
+ fragment.assign_replaced_block_size_if_necessary();
}
// Reset our state, so that we handle incremental reflow correctly.
diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs
index b3f8df9752d..20cc7bfa850 100644
--- a/components/layout/list_item.rs
+++ b/components/layout/list_item.rs
@@ -111,9 +111,7 @@ impl Flow for ListItemFlow {
&mut layout_context.font_context(),
&*self.block_flow.fragment.style);
for marker in &mut self.marker_fragments {
- let containing_block_block_size =
- self.block_flow.base.block_container_explicit_block_size;
- marker.assign_replaced_block_size_if_necessary(containing_block_block_size);
+ marker.assign_replaced_block_size_if_necessary();
let marker_inline_metrics = marker.aligned_inline_metrics(layout_context,
&marker_line_metrics,
Some(&marker_line_metrics));
diff --git a/components/layout/model.rs b/components/layout/model.rs
index a0693e0d8f8..89847e0190b 100644
--- a/components/layout/model.rs
+++ b/components/layout/model.rs
@@ -436,6 +436,21 @@ impl MaybeAuto {
}
}
+/// Receive an optional container size and return used value for width or height.
+///
+/// `style_length`: content size as given in the CSS.
+pub fn style_length(style_length: LengthOrPercentageOrAuto,
+ container_size: Option<Au>) -> MaybeAuto {
+ match container_size {
+ Some(length) => MaybeAuto::from_style(style_length, length),
+ None => if let LengthOrPercentageOrAuto::Length(length) = style_length {
+ MaybeAuto::Specified(length)
+ } else {
+ MaybeAuto::Auto
+ }
+ }
+}
+
pub fn specified_or_none(length: LengthOrPercentageOrNone, containing_length: Au) -> Option<Au> {
match length {
LengthOrPercentageOrNone::None => None,
@@ -504,64 +519,60 @@ impl ToGfxMatrix for ComputedMatrix {
}
}
-// https://drafts.csswg.org/css2/visudet.html#min-max-widths
-// https://drafts.csswg.org/css2/visudet.html#min-max-heights
-/// A min or max constraint
-///
-/// A `max` of `None` is equivalent to no limmit for the size in the given
-/// dimension. The `min` is >= 0, as negative values are illegal and by
-/// default `min` is 0.
-#[derive(Debug)]
-pub struct MinMaxConstraint {
- min: Au,
- max: Option<Au>
+/// A min-size and max-size constraint. The constructor has a optional `border`
+/// parameter, and when it is present the constraint will be subtracted. This is
+/// used to adjust the constraint for `box-sizing: border-box`, and when you do so
+/// make sure the size you want to clamp is intended to be used for content box.
+#[derive(Clone, Copy, Debug)]
+pub struct SizeConstraint {
+ min_size: Au,
+ max_size: Option<Au>,
}
-impl MinMaxConstraint {
- /// Create a `MinMaxConstraint` for a dimension given the min, max, and content box size for
- /// an axis
- pub fn new(content_size: Option<Au>, min: LengthOrPercentage,
- max: LengthOrPercentageOrNone) -> MinMaxConstraint {
- let min = match min {
- LengthOrPercentage::Length(length) => length,
- LengthOrPercentage::Percentage(percent) => {
- match content_size {
- Some(size) => size.scale_by(percent),
- None => Au(0),
- }
- },
- LengthOrPercentage::Calc(calc) => {
- match content_size {
- Some(size) => size.scale_by(calc.percentage()),
- None => Au(0),
- }
+impl SizeConstraint {
+ /// Create a `SizeConstraint` for an axis.
+ pub fn new(container_size: Option<Au>,
+ min_size: LengthOrPercentage,
+ max_size: LengthOrPercentageOrNone,
+ border: Option<Au>) -> SizeConstraint {
+ let mut min_size = match container_size {
+ Some(container_size) => specified(min_size, container_size),
+ None => if let LengthOrPercentage::Length(length) = min_size {
+ length
+ } else {
+ Au(0)
}
};
- let max = match max {
- LengthOrPercentageOrNone::Length(length) => Some(length),
- LengthOrPercentageOrNone::Percentage(percent) => {
- content_size.map(|size| size.scale_by(percent))
- },
- LengthOrPercentageOrNone::Calc(calc) => {
- content_size.map(|size| size.scale_by(calc.percentage()))
+ let mut max_size = match container_size {
+ Some(container_size) => specified_or_none(max_size, container_size),
+ None => if let LengthOrPercentageOrNone::Length(length) = max_size {
+ Some(length)
+ } else {
+ None
}
- LengthOrPercentageOrNone::None => None,
};
+ // Make sure max size is not smaller than min size.
+ max_size = max_size.map(|x| max(x, min_size));
+
+ if let Some(border) = border {
+ min_size = max((min_size - border), Au(0));
+ max_size = max_size.map(|x| max(x - border, Au(0)));
+ }
- MinMaxConstraint {
- min: min,
- max: max
+ SizeConstraint {
+ min_size: min_size,
+ max_size: max_size
}
}
- /// Clamp the given size by the given `min` and `max` constraints.
+ /// Clamp the given size by the given min size and max size constraint.
pub fn clamp(&self, other: Au) -> Au {
- if other < self.min {
- self.min
+ if other < self.min_size {
+ self.min_size
} else {
- match self.max {
- Some(max) if max < other => max,
+ match self.max_size {
+ Some(max_size) if max_size < other => max_size,
_ => other
}
}
diff --git a/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-004.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-004.htm.ini
deleted file mode 100644
index 77d7591b943..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-004.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[block-replaced-height-004.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-005.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-005.htm.ini
deleted file mode 100644
index 809b647e787..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-005.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[block-replaced-height-005.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-007.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-007.htm.ini
deleted file mode 100644
index 4e7ca96d91b..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/block-replaced-height-007.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[block-replaced-height-007.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/c43-rpl-bbx-002.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/c43-rpl-bbx-002.htm.ini
deleted file mode 100644
index faf1586d11f..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/c43-rpl-bbx-002.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[c43-rpl-bbx-002.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/c44-ln-box-003.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/c44-ln-box-003.htm.ini
deleted file mode 100644
index 1606d37ec43..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/c44-ln-box-003.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[c44-ln-box-003.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-004.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-004.htm.ini
deleted file mode 100644
index 79e9eef8833..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-004.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[float-replaced-height-004.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-005.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-005.htm.ini
deleted file mode 100644
index 2c55c9b3713..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-005.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[float-replaced-height-005.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-007.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-007.htm.ini
deleted file mode 100644
index 8a2cfba07f0..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/float-replaced-height-007.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[float-replaced-height-007.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-004.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-004.htm.ini
deleted file mode 100644
index 1562237ce6e..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-004.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[inline-block-replaced-height-004.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-005.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-005.htm.ini
deleted file mode 100644
index 5932e779dc7..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-005.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[inline-block-replaced-height-005.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-007.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-007.htm.ini
deleted file mode 100644
index 5fbf45656e7..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/inline-block-replaced-height-007.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[inline-block-replaced-height-007.htm]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/metadata-css/css21_dev/html4/max-height-percentage-003.htm.ini b/tests/wpt/metadata-css/css21_dev/html4/max-height-percentage-003.htm.ini
deleted file mode 100644
index 0b2d7e75a54..00000000000
--- a/tests/wpt/metadata-css/css21_dev/html4/max-height-percentage-003.htm.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[max-height-percentage-003.htm]
- type: reftest
- expected: FAIL