diff --git a/components/compositing/compositor_layer.rs b/components/compositing/compositor_layer.rs index 4c13d7fb8a0..3658172847e 100644 --- a/components/compositing/compositor_layer.rs +++ b/components/compositing/compositor_layer.rs @@ -283,8 +283,7 @@ impl CompositorLayer for Layer { self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta) } - fn clamp_scroll_offset_and_scroll_layer(&self, - new_offset: TypedPoint2D) + fn clamp_scroll_offset_and_scroll_layer(&self, new_offset: TypedPoint2D) -> ScrollEventResult { let layer_size = self.bounds.borrow().size; let content_size = calculate_content_size_for_layer(self); @@ -339,17 +338,14 @@ impl CompositorLayer for Layer { let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message)); } - fn scroll_layer_and_all_child_layers(&self, - new_offset: TypedPoint2D) + fn scroll_layer_and_all_child_layers(&self, new_offset: TypedPoint2D) -> bool { let mut result = false; // Only scroll this layer if it's not fixed-positioned. if self.extra_data.borrow().scroll_policy != FixedPosition { let new_offset = new_offset.to_untyped(); - *self.transform.borrow_mut() = identity().translate(new_offset.x, - new_offset.y, - 0.0); + *self.transform.borrow_mut() = identity().translate(new_offset.x, new_offset.y, 0.0); *self.content_offset.borrow_mut() = Point2D::from_untyped(&new_offset); result = true } diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index af32ffad76b..1905f73885c 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -34,7 +34,7 @@ use servo_msg::compositor_msg::LayerId; use servo_net::image::base::Image; use servo_util::cursor::Cursor; use servo_util::dlist as servo_dlist; -use servo_util::geometry::{mod, Au, MAX_RECT, ZERO_POINT, ZERO_RECT}; +use servo_util::geometry::{mod, Au, MAX_RECT, ZERO_RECT}; use servo_util::range::Range; use servo_util::smallvec::{SmallVec, SmallVec8}; use std::fmt; @@ -160,9 +160,8 @@ pub struct StackingContext { pub layer: Option>, /// The position and size of this stacking context. pub bounds: Rect, - /// The clipping rect for this stacking context, in the coordinate system of the *parent* - /// stacking context. - pub clip_rect: Rect, + /// The overflow rect for this stacking context in its coordinate system. + pub overflow: Rect, /// The `z-index` for this stacking context. pub z_index: i32, /// The opacity of this stacking context. @@ -171,12 +170,10 @@ pub struct StackingContext { impl StackingContext { /// Creates a new stacking context. - /// - /// TODO(pcwalton): Stacking contexts should not always be clipped to their bounds, to handle - /// overflow properly. #[inline] pub fn new(display_list: Box, - bounds: Rect, + bounds: &Rect, + overflow: &Rect, z_index: i32, opacity: AzFloat, layer: Option>) @@ -184,8 +181,8 @@ impl StackingContext { StackingContext { display_list: display_list, layer: layer, - bounds: bounds, - clip_rect: Rect(ZERO_POINT, bounds.size), + bounds: *bounds, + overflow: *overflow, z_index: z_index, opacity: opacity, } @@ -196,7 +193,7 @@ impl StackingContext { paint_context: &mut PaintContext, tile_bounds: &Rect, transform: &Matrix2D, - clip_rect: Option>) { + clip_rect: Option<&Rect>) { let temporary_draw_target = paint_context.get_or_create_temporary_draw_target(self.opacity); { @@ -205,7 +202,7 @@ impl StackingContext { font_ctx: &mut *paint_context.font_ctx, page_rect: paint_context.page_rect, screen_rect: paint_context.screen_rect, - clip_rect: clip_rect, + clip_rect: clip_rect.map(|clip_rect| *clip_rect), transient_clip: None, }; @@ -252,7 +249,7 @@ impl StackingContext { positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, &new_tile_rect, &new_transform, - Some(positioned_kid.clip_rect)) + Some(&positioned_kid.overflow)) } } @@ -295,7 +292,7 @@ impl StackingContext { positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, &new_tile_rect, &new_transform, - Some(positioned_kid.clip_rect)) + Some(&positioned_kid.overflow)) } } @@ -329,11 +326,18 @@ impl StackingContext { } }; - let child_stacking_context_bounds = child_stacking_context.bounds.to_azure_rect(); - let tile_subrect = tile_bounds.intersection(&child_stacking_context_bounds) + // Translate the child's overflow region into our coordinate system. + let child_stacking_context_overflow = + child_stacking_context.overflow.translate(&child_stacking_context.bounds.origin) + .to_azure_rect(); + + // Intersect that with the current tile boundaries to find the tile boundaries that the + // child covers. + let tile_subrect = tile_bounds.intersection(&child_stacking_context_overflow) .unwrap_or(ZERO_AZURE_RECT); - let offset = tile_subrect.origin - child_stacking_context_bounds.origin; - Rect(offset, tile_subrect.size) + + // Translate the resulting rect into the child's coordinate system. + tile_subrect.translate(&-child_stacking_context.bounds.to_azure_rect().origin) } /// Places all nodes containing the point of interest into `result`, topmost first. If @@ -605,6 +609,20 @@ impl ClippingRegion { }); self } + + /// Translates this clipping region by the given vector. + #[inline] + pub fn translate(&self, delta: &Point2D) -> ClippingRegion { + ClippingRegion { + main: self.main.translate(delta), + complex: self.complex.iter().map(|complex| { + ComplexClippingRegion { + rect: complex.rect.translate(delta), + radii: complex.radii, + } + }).collect(), + } + } } /// Metadata attached to each display item. This is useful for performing auxiliary tasks with diff --git a/components/gfx/display_list/optimizer.rs b/components/gfx/display_list/optimizer.rs index c0dac718c51..1b7998f86c9 100644 --- a/components/gfx/display_list/optimizer.rs +++ b/components/gfx/display_list/optimizer.rs @@ -59,7 +59,8 @@ impl DisplayListOptimizer { mut stacking_contexts: I) where I: Iterator<&'a Arc> { for stacking_context in stacking_contexts { - if self.visible_rect.intersects(&stacking_context.bounds) { + let overflow = stacking_context.overflow.translate(&stacking_context.bounds.origin); + if self.visible_rect.intersects(&overflow) { result_list.push_back((*stacking_context).clone()) } } diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index 1210c34627b..5fdacfa838d 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -148,20 +148,21 @@ fn initialize_layers(compositor: &mut C, stacking_context: &StackingContext, page_position: &Point2D) { let page_position = stacking_context.bounds.origin + *page_position; - match stacking_context.layer { - None => {} - Some(ref paint_layer) => { - metadata.push(LayerMetadata { - id: paint_layer.id, - position: - Rect(Point2D(page_position.x.to_nearest_px() as uint, - page_position.y.to_nearest_px() as uint), - Size2D(stacking_context.bounds.size.width.to_nearest_px() as uint, - stacking_context.bounds.size.height.to_nearest_px() as uint)), - background_color: paint_layer.background_color, - scroll_policy: paint_layer.scroll_policy, - }) - } + if let Some(ref paint_layer) = stacking_context.layer { + // Layers start at the top left of their overflow rect, as far as the info we give to + // the compositor is concerned. + let overflow_relative_page_position = page_position + stacking_context.overflow.origin; + let layer_position = + Rect(Point2D(overflow_relative_page_position.x.to_nearest_px() as i32, + overflow_relative_page_position.y.to_nearest_px() as i32), + Size2D(stacking_context.overflow.size.width.to_nearest_px() as i32, + stacking_context.overflow.size.height.to_nearest_px() as i32)); + metadata.push(LayerMetadata { + id: paint_layer.id, + position: layer_position, + background_color: paint_layer.background_color, + scroll_policy: paint_layer.scroll_policy, + }) } for kid in stacking_context.display_list.children.iter() { @@ -384,15 +385,14 @@ impl PaintTask where C: PaintListener + Send { layer_id: LayerId) { profile(TimeProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || { // Bail out if there is no appropriate stacking context. - let stacking_context = match self.root_stacking_context { - Some(ref stacking_context) => { - match display_list::find_stacking_context_with_layer_id(stacking_context, - layer_id) { - Some(stacking_context) => stacking_context, - None => return, - } + let stacking_context = if let Some(ref stacking_context) = self.root_stacking_context { + match display_list::find_stacking_context_with_layer_id(stacking_context, + layer_id) { + Some(stacking_context) => stacking_context, + None => return, } - None => return, + } else { + return }; // Divide up the layer into tiles and distribute them to workers via a simple round- @@ -547,8 +547,13 @@ impl WorkerThread { transient_clip: None, }; + // Apply a translation to start at the boundaries of the stacking context, since the + // layer's origin starts at its overflow rect's origin. + let tile_bounds = tile.page_rect.translate( + &Point2D(stacking_context.overflow.origin.x.to_subpx() as AzFloat, + stacking_context.overflow.origin.y.to_subpx() as AzFloat)); + // Apply the translation to paint the tile we want. - let tile_bounds = tile.page_rect; let matrix: Matrix2D = Matrix2D::identity(); let matrix = matrix.scale(scale as AzFloat, scale as AzFloat); let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat, @@ -561,7 +566,7 @@ impl WorkerThread { profile(TimeProfilerCategory::PaintingPerTile, None, self.time_profiler_sender.clone(), || { stacking_context.optimize_and_draw_into_context(&mut paint_context, - &tile.page_rect, + &tile_bounds, &matrix, None); paint_context.draw_target.flush(); diff --git a/components/layout/block.rs b/components/layout/block.rs index 02b58ce463e..3f7fd4be823 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -32,7 +32,7 @@ use context::LayoutContext; use css::node_style::StyledNode; use display_list_builder::{BlockFlowDisplayListBuilding, FragmentDisplayListBuilding}; use floats::{ClearType, FloatKind, Floats, PlacementInfo}; -use flow::{AbsolutePositionInfo, BaseFlow, ForceNonfloatedFlag, FlowClass, Flow}; +use flow::{mod, AbsolutePositionInfo, BaseFlow, ForceNonfloatedFlag, FlowClass, Flow}; use flow::{ImmutableFlowUtils, MutableFlowUtils, PreorderFlowTraversal}; use flow::{PostorderFlowTraversal, mut_base}; use flow::{HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS}; @@ -40,8 +40,7 @@ use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use flow::{LAYERS_NEEDED_FOR_DESCENDANTS, NEEDS_LAYER}; use flow::{IS_ABSOLUTELY_POSITIONED}; use flow::{CLEARS_LEFT, CLEARS_RIGHT}; -use flow; -use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo}; +use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use layout_debug; use model::{IntrinsicISizes, MarginCollapseInfo}; @@ -49,11 +48,11 @@ use model::{MaybeAuto, CollapsibleMargins, specified, specified_or_none}; use table::ColumnComputedInlineSize; use wrapper::ThreadSafeLayoutNode; -use geom::Size2D; +use geom::{Point2D, Rect, Size2D}; use gfx::display_list::{ClippingRegion, DisplayList}; use serialize::{Encoder, Encodable}; use servo_msg::compositor_msg::LayerId; -use servo_util::geometry::{Au, MAX_AU, ZERO_POINT}; +use servo_util::geometry::{Au, MAX_AU}; use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize}; use servo_util::opts; use std::cmp::{max, min}; @@ -1769,23 +1768,40 @@ impl Flow for BlockFlow { }; // Compute the origin and clipping rectangle for children. - let origin_for_children = if self.fragment.establishes_stacking_context() { - ZERO_POINT + let relative_offset = relative_offset.to_physical(self.base.writing_mode); + let origin_for_children; + let clip_in_child_coordinate_system; + if self.fragment.establishes_stacking_context() { + // We establish a stacking context, so the position of our children is vertically + // correct, but has to be adjusted to accommodate horizontal margins. (Note the + // calculation involving `position` below and recall that inline-direction flow + // positions are relative to the edges of the margin box.) + // + // FIXME(pcwalton): Is this vertical-writing-direction-safe? + let margin = self.fragment.margin.to_physical(self.base.writing_mode); + origin_for_children = Point2D(-margin.left, Au(0)) + relative_offset; + clip_in_child_coordinate_system = + self.base.clip.translate(&-self.base.stacking_relative_position) } else { - self.base.stacking_relative_position - }; - let clip = self.fragment.clipping_region_for_children(&self.base.clip, - &origin_for_children); + origin_for_children = self.base.stacking_relative_position + relative_offset; + clip_in_child_coordinate_system = self.base.clip.clone() + } + let stacking_relative_border_box = + self.fragment + .stacking_relative_border_box(&self.base.stacking_relative_position, + &self.base + .absolute_position_info + .relative_containing_block_size, + CoordinateSystem::Self); + let clip = self.fragment.clipping_region_for_children(&clip_in_child_coordinate_system, + &stacking_relative_border_box); // Process children. - let writing_mode = self.base.writing_mode; for kid in self.base.child_iter() { if !flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) { let kid_base = flow::mut_base(kid); - kid_base.stacking_relative_position = - origin_for_children - + kid_base.position.start.to_physical(kid_base.writing_mode, container_size) - + relative_offset.to_physical(writing_mode); + kid_base.stacking_relative_position = origin_for_children + + kid_base.position.start.to_physical(kid_base.writing_mode, container_size); } flow::mut_base(kid).absolute_position_info = absolute_position_info_for_children; @@ -1797,13 +1813,6 @@ impl Flow for BlockFlow { self.flags.insert(IS_ROOT) } - /// Return true if store overflow is delayed for this flow. - /// - /// Currently happens only for absolutely positioned flows. - fn is_store_overflow_delayed(&mut self) -> bool { - self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) - } - fn is_root(&self) -> bool { self.flags.contains(IS_ROOT) } @@ -1839,16 +1848,20 @@ impl Flow for BlockFlow { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) && - self.fragment.style().logical_position().inline_start == LengthOrPercentageOrAuto::Auto && - self.fragment.style().logical_position().inline_end == LengthOrPercentageOrAuto::Auto { + self.fragment.style().logical_position().inline_start == + LengthOrPercentageOrAuto::Auto && + self.fragment.style().logical_position().inline_end == + LengthOrPercentageOrAuto::Auto { self.base.position.start.i = inline_position } } fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) && - self.fragment.style().logical_position().block_start == LengthOrPercentageOrAuto::Auto && - self.fragment.style().logical_position().block_end == LengthOrPercentageOrAuto::Auto { + self.fragment.style().logical_position().block_start == + LengthOrPercentageOrAuto::Auto && + self.fragment.style().logical_position().block_end == + LengthOrPercentageOrAuto::Auto { self.base.position.start.b = block_position } } @@ -1864,19 +1877,36 @@ impl Flow for BlockFlow { self.fragment.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - if iterator.should_process(&self.fragment) { - let fragment_origin = - self.base.stacking_relative_position_of_child_fragment(&self.fragment); - iterator.process(&self.fragment, - self.fragment.stacking_relative_bounds(&fragment_origin)); + fn compute_overflow(&self) -> Rect { + self.fragment.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + if !iterator.should_process(&self.fragment) { + return } + + iterator.process(&self.fragment, + &self.fragment + .stacking_relative_border_box(&self.base.stacking_relative_position, + &self.base + .absolute_position_info + .relative_containing_block_size, + CoordinateSystem::Parent) + .translate(stacking_context_position)); } } impl fmt::Show for BlockFlow { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} - {:x}: frag={} ({})", self.class(), self.base.debug_id(), self.fragment, self.base) + write!(f, + "{} - {:x}: frag={} ({})", + self.class(), + self.base.debug_id(), + self.fragment, + self.base) } } @@ -2455,11 +2485,14 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced { MaybeAuto::Specified(fragment.content_inline_size()) } - fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext) -> Au { + fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext) + -> Au { block.containing_block_size(ctx.shared.screen_size).inline } - fn set_flow_x_coord_if_necessary(&self, block: &mut BlockFlow, solution: ISizeConstraintSolution) { + fn set_flow_x_coord_if_necessary(&self, + block: &mut BlockFlow, + solution: ISizeConstraintSolution) { // Set the x-coordinate of the absolute flow wrt to its containing block. block.base.position.start.i = solution.inline_start; } diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 94605e103ec..c2911b13640 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -52,9 +52,9 @@ use servo_util::opts; use std::collections::DList; use std::mem; use std::sync::atomic::Relaxed; -use style::ComputedValues; use style::computed_values::{caption_side, display, empty_cells, float, list_style_position}; use style::computed_values::{position}; +use style::{mod, ComputedValues}; use sync::Arc; use url::Url; @@ -681,7 +681,7 @@ impl<'a> FlowConstructor<'a> { /// doesn't render its children, so this just nukes a child's fragments and creates a /// `Fragment`. fn build_fragments_for_replaced_inline_content(&mut self, node: &ThreadSafeLayoutNode) - -> ConstructionResult { + -> ConstructionResult { for kid in node.children() { kid.set_flow_construction_result(ConstructionResult::None) } @@ -697,24 +697,42 @@ impl<'a> FlowConstructor<'a> { node.restyle_damage())) } + // If the value of `display` property is not `inline`, then we have a situation like + // `
foo bar baz
`. The fragments for `foo`, `bar`, and + // `baz` had better not be absolutely positioned! + let mut style = (*node.style()).clone(); + if style.get_box().display != display::inline { + style = Arc::new(style::make_inline(&*style)) + } + // If this is generated content, then we need to initialize the accumulator with the // fragment corresponding to that content. Otherwise, just initialize with the ordinary // fragment that needs to be generated for this inline node. let fragment = if node.get_pseudo_element_type() != PseudoElementType::Normal { - let fragment_info = SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node)); - Fragment::new_from_specific_info(node, fragment_info) + let fragment_info = + SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node)); + Fragment::from_opaque_node_and_style( + OpaqueNodeMethods::from_thread_safe_layout_node(node), + style, + node.restyle_damage(), + fragment_info) } else { - Fragment::new(self, node) + Fragment::from_opaque_node_and_style( + OpaqueNodeMethods::from_thread_safe_layout_node(node), + style, + node.restyle_damage(), + self.build_specific_fragment_info_for_node(node)) }; let mut fragments = DList::new(); fragments.push_back(fragment); - let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { - splits: DList::new(), - fragments: fragments, - abs_descendants: Descendants::new(), - }); + let construction_item = + ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { + splits: DList::new(), + fragments: fragments, + abs_descendants: Descendants::new(), + }); ConstructionResult::ConstructionItem(construction_item) } @@ -726,17 +744,19 @@ impl<'a> FlowConstructor<'a> { _ => unreachable!() }; - let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new(block_flow)); + let fragment_info = SpecificFragmentInfo::InlineBlock(InlineBlockFragmentInfo::new( + block_flow)); let fragment = Fragment::new_from_specific_info(node, fragment_info); let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); fragment_accumulator.fragments.push_back(fragment); - let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { - splits: DList::new(), - fragments: fragment_accumulator.to_dlist(), - abs_descendants: abs_descendants, - }); + let construction_item = + ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { + splits: DList::new(), + fragments: fragment_accumulator.to_dlist(), + abs_descendants: abs_descendants, + }); ConstructionResult::ConstructionItem(construction_item) } @@ -757,11 +777,12 @@ impl<'a> FlowConstructor<'a> { let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); fragment_accumulator.fragments.push_back(fragment); - let construction_item = ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { - splits: DList::new(), - fragments: fragment_accumulator.to_dlist(), - abs_descendants: abs_descendants, - }); + let construction_item = + ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { + splits: DList::new(), + fragments: fragment_accumulator.to_dlist(), + abs_descendants: abs_descendants, + }); ConstructionResult::ConstructionItem(construction_item) } diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index a9ca6d5f547..80877ffaaf9 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -13,8 +13,9 @@ use block::BlockFlow; use context::LayoutContext; use flow::{mod, Flow, IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER}; -use fragment::{Fragment, SpecificFragmentInfo, IframeFragmentInfo, ImageFragmentInfo}; -use fragment::ScannedTextFragmentInfo; +use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo}; +use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo}; +use inline::InlineFlow; use list_item::ListItemFlow; use model; use util::{OpaqueNodeMethods, ToGfxColor}; @@ -36,8 +37,8 @@ use servo_msg::constellation_msg::Msg as ConstellationMsg; use servo_msg::constellation_msg::ConstellationChan; use servo_net::image::holder::ImageHolder; use servo_util::cursor::{DefaultCursor, TextCursor, VerticalTextCursor}; -use servo_util::geometry::{mod, Au, ZERO_POINT}; -use servo_util::logical_geometry::{LogicalRect, WritingMode}; +use servo_util::geometry::{mod, Au}; +use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize}; use servo_util::opts; use std::default::Default; use std::num::FloatMath; @@ -133,16 +134,19 @@ pub trait FragmentDisplayListBuilding { absolute_bounds: &Rect, clip: &ClippingRegion); + /// Adds display items necessary to draw debug boxes around a scanned text fragment. fn build_debug_borders_around_text_fragments(&self, style: &ComputedValues, display_list: &mut DisplayList, - flow_origin: Point2D, + stacking_relative_border_box: &Rect, + stacking_relative_content_box: &Rect, text_fragment: &ScannedTextFragmentInfo, clip: &ClippingRegion); + /// Adds display items necessary to draw debug boxes around this fragment. fn build_debug_borders_around_fragment(&self, display_list: &mut DisplayList, - flow_origin: Point2D, + stacking_relative_border_box: &Rect, clip: &ClippingRegion); /// Adds the display items for this fragment to the given display list. @@ -152,12 +156,16 @@ pub trait FragmentDisplayListBuilding { /// * `display_list`: The display list to add display items to. /// * `layout_context`: The layout context. /// * `dirty`: The dirty rectangle in the coordinate system of the owning flow. - /// * `flow_origin`: Position of the origin of the owning flow wrt the display list root flow. + /// * `stacking_relative_flow_origin`: Position of the origin of the owning flow with respect + /// to its nearest ancestor stacking context. + /// * `relative_containing_block_size`: The size of the containing block that + /// `position: relative` makes use of. /// * `clip`: The region to clip the display items to. fn build_display_list(&mut self, display_list: &mut DisplayList, layout_context: &LayoutContext, - flow_origin: Point2D, + stacking_relative_flow_origin: &Point2D, + relative_containing_block_size: &LogicalSize, background_and_border_level: BackgroundAndBorderLevel, clip: &ClippingRegion); @@ -168,12 +176,17 @@ pub trait FragmentDisplayListBuilding { offset: Point2D, layout_context: &LayoutContext); - fn clipping_region_for_children(&self, current_clip: &ClippingRegion, flow_origin: &Point2D) + /// Returns the appropriate clipping region for descendants of this flow. + fn clipping_region_for_children(&self, + current_clip: &ClippingRegion, + stacking_relative_border_box: &Rect) -> ClippingRegion; /// Calculates the clipping rectangle for a fragment, taking the `clip` property into account /// per CSS 2.1 § 11.1.2. - fn calculate_style_specified_clip(&self, parent_clip: &ClippingRegion, origin: &Point2D) + fn calculate_style_specified_clip(&self, + parent_clip: &ClippingRegion, + stacking_relative_border_box: &Rect) -> ClippingRegion; /// Creates the text display item for one text fragment. @@ -181,23 +194,20 @@ pub trait FragmentDisplayListBuilding { display_list: &mut DisplayList, text_fragment: &ScannedTextFragmentInfo, text_color: RGBA, - offset: &Point2D, - flow_origin: &Point2D, + stacking_relative_content_box: &Rect, clip: &ClippingRegion); /// Creates the display item for a text decoration: underline, overline, or line-through. fn build_display_list_for_text_decoration(&self, display_list: &mut DisplayList, - color: RGBA, - flow_origin: &Point2D, - clip: &ClippingRegion, - logical_bounds: &LogicalRect, - offset: &Point2D); + color: &RGBA, + stacking_relative_box: &LogicalRect, + clip: &ClippingRegion); /// A helper method that `build_display_list` calls to create per-fragment-type display items. fn build_fragment_type_specific_display_items(&mut self, display_list: &mut DisplayList, - flow_origin: Point2D, + stacking_relative_border_box: &Rect, clip: &ClippingRegion); } @@ -580,20 +590,16 @@ impl FragmentDisplayListBuilding for Fragment { fn build_debug_borders_around_text_fragments(&self, style: &ComputedValues, display_list: &mut DisplayList, - flow_origin: Point2D, + stacking_relative_border_box: &Rect, + stacking_relative_content_box: &Rect, text_fragment: &ScannedTextFragmentInfo, clip: &ClippingRegion) { - // FIXME(#2795): Get the real container size + // FIXME(pcwalton, #2795): Get the real container size. let container_size = Size2D::zero(); - // Fragment position wrt to the owning flow. - let fragment_bounds = self.border_box.to_physical(self.style.writing_mode, container_size); - let absolute_fragment_bounds = Rect( - fragment_bounds.origin + flow_origin, - fragment_bounds.size); // Compute the text fragment bounds and draw a border surrounding them. display_list.content.push_back(DisplayItem::BorderClass(box BorderDisplayItem { - base: BaseDisplayItem::new(absolute_fragment_bounds, + base: BaseDisplayItem::new(*stacking_relative_border_box, DisplayItemMetadata::new(self.node, style, DefaultCursor), (*clip).clone()), border_widths: SideOffsets2D::new_all_same(Au::from_px(1)), @@ -603,12 +609,12 @@ impl FragmentDisplayListBuilding for Fragment { })); // Draw a rectangle representing the baselines. - let ascent = text_fragment.run.ascent(); - let mut baseline = self.border_box.clone(); - baseline.start.b = baseline.start.b + ascent; + let mut baseline = LogicalRect::from_physical(self.style.writing_mode, + *stacking_relative_content_box, + container_size); + baseline.start.b = baseline.start.b + text_fragment.run.ascent(); baseline.size.block = Au(0); - let mut baseline = baseline.to_physical(self.style.writing_mode, container_size); - baseline.origin = baseline.origin + flow_origin; + let baseline = baseline.to_physical(self.style.writing_mode, container_size); let line_display_item = box LineDisplayItem { base: BaseDisplayItem::new(baseline, @@ -622,19 +628,11 @@ impl FragmentDisplayListBuilding for Fragment { fn build_debug_borders_around_fragment(&self, display_list: &mut DisplayList, - flow_origin: Point2D, + stacking_relative_border_box: &Rect, clip: &ClippingRegion) { - // FIXME(#2795): Get the real container size - let container_size = Size2D::zero(); - // Fragment position wrt to the owning flow. - let fragment_bounds = self.border_box.to_physical(self.style.writing_mode, container_size); - let absolute_fragment_bounds = Rect( - fragment_bounds.origin + flow_origin, - fragment_bounds.size); - // This prints a debug border around the border of this fragment. display_list.content.push_back(DisplayItem::BorderClass(box BorderDisplayItem { - base: BaseDisplayItem::new(absolute_fragment_bounds, + base: BaseDisplayItem::new(*stacking_relative_border_box, DisplayItemMetadata::new(self.node, &*self.style, DefaultCursor), @@ -646,7 +644,9 @@ impl FragmentDisplayListBuilding for Fragment { })); } - fn calculate_style_specified_clip(&self, parent_clip: &ClippingRegion, origin: &Point2D) + fn calculate_style_specified_clip(&self, + parent_clip: &ClippingRegion, + stacking_relative_border_box: &Rect) -> ClippingRegion { // Account for `clip` per CSS 2.1 § 11.1.2. let style_clip_rect = match (self.style().get_box().position, @@ -656,54 +656,49 @@ impl FragmentDisplayListBuilding for Fragment { }; // FIXME(pcwalton, #2795): Get the real container size. - let border_box = self.border_box.to_physical(self.style.writing_mode, Size2D::zero()); - let clip_origin = Point2D(border_box.origin.x + style_clip_rect.left, - border_box.origin.y + style_clip_rect.top); - let new_clip_rect = - Rect(clip_origin + *origin, - Size2D(style_clip_rect.right.unwrap_or(border_box.size.width) - clip_origin.x, - style_clip_rect.bottom.unwrap_or(border_box.size.height) - clip_origin.y)); - (*parent_clip).clone().intersect_rect(&new_clip_rect) + let clip_origin = Point2D(stacking_relative_border_box.origin.x + style_clip_rect.left, + stacking_relative_border_box.origin.y + style_clip_rect.top); + let right = style_clip_rect.right.unwrap_or(stacking_relative_border_box.size.width); + let bottom = style_clip_rect.bottom.unwrap_or(stacking_relative_border_box.size.height); + let clip_size = Size2D(right - clip_origin.x, bottom - clip_origin.y); + (*parent_clip).clone().intersect_rect(&Rect(clip_origin, clip_size)) } fn build_display_list(&mut self, display_list: &mut DisplayList, layout_context: &LayoutContext, - flow_origin: Point2D, + stacking_relative_flow_origin: &Point2D, + relative_containing_block_size: &LogicalSize, background_and_border_level: BackgroundAndBorderLevel, clip: &ClippingRegion) { // Compute the fragment position relative to the parent stacking context. If the fragment // itself establishes a stacking context, then the origin of its position will be (0, 0) // for the purposes of this computation. - let stacking_relative_flow_origin = if self.establishes_stacking_context() { - ZERO_POINT - } else { - flow_origin - }; - let absolute_fragment_bounds = - self.stacking_relative_bounds(&stacking_relative_flow_origin); + let stacking_relative_border_box = + self.stacking_relative_border_box(stacking_relative_flow_origin, + relative_containing_block_size, + CoordinateSystem::Self); - debug!("Fragment::build_display_list at rel={}, abs={}: {}", + debug!("Fragment::build_display_list at rel={}, abs={}, dirty={}, flow origin={}: {}", self.border_box, - absolute_fragment_bounds, - self); - debug!("Fragment::build_display_list: dirty={}, flow_origin={}", + stacking_relative_border_box, layout_context.shared.dirty, - flow_origin); + stacking_relative_flow_origin, + self); if self.style().get_inheritedbox().visibility != visibility::visible { return } - if !absolute_fragment_bounds.intersects(&layout_context.shared.dirty) { + if !stacking_relative_border_box.intersects(&layout_context.shared.dirty) { debug!("Fragment::build_display_list: Did not intersect..."); return } // Calculate the clip rect. If there's nothing to render at all, don't even construct // display list items. - let clip = self.calculate_style_specified_clip(clip, &absolute_fragment_bounds.origin); - if !clip.might_intersect_rect(&absolute_fragment_bounds) { + let clip = self.calculate_style_specified_clip(clip, &stacking_relative_border_box); + if !clip.might_intersect_rect(&stacking_relative_border_box) { return; } @@ -713,15 +708,34 @@ impl FragmentDisplayListBuilding for Fragment { let level = StackingLevel::from_background_and_border_level(background_and_border_level); - // Add a shadow to the list, if applicable. + // Add shadows, background, borders, and outlines, if applicable. if let Some(ref inline_context) = self.inline_context { for style in inline_context.styles.iter().rev() { - self.build_display_list_for_box_shadow_if_applicable(&**style, - display_list, - layout_context, - level, - &absolute_fragment_bounds, - &clip); + self.build_display_list_for_box_shadow_if_applicable( + &**style, + display_list, + layout_context, + level, + &stacking_relative_border_box, + &clip); + self.build_display_list_for_background_if_applicable( + &**style, + display_list, + layout_context, + level, + &stacking_relative_border_box, + &clip); + self.build_display_list_for_borders_if_applicable( + &**style, + display_list, + &stacking_relative_border_box, + level, + &clip); + self.build_display_list_for_outline_if_applicable( + &**style, + display_list, + &stacking_relative_border_box, + &clip); } } if !self.is_scanned_text_fragment() { @@ -729,62 +743,35 @@ impl FragmentDisplayListBuilding for Fragment { display_list, layout_context, level, - &absolute_fragment_bounds, + &stacking_relative_border_box, &clip); - } - - // Add the background to the list, if applicable. - if let Some(ref inline_context) = self.inline_context { - for style in inline_context.styles.iter().rev() { - self.build_display_list_for_background_if_applicable(&**style, - display_list, - layout_context, - level, - &absolute_fragment_bounds, - &clip); - } - } - if !self.is_scanned_text_fragment() { self.build_display_list_for_background_if_applicable(&*self.style, display_list, layout_context, level, - &absolute_fragment_bounds, + &stacking_relative_border_box, &clip); - } - - // Add a border and outlines, if applicable. - if let Some(ref inline_context) = self.inline_context { - for style in inline_context.styles.iter().rev() { - self.build_display_list_for_borders_if_applicable(&**style, - display_list, - &absolute_fragment_bounds, - level, - &clip); - self.build_display_list_for_outline_if_applicable(&**style, - display_list, - &absolute_fragment_bounds, - &clip); - } - } - if !self.is_scanned_text_fragment() { self.build_display_list_for_borders_if_applicable(&*self.style, display_list, - &absolute_fragment_bounds, + &stacking_relative_border_box, level, &clip); self.build_display_list_for_outline_if_applicable(&*self.style, display_list, - &absolute_fragment_bounds, + &stacking_relative_border_box, &clip); } } // Create special per-fragment-type display items. - self.build_fragment_type_specific_display_items(display_list, flow_origin, &clip); + self.build_fragment_type_specific_display_items(display_list, + &stacking_relative_border_box, + &clip); if opts::get().show_debug_fragment_borders { - self.build_debug_borders_around_fragment(display_list, flow_origin, &clip) + self.build_debug_borders_around_fragment(display_list, + &stacking_relative_border_box, + &clip) } // If this is an iframe, then send its position and size up to the constellation. @@ -799,31 +786,18 @@ impl FragmentDisplayListBuilding for Fragment { // the iframe is actually going to be displayed. if let SpecificFragmentInfo::Iframe(ref iframe_fragment) = self.specific { self.finalize_position_and_size_of_iframe(&**iframe_fragment, - absolute_fragment_bounds.origin, + stacking_relative_border_box.origin, layout_context) } } fn build_fragment_type_specific_display_items(&mut self, display_list: &mut DisplayList, - flow_origin: Point2D, + stacking_relative_border_box: &Rect, clip: &ClippingRegion) { - // Compute the fragment position relative to the parent stacking context. If the fragment - // itself establishes a stacking context, then the origin of its position will be (0, 0) - // for the purposes of this computation. - let stacking_relative_flow_origin = if self.establishes_stacking_context() { - ZERO_POINT - } else { - flow_origin - }; - - // FIXME(#2795): Get the real container size. - let content_box = self.content_box(); - let container_size = Size2D::zero(); - let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect| { - let physical_rect = logical_rect.to_physical(writing_mode, container_size); - Rect(physical_rect.origin + stacking_relative_flow_origin, physical_rect.size) - }; + // Compute the context box position relative to the parent stacking context. + let stacking_relative_content_box = + self.stacking_relative_content_box(stacking_relative_border_box); match self.specific { SpecificFragmentInfo::UnscannedText(_) => { @@ -838,16 +812,16 @@ impl FragmentDisplayListBuilding for Fragment { self.build_display_list_for_text_fragment(display_list, &**text_fragment, text_color, - &flow_origin, - &Point2D(Au(0), Au(0)), + &stacking_relative_content_box, clip); if opts::get().show_debug_fragment_borders { self.build_debug_borders_around_text_fragments(self.style(), display_list, - flow_origin, + stacking_relative_border_box, + &stacking_relative_content_box, &**text_fragment, - clip); + clip) } } SpecificFragmentInfo::Generic | @@ -859,25 +833,25 @@ impl FragmentDisplayListBuilding for Fragment { SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => { if opts::get().show_debug_fragment_borders { - self.build_debug_borders_around_fragment(display_list, flow_origin, clip); + self.build_debug_borders_around_fragment(display_list, + stacking_relative_border_box, + clip); } } SpecificFragmentInfo::Image(ref mut image_fragment) => { let image_ref = &mut image_fragment.image; if let Some(image) = image_ref.get_image(self.node.to_untrusted_node_address()) { debug!("(building display list) building image fragment"); - let absolute_content_box = rect_to_absolute(self.style.writing_mode, - content_box); // Place the image into the display list. display_list.content.push_back(DisplayItem::ImageClass(box ImageDisplayItem { - base: BaseDisplayItem::new(absolute_content_box, + base: BaseDisplayItem::new(stacking_relative_content_box, DisplayItemMetadata::new(self.node, &*self.style, DefaultCursor), (*clip).clone()), image: image.clone(), - stretch_size: absolute_content_box.size, + stretch_size: stacking_relative_content_box.size, })); } else { // No image data at all? Do nothing. @@ -910,7 +884,9 @@ impl FragmentDisplayListBuilding for Fragment { iframe_rect)); } - fn clipping_region_for_children(&self, current_clip: &ClippingRegion, flow_origin: &Point2D) + fn clipping_region_for_children(&self, + current_clip: &ClippingRegion, + stacking_relative_border_box: &Rect) -> ClippingRegion { // Don't clip if we're text. if self.is_scanned_text_fragment() { @@ -918,27 +894,24 @@ impl FragmentDisplayListBuilding for Fragment { } // Account for style-specified `clip`. - let current_clip = self.calculate_style_specified_clip(current_clip, flow_origin); + let current_clip = self.calculate_style_specified_clip(current_clip, + stacking_relative_border_box); // Only clip if `overflow` tells us to. match self.style.get_box().overflow { - overflow::hidden | overflow::auto | overflow::scroll => {} - _ => return current_clip, + overflow::hidden | overflow::auto | overflow::scroll => { + // Create a new clip rect. + current_clip.intersect_rect(stacking_relative_border_box) + } + _ => current_clip, } - - // Create a new clip rect. - // - // FIXME(#2795): Get the real container size. - let physical_rect = self.border_box.to_physical(self.style.writing_mode, Size2D::zero()); - current_clip.intersect_rect(&Rect(physical_rect.origin + *flow_origin, physical_rect.size)) } fn build_display_list_for_text_fragment(&self, display_list: &mut DisplayList, text_fragment: &ScannedTextFragmentInfo, text_color: RGBA, - flow_origin: &Point2D, - offset: &Point2D, + stacking_relative_content_box: &Rect, clip: &ClippingRegion) { // Determine the orientation and cursor to use. let (orientation, cursor) = if self.style.writing_mode.is_vertical() { @@ -955,29 +928,16 @@ impl FragmentDisplayListBuilding for Fragment { // // FIXME(pcwalton): Get the real container size. let container_size = Size2D::zero(); - let content_box = self.content_box(); let metrics = &text_fragment.run.font_metrics; - let baseline_origin = { - let mut content_box_start = content_box.start; - content_box_start.b = content_box_start.b + metrics.ascent; - content_box_start.to_physical(self.style.writing_mode, container_size) + *flow_origin + - *offset - }; - let stacking_relative_flow_origin = if self.establishes_stacking_context() { - ZERO_POINT - } else { - *flow_origin - }; - let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect| { - let physical_rect = logical_rect.to_physical(writing_mode, container_size); - Rect(physical_rect.origin + stacking_relative_flow_origin, physical_rect.size) - }; - let content_rect = rect_to_absolute(self.style.writing_mode, - content_box).translate(offset); + let baseline_origin = stacking_relative_content_box.origin + + LogicalPoint::new(self.style.writing_mode, + Au(0), + metrics.ascent).to_physical(self.style.writing_mode, + container_size); // Create the text display item. display_list.content.push_back(DisplayItem::TextClass(box TextDisplayItem { - base: BaseDisplayItem::new(content_rect, + base: BaseDisplayItem::new(*stacking_relative_content_box, DisplayItemMetadata::new(self.node, self.style(), cursor), (*clip).clone()), text_run: text_fragment.run.clone(), @@ -989,63 +949,55 @@ impl FragmentDisplayListBuilding for Fragment { // Create display items for text decorations. let text_decorations = self.style().get_inheritedtext()._servo_text_decorations_in_effect; - if let Some(underline_color) = text_decorations.underline { - let mut rect = content_box.clone(); - rect.start.b = rect.start.b + metrics.ascent - metrics.underline_offset; - rect.size.block = metrics.underline_size; + let stacking_relative_content_box = + LogicalRect::from_physical(self.style.writing_mode, + *stacking_relative_content_box, + container_size); + if let Some(ref underline_color) = text_decorations.underline { + let mut stacking_relative_box = stacking_relative_content_box; + stacking_relative_box.start.b = stacking_relative_content_box.start.b + + metrics.ascent - metrics.underline_offset; + stacking_relative_box.size.block = metrics.underline_size; self.build_display_list_for_text_decoration(display_list, underline_color, - flow_origin, - clip, - &rect, - offset) + &stacking_relative_box, + clip) } - if let Some(overline_color) = text_decorations.overline { - let mut rect = content_box.clone(); - rect.size.block = metrics.underline_size; + if let Some(ref overline_color) = text_decorations.overline { + let mut stacking_relative_box = stacking_relative_content_box; + stacking_relative_box.size.block = metrics.underline_size; self.build_display_list_for_text_decoration(display_list, overline_color, - flow_origin, - clip, - &rect, - offset) + &stacking_relative_box, + clip) } - if let Some(line_through_color) = text_decorations.line_through { - let mut rect = content_box.clone(); - rect.start.b = rect.start.b + metrics.ascent - metrics.strikeout_offset; - rect.size.block = metrics.strikeout_size; + if let Some(ref line_through_color) = text_decorations.line_through { + let mut stacking_relative_box = stacking_relative_content_box; + stacking_relative_box.start.b = stacking_relative_box.start.b + metrics.ascent - + metrics.strikeout_offset; + stacking_relative_box.size.block = metrics.strikeout_size; self.build_display_list_for_text_decoration(display_list, line_through_color, - flow_origin, - clip, - &rect, - offset) + &stacking_relative_box, + clip) } } fn build_display_list_for_text_decoration(&self, display_list: &mut DisplayList, - color: RGBA, - flow_origin: &Point2D, - clip: &ClippingRegion, - logical_bounds: &LogicalRect, - offset: &Point2D) { - // FIXME(pcwalton): Get the real container size. + color: &RGBA, + stacking_relative_box: &LogicalRect, + clip: &ClippingRegion) { + // FIXME(pcwalton, #2795): Get the real container size. let container_size = Size2D::zero(); - let stacking_relative_flow_origin = if self.establishes_stacking_context() { - ZERO_POINT - } else { - *flow_origin - }; - let physical_rect = logical_bounds.to_physical(self.style.writing_mode, container_size); + let stacking_relative_box = stacking_relative_box.to_physical(self.style.writing_mode, + container_size); - let bounds = Rect(physical_rect.origin + stacking_relative_flow_origin, - physical_rect.size).translate(offset); let metadata = DisplayItemMetadata::new(self.node, &*self.style, DefaultCursor); display_list.content.push_back(DisplayItem::SolidColorClass(box SolidColorDisplayItem { - base: BaseDisplayItem::new(bounds, metadata, (*clip).clone()), + base: BaseDisplayItem::new(stacking_relative_box, metadata, (*clip).clone()), color: color.to_gfx_color(), })) } @@ -1081,14 +1033,16 @@ impl BlockFlowDisplayListBuilding for BlockFlow { layout_context: &LayoutContext, background_border_level: BackgroundAndBorderLevel) { // Add the box that starts the block context. - let stacking_relative_fragment_origin = - self.base.stacking_relative_position_of_child_fragment(&self.fragment); self.fragment.build_display_list(display_list, layout_context, - stacking_relative_fragment_origin, + &self.base.stacking_relative_position, + &self.base + .absolute_position_info + .relative_containing_block_size, background_border_level, &self.base.clip); + // Add children. for kid in self.base.children.iter_mut() { flow::mut_base(kid).display_list_building_result.add_to(display_list); } @@ -1103,7 +1057,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow { background_border_level); self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { - DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None)) + DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, + None)) } else { DisplayListBuildingResult::Normal(display_list) } @@ -1120,7 +1075,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow { !self.base.flags.contains(NEEDS_LAYER) { // We didn't need a layer. self.base.display_list_building_result = - DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None)); + DisplayListBuildingResult::StackingContext(self.create_stacking_context( + display_list, + None)); return } @@ -1137,7 +1094,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow { Some(Arc::new(PaintLayer::new(self.layer_id(0), transparent, scroll_policy)))); - self.base.display_list_building_result = DisplayListBuildingResult::StackingContext(stacking_context) + self.base.display_list_building_result = + DisplayListBuildingResult::StackingContext(stacking_context) } fn build_display_list_for_floating_block(&mut self, @@ -1149,7 +1107,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow { display_list.form_float_pseudo_stacking_context(); self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { - DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None)) + DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, + None)) } else { DisplayListBuildingResult::Normal(display_list) } @@ -1165,7 +1124,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow { } else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) { self.build_display_list_for_absolutely_positioned_block(display_list, layout_context) } else { - self.build_display_list_for_static_block(display_list, layout_context, BackgroundAndBorderLevel::Block) + self.build_display_list_for_static_block(display_list, + layout_context, + BackgroundAndBorderLevel::Block) } } @@ -1173,11 +1134,67 @@ impl BlockFlowDisplayListBuilding for BlockFlow { display_list: Box, layer: Option>) -> Arc { - let bounds = Rect(self.base.stacking_relative_position, - self.base.overflow.size.to_physical(self.base.writing_mode)); - let z_index = self.fragment.style().get_box().z_index.number_or_zero(); - let opacity = self.fragment.style().get_effects().opacity as f32; - Arc::new(StackingContext::new(display_list, bounds, z_index, opacity, layer)) + debug_assert!(self.fragment.establishes_stacking_context()); + let border_box = self.fragment + .stacking_relative_border_box(&self.base.stacking_relative_position, + &self.base + .absolute_position_info + .relative_containing_block_size, + CoordinateSystem::Parent); + + // FIXME(pcwalton): Is this vertical-writing-direction-safe? + let margin = self.fragment.margin.to_physical(self.base.writing_mode); + let overflow = self.base.overflow.translate(&-Point2D(margin.left, Au(0))); + + Arc::new(StackingContext::new(display_list, + &border_box, + &overflow, + self.fragment.style().get_box().z_index.number_or_zero(), + self.fragment.style().get_effects().opacity as f32, + layer)) + } +} + +pub trait InlineFlowDisplayListBuilding { + fn build_display_list_for_inline(&mut self, layout_context: &LayoutContext); +} + +impl InlineFlowDisplayListBuilding for InlineFlow { + fn build_display_list_for_inline(&mut self, layout_context: &LayoutContext) { + // TODO(#228): Once we form lines and have their cached bounds, we can be smarter and + // not recurse on a line if nothing in it can intersect the dirty region. + debug!("Flow: building display list for {:u} inline fragments", self.fragments.len()); + + let mut display_list = box DisplayList::new(); + for fragment in self.fragments.fragments.iter_mut() { + fragment.build_display_list(&mut *display_list, + layout_context, + &self.base.stacking_relative_position, + &self.base + .absolute_position_info + .relative_containing_block_size, + BackgroundAndBorderLevel::Content, + &self.base.clip); + match fragment.specific { + SpecificFragmentInfo::InlineBlock(ref mut block_flow) => { + let block_flow = block_flow.flow_ref.deref_mut(); + flow::mut_base(block_flow).display_list_building_result + .add_to(&mut *display_list) + } + SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => { + let block_flow = block_flow.flow_ref.deref_mut(); + flow::mut_base(block_flow).display_list_building_result + .add_to(&mut *display_list) + } + _ => {} + } + } + + self.base.display_list_building_result = DisplayListBuildingResult::Normal(display_list); + + if opts::get().validate_display_list_geometry { + self.base.validate_display_list_geometry(); + } } } @@ -1192,17 +1209,16 @@ impl ListItemFlowDisplayListBuilding for ListItemFlow { mut display_list: Box, layout_context: &LayoutContext) { // Draw the marker, if applicable. - match self.marker { - None => {} - Some(ref mut marker) => { - let stacking_relative_fragment_origin = - self.block_flow.base.stacking_relative_position_of_child_fragment(marker); - marker.build_display_list(&mut *display_list, - layout_context, - stacking_relative_fragment_origin, - BackgroundAndBorderLevel::Content, - &self.block_flow.base.clip); - } + if let Some(ref mut marker) = self.marker { + marker.build_display_list(&mut *display_list, + layout_context, + &self.block_flow.base.stacking_relative_position, + &self.block_flow + .base + .absolute_position_info + .relative_containing_block_size, + BackgroundAndBorderLevel::Content, + &self.block_flow.base.clip); } // Draw the rest of the block. @@ -1280,3 +1296,4 @@ impl StackingContextConstruction for DisplayList { } } } + diff --git a/components/layout/flow.rs b/components/layout/flow.rs index a36fca0df0a..d252a93269b 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -32,7 +32,7 @@ use display_list_builder::DisplayListBuildingResult; use floats::Floats; use flow_list::{FlowList, FlowListIterator, MutFlowListIterator}; use flow_ref::FlowRef; -use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo}; +use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage}; use inline::InlineFlow; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; @@ -50,7 +50,7 @@ use geom::{Point2D, Rect, Size2D}; use gfx::display_list::ClippingRegion; use serialize::{Encoder, Encodable}; use servo_msg::compositor_msg::LayerId; -use servo_util::geometry::Au; +use servo_util::geometry::{Au, ZERO_RECT}; use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; use std::mem; use std::fmt; @@ -220,8 +220,13 @@ pub trait Flow: fmt::Show + ToString + Sync { /// Phase 5 of reflow: builds display lists. fn build_display_list(&mut self, layout_context: &LayoutContext); - /// Perform an iteration of fragment bounds on this flow. - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator); + /// Returns the union of all overflow rects of all of this flow's fragments. + fn compute_overflow(&self) -> Rect; + + /// Iterates through border boxes of all of this flow's fragments. + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D); fn compute_collapsible_block_start_margin(&mut self, _layout_context: &mut LayoutContext, @@ -718,7 +723,7 @@ pub struct BaseFlow { /// The amount of overflow of this flow, relative to the containing block. Must include all the /// pixels of all the display list items for correct invalidation. - pub overflow: LogicalRect, + pub overflow: Rect, /// Data used during parallel traversals. /// @@ -894,7 +899,7 @@ impl BaseFlow { children: FlowList::new(), intrinsic_inline_sizes: IntrinsicISizes::new(), position: LogicalRect::zero(writing_mode), - overflow: LogicalRect::zero(writing_mode), + overflow: ZERO_RECT, parallel: FlowParallelInfo::new(), floats: Floats::new(writing_mode), collapsible_margins: CollapsibleMargins::new(), @@ -929,10 +934,12 @@ impl BaseFlow { /// Ensures that all display list items generated by this flow are within the flow's overflow /// rect. This should only be used for debugging. pub fn validate_display_list_geometry(&self) { - let position_with_overflow = self.position.union(&self.overflow); - let bounds = Rect(self.stacking_relative_position, - Size2D(position_with_overflow.size.inline, - position_with_overflow.size.block)); + // FIXME(pcwalton, #2795): Get the real container size. + let container_size = Size2D::zero(); + let position_with_overflow = self.position + .to_physical(self.writing_mode, container_size) + .union(&self.overflow); + let bounds = Rect(self.stacking_relative_position, position_with_overflow.size); let all_items = match self.display_list_building_result { DisplayListBuildingResult::None => Vec::new(), @@ -953,17 +960,6 @@ impl BaseFlow { } } } - - /// Returns the position of the given fragment relative to the start of the nearest ancestor - /// stacking context. The fragment must be a child fragment of this flow. - pub fn stacking_relative_position_of_child_fragment(&self, fragment: &Fragment) - -> Point2D { - let relative_offset = - fragment.relative_position(&self - .absolute_position_info - .relative_containing_block_size); - self.stacking_relative_position.add_size(&relative_offset.to_physical(self.writing_mode)) - } } impl<'a> ImmutableFlowUtils for &'a Flow + 'a { @@ -1060,14 +1056,14 @@ impl<'a> ImmutableFlowUtils for &'a Flow + 'a { let flow = match self.class() { FlowClass::Table | FlowClass::TableRowGroup => { let fragment = - Fragment::new_anonymous_table_fragment(node, - SpecificFragmentInfo::TableRow); + Fragment::new_anonymous_from_specific_info(node, + SpecificFragmentInfo::TableRow); box TableRowFlow::from_node_and_fragment(node, fragment) as Box }, FlowClass::TableRow => { let fragment = - Fragment::new_anonymous_table_fragment(node, - SpecificFragmentInfo::TableCell); + Fragment::new_anonymous_from_specific_info(node, + SpecificFragmentInfo::TableCell); let hide = node.style().get_inheritedtable().empty_cells == empty_cells::hide; box TableCellFlow::from_node_fragment_and_visibility_flag(node, fragment, !hide) as Box @@ -1175,40 +1171,29 @@ impl<'a> MutableFlowUtils for &'a mut Flow + 'a { /// already been set. /// Assumption: Absolute descendants have had their overflow calculated. fn store_overflow(self, _: &LayoutContext) { - let my_position = mut_base(self).position; - - // FIXME(pcwalton): We should calculate overflow on a per-fragment basis, because their - // styles can affect overflow regions. Consider `box-shadow`, `outline`, etc.--anything - // that can draw outside the border box. For now we assume overflow is the border box, but - // that is wrong. - let mut overflow = my_position; - + // Calculate overflow on a per-fragment basis. + let mut overflow = self.compute_overflow(); if self.is_block_container() { - let writing_mode = base(self).writing_mode; - // FIXME(#2795): Get the real container size + // FIXME(#2795): Get the real container size. let container_size = Size2D::zero(); for kid in child_iter(self) { - if kid.is_store_overflow_delayed() { - // Absolute flows will be handled by their CB. If we are - // their CB, they will show up in `abs_descendants`. - continue; + if base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) { + continue } - let kid_base = base(kid); - let mut kid_overflow = kid_base.overflow.convert( - kid_base.writing_mode, writing_mode, container_size); - kid_overflow = kid_overflow.translate(&my_position.start); - overflow = overflow.union(&kid_overflow) + let kid_overflow = base(kid).overflow; + let kid_position = base(kid).position.to_physical(base(kid).writing_mode, + container_size); + overflow = overflow.union(&kid_overflow.translate(&kid_position.origin)) } - // FIXME(#2004, pcwalton): This is wrong for `position: fixed`. - for descendant_link in mut_base(self).abs_descendants.iter() { - let kid_base = base(descendant_link); - let mut kid_overflow = kid_base.overflow.convert( - kid_base.writing_mode, writing_mode, container_size); - kid_overflow = kid_overflow.translate(&my_position.start); - overflow = overflow.union(&kid_overflow) + for kid in mut_base(self).abs_descendants.iter() { + let kid_overflow = base(kid).overflow; + let kid_position = base(kid).position.to_physical(base(kid).writing_mode, + container_size); + overflow = overflow.union(&kid_overflow.translate(&kid_position.origin)) } } + mut_base(self).overflow = overflow; } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index b50f484f8d9..cfc2ab8b1a5 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -23,7 +23,7 @@ use util::OpaqueNodeMethods; use wrapper::{TLayoutNode, ThreadSafeLayoutNode}; use geom::{Point2D, Rect, Size2D}; -use gfx::display_list::OpaqueNode; +use gfx::display_list::{BOX_SHADOW_INFLATION_FACTOR, OpaqueNode}; use gfx::text::glyph::CharIndex; use gfx::text::text_run::{TextRun, TextRunSlice}; use script_traits::UntrustedNodeAddress; @@ -31,8 +31,7 @@ use serialize::{Encodable, Encoder}; use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_net::image::holder::ImageHolder; use servo_net::local_image_cache::LocalImageCache; -use servo_util::geometry::Au; -use servo_util::geometry; +use servo_util::geometry::{mod, Au, ZERO_POINT}; use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin}; use servo_util::range::*; use servo_util::smallvec::SmallVec; @@ -62,8 +61,8 @@ use url::Url; /// positioned as if it were a block fragment, but its children are positioned according to /// inline flow. /// -/// A `SpecificFragmentInfo::Generic` is an empty fragment that contributes only borders, margins, padding, and -/// backgrounds. It is analogous to a CSS nonreplaced content box. +/// A `SpecificFragmentInfo::Generic` is an empty fragment that contributes only borders, margins, +/// padding, and backgrounds. It is analogous to a CSS nonreplaced content box. /// /// A fragment's type influences how its styles are interpreted during layout. For example, /// replaced content such as images are resized differently from tables, text, or other content. @@ -83,8 +82,10 @@ pub struct Fragment { /// The CSS style of this fragment. pub style: Arc, - /// The position of this fragment relative to its owning flow. - /// The size includes padding and border, but not margin. + /// The position of this fragment relative to its owning flow. The size includes padding and + /// border, but not margin. + /// + /// NB: This does not account for relative positioning. pub border_box: LogicalRect, /// The sum of border and padding; i.e. the distance from the edge of the border box to the @@ -520,10 +521,28 @@ impl Fragment { } } + /// Constructs a new `Fragment` instance for an anonymous object. + pub fn new_anonymous(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) + -> Fragment { + let node_style = cascade_anonymous(&**node.style()); + let writing_mode = node_style.writing_mode; + Fragment { + node: OpaqueNodeMethods::from_thread_safe_layout_node(node), + style: Arc::new(node_style), + restyle_damage: node.restyle_damage(), + border_box: LogicalRect::zero(writing_mode), + border_padding: LogicalMargin::zero(writing_mode), + margin: LogicalMargin::zero(writing_mode), + specific: constructor.build_specific_fragment_info_for_node(node), + inline_context: None, + debug_id: layout_debug::generate_unique_debug_id(), + } + } + /// Constructs a new `Fragment` instance for an anonymous table object. - pub fn new_anonymous_table_fragment(node: &ThreadSafeLayoutNode, - specific: SpecificFragmentInfo) - -> Fragment { + pub fn new_anonymous_from_specific_info(node: &ThreadSafeLayoutNode, + specific: SpecificFragmentInfo) + -> Fragment { // CSS 2.1 § 17.2.1 This is for non-inherited properties on anonymous table fragments // example: // @@ -531,8 +550,9 @@ impl Fragment { // Foo // // - // Anonymous table fragments, SpecificFragmentInfo::TableRow and SpecificFragmentInfo::TableCell, are generated around - // `Foo`, but they shouldn't inherit the border. + // Anonymous table fragments, SpecificFragmentInfo::TableRow and + // SpecificFragmentInfo::TableCell, are generated around `Foo`, but they shouldn't inherit + // the border. let node_style = cascade_anonymous(&**node.style()); let writing_mode = node_style.writing_mode; @@ -647,7 +667,10 @@ impl Fragment { fn quantities_included_in_intrinsic_inline_size(&self) -> QuantitiesIncludedInIntrinsicInlineSizes { match self.specific { - SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::InlineBlock(_) => { + SpecificFragmentInfo::Generic | + SpecificFragmentInfo::Iframe(_) | + SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::InlineBlock(_) => { QuantitiesIncludedInIntrinsicInlineSizes::all() } SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => { @@ -836,9 +859,7 @@ impl Fragment { } // Return offset from original position because of `position: relative`. - pub fn relative_position(&self, - containing_block_size: &LogicalSize) - -> LogicalSize { + pub fn relative_position(&self, containing_block_size: &LogicalSize) -> LogicalSize { fn from_style(style: &ComputedValues, container_size: &LogicalSize) -> LogicalSize { let offsets = style.logical_position(); @@ -1506,10 +1527,17 @@ impl Fragment { /// because the corresponding table flow is the primary fragment. pub fn is_primary_fragment(&self) -> bool { match self.specific { - SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | + SpecificFragmentInfo::InlineBlock(_) | + SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::TableWrapper => false, - SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | - SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableColumn(_) | SpecificFragmentInfo::TableRow | + SpecificFragmentInfo::Generic | + SpecificFragmentInfo::Iframe(_) | + SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::ScannedText(_) | + SpecificFragmentInfo::Table | + SpecificFragmentInfo::TableCell | + SpecificFragmentInfo::TableColumn(_) | + SpecificFragmentInfo::TableRow | SpecificFragmentInfo::UnscannedText(_) => true, } } @@ -1538,15 +1566,48 @@ impl Fragment { self.style = (*new_style).clone() } - /// Given the stacking-context-relative position of the containing flow, returns the boundaries - /// of this fragment relative to the parent stacking context. - pub fn stacking_relative_bounds(&self, stacking_relative_flow_origin: &Point2D) - -> Rect { - // FIXME(#2795): Get the real container size + /// Given the stacking-context-relative position of the containing flow, returns the border box + /// of this fragment relative to the parent stacking context. This takes `position: relative` + /// into account. + /// + /// If `coordinate_system` is `Parent`, this returns the border box in the parent stacking + /// context's coordinate system. Otherwise, if `coordinate_system` is `Self` and this fragment + /// establishes a stacking context itself, this returns a border box anchored at (0, 0). (If + /// this fragment does not establish a stacking context, then it always belongs to its parent + /// stacking context and thus `coordinate_system` is ignored.) + /// + /// This is the method you should use for display list construction as well as + /// `getBoundingClientRect()` and so forth. + pub fn stacking_relative_border_box(&self, + stacking_relative_flow_origin: &Point2D, + relative_containing_block_size: &LogicalSize, + coordinate_system: CoordinateSystem) + -> Rect { + // FIXME(pcwalton, #2795): Get the real container size. let container_size = Size2D::zero(); - self.border_box - .to_physical(self.style.writing_mode, container_size) - .translate(stacking_relative_flow_origin) + let border_box = self.border_box.to_physical(self.style.writing_mode, container_size); + if coordinate_system == CoordinateSystem::Self && self.establishes_stacking_context() { + return Rect(ZERO_POINT, border_box.size) + } + + // FIXME(pcwalton): This can double-count relative position sometimes for inlines (e.g. + // `
x
`, because the `position:relative` trickles down + // to the inline flow. Possibly we should extend the notion of "primary fragment" to fix + // this. + let relative_position = self.relative_position(relative_containing_block_size); + border_box.translate_by_size(&relative_position.to_physical(self.style.writing_mode)) + .translate(stacking_relative_flow_origin) + } + + /// Given the stacking-context-relative border box, returns the stacking-context-relative + /// content box. + pub fn stacking_relative_content_box(&self, stacking_relative_border_box: &Rect) + -> Rect { + let border_padding = self.border_padding.to_physical(self.style.writing_mode); + Rect(Point2D(stacking_relative_border_box.origin.x + border_padding.left, + stacking_relative_border_box.origin.y + border_padding.top), + Size2D(stacking_relative_border_box.size.width - border_padding.horizontal(), + stacking_relative_border_box.size.height - border_padding.vertical())) } /// Returns true if this fragment establishes a new stacking context and false otherwise. @@ -1567,6 +1628,41 @@ impl Fragment { } } } + + /// Computes the overflow rect of this fragment relative to the start of the flow. + pub fn compute_overflow(&self) -> Rect { + // FIXME(pcwalton, #2795): Get the real container size. + let container_size = Size2D::zero(); + let mut border_box = self.border_box.to_physical(self.style.writing_mode, container_size); + + // Relative position can cause us to draw outside our border box. + // + // FIXME(pcwalton): I'm not a fan of the way this makes us crawl though so many styles all + // the time. Can't we handle relative positioning by just adjusting `border_box`? + let relative_position = + self.relative_position(&LogicalSize::zero(self.style.writing_mode)); + border_box = + border_box.translate_by_size(&relative_position.to_physical(self.style.writing_mode)); + let mut overflow = border_box; + + // Box shadows cause us to draw outside our border box. + for box_shadow in self.style().get_effects().box_shadow.iter() { + let offset = Point2D(box_shadow.offset_x, box_shadow.offset_y); + let inflation = box_shadow.spread_radius + + box_shadow.blur_radius * BOX_SHADOW_INFLATION_FACTOR; + overflow = overflow.union(&border_box.translate(&offset).inflate(inflation, inflation)) + } + + // Outlines cause us to draw outside our border box. + let outline_width = self.style.get_outline().outline_width; + if outline_width != Au(0) { + overflow = overflow.union(&border_box.inflate(outline_width, outline_width)) + } + + // FIXME(pcwalton): Sometimes excessively fancy glyphs can make us draw outside our border + // box too. + overflow + } } impl fmt::Show for Fragment { @@ -1600,13 +1696,23 @@ bitflags! { } } -/// A top-down fragment bounds iteration handler. -pub trait FragmentBoundsIterator { +/// A top-down fragment border box iteration handler. +pub trait FragmentBorderBoxIterator { /// The operation to perform. - fn process(&mut self, fragment: &Fragment, bounds: Rect); + fn process(&mut self, fragment: &Fragment, overflow: &Rect); /// Returns true if this fragment must be processed in-order. If this returns false, /// we skip the operation for this fragment, but continue processing siblings. fn should_process(&mut self, fragment: &Fragment) -> bool; } +/// The coordinate system used in `stacking_relative_border_box()`. See the documentation of that +/// method for details. +#[deriving(Clone, PartialEq, Show)] +pub enum CoordinateSystem { + /// The border box returned is relative to the fragment's parent stacking context. + Parent, + /// The border box returned is relative to the fragment's own stacking context, if applicable. + Self, +} + diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 2230fb3e823..0a2234bfa8b 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -6,13 +6,13 @@ use css::node_style::StyledNode; use context::LayoutContext; -use display_list_builder::{BackgroundAndBorderLevel, DisplayListBuildingResult, FragmentDisplayListBuilding}; +use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding}; use floats::{FloatKind, Floats, PlacementInfo}; use flow::{BaseFlow, FlowClass, Flow, MutableFlowUtils, ForceNonfloatedFlag}; use flow::{IS_ABSOLUTELY_POSITIONED}; use flow; -use fragment::{Fragment, SpecificFragmentInfo}; -use fragment::{FragmentBoundsIterator, ScannedTextFragmentInfo}; +use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, ScannedTextFragmentInfo}; +use fragment::{SpecificFragmentInfo}; use fragment::SplitInfo; use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use layout_debug; @@ -20,16 +20,14 @@ use model::IntrinsicISizesContribution; use text; use collections::{RingBuf}; -use geom::Size2D; -use gfx::display_list::DisplayList; +use geom::{Point2D, Rect}; use gfx::font::FontMetrics; use gfx::font_context::FontContext; use gfx::text::glyph::CharIndex; -use servo_util::geometry::Au; -use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; -use servo_util::opts; -use servo_util::range::{Range, RangeIndex}; use servo_util::arc_ptr_eq; +use servo_util::geometry::{Au, ZERO_RECT}; +use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; +use servo_util::range::{Range, RangeIndex}; use std::cmp::max; use std::fmt; use std::mem; @@ -1186,44 +1184,29 @@ impl Flow for InlineFlow { fn compute_absolute_position(&mut self) { for fragment in self.fragments.fragments.iter_mut() { - let stacking_relative_position = match fragment.specific { - SpecificFragmentInfo::InlineBlock(ref mut info) => { - let block_flow = info.flow_ref.as_block(); - block_flow.base.absolute_position_info = self.base.absolute_position_info; - - // FIXME(#2795): Get the real container size - let container_size = Size2D::zero(); - block_flow.base.stacking_relative_position = - self.base.stacking_relative_position + - fragment.border_box.start.to_physical(self.base.writing_mode, - container_size); - block_flow.base.stacking_relative_position - } - SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => { - let block_flow = info.flow_ref.as_block(); - block_flow.base.absolute_position_info = self.base.absolute_position_info; - - // FIXME(#2795): Get the real container size - let container_size = Size2D::zero(); - block_flow.base.stacking_relative_position = - self.base.stacking_relative_position + - fragment.border_box.start.to_physical(self.base.writing_mode, - container_size); - block_flow.base.stacking_relative_position - - } - _ => continue, - }; - + let stacking_relative_border_box = + fragment.stacking_relative_border_box(&self.base.stacking_relative_position, + &self.base + .absolute_position_info + .relative_containing_block_size, + CoordinateSystem::Self); let clip = fragment.clipping_region_for_children(&self.base.clip, - &stacking_relative_position); - + &stacking_relative_border_box); match fragment.specific { SpecificFragmentInfo::InlineBlock(ref mut info) => { - flow::mut_base(info.flow_ref.deref_mut()).clip = clip + flow::mut_base(info.flow_ref.deref_mut()).clip = clip; + let block_flow = info.flow_ref.as_block(); + block_flow.base.absolute_position_info = self.base.absolute_position_info; + block_flow.base.stacking_relative_position = + stacking_relative_border_box.origin; } SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => { - flow::mut_base(info.flow_ref.deref_mut()).clip = clip + flow::mut_base(info.flow_ref.deref_mut()).clip = clip; + let block_flow = info.flow_ref.as_block(); + block_flow.base.absolute_position_info = self.base.absolute_position_info; + block_flow.base.stacking_relative_position = + stacking_relative_border_box.origin + } _ => {} } @@ -1235,49 +1218,36 @@ impl Flow for InlineFlow { fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {} fn build_display_list(&mut self, layout_context: &LayoutContext) { - // TODO(#228): Once we form lines and have their cached bounds, we can be smarter and - // not recurse on a line if nothing in it can intersect the dirty region. - debug!("Flow: building display list for {} inline fragments", self.fragments.len()); - - let mut display_list = box DisplayList::new(); - for fragment in self.fragments.fragments.iter_mut() { - let fragment_origin = self.base.stacking_relative_position_of_child_fragment(fragment); - fragment.build_display_list(&mut *display_list, - layout_context, - fragment_origin, - BackgroundAndBorderLevel::Content, - &self.base.clip); - match fragment.specific { - SpecificFragmentInfo::InlineBlock(ref mut block_flow) => { - let block_flow = block_flow.flow_ref.deref_mut(); - flow::mut_base(block_flow).display_list_building_result - .add_to(&mut *display_list) - } - SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => { - let block_flow = block_flow.flow_ref.deref_mut(); - flow::mut_base(block_flow).display_list_building_result - .add_to(&mut *display_list) - } - _ => {} - } - } - - self.base.display_list_building_result = DisplayListBuildingResult::Normal(display_list); - - if opts::get().validate_display_list_geometry { - self.base.validate_display_list_geometry(); - } + self.build_display_list_for_inline(layout_context) } fn repair_style(&mut self, _: &Arc) {} - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { + fn compute_overflow(&self) -> Rect { + let mut overflow = ZERO_RECT; for fragment in self.fragments.fragments.iter() { - if iterator.should_process(fragment) { - let fragment_origin = - self.base.stacking_relative_position_of_child_fragment(fragment); - iterator.process(fragment, fragment.stacking_relative_bounds(&fragment_origin)); + overflow = overflow.union(&fragment.compute_overflow()) + } + overflow + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + // FIXME(#2795): Get the real container size. + for fragment in self.fragments.fragments.iter() { + if !iterator.should_process(fragment) { + continue } + + let stacking_relative_position = &self.base.stacking_relative_position; + let relative_containing_block_size = + &self.base.absolute_position_info.relative_containing_block_size; + iterator.process(fragment, + &fragment.stacking_relative_border_box(stacking_relative_position, + relative_containing_block_size, + CoordinateSystem::Parent) + .translate(stacking_context_position)) } } } diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 090b51cee70..3309ff9c28b 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -10,7 +10,7 @@ use construct::ConstructionResult; use context::SharedLayoutContext; use flow::{mod, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; use flow_ref::FlowRef; -use fragment::{Fragment, FragmentBoundsIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator}; use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT}; use layout_debug; use parallel::{mod, UnsafeFlow}; @@ -604,8 +604,8 @@ impl LayoutTask { // FIXME(pcwalton): This has not been updated to handle the stacking context relative // stuff. So the position is wrong in most cases. let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); - let mut iterator = UnioningFragmentBoundsIterator::new(requested_node); - sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator); + let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node); + sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); rw_data.content_box_response = iterator.rect; } @@ -616,8 +616,8 @@ impl LayoutTask { // FIXME(pcwalton): This has not been updated to handle the stacking context relative // stuff. So the position is wrong in most cases. let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); - let mut iterator = CollectingFragmentBoundsIterator::new(requested_node); - sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator); + let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node); + sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); rw_data.content_boxes_response = iterator.rects; } @@ -689,11 +689,12 @@ impl LayoutTask { flow::mut_base(layout_root.deref_mut()).display_list_building_result .add_to(&mut *display_list); let paint_layer = Arc::new(PaintLayer::new(layout_root.layer_id(0), - color, - Scrollable)); + color, + Scrollable)); let origin = Rect(Point2D(Au(0), Au(0)), root_size); let stacking_context = Arc::new(StackingContext::new(display_list, - origin, + &origin, + &origin, 0, 1.0, Some(paint_layer))); @@ -1016,26 +1017,26 @@ impl LayoutRPC for LayoutRPCImpl { } } -struct UnioningFragmentBoundsIterator { +struct UnioningFragmentBorderBoxIterator { node_address: OpaqueNode, rect: Rect, } -impl UnioningFragmentBoundsIterator { - fn new(node_address: OpaqueNode) -> UnioningFragmentBoundsIterator { - UnioningFragmentBoundsIterator { +impl UnioningFragmentBorderBoxIterator { + fn new(node_address: OpaqueNode) -> UnioningFragmentBorderBoxIterator { + UnioningFragmentBorderBoxIterator { node_address: node_address, rect: Rect::zero(), } } } -impl FragmentBoundsIterator for UnioningFragmentBoundsIterator { - fn process(&mut self, _: &Fragment, bounds: Rect) { - if self.rect.is_empty() { - self.rect = bounds; +impl FragmentBorderBoxIterator for UnioningFragmentBorderBoxIterator { + fn process(&mut self, _: &Fragment, border_box: &Rect) { + self.rect = if self.rect.is_empty() { + *border_box } else { - self.rect = self.rect.union(&bounds); + self.rect.union(border_box) } } @@ -1044,23 +1045,23 @@ impl FragmentBoundsIterator for UnioningFragmentBoundsIterator { } } -struct CollectingFragmentBoundsIterator { +struct CollectingFragmentBorderBoxIterator { node_address: OpaqueNode, rects: Vec>, } -impl CollectingFragmentBoundsIterator { - fn new(node_address: OpaqueNode) -> CollectingFragmentBoundsIterator { - CollectingFragmentBoundsIterator { +impl CollectingFragmentBorderBoxIterator { + fn new(node_address: OpaqueNode) -> CollectingFragmentBorderBoxIterator { + CollectingFragmentBorderBoxIterator { node_address: node_address, rects: Vec::new(), } } } -impl FragmentBoundsIterator for CollectingFragmentBoundsIterator { - fn process(&mut self, _: &Fragment, bounds: Rect) { - self.rects.push(bounds); +impl FragmentBorderBoxIterator for CollectingFragmentBorderBoxIterator { + fn process(&mut self, _: &Fragment, border_box: &Rect) { + self.rects.push(*border_box); } fn should_process(&mut self, fragment: &Fragment) -> bool { diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs index 3b31d1fdc44..b13630496c5 100644 --- a/components/layout/list_item.rs +++ b/components/layout/list_item.rs @@ -12,9 +12,10 @@ use construct::FlowConstructor; use context::LayoutContext; use display_list_builder::ListItemFlowDisplayListBuilding; use flow::{Flow, FlowClass}; -use fragment::{Fragment, FragmentBoundsIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator}; use wrapper::ThreadSafeLayoutNode; +use geom::{Point2D, Rect}; use gfx::display_list::DisplayList; use servo_util::geometry::Au; use servo_util::opts; @@ -111,8 +112,14 @@ impl Flow for ListItemFlow { self.block_flow.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - self.block_flow.iterate_through_fragment_bounds(iterator); + fn compute_overflow(&self) -> Rect { + self.block_flow.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) } } diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index 4636fa9c3eb..1be77041113 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -5,11 +5,10 @@ //! Implements sequential traversals over the DOM and flow trees. use context::{LayoutContext, SharedLayoutContext}; -use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal}; -use flow; +use flow::{mod, Flow, ImmutableFlowUtils, MutableFlowUtils, PostorderFlowTraversal}; +use flow::{PreorderFlowTraversal}; use flow_ref::FlowRef; -use fragment::FragmentBoundsIterator; -use servo_util::opts; +use fragment::FragmentBorderBoxIterator; use traversal::{BubbleISizes, RecalcStyleForNode, ConstructFlows}; use traversal::{AssignBSizesAndStoreOverflow, AssignISizes}; use traversal::{ComputeAbsolutePositions, BuildDisplayList}; @@ -17,6 +16,10 @@ use wrapper::LayoutNode; use wrapper::{PostorderNodeMutTraversal}; use wrapper::{PreorderDomTraversal, PostorderDomTraversal}; +use geom::point::Point2D; +use servo_util::geometry::{Au, ZERO_POINT}; +use servo_util::opts; + pub fn traverse_dom_preorder(root: LayoutNode, shared_layout_context: &SharedLayoutContext) { fn doit(node: LayoutNode, recalc_style: RecalcStyleForNode, construct_flows: ConstructFlows) { @@ -94,15 +97,25 @@ pub fn build_display_list_for_subtree(root: &mut FlowRef, doit(root.deref_mut(), compute_absolute_positions, build_display_list); } -pub fn iterate_through_flow_tree_fragment_bounds(root: &mut FlowRef, - iterator: &mut FragmentBoundsIterator) { - fn doit(flow: &mut Flow, iterator: &mut FragmentBoundsIterator) { - flow.iterate_through_fragment_bounds(iterator); +pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut FlowRef, + iterator: &mut FragmentBorderBoxIterator) { + fn doit(flow: &mut Flow, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position); for kid in flow::mut_base(flow).child_iter() { - doit(kid, iterator); + let stacking_context_position = + if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() { + *stacking_context_position + flow::base(kid).stacking_relative_position + } else { + *stacking_context_position + }; + + // FIXME(#2795): Get the real container size. + doit(kid, iterator, &stacking_context_position); } } - doit(root.deref_mut(), iterator); + doit(root.deref_mut(), iterator, &ZERO_POINT); } diff --git a/components/layout/table.rs b/components/layout/table.rs index 8f46ef868ff..e05abd4d67e 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -13,13 +13,14 @@ use context::LayoutContext; use floats::FloatKind; use flow::{mod, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use flow::ImmutableFlowUtils; -use fragment::{Fragment, FragmentBoundsIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator}; use layout_debug; use model::{IntrinsicISizes, IntrinsicISizesContribution}; use table_row::CellIntrinsicInlineSize; use table_wrapper::TableLayout; use wrapper::ThreadSafeLayoutNode; +use geom::{Point2D, Rect}; use servo_util::geometry::Au; use servo_util::logical_geometry::LogicalRect; use std::cmp::max; @@ -384,8 +385,14 @@ impl Flow for TableFlow { self.block_flow.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - self.block_flow.iterate_through_fragment_bounds(iterator); + fn compute_overflow(&self) -> Rect { + self.block_flow.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) } } diff --git a/components/layout/table_caption.rs b/components/layout/table_caption.rs index 65493e2c24a..1a77cde7092 100644 --- a/components/layout/table_caption.rs +++ b/components/layout/table_caption.rs @@ -10,9 +10,10 @@ use block::BlockFlow; use construct::FlowConstructor; use context::LayoutContext; use flow::{FlowClass, Flow}; -use fragment::FragmentBoundsIterator; +use fragment::FragmentBorderBoxIterator; use wrapper::ThreadSafeLayoutNode; +use geom::{Point2D, Rect}; use servo_util::geometry::Au; use std::fmt; use style::ComputedValues; @@ -81,8 +82,14 @@ impl Flow for TableCaptionFlow { self.block_flow.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - self.block_flow.iterate_through_fragment_bounds(iterator); + fn compute_overflow(&self) -> Rect { + self.block_flow.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) } } diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 3d1f1fd54e3..b97a12e143d 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -9,12 +9,13 @@ use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag}; use context::LayoutContext; use flow::{Flow, FlowClass}; -use fragment::{Fragment, FragmentBoundsIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator}; use model::{MaybeAuto}; use layout_debug; use table::InternalTable; use wrapper::ThreadSafeLayoutNode; +use geom::{Point2D, Rect}; use servo_util::geometry::Au; use std::fmt; use style::{UnsignedIntegerAttribute, ComputedValues}; @@ -162,8 +163,14 @@ impl Flow for TableCellFlow { self.block_flow.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - self.block_flow.iterate_through_fragment_bounds(iterator); + fn compute_overflow(&self) -> Rect { + self.block_flow.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) } } diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs index 5ce9f559268..5e7b066d206 100644 --- a/components/layout/table_colgroup.rs +++ b/components/layout/table_colgroup.rs @@ -9,11 +9,12 @@ use context::LayoutContext; use css::node_style::StyledNode; use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag}; -use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo}; +use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use layout_debug; use wrapper::ThreadSafeLayoutNode; -use servo_util::geometry::Au; +use geom::{Point2D, Rect}; +use servo_util::geometry::{Au, ZERO_RECT}; use std::cmp::max; use std::fmt; use style::computed_values::LengthOrPercentageOrAuto; @@ -96,8 +97,13 @@ impl Flow for TableColGroupFlow { fn repair_style(&mut self, _: &Arc) {} - fn iterate_through_fragment_bounds(&self, _: &mut FragmentBoundsIterator) { + fn compute_overflow(&self) -> Rect { + ZERO_RECT } + + fn iterate_through_fragment_border_boxes(&self, + _: &mut FragmentBorderBoxIterator, + _: &Point2D) {} } impl fmt::Show for TableColGroupFlow { diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index d4979de8800..b3e9e1ae7f6 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -12,12 +12,13 @@ use construct::FlowConstructor; use context::LayoutContext; use flow::{FlowClass, Flow, ImmutableFlowUtils}; use flow; -use fragment::{Fragment, FragmentBoundsIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator}; use layout_debug; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; use model::MaybeAuto; use wrapper::ThreadSafeLayoutNode; +use geom::{Point2D, Rect}; use servo_util::geometry::Au; use std::cmp::max; use std::fmt; @@ -315,8 +316,14 @@ impl Flow for TableRowFlow { self.block_flow.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - self.block_flow.iterate_through_fragment_bounds(iterator); + fn compute_overflow(&self) -> Rect { + self.block_flow.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) } } diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index e004890c53d..2c2847565c7 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -10,11 +10,12 @@ use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag}; use construct::FlowConstructor; use context::LayoutContext; use flow::{FlowClass, Flow}; -use fragment::{Fragment, FragmentBoundsIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator}; use layout_debug; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; use wrapper::ThreadSafeLayoutNode; +use geom::{Point2D, Rect}; use servo_util::geometry::Au; use std::fmt; use style::ComputedValues; @@ -150,8 +151,14 @@ impl Flow for TableRowGroupFlow { self.block_flow.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - self.block_flow.iterate_through_fragment_bounds(iterator); + fn compute_overflow(&self) -> Rect { + self.block_flow.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) } } diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index e3d6433a36f..1c68b7fa924 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -19,10 +19,11 @@ use context::LayoutContext; use floats::FloatKind; use flow::{FlowClass, Flow, ImmutableFlowUtils}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; -use fragment::{Fragment, FragmentBoundsIterator}; +use fragment::{Fragment, FragmentBorderBoxIterator}; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; use wrapper::ThreadSafeLayoutNode; +use geom::{Point2D, Rect}; use servo_util::geometry::Au; use std::cmp::{max, min}; use std::fmt; @@ -358,8 +359,14 @@ impl Flow for TableWrapperFlow { self.block_flow.repair_style(new_style) } - fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { - self.block_flow.iterate_through_fragment_bounds(iterator); + fn compute_overflow(&self) -> Rect { + self.block_flow.compute_overflow() + } + + fn iterate_through_fragment_border_boxes(&self, + iterator: &mut FragmentBorderBoxIterator, + stacking_context_position: &Point2D) { + self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position) } } diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 4b824160902..df56254c066 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -332,12 +332,7 @@ impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> { } flow.assign_block_size(self.layout_context); - - // Skip store-overflow for absolutely positioned flows. That will be - // done in a separate traversal. - if !flow.is_store_overflow_delayed() { - flow.store_overflow(self.layout_context); - } + flow.store_overflow(self.layout_context); } #[inline] diff --git a/components/msg/compositor_msg.rs b/components/msg/compositor_msg.rs index 284e40b53af..9d280cef673 100644 --- a/components/msg/compositor_msg.rs +++ b/components/msg/compositor_msg.rs @@ -75,7 +75,7 @@ pub struct LayerMetadata { /// An opaque ID. This is usually the address of the flow and index of the box within it. pub id: LayerId, /// The position and size of the layer in pixels. - pub position: Rect, + pub position: Rect, /// The background color of the layer. pub background_color: Color, /// The scrolling policy of this layer. diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index e3662c1a3c4..b92f7ea77ce 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -248,7 +248,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45 [[package]] name = "geom" version = "0.1.0" -source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498" +source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2" [[package]] name = "gfx" diff --git a/components/style/lib.rs b/components/style/lib.rs index 23739b52b1a..4c8efd3a3aa 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -44,7 +44,7 @@ pub use selector_matching::{matches, matches_simple_selector, common_style_affec pub use selector_matching::{rare_style_affecting_attributes}; pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE}; pub use properties::{cascade, cascade_anonymous, computed, longhands_from_shorthand}; -pub use properties::is_supported_property; +pub use properties::{is_supported_property, make_inline}; pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs}; pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult}; diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index 02e3886c522..47db730d0f1 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -3183,6 +3183,15 @@ pub fn cascade_anonymous(parent_style: &ComputedValues) -> ComputedValues { result } +/// Sets `display` to `inline` and `position` to `static`. +#[inline] +pub fn make_inline(style: &ComputedValues) -> ComputedValues { + let mut style = (*style).clone(); + style.box_.make_unique().display = longhands::display::computed_value::T::inline; + style.box_.make_unique().position = longhands::position::computed_value::T::static_; + style +} + pub fn is_supported_property(property: &str) -> bool { match property { % for property in SHORTHANDS: diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 3ebeef17673..e203988b28b 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -244,7 +244,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45 [[package]] name = "geom" version = "0.1.0" -source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498" +source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2" [[package]] name = "gfx" diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index 19641c7399c..6be4f9e4535 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -227,7 +227,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45 [[package]] name = "geom" version = "0.1.0" -source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498" +source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2" [[package]] name = "gfx" diff --git a/tests/content/harness.js b/tests/content/harness.js index 2738ca2e6a6..452c72fa67d 100644 --- a/tests/content/harness.js +++ b/tests/content/harness.js @@ -22,7 +22,7 @@ function _pass(s, m) { function _printer(opstr, op) { return function (a, b, msg) { - let f = op(a,b) ? _pass : _fail; + var f = op(a,b) ? _pass : _fail; if (!msg) msg = ""; f(a + " " + opstr + " " + b, msg); }; diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 29ad0825f00..67e6300969f 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -222,3 +222,5 @@ fragment=top != ../html/acid2.html acid2_ref.html != inset_blackborder.html blackborder_ref.html != outset_blackborder.html blackborder_ref.html == border_radius_clip_a.html border_radius_clip_ref.html +== stacking_context_overflow_a.html stacking_context_overflow_ref.html +== stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html diff --git a/tests/ref/position_fixed_tile_edge_3.html b/tests/ref/position_fixed_tile_edge_3.html index dcf2341c170..60e20fb22b0 100644 --- a/tests/ref/position_fixed_tile_edge_3.html +++ b/tests/ref/position_fixed_tile_edge_3.html @@ -1,7 +1,7 @@
-
+
diff --git a/tests/ref/stacking_context_overflow_a.html b/tests/ref/stacking_context_overflow_a.html new file mode 100644 index 00000000000..ea87a5dba55 --- /dev/null +++ b/tests/ref/stacking_context_overflow_a.html @@ -0,0 +1,22 @@ + + + + + + +
CSS IS AWESOME
+ + + diff --git a/tests/ref/stacking_context_overflow_ref.html b/tests/ref/stacking_context_overflow_ref.html new file mode 100644 index 00000000000..49991c449ab --- /dev/null +++ b/tests/ref/stacking_context_overflow_ref.html @@ -0,0 +1,21 @@ + + + + + + +
CSS IS AWESOME
+ + + + diff --git a/tests/ref/stacking_context_overflow_relative_outline_a.html b/tests/ref/stacking_context_overflow_relative_outline_a.html new file mode 100644 index 00000000000..64b965063fc --- /dev/null +++ b/tests/ref/stacking_context_overflow_relative_outline_a.html @@ -0,0 +1,25 @@ + + + + +

+ + + diff --git a/tests/ref/stacking_context_overflow_relative_outline_ref.html b/tests/ref/stacking_context_overflow_relative_outline_ref.html new file mode 100644 index 00000000000..6117d76ff8f --- /dev/null +++ b/tests/ref/stacking_context_overflow_relative_outline_ref.html @@ -0,0 +1,18 @@ + + + + +
+ + + +