aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-10-21 21:05:44 -0700
committerPatrick Walton <pcwalton@mimiga.net>2014-10-22 08:02:17 -0700
commit821793351e3a593f1affed0c57c00fb2443b5af7 (patch)
tree193600e46cfd07a1308cb3ca3d53b2829384af2b /components
parent691e42f7ef9005b2466bff85eee21e0363c77050 (diff)
downloadservo-821793351e3a593f1affed0c57c00fb2443b5af7.tar.gz
servo-821793351e3a593f1affed0c57c00fb2443b5af7.zip
layout: Largely move display list building out to a separate file.
`layout::fragment` and `layout::block` were getting too big.
Diffstat (limited to 'components')
-rw-r--r--components/layout/block.rs133
-rw-r--r--components/layout/display_list_builder.rs710
-rw-r--r--components/layout/flow.rs92
-rw-r--r--components/layout/fragment.rs551
-rw-r--r--components/layout/inline.rs82
-rw-r--r--components/layout/lib.rs1
-rw-r--r--components/layout/table.rs9
-rw-r--r--components/layout/table_caption.rs10
-rw-r--r--components/layout/table_cell.rs9
-rw-r--r--components/layout/table_colgroup.rs3
-rw-r--r--components/layout/table_row.rs9
-rw-r--r--components/layout/table_rowgroup.rs10
-rw-r--r--components/layout/table_wrapper.rs9
13 files changed, 843 insertions, 785 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs
index db55e3a88fe..1f32e685b2a 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -29,6 +29,7 @@
use construct::FlowConstructor;
use context::LayoutContext;
+use display_list_builder::{BlockFlowDisplayListBuilding, FragmentDisplayListBuilding};
use floats::{ClearBoth, ClearLeft, ClearRight, FloatKind, FloatLeft, Floats, PlacementInfo};
use flow::{BaseFlow, BlockFlowClass, FlowClass, Flow, ImmutableFlowUtils};
use flow::{MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal, mut_base};
@@ -40,24 +41,18 @@ use model::{MaybeAuto, NoCollapsibleMargins, Specified, specified, specified_or_
use table::ColumnInlineSize;
use wrapper::ThreadSafeLayoutNode;
-use collections::dlist::DList;
-use geom::{Size2D, Point2D, Rect};
-use gfx::color;
-use gfx::display_list::{BackgroundAndBorderLevel, BlockLevel, ContentStackingLevel, DisplayList};
-use gfx::display_list::{FloatStackingLevel, PositionedDescendantStackingLevel};
-use gfx::display_list::{RootOfStackingContextLevel};
-use gfx::render_task::RenderLayer;
+use geom::Size2D;
+use gfx::display_list::BlockLevel;
use serialize::{Encoder, Encodable};
-use servo_msg::compositor_msg::{FixedPosition, LayerId, Scrollable};
+use servo_msg::compositor_msg::LayerId;
use servo_util::geometry::{Au, MAX_AU, MAX_RECT};
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
+use servo_util::opts;
use std::cmp::{max, min};
use std::fmt;
-use std::mem;
use style::computed_values::{LPA_Auto, LPA_Length, LPA_Percentage, LPN_Length, LPN_None};
use style::computed_values::{LPN_Percentage, LP_Length, LP_Percentage, box_sizing, clear};
use style::computed_values::{display, float, overflow, position};
-use sync::Arc;
/// Information specific to floated blocks.
#[deriving(Clone, Encodable)]
@@ -1070,70 +1065,6 @@ impl BlockFlow {
self.base.position = self.base.position.translate(&float_offset).translate(&margin_offset);
}
- fn build_display_list_block_common(&mut self,
- layout_context: &LayoutContext,
- background_border_level: BackgroundAndBorderLevel) {
- let relative_offset =
- self.fragment.relative_position(&self.base
- .absolute_position_info
- .relative_containing_block_size);
-
- // Add the box that starts the block context.
- let mut display_list = DisplayList::new();
- self.fragment.build_display_list(&mut display_list,
- layout_context,
- self.base.abs_position.add_size(
- &relative_offset.to_physical(self.base.writing_mode)),
- background_border_level,
- &self.base.clip_rect);
-
- let mut child_layers = DList::new();
- for kid in self.base.child_iter() {
- if kid.is_absolutely_positioned() {
- // All absolute flows will be handled by their containing block.
- continue
- }
-
- display_list.push_all_move(mem::replace(&mut flow::mut_base(kid).display_list,
- DisplayList::new()));
- child_layers.append(mem::replace(&mut flow::mut_base(kid).layers, DList::new()))
- }
-
- // Process absolute descendant links.
- for abs_descendant_link in self.base.abs_descendants.iter() {
- // TODO(pradeep): Send in our absolute position directly.
- display_list.push_all_move(mem::replace(
- &mut flow::mut_base(abs_descendant_link).display_list,
- DisplayList::new()));
- child_layers.append(mem::replace(&mut flow::mut_base(abs_descendant_link).layers,
- DList::new()));
- }
-
- self.base.display_list = display_list;
- self.base.layers = child_layers
- }
-
- /// Add display items for current block.
- ///
- /// Set the absolute position for children after doing any offsetting for
- /// position: relative.
- pub fn build_display_list_block(&mut self, layout_context: &LayoutContext) {
- if self.is_float() {
- // TODO(#2009, pcwalton): This is a pseudo-stacking context. We need to merge `z-index:
- // auto` kids into the parent stacking context, when that is supported.
- self.build_display_list_float(layout_context)
- } else if self.is_absolutely_positioned() {
- self.build_display_list_abs(layout_context)
- } else {
- self.build_display_list_block_common(layout_context, BlockLevel)
- }
- }
-
- pub fn build_display_list_float(&mut self, layout_context: &LayoutContext) {
- self.build_display_list_block_common(layout_context, RootOfStackingContextLevel);
- self.base.display_list = mem::replace(&mut self.base.display_list,
- DisplayList::new()).flatten(FloatStackingLevel)
- }
/// Calculate and set the block-size, offsets, etc. for absolutely positioned flow.
///
@@ -1232,43 +1163,6 @@ impl BlockFlow {
self.base.position.size.block = block_size;
}
- /// Add display items for Absolutely Positioned flow.
- fn build_display_list_abs(&mut self, layout_context: &LayoutContext) {
- self.build_display_list_block_common(layout_context, RootOfStackingContextLevel);
-
- if !self.base.absolute_position_info.layers_needed_for_positioned_flows &&
- !self.base.flags.needs_layer() {
- // We didn't need a layer.
- let z_index = self.fragment.style().get_box().z_index.number_or_zero();
- let level = PositionedDescendantStackingLevel(z_index);
- self.base.display_list = mem::replace(&mut self.base.display_list,
- DisplayList::new()).flatten(level);
- return
- }
-
- // If we got here, then we need a new layer.
- let layer_rect = self.base.position.union(&self.base.overflow);
- let size = Size2D(layer_rect.size.inline.to_nearest_px() as uint,
- layer_rect.size.block.to_nearest_px() as uint);
- let origin = Point2D(self.base.abs_position.x.to_nearest_px() as uint,
- self.base.abs_position.y.to_nearest_px() as uint);
-
- let scroll_policy = if self.is_fixed() {
- FixedPosition
- } else {
- Scrollable
- };
- let display_list = mem::replace(&mut self.base.display_list, DisplayList::new());
- let new_layer = RenderLayer {
- id: self.layer_id(0),
- display_list: Arc::new(display_list.flatten(ContentStackingLevel)),
- position: Rect(origin, size),
- background_color: color::rgba(1.0, 1.0, 1.0, 0.0),
- scroll_policy: scroll_policy,
- };
- self.base.layers.push(new_layer)
- }
-
/// Return the block-start outer edge of the hypothetical box for an absolute flow.
///
/// This is wrt its parent flow box.
@@ -1839,6 +1733,22 @@ impl Flow for BlockFlow {
self.base.position.start.b = block_position
}
}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ if self.is_float() {
+ // TODO(#2009, pcwalton): This is a pseudo-stacking context. We need to merge `z-index:
+ // auto` kids into the parent stacking context, when that is supported.
+ self.build_display_list_for_floating_block(layout_context)
+ } else if self.is_absolutely_positioned() {
+ self.build_display_list_for_absolutely_positioned_block(layout_context)
+ } else {
+ self.build_display_list_for_block(layout_context, BlockLevel)
+ }
+
+ if opts::get().validate_display_list_geometry {
+ self.base.validate_display_list_geometry();
+ }
+ }
}
impl fmt::Show for BlockFlow {
@@ -2562,3 +2472,4 @@ fn propagate_column_inline_sizes_to_child(kid: &mut Flow,
*inline_start_margin_edge = *inline_start_margin_edge + inline_size
}
}
+
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
new file mode 100644
index 00000000000..3f298a92686
--- /dev/null
+++ b/components/layout/display_list_builder.rs
@@ -0,0 +1,710 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! Builds display lists from flows and fragments.
+//!
+//! Other browser engines sometimes call this "painting", but it is more accurately called display
+//! list building, as the actual painting does not happen here—only deciding *what* we're going to
+//! paint.
+
+#![deny(unsafe_block)]
+
+use block::BlockFlow;
+use context::LayoutContext;
+use flow::{mod, Flow};
+use fragment::{Fragment, GenericFragment, IframeFragment, IframeFragmentInfo, ImageFragment};
+use fragment::{ImageFragmentInfo, InlineAbsoluteHypotheticalFragment, InlineBlockFragment};
+use fragment::{InputFragment, ScannedTextFragment, ScannedTextFragmentInfo, TableFragment};
+use fragment::{TableCellFragment, TableColumnFragment, TableRowFragment, TableWrapperFragment};
+use fragment::{UnscannedTextFragment};
+use model;
+use util::{OpaqueNodeMethods, ToGfxColor};
+
+use collections::dlist::DList;
+use geom::approxeq::ApproxEq;
+use geom::{Point2D, Rect, Size2D, SideOffsets2D};
+use gfx::color;
+use gfx::display_list::{BackgroundAndBorderLevel, BaseDisplayItem, BorderDisplayItem};
+use gfx::display_list::{BorderDisplayItemClass, ContentStackingLevel, DisplayList};
+use gfx::display_list::{FloatStackingLevel, ImageDisplayItem, ImageDisplayItemClass};
+use gfx::display_list::{LineDisplayItem, LineDisplayItemClass, PositionedDescendantStackingLevel};
+use gfx::display_list::{PseudoDisplayItemClass, RootOfStackingContextLevel, SidewaysLeft};
+use gfx::display_list::{SidewaysRight, SolidColorDisplayItem, SolidColorDisplayItemClass};
+use gfx::display_list::{StackingLevel, TextDisplayItem, TextDisplayItemClass, Upright};
+use gfx::render_task::RenderLayer;
+use servo_msg::compositor_msg::{FixedPosition, Scrollable};
+use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg};
+use servo_net::image::holder::ImageHolder;
+use servo_util::geometry::{mod, Au, ZERO_RECT};
+use servo_util::logical_geometry::{LogicalRect, WritingMode};
+use servo_util::opts;
+use std::mem;
+use style::{ComputedValues, RGBA};
+use style::computed_values::{background_attachment, background_repeat, border_style, overflow};
+use style::computed_values::{visibility};
+use sync::Arc;
+
+pub trait FragmentDisplayListBuilding {
+ /// Adds the display items necessary to paint the background of this fragment to the display
+ /// list if necessary.
+ fn build_display_list_for_background_if_applicable(&self,
+ style: &ComputedValues,
+ list: &mut DisplayList,
+ layout_context: &LayoutContext,
+ level: StackingLevel,
+ absolute_bounds: &Rect<Au>,
+ clip_rect: &Rect<Au>);
+
+ /// Adds the display items necessary to paint the borders of this fragment to a display list if
+ /// necessary.
+ fn build_display_list_for_borders_if_applicable(&self,
+ style: &ComputedValues,
+ list: &mut DisplayList,
+ abs_bounds: &Rect<Au>,
+ level: StackingLevel,
+ clip_rect: &Rect<Au>);
+
+ fn build_debug_borders_around_text_fragments(&self,
+ display_list: &mut DisplayList,
+ flow_origin: Point2D<Au>,
+ text_fragment: &ScannedTextFragmentInfo,
+ clip_rect: &Rect<Au>);
+
+ fn build_debug_borders_around_fragment(&self,
+ display_list: &mut DisplayList,
+ flow_origin: Point2D<Au>,
+ clip_rect: &Rect<Au>);
+
+ /// Adds the display items for this fragment to the given stacking context.
+ ///
+ /// Arguments:
+ ///
+ /// * `display_list`: The unflattened 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.
+ /// * `clip_rect`: The rectangle to clip the display items to.
+ fn build_display_list(&mut self,
+ display_list: &mut DisplayList,
+ layout_context: &LayoutContext,
+ flow_origin: Point2D<Au>,
+ background_and_border_level: BackgroundAndBorderLevel,
+ clip_rect: &Rect<Au>);
+
+ /// Sends the size and position of this iframe fragment to the constellation. This is out of
+ /// line to guide inlining.
+ fn finalize_position_and_size_of_iframe(&self,
+ iframe_fragment: &IframeFragmentInfo,
+ offset: Point2D<Au>,
+ layout_context: &LayoutContext);
+
+ fn clip_rect_for_children(&self, current_clip_rect: Rect<Au>, flow_origin: Point2D<Au>)
+ -> Rect<Au>;
+}
+
+impl FragmentDisplayListBuilding for Fragment {
+ fn build_display_list_for_background_if_applicable(&self,
+ style: &ComputedValues,
+ list: &mut DisplayList,
+ layout_context: &LayoutContext,
+ level: StackingLevel,
+ absolute_bounds: &Rect<Au>,
+ clip_rect: &Rect<Au>) {
+ // FIXME: This causes a lot of background colors to be displayed when they are clearly not
+ // needed. We could use display list optimization to clean this up, but it still seems
+ // inefficient. What we really want is something like "nearest ancestor element that
+ // doesn't have a fragment".
+ let background_color = style.resolve_color(style.get_background().background_color);
+ if !background_color.alpha.approx_eq(&0.0) {
+ let display_item = box SolidColorDisplayItem {
+ base: BaseDisplayItem::new(*absolute_bounds, self.node, level, *clip_rect),
+ color: background_color.to_gfx_color(),
+ };
+
+ list.push(SolidColorDisplayItemClass(display_item))
+ }
+
+ // The background image is painted on top of the background color.
+ // Implements background image, per spec:
+ // http://www.w3.org/TR/CSS21/colors.html#background
+ let background = style.get_background();
+ let image_url = match background.background_image {
+ None => return,
+ Some(ref image_url) => image_url,
+ };
+
+ let mut holder = ImageHolder::new(image_url.clone(),
+ layout_context.shared.image_cache.clone());
+ let image = match holder.get_image(self.node.to_untrusted_node_address()) {
+ None => {
+ // No image data at all? Do nothing.
+ //
+ // TODO: Add some kind of placeholder background image.
+ debug!("(building display list) no background image :(");
+ return
+ }
+ Some(image) => image,
+ };
+ debug!("(building display list) building background image");
+
+ let image_width = Au::from_px(image.width as int);
+ let image_height = Au::from_px(image.height as int);
+ let mut bounds = *absolute_bounds;
+
+ // Clip.
+ //
+ // TODO: Check the bounds to see if a clip item is actually required.
+ let clip_rect = clip_rect.intersection(&bounds).unwrap_or(ZERO_RECT);
+
+ // Use background-attachment to get the initial virtual origin
+ let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
+ background_attachment::scroll => {
+ (absolute_bounds.origin.x, absolute_bounds.origin.y)
+ }
+ background_attachment::fixed => {
+ (Au(0), Au(0))
+ }
+ };
+
+ // Use background-position to get the offset
+ let horizontal_position = model::specified(background.background_position.horizontal,
+ bounds.size.width - image_width);
+ let vertical_position = model::specified(background.background_position.vertical,
+ bounds.size.height - image_height);
+
+ let abs_x = virtual_origin_x + horizontal_position;
+ let abs_y = virtual_origin_y + vertical_position;
+
+ // Adjust origin and size based on background-repeat
+ match background.background_repeat {
+ background_repeat::no_repeat => {
+ bounds.origin.x = abs_x;
+ bounds.origin.y = abs_y;
+ bounds.size.width = image_width;
+ bounds.size.height = image_height;
+ }
+ background_repeat::repeat_x => {
+ bounds.origin.y = abs_y;
+ bounds.size.height = image_height;
+ ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
+ abs_x, image.width);
+ }
+ background_repeat::repeat_y => {
+ bounds.origin.x = abs_x;
+ bounds.size.width = image_width;
+ ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
+ abs_y, image.height);
+ }
+ background_repeat::repeat => {
+ ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
+ abs_x, image.width);
+ ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
+ abs_y, image.height);
+ }
+ };
+
+ // Create the image display item.
+ let image_display_item = ImageDisplayItemClass(box ImageDisplayItem {
+ base: BaseDisplayItem::new(bounds, self.node, level, clip_rect),
+ image: image.clone(),
+ stretch_size: Size2D(Au::from_px(image.width as int),
+ Au::from_px(image.height as int)),
+ });
+ list.push(image_display_item)
+ }
+
+ /// Adds the display items necessary to paint the borders of this fragment to a display list if
+ /// necessary.
+ fn build_display_list_for_borders_if_applicable(&self,
+ style: &ComputedValues,
+ list: &mut DisplayList,
+ abs_bounds: &Rect<Au>,
+ level: StackingLevel,
+ clip_rect: &Rect<Au>) {
+ let border = style.logical_border_width();
+ if border.is_zero() {
+ return
+ }
+
+ let top_color = style.resolve_color(style.get_border().border_top_color);
+ let right_color = style.resolve_color(style.get_border().border_right_color);
+ let bottom_color = style.resolve_color(style.get_border().border_bottom_color);
+ let left_color = style.resolve_color(style.get_border().border_left_color);
+
+ // Append the border to the display list.
+ let border_display_item = box BorderDisplayItem {
+ base: BaseDisplayItem::new(*abs_bounds, self.node, level, *clip_rect),
+ border: border.to_physical(style.writing_mode),
+ color: SideOffsets2D::new(top_color.to_gfx_color(),
+ right_color.to_gfx_color(),
+ bottom_color.to_gfx_color(),
+ left_color.to_gfx_color()),
+ style: SideOffsets2D::new(style.get_border().border_top_style,
+ style.get_border().border_right_style,
+ style.get_border().border_bottom_style,
+ style.get_border().border_left_style)
+ };
+
+ list.push(BorderDisplayItemClass(border_display_item))
+ }
+
+ fn build_debug_borders_around_text_fragments(&self,
+ display_list: &mut DisplayList,
+ flow_origin: Point2D<Au>,
+ text_fragment: &ScannedTextFragmentInfo,
+ clip_rect: &Rect<Au>) {
+ // 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);
+
+ // Compute the text fragment bounds and draw a border surrounding them.
+ let border_display_item = box BorderDisplayItem {
+ base: BaseDisplayItem::new(absolute_fragment_bounds,
+ self.node,
+ ContentStackingLevel,
+ *clip_rect),
+ border: SideOffsets2D::new_all_same(Au::from_px(1)),
+ color: SideOffsets2D::new_all_same(color::rgb(0, 0, 200)),
+ style: SideOffsets2D::new_all_same(border_style::solid)
+ };
+ display_list.push(BorderDisplayItemClass(border_display_item));
+
+ // 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;
+ baseline.size.block = Au(0);
+ let mut baseline = baseline.to_physical(self.style.writing_mode, container_size);
+ baseline.origin = baseline.origin + flow_origin;
+
+ let line_display_item = box LineDisplayItem {
+ base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel, *clip_rect),
+ color: color::rgb(0, 200, 0),
+ style: border_style::dashed,
+ };
+ display_list.push(LineDisplayItemClass(line_display_item));
+ }
+
+ fn build_debug_borders_around_fragment(&self,
+ display_list: &mut DisplayList,
+ flow_origin: Point2D<Au>,
+ clip_rect: &Rect<Au>) {
+ // 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.
+ let border_display_item = box BorderDisplayItem {
+ base: BaseDisplayItem::new(absolute_fragment_bounds,
+ self.node,
+ ContentStackingLevel,
+ *clip_rect),
+ border: SideOffsets2D::new_all_same(Au::from_px(1)),
+ color: SideOffsets2D::new_all_same(color::rgb(0, 0, 200)),
+ style: SideOffsets2D::new_all_same(border_style::solid)
+ };
+ display_list.push(BorderDisplayItemClass(border_display_item))
+ }
+
+ fn build_display_list(&mut self,
+ display_list: &mut DisplayList,
+ layout_context: &LayoutContext,
+ flow_origin: Point2D<Au>,
+ background_and_border_level: BackgroundAndBorderLevel,
+ clip_rect: &Rect<Au>) {
+ // FIXME(#2795): Get the real container size
+ let container_size = Size2D::zero();
+ let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect<Au>| {
+ let physical_rect = logical_rect.to_physical(writing_mode, container_size);
+ Rect(physical_rect.origin + flow_origin, physical_rect.size)
+ };
+ // Fragment position wrt to the owning flow.
+ let absolute_fragment_bounds = rect_to_absolute(self.style.writing_mode, self.border_box);
+ debug!("Fragment::build_display_list at rel={}, abs={}: {}",
+ self.border_box,
+ absolute_fragment_bounds,
+ self);
+ debug!("Fragment::build_display_list: dirty={}, flow_origin={}",
+ layout_context.shared.dirty,
+ flow_origin);
+
+ if self.style().get_inheritedbox().visibility != visibility::visible {
+ return
+ }
+
+ if !absolute_fragment_bounds.intersects(&layout_context.shared.dirty) {
+ debug!("Fragment::build_display_list: Did not intersect...");
+ return
+ }
+
+ debug!("Fragment::build_display_list: intersected. Adding display item...");
+
+ if self.is_primary_fragment() {
+ let level =
+ StackingLevel::from_background_and_border_level(background_and_border_level);
+
+ // Add a pseudo-display item for content box queries. This is a very bogus thing to do.
+ let base_display_item = box BaseDisplayItem::new(absolute_fragment_bounds,
+ self.node,
+ level,
+ *clip_rect);
+ display_list.push(PseudoDisplayItemClass(base_display_item));
+
+ // Add the background to the list, if applicable.
+ match self.inline_context {
+ Some(ref 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_rect);
+ }
+ }
+ None => {}
+ }
+ match self.specific {
+ ScannedTextFragment(_) => {},
+ _ => {
+ self.build_display_list_for_background_if_applicable(
+ &*self.style,
+ display_list,
+ layout_context,
+ level,
+ &absolute_fragment_bounds,
+ clip_rect);
+ }
+ }
+
+ // Add a border, if applicable.
+ //
+ // TODO: Outlines.
+ match self.inline_context {
+ Some(ref 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_rect);
+ }
+ }
+ None => {}
+ }
+ match self.specific {
+ ScannedTextFragment(_) => {},
+ _ => {
+ self.build_display_list_for_borders_if_applicable(
+ &*self.style,
+ display_list,
+ &absolute_fragment_bounds,
+ level,
+ clip_rect);
+ }
+ }
+ }
+
+ let content_box = self.content_box();
+ let absolute_content_box = rect_to_absolute(self.style.writing_mode, content_box);
+
+ // Create special per-fragment-type display items.
+ match self.specific {
+ UnscannedTextFragment(_) => fail!("Shouldn't see unscanned fragments here."),
+ TableColumnFragment(_) => fail!("Shouldn't see table column fragments here."),
+ ScannedTextFragment(ref text_fragment) => {
+ // Create the text display item.
+ let orientation = if self.style.writing_mode.is_vertical() {
+ if self.style.writing_mode.is_sideways_left() {
+ SidewaysLeft
+ } else {
+ SidewaysRight
+ }
+ } else {
+ Upright
+ };
+
+ let metrics = &text_fragment.run.font_metrics;
+ let baseline_origin ={
+ let mut tmp = content_box.start;
+ tmp.b = tmp.b + metrics.ascent;
+ tmp.to_physical(self.style.writing_mode, container_size) + flow_origin
+ };
+
+ let text_display_item = box TextDisplayItem {
+ base: BaseDisplayItem::new(absolute_content_box,
+ self.node,
+ ContentStackingLevel,
+ *clip_rect),
+ text_run: text_fragment.run.clone(),
+ range: text_fragment.range,
+ text_color: self.style().get_color().color.to_gfx_color(),
+ orientation: orientation,
+ baseline_origin: baseline_origin,
+ };
+ display_list.push(TextDisplayItemClass(text_display_item));
+
+ // Create display items for text decoration
+ {
+ let line = |maybe_color: Option<RGBA>, rect: || -> LogicalRect<Au>| {
+ match maybe_color {
+ None => {},
+ Some(color) => {
+ display_list.push(SolidColorDisplayItemClass(
+ box SolidColorDisplayItem {
+ base: BaseDisplayItem::new(
+ rect_to_absolute(
+ self.style.writing_mode,
+ rect()),
+ self.node,
+ ContentStackingLevel,
+ *clip_rect),
+ color: color.to_gfx_color(),
+ }));
+ }
+ }
+ };
+
+ let text_decorations =
+ self.style().get_inheritedtext()._servo_text_decorations_in_effect;
+ line(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;
+ rect
+ });
+
+ line(text_decorations.overline, || {
+ let mut rect = content_box.clone();
+ rect.size.block = metrics.underline_size;
+ rect
+ });
+
+ line(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;
+ rect
+ });
+ }
+
+ if opts::get().show_debug_fragment_borders {
+ self.build_debug_borders_around_text_fragments(display_list,
+ flow_origin,
+ text_fragment,
+ clip_rect);
+ }
+ }
+ GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment |
+ TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | InputFragment |
+ InlineAbsoluteHypotheticalFragment(_) => {
+ if opts::get().show_debug_fragment_borders {
+ self.build_debug_borders_around_fragment(display_list,
+ flow_origin,
+ clip_rect);
+ }
+ }
+ ImageFragment(ref mut image_fragment) => {
+ let image_ref = &mut image_fragment.image;
+ match image_ref.get_image(self.node.to_untrusted_node_address()) {
+ Some(image) => {
+ debug!("(building display list) building image fragment");
+
+ // Place the image into the display list.
+ let image_display_item = box ImageDisplayItem {
+ base: BaseDisplayItem::new(absolute_content_box,
+ self.node,
+ ContentStackingLevel,
+ *clip_rect),
+ image: image.clone(),
+ stretch_size: absolute_content_box.size,
+ };
+
+ display_list.push(ImageDisplayItemClass(image_display_item))
+ }
+ None => {
+ // No image data at all? Do nothing.
+ //
+ // TODO: Add some kind of placeholder image.
+ debug!("(building display list) no image :(");
+ }
+ }
+ }
+ }
+
+ if opts::get().show_debug_fragment_borders {
+ self.build_debug_borders_around_fragment(display_list, flow_origin, clip_rect)
+ }
+
+ // If this is an iframe, then send its position and size up to the constellation.
+ //
+ // FIXME(pcwalton): Doing this during display list construction seems potentially
+ // problematic if iframes are outside the area we're computing the display list for, since
+ // they won't be able to reflow at all until the user scrolls to them. Perhaps we should
+ // separate this into two parts: first we should send the size only to the constellation
+ // once that's computed during assign-block-sizes, and second we should should send the
+ // origin to the constellation here during display list construction. This should work
+ // because layout for the iframe only needs to know size, and origin is only relevant if
+ // the iframe is actually going to be displayed.
+ match self.specific {
+ IframeFragment(ref iframe_fragment) => {
+ self.finalize_position_and_size_of_iframe(iframe_fragment,
+ absolute_fragment_bounds.origin,
+ layout_context)
+ }
+ _ => {}
+ }
+ }
+
+ #[inline(never)]
+ fn finalize_position_and_size_of_iframe(&self,
+ iframe_fragment: &IframeFragmentInfo,
+ offset: Point2D<Au>,
+ layout_context: &LayoutContext) {
+ let border_padding = (self.border_padding).to_physical(self.style.writing_mode);
+ let content_size = self.content_box().size.to_physical(self.style.writing_mode);
+ let iframe_rect = Rect(Point2D(geometry::to_frac_px(offset.x + border_padding.left) as f32,
+ geometry::to_frac_px(offset.y + border_padding.top) as f32),
+ Size2D(geometry::to_frac_px(content_size.width) as f32,
+ geometry::to_frac_px(content_size.height) as f32));
+
+ debug!("finalizing position and size of iframe for {:?},{:?}",
+ iframe_fragment.pipeline_id,
+ iframe_fragment.subpage_id);
+ let ConstellationChan(ref chan) = layout_context.shared.constellation_chan;
+ chan.send(FrameRectMsg(iframe_fragment.pipeline_id,
+ iframe_fragment.subpage_id,
+ iframe_rect));
+ }
+
+ fn clip_rect_for_children(&self, current_clip_rect: Rect<Au>, flow_origin: Point2D<Au>)
+ -> Rect<Au> {
+ // Don't clip if we're text.
+ match self.specific {
+ ScannedTextFragment(_) => return current_clip_rect,
+ _ => {}
+ }
+
+ // Only clip if `overflow` tells us to.
+ match self.style.get_box().overflow {
+ overflow::hidden | overflow::auto | overflow::scroll => {}
+ _ => return current_clip_rect,
+ }
+
+ // 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_rect.intersection(&Rect(physical_rect.origin + flow_origin,
+ physical_rect.size)).unwrap_or(ZERO_RECT)
+ }
+}
+
+pub trait BlockFlowDisplayListBuilding {
+ fn build_display_list_for_block(&mut self,
+ layout_context: &LayoutContext,
+ background_border_level: BackgroundAndBorderLevel);
+ fn build_display_list_for_absolutely_positioned_block(&mut self,
+ layout_context: &LayoutContext);
+ fn build_display_list_for_floating_block(&mut self, layout_context: &LayoutContext);
+}
+
+impl BlockFlowDisplayListBuilding for BlockFlow {
+ fn build_display_list_for_block(&mut self,
+ layout_context: &LayoutContext,
+ background_border_level: BackgroundAndBorderLevel) {
+ let relative_offset =
+ self.fragment.relative_position(&self.base
+ .absolute_position_info
+ .relative_containing_block_size);
+
+ // Add the box that starts the block context.
+ let mut display_list = DisplayList::new();
+ self.fragment.build_display_list(&mut display_list,
+ layout_context,
+ self.base.abs_position.add_size(
+ &relative_offset.to_physical(self.base.writing_mode)),
+ background_border_level,
+ &self.base.clip_rect);
+
+ let mut child_layers = DList::new();
+ for kid in self.base.child_iter() {
+ if kid.is_absolutely_positioned() {
+ // All absolute flows will be handled by their containing block.
+ continue
+ }
+
+ display_list.push_all_move(mem::replace(&mut flow::mut_base(kid).display_list,
+ DisplayList::new()));
+ child_layers.append(mem::replace(&mut flow::mut_base(kid).layers, DList::new()))
+ }
+
+ // Process absolute descendant links.
+ for abs_descendant_link in self.base.abs_descendants.iter() {
+ // TODO(pradeep): Send in our absolute position directly.
+ display_list.push_all_move(mem::replace(
+ &mut flow::mut_base(abs_descendant_link).display_list,
+ DisplayList::new()));
+ child_layers.append(mem::replace(&mut flow::mut_base(abs_descendant_link).layers,
+ DList::new()));
+ }
+
+ self.base.display_list = display_list;
+ self.base.layers = child_layers
+ }
+
+ fn build_display_list_for_absolutely_positioned_block(&mut self,
+ layout_context: &LayoutContext) {
+ self.build_display_list_for_block(layout_context, RootOfStackingContextLevel);
+
+ if !self.base.absolute_position_info.layers_needed_for_positioned_flows &&
+ !self.base.flags.needs_layer() {
+ // We didn't need a layer.
+ let z_index = self.fragment.style().get_box().z_index.number_or_zero();
+ let level = PositionedDescendantStackingLevel(z_index);
+ self.base.display_list = mem::replace(&mut self.base.display_list,
+ DisplayList::new()).flatten(level);
+ return
+ }
+
+ // If we got here, then we need a new layer.
+ let layer_rect = self.base.position.union(&self.base.overflow);
+ let size = Size2D(layer_rect.size.inline.to_nearest_px() as uint,
+ layer_rect.size.block.to_nearest_px() as uint);
+ let origin = Point2D(self.base.abs_position.x.to_nearest_px() as uint,
+ self.base.abs_position.y.to_nearest_px() as uint);
+
+ let scroll_policy = if self.is_fixed() {
+ FixedPosition
+ } else {
+ Scrollable
+ };
+ let display_list = mem::replace(&mut self.base.display_list, DisplayList::new());
+ let new_layer = RenderLayer {
+ id: self.layer_id(0),
+ display_list: Arc::new(display_list.flatten(ContentStackingLevel)),
+ position: Rect(origin, size),
+ background_color: color::rgba(1.0, 1.0, 1.0, 0.0),
+ scroll_policy: scroll_policy,
+ };
+ self.base.layers.push(new_layer)
+ }
+
+ fn build_display_list_for_floating_block(&mut self, layout_context: &LayoutContext) {
+ self.build_display_list_for_block(layout_context, RootOfStackingContextLevel);
+ self.base.display_list = mem::replace(&mut self.base.display_list,
+ DisplayList::new()).flatten(FloatStackingLevel)
+ }
+}
+
diff --git a/components/layout/flow.rs b/components/layout/flow.rs
index 269aac1b81d..38ee01b3c96 100644
--- a/components/layout/flow.rs
+++ b/components/layout/flow.rs
@@ -54,7 +54,6 @@ use servo_msg::compositor_msg::LayerId;
use servo_util::geometry::Au;
use servo_util::logical_geometry::WritingMode;
use servo_util::logical_geometry::{LogicalRect, LogicalSize};
-use servo_util::opts;
use std::mem;
use std::num::Zero;
use std::fmt;
@@ -209,6 +208,9 @@ pub trait Flow: fmt::Show + ToString + Sync {
// The default implementation is a no-op.
}
+ /// Phase 5 of reflow: builds display lists.
+ fn build_display_list(&mut self, layout_context: &LayoutContext);
+
/// Returns the direction that this flow clears floats in, if any.
fn float_clearance(&self) -> clear::T {
clear::none
@@ -406,9 +408,6 @@ pub trait ImmutableFlowUtils {
/// Dumps the flow tree for debugging, with a prefix to indicate that we're at the given level.
fn dump_with_level(self, level: uint);
-
- /// Print an error when this Flow's display list items are not within its boundaries.
- fn validate_display_list_geometry(self);
}
pub trait MutableFlowUtils {
@@ -425,9 +424,6 @@ pub trait MutableFlowUtils {
/// Computes the overflow region for this flow.
fn store_overflow(self, _: &LayoutContext);
- /// Builds the display lists for this flow.
- fn build_display_list(self, layout_context: &LayoutContext);
-
/// Gathers static block-offsets bubbled up by kids.
///
/// This essentially gives us offsets of all absolutely positioned direct descendants and all
@@ -858,6 +854,28 @@ impl BaseFlow {
let p = self as *const _;
p as uint
}
+
+ pub fn validate_display_list_geometry(&self) {
+ let position_with_overflow = self.position.union(&self.overflow);
+ let bounds = Rect(self.abs_position,
+ Size2D(position_with_overflow.size.inline,
+ position_with_overflow.size.block));
+
+ for item in self.display_list.iter() {
+ let paint_bounds = match item.base().bounds.intersection(&item.base().clip_rect) {
+ None => continue,
+ Some(rect) => rect,
+ };
+
+ if paint_bounds.is_empty() {
+ continue;
+ }
+
+ if bounds.union(&paint_bounds) != bounds {
+ error!("DisplayList item {} outside of Flow overflow ({})", item, paint_bounds);
+ }
+ }
+ }
}
impl<'a> ImmutableFlowUtils for &'a Flow + 'a {
@@ -1028,28 +1046,6 @@ impl<'a> ImmutableFlowUtils for &'a Flow + 'a {
kid.dump_with_level(level + 1)
}
}
-
- fn validate_display_list_geometry(self) {
- let position_with_overflow = base(self).position.union(&base(self).overflow);
- let bounds = Rect(base(self).abs_position,
- Size2D(position_with_overflow.size.inline,
- position_with_overflow.size.block));
-
- for item in base(self).display_list.iter() {
- let paint_bounds = match item.base().bounds.intersection(&item.base().clip_rect) {
- None => continue,
- Some(rect) => rect,
- };
-
- if paint_bounds.is_empty() {
- continue;
- }
-
- if bounds.union(&paint_bounds) != bounds {
- error!("DisplayList item {} outside of Flow overflow ({})", item, paint_bounds);
- }
- }
- }
}
impl<'a> MutableFlowUtils for &'a mut Flow + 'a {
@@ -1110,44 +1106,6 @@ impl<'a> MutableFlowUtils for &'a mut Flow + 'a {
mut_base(self).overflow = overflow;
}
- /// Push display items for current flow and its descendants onto the appropriate display lists
- /// of the given stacking context.
- ///
- /// Arguments:
- ///
- /// * `builder`: The display list builder, which contains information used during the entire
- /// display list building pass.
- ///
- /// * `info`: Per-flow display list building information.
- fn build_display_list(self, layout_context: &LayoutContext) {
- debug!("Flow: building display list");
- match self.class() {
- BlockFlowClass => self.as_block().build_display_list_block(layout_context),
- InlineFlowClass => self.as_inline().build_display_list_inline(layout_context),
- TableWrapperFlowClass => {
- self.as_table_wrapper().build_display_list_table_wrapper(layout_context)
- }
- TableFlowClass => self.as_table().build_display_list_table(layout_context),
- TableRowGroupFlowClass => {
- self.as_table_rowgroup().build_display_list_table_rowgroup(layout_context)
- }
- TableRowFlowClass => self.as_table_row().build_display_list_table_row(layout_context),
- TableCaptionFlowClass => {
- self.as_table_caption().build_display_list_table_caption(layout_context)
- }
- TableCellFlowClass => {
- self.as_table_cell().build_display_list_table_cell(layout_context)
- }
- TableColGroupFlowClass => {
- // Nothing to do here, as column groups don't render.
- }
- }
-
- if opts::get().validate_display_list_geometry {
- self.validate_display_list_geometry();
- }
- }
-
/// Collect and update static y-offsets bubbled up by kids.
///
/// This would essentially give us offsets of all absolutely positioned
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 80d6c68be2a..c946ecf79a9 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -19,44 +19,33 @@ use layout_debug;
use model::{Auto, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, Specified, specified};
use model;
use text;
-use util::{OpaqueNodeMethods, ToGfxColor};
+use util::OpaqueNodeMethods;
use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
-use geom::{Point2D, Rect, Size2D, SideOffsets2D};
-use geom::approxeq::ApproxEq;
-use gfx::color::rgb;
-use gfx::display_list::{BackgroundAndBorderLevel, BaseDisplayItem, BorderDisplayItem};
-use gfx::display_list::{BorderDisplayItemClass, ContentStackingLevel, DisplayList};
-use gfx::display_list::{ImageDisplayItem, ImageDisplayItemClass, LineDisplayItem};
-use gfx::display_list::{LineDisplayItemClass, OpaqueNode, PseudoDisplayItemClass};
-use gfx::display_list::{SidewaysLeft, SidewaysRight, SolidColorDisplayItem};
-use gfx::display_list::{SolidColorDisplayItemClass, StackingLevel, TextDisplayItem};
-use gfx::display_list::{TextDisplayItemClass, Upright};
+use geom::Size2D;
+use gfx::display_list::OpaqueNode;
use gfx::text::glyph::CharIndex;
use gfx::text::text_run::TextRun;
use script_traits::UntrustedNodeAddress;
use serialize::{Encodable, Encoder};
-use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
+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, ZERO_RECT};
+use servo_util::geometry::Au;
use servo_util::geometry;
-use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin, WritingMode};
-use servo_util::opts;
+use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin};
use servo_util::range::*;
use servo_util::smallvec::SmallVec;
use servo_util::str::is_whitespace;
use std::cmp::{max, min};
use std::fmt;
use std::from_str::FromStr;
-use std::num::Zero;
use string_cache::Atom;
-use style::{ComputedValues, TElement, TNode, cascade_anonymous, RGBA};
+use style::{ComputedValues, TElement, TNode, cascade_anonymous};
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto};
use style::computed_values::{LengthOrPercentageOrNone};
-use style::computed_values::{overflow, LPA_Auto, background_attachment};
-use style::computed_values::{background_repeat, border_style, clear, position, text_align};
-use style::computed_values::{text_decoration, vertical_align, visibility, white_space};
+use style::computed_values::{LPA_Auto, clear, position, text_align, text_decoration};
+use style::computed_values::{vertical_align, white_space};
use sync::{Arc, Mutex};
use url::Url;
@@ -132,6 +121,8 @@ impl<E, S: Encoder<E>> Encodable<S, E> for Fragment {
}
/// Info specific to the kind of fragment. Keep this enum small.
+///
+/// FIXME(pcwalton): We have completely failed at keeping this enum small.
#[deriving(Clone)]
pub enum SpecificFragmentInfo {
GenericFragment,
@@ -935,480 +926,6 @@ impl Fragment {
}
}
- /// Adds the display items necessary to paint the background of this fragment to the display
- /// list if necessary.
- pub fn build_display_list_for_background_if_applicable(&self,
- style: &ComputedValues,
- list: &mut DisplayList,
- layout_context: &LayoutContext,
- level: StackingLevel,
- absolute_bounds: &Rect<Au>,
- clip_rect: &Rect<Au>) {
- // FIXME: This causes a lot of background colors to be displayed when they are clearly not
- // needed. We could use display list optimization to clean this up, but it still seems
- // inefficient. What we really want is something like "nearest ancestor element that
- // doesn't have a fragment".
- let background_color = style.resolve_color(style.get_background().background_color);
- if !background_color.alpha.approx_eq(&0.0) {
- let display_item = box SolidColorDisplayItem {
- base: BaseDisplayItem::new(*absolute_bounds, self.node, level, *clip_rect),
- color: background_color.to_gfx_color(),
- };
-
- list.push(SolidColorDisplayItemClass(display_item))
- }
-
- // The background image is painted on top of the background color.
- // Implements background image, per spec:
- // http://www.w3.org/TR/CSS21/colors.html#background
- let background = style.get_background();
- let image_url = match background.background_image {
- None => return,
- Some(ref image_url) => image_url,
- };
-
- let mut holder = ImageHolder::new(image_url.clone(), layout_context.shared.image_cache.clone());
- let image = match holder.get_image(self.node.to_untrusted_node_address()) {
- None => {
- // No image data at all? Do nothing.
- //
- // TODO: Add some kind of placeholder background image.
- debug!("(building display list) no background image :(");
- return
- }
- Some(image) => image,
- };
- debug!("(building display list) building background image");
-
- let image_width = Au::from_px(image.width as int);
- let image_height = Au::from_px(image.height as int);
- let mut bounds = *absolute_bounds;
-
- // Clip.
- //
- // TODO: Check the bounds to see if a clip item is actually required.
- let clip_rect = clip_rect.intersection(&bounds).unwrap_or(ZERO_RECT);
-
- // Use background-attachment to get the initial virtual origin
- let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
- background_attachment::scroll => {
- (absolute_bounds.origin.x, absolute_bounds.origin.y)
- }
- background_attachment::fixed => {
- (Au(0), Au(0))
- }
- };
-
- // Use background-position to get the offset
- let horizontal_position = model::specified(background.background_position.horizontal,
- bounds.size.width - image_width);
- let vertical_position = model::specified(background.background_position.vertical,
- bounds.size.height - image_height);
-
- let abs_x = virtual_origin_x + horizontal_position;
- let abs_y = virtual_origin_y + vertical_position;
-
- // Adjust origin and size based on background-repeat
- match background.background_repeat {
- background_repeat::no_repeat => {
- bounds.origin.x = abs_x;
- bounds.origin.y = abs_y;
- bounds.size.width = image_width;
- bounds.size.height = image_height;
- }
- background_repeat::repeat_x => {
- bounds.origin.y = abs_y;
- bounds.size.height = image_height;
- ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
- abs_x, image.width);
- }
- background_repeat::repeat_y => {
- bounds.origin.x = abs_x;
- bounds.size.width = image_width;
- ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
- abs_y, image.height);
- }
- background_repeat::repeat => {
- ImageFragmentInfo::tile_image(&mut bounds.origin.x, &mut bounds.size.width,
- abs_x, image.width);
- ImageFragmentInfo::tile_image(&mut bounds.origin.y, &mut bounds.size.height,
- abs_y, image.height);
- }
- };
-
- // Create the image display item.
- let image_display_item = ImageDisplayItemClass(box ImageDisplayItem {
- base: BaseDisplayItem::new(bounds, self.node, level, clip_rect),
- image: image.clone(),
- stretch_size: Size2D(Au::from_px(image.width as int),
- Au::from_px(image.height as int)),
- });
- list.push(image_display_item)
- }
-
- /// Adds the display items necessary to paint the borders of this fragment to a display list if
- /// necessary.
- pub fn build_display_list_for_borders_if_applicable(&self,
- style: &ComputedValues,
- list: &mut DisplayList,
- abs_bounds: &Rect<Au>,
- level: StackingLevel,
- clip_rect: &Rect<Au>) {
- let border = style.logical_border_width();
- if border.is_zero() {
- return
- }
-
- let top_color = style.resolve_color(style.get_border().border_top_color);
- let right_color = style.resolve_color(style.get_border().border_right_color);
- let bottom_color = style.resolve_color(style.get_border().border_bottom_color);
- let left_color = style.resolve_color(style.get_border().border_left_color);
-
- // Append the border to the display list.
- let border_display_item = box BorderDisplayItem {
- base: BaseDisplayItem::new(*abs_bounds, self.node, level, *clip_rect),
- border: border.to_physical(style.writing_mode),
- color: SideOffsets2D::new(top_color.to_gfx_color(),
- right_color.to_gfx_color(),
- bottom_color.to_gfx_color(),
- left_color.to_gfx_color()),
- style: SideOffsets2D::new(style.get_border().border_top_style,
- style.get_border().border_right_style,
- style.get_border().border_bottom_style,
- style.get_border().border_left_style)
- };
-
- list.push(BorderDisplayItemClass(border_display_item))
- }
-
- fn build_debug_borders_around_text_fragments(&self,
- display_list: &mut DisplayList,
- flow_origin: Point2D<Au>,
- text_fragment: &ScannedTextFragmentInfo,
- clip_rect: &Rect<Au>) {
- // 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);
-
- // Compute the text fragment bounds and draw a border surrounding them.
- let border_display_item = box BorderDisplayItem {
- base: BaseDisplayItem::new(absolute_fragment_bounds,
- self.node,
- ContentStackingLevel,
- *clip_rect),
- border: SideOffsets2D::new_all_same(Au::from_px(1)),
- color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
- style: SideOffsets2D::new_all_same(border_style::solid)
- };
- display_list.push(BorderDisplayItemClass(border_display_item));
-
- // 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;
- baseline.size.block = Au(0);
- let mut baseline = baseline.to_physical(self.style.writing_mode, container_size);
- baseline.origin = baseline.origin + flow_origin;
-
- let line_display_item = box LineDisplayItem {
- base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel, *clip_rect),
- color: rgb(0, 200, 0),
- style: border_style::dashed,
- };
- display_list.push(LineDisplayItemClass(line_display_item));
- }
-
- fn build_debug_borders_around_fragment(&self,
- display_list: &mut DisplayList,
- flow_origin: Point2D<Au>,
- clip_rect: &Rect<Au>) {
- // 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.
- let border_display_item = box BorderDisplayItem {
- base: BaseDisplayItem::new(absolute_fragment_bounds,
- self.node,
- ContentStackingLevel,
- *clip_rect),
- border: SideOffsets2D::new_all_same(Au::from_px(1)),
- color: SideOffsets2D::new_all_same(rgb(0, 0, 200)),
- style: SideOffsets2D::new_all_same(border_style::solid)
- };
- display_list.push(BorderDisplayItemClass(border_display_item))
- }
-
- /// Adds the display items for this fragment to the given stacking context.
- ///
- /// Arguments:
- ///
- /// * `display_list`: The unflattened 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.
- /// * `clip_rect`: The rectangle to clip the display items to.
- pub fn build_display_list(&mut self,
- display_list: &mut DisplayList,
- layout_context: &LayoutContext,
- flow_origin: Point2D<Au>,
- background_and_border_level: BackgroundAndBorderLevel,
- clip_rect: &Rect<Au>) {
- // FIXME(#2795): Get the real container size
- let container_size = Size2D::zero();
- let rect_to_absolute = |writing_mode: WritingMode, logical_rect: LogicalRect<Au>| {
- let physical_rect = logical_rect.to_physical(writing_mode, container_size);
- Rect(physical_rect.origin + flow_origin, physical_rect.size)
- };
- // Fragment position wrt to the owning flow.
- let absolute_fragment_bounds = rect_to_absolute(self.style.writing_mode, self.border_box);
- debug!("Fragment::build_display_list at rel={}, abs={}: {}",
- self.border_box,
- absolute_fragment_bounds,
- self);
- debug!("Fragment::build_display_list: dirty={}, flow_origin={}",
- layout_context.shared.dirty,
- flow_origin);
-
- if self.style().get_inheritedbox().visibility != visibility::visible {
- return
- }
-
- if !absolute_fragment_bounds.intersects(&layout_context.shared.dirty) {
- debug!("Fragment::build_display_list: Did not intersect...");
- return
- }
-
- debug!("Fragment::build_display_list: intersected. Adding display item...");
-
- if self.is_primary_fragment() {
- let level =
- StackingLevel::from_background_and_border_level(background_and_border_level);
-
- // Add a pseudo-display item for content box queries. This is a very bogus thing to do.
- let base_display_item = box BaseDisplayItem::new(absolute_fragment_bounds,
- self.node,
- level,
- *clip_rect);
- display_list.push(PseudoDisplayItemClass(base_display_item));
-
- // Add the background to the list, if applicable.
- match self.inline_context {
- Some(ref 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_rect);
- }
- }
- None => {}
- }
- match self.specific {
- ScannedTextFragment(_) => {},
- _ => {
- self.build_display_list_for_background_if_applicable(
- &*self.style,
- display_list,
- layout_context,
- level,
- &absolute_fragment_bounds,
- clip_rect);
- }
- }
-
- // Add a border, if applicable.
- //
- // TODO: Outlines.
- match self.inline_context {
- Some(ref 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_rect);
- }
- }
- None => {}
- }
- match self.specific {
- ScannedTextFragment(_) => {},
- _ => {
- self.build_display_list_for_borders_if_applicable(
- &*self.style,
- display_list,
- &absolute_fragment_bounds,
- level,
- clip_rect);
- }
- }
- }
-
- let content_box = self.content_box();
- let absolute_content_box = rect_to_absolute(self.style.writing_mode, content_box);
-
- // Create special per-fragment-type display items.
- match self.specific {
- UnscannedTextFragment(_) => fail!("Shouldn't see unscanned fragments here."),
- TableColumnFragment(_) => fail!("Shouldn't see table column fragments here."),
- ScannedTextFragment(ref text_fragment) => {
- // Create the text display item.
- let orientation = if self.style.writing_mode.is_vertical() {
- if self.style.writing_mode.is_sideways_left() {
- SidewaysLeft
- } else {
- SidewaysRight
- }
- } else {
- Upright
- };
-
- let metrics = &text_fragment.run.font_metrics;
- let baseline_origin ={
- let mut tmp = content_box.start;
- tmp.b = tmp.b + metrics.ascent;
- tmp.to_physical(self.style.writing_mode, container_size) + flow_origin
- };
-
- let text_display_item = box TextDisplayItem {
- base: BaseDisplayItem::new(absolute_content_box,
- self.node,
- ContentStackingLevel,
- *clip_rect),
- text_run: text_fragment.run.clone(),
- range: text_fragment.range,
- text_color: self.style().get_color().color.to_gfx_color(),
- orientation: orientation,
- baseline_origin: baseline_origin,
- };
- display_list.push(TextDisplayItemClass(text_display_item));
-
- // Create display items for text decoration
- {
- let line = |maybe_color: Option<RGBA>, rect: || -> LogicalRect<Au>| {
- match maybe_color {
- None => {},
- Some(color) => {
- display_list.push(SolidColorDisplayItemClass(
- box SolidColorDisplayItem {
- base: BaseDisplayItem::new(
- rect_to_absolute(
- self.style.writing_mode,
- rect()),
- self.node,
- ContentStackingLevel,
- *clip_rect),
- color: color.to_gfx_color(),
- }));
- }
- }
- };
-
- let text_decorations =
- self.style().get_inheritedtext()._servo_text_decorations_in_effect;
- line(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;
- rect
- });
-
- line(text_decorations.overline, || {
- let mut rect = content_box.clone();
- rect.size.block = metrics.underline_size;
- rect
- });
-
- line(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;
- rect
- });
- }
-
- if opts::get().show_debug_fragment_borders {
- self.build_debug_borders_around_text_fragments(display_list,
- flow_origin,
- text_fragment,
- clip_rect);
- }
- }
- GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment |
- TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | InputFragment |
- InlineAbsoluteHypotheticalFragment(_) => {
- if opts::get().show_debug_fragment_borders {
- self.build_debug_borders_around_fragment(display_list,
- flow_origin,
- clip_rect);
- }
- }
- ImageFragment(ref mut image_fragment) => {
- let image_ref = &mut image_fragment.image;
- match image_ref.get_image(self.node.to_untrusted_node_address()) {
- Some(image) => {
- debug!("(building display list) building image fragment");
-
- // Place the image into the display list.
- let image_display_item = box ImageDisplayItem {
- base: BaseDisplayItem::new(absolute_content_box,
- self.node,
- ContentStackingLevel,
- *clip_rect),
- image: image.clone(),
- stretch_size: absolute_content_box.size,
- };
-
- display_list.push(ImageDisplayItemClass(image_display_item))
- }
- None => {
- // No image data at all? Do nothing.
- //
- // TODO: Add some kind of placeholder image.
- debug!("(building display list) no image :(");
- }
- }
- }
- }
-
- // FIXME(pcwalton): This is a bit of an abuse of the logging
- // infrastructure. We should have a real `SERVO_DEBUG` system.
- debug!("{:?}",
- self.build_debug_borders_around_fragment(display_list, flow_origin, clip_rect))
-
- // If this is an iframe, then send its position and size up to the constellation.
- //
- // FIXME(pcwalton): Doing this during display list construction seems potentially
- // problematic if iframes are outside the area we're computing the display list for, since
- // they won't be able to reflow at all until the user scrolls to them. Perhaps we should
- // separate this into two parts: first we should send the size only to the constellation
- // once that's computed during assign-block-sizes, and second we should should send the
- // origin to the constellation here during display list construction. This should work
- // because layout for the iframe only needs to know size, and origin is only relevant if
- // the iframe is actually going to be displayed.
- match self.specific {
- IframeFragment(ref iframe_fragment) => {
- self.finalize_position_and_size_of_iframe(iframe_fragment,
- absolute_fragment_bounds.origin,
- layout_context)
- }
- _ => {}
- }
- }
-
/// Computes the intrinsic inline-sizes of this fragment.
pub fn compute_intrinsic_inline_sizes(&mut self) -> IntrinsicISizesContribution {
let mut result = self.style_specified_intrinsic_inline_size();
@@ -1889,29 +1406,6 @@ impl Fragment {
}
}
- /// Sends the size and position of this iframe fragment to the constellation. This is out of
- /// line to guide inlining.
- #[inline(never)]
- fn finalize_position_and_size_of_iframe(&self,
- iframe_fragment: &IframeFragmentInfo,
- offset: Point2D<Au>,
- layout_context: &LayoutContext) {
- let border_padding = (self.border_padding).to_physical(self.style.writing_mode);
- let content_size = self.content_box().size.to_physical(self.style.writing_mode);
- let iframe_rect = Rect(Point2D(geometry::to_frac_px(offset.x + border_padding.left) as f32,
- geometry::to_frac_px(offset.y + border_padding.top) as f32),
- Size2D(geometry::to_frac_px(content_size.width) as f32,
- geometry::to_frac_px(content_size.height) as f32));
-
- debug!("finalizing position and size of iframe for {:?},{:?}",
- iframe_fragment.pipeline_id,
- iframe_fragment.subpage_id);
- let ConstellationChan(ref chan) = layout_context.shared.constellation_chan;
- chan.send(FrameRectMsg(iframe_fragment.pipeline_id,
- iframe_fragment.subpage_id,
- iframe_rect));
- }
-
/// Returns true if and only if this is the *primary fragment* for the fragment's style object
/// (conceptually, though style sharing makes this not really true, of course). The primary
/// fragment is the one that draws backgrounds, borders, etc., and takes borders, padding and
@@ -1921,7 +1415,7 @@ impl Fragment {
/// fragments. Inline-block fragments are not primary fragments because the corresponding block
/// flow is the primary fragment, while table wrapper fragments are not primary fragments
/// because the corresponding table flow is the primary fragment.
- fn is_primary_fragment(&self) -> bool {
+ pub fn is_primary_fragment(&self) -> bool {
match self.specific {
InlineBlockFragment(_) | InlineAbsoluteHypotheticalFragment(_) |
TableWrapperFragment => false,
@@ -1951,27 +1445,6 @@ impl Fragment {
}
}
- pub fn clip_rect_for_children(&self, current_clip_rect: Rect<Au>, flow_origin: Point2D<Au>)
- -> Rect<Au> {
- // Don't clip if we're text.
- match self.specific {
- ScannedTextFragment(_) => return current_clip_rect,
- _ => {}
- }
-
- // Only clip if `overflow` tells us to.
- match self.style.get_box().overflow {
- overflow::hidden | overflow::auto | overflow::scroll => {}
- _ => return current_clip_rect,
- }
-
- // 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_rect.intersection(&Rect(physical_rect.origin + flow_origin,
- physical_rect.size)).unwrap_or(ZERO_RECT)
- }
}
impl fmt::Show for Fragment {
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index bdfc9474fe7..154409d0a3f 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -6,6 +6,7 @@
use css::node_style::StyledNode;
use context::LayoutContext;
+use display_list_builder::FragmentDisplayListBuilding;
use floats::{FloatLeft, Floats, PlacementInfo};
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils};
use flow;
@@ -24,6 +25,7 @@ use gfx::font_context::FontContext;
use gfx::text::glyph::CharIndex;
use servo_util::geometry::Au;
use servo_util::logical_geometry::{LogicalRect, LogicalSize};
+use servo_util::opts;
use servo_util::range::{IntRangeIndex, Range, RangeIndex};
use servo_util::arc_ptr_eq;
use std::cmp::max;
@@ -706,44 +708,6 @@ impl InlineFlow {
}
}
- pub fn build_display_list_inline(&mut self, layout_context: &LayoutContext) {
- let size = self.base.position.size.to_physical(self.base.writing_mode);
- if !Rect(self.base.abs_position, size).intersects(&layout_context.shared.dirty) {
- debug!("inline block (abs pos {}, size {}) didn't intersect \
- dirty rect two",
- self.base.abs_position,
- size);
- return
- }
-
- // 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());
-
- for fragment in self.fragments.fragments.iter_mut() {
- let rel_offset = fragment.relative_position(&self.base
- .absolute_position_info
- .relative_containing_block_size);
- let fragment_position = self.base
- .abs_position
- .add_size(&rel_offset.to_physical(self.base.writing_mode));
- fragment.build_display_list(&mut self.base.display_list,
- layout_context,
- fragment_position,
- ContentLevel,
- &self.base.clip_rect);
- match fragment.specific {
- InlineBlockFragment(ref mut block_flow) => {
- let block_flow = block_flow.flow_ref.deref_mut();
- self.base.display_list.push_all_move(
- mem::replace(&mut flow::mut_base(block_flow).display_list,
- DisplayList::new()));
- }
- _ => {}
- }
- }
- }
-
/// Returns the distance from the baseline for the logical block-start inline-start corner of
/// this fragment, taking into account the value of the CSS `vertical-align` property.
/// Negative values mean "toward the logical block-start" and positive values mean "toward the
@@ -1201,6 +1165,48 @@ impl Flow for InlineFlow {
fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {}
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ let size = self.base.position.size.to_physical(self.base.writing_mode);
+ if !Rect(self.base.abs_position, size).intersects(&layout_context.shared.dirty) {
+ debug!("inline block (abs pos {}, size {}) didn't intersect \
+ dirty rect two",
+ self.base.abs_position,
+ size);
+ return
+ }
+
+ // 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());
+
+ for fragment in self.fragments.fragments.iter_mut() {
+ let rel_offset = fragment.relative_position(&self.base
+ .absolute_position_info
+ .relative_containing_block_size);
+ let fragment_position = self.base
+ .abs_position
+ .add_size(&rel_offset.to_physical(self.base.writing_mode));
+ fragment.build_display_list(&mut self.base.display_list,
+ layout_context,
+ fragment_position,
+ ContentLevel,
+ &self.base.clip_rect);
+ match fragment.specific {
+ InlineBlockFragment(ref mut block_flow) => {
+ let block_flow = block_flow.flow_ref.deref_mut();
+ self.base.display_list.push_all_move(
+ mem::replace(&mut flow::mut_base(block_flow).display_list,
+ DisplayList::new()));
+ }
+ _ => {}
+ }
+ }
+
+ if opts::get().validate_display_list_geometry {
+ self.base.validate_display_list_geometry();
+ }
+ }
}
impl fmt::Show for InlineFlow {
diff --git a/components/layout/lib.rs b/components/layout/lib.rs
index 0e7eb9434d2..94b2bbc5b68 100644
--- a/components/layout/lib.rs
+++ b/components/layout/lib.rs
@@ -46,6 +46,7 @@ pub mod layout_debug;
pub mod block;
pub mod construct;
pub mod context;
+pub mod display_list_builder;
pub mod floats;
pub mod flow;
pub mod flow_list;
diff --git a/components/layout/table.rs b/components/layout/table.rs
index 5d8bce0d357..f90f291bf22 100644
--- a/components/layout/table.rs
+++ b/components/layout/table.rs
@@ -126,11 +126,6 @@ impl TableFlow {
fn assign_block_size_table_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse);
}
-
- pub fn build_display_list_table(&mut self, layout_context: &LayoutContext) {
- debug!("build_display_list_table: same process as block flow");
- self.block_flow.build_display_list_block(layout_context);
- }
}
impl Flow for TableFlow {
@@ -323,6 +318,10 @@ impl Flow for TableFlow {
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ self.block_flow.build_display_list(layout_context);
+ }
}
impl fmt::Show for TableFlow {
diff --git a/components/layout/table_caption.rs b/components/layout/table_caption.rs
index 7a46fddb833..96e50747dc9 100644
--- a/components/layout/table_caption.rs
+++ b/components/layout/table_caption.rs
@@ -28,11 +28,6 @@ impl TableCaptionFlow {
block_flow: BlockFlow::from_node(constructor, node)
}
}
-
- pub fn build_display_list_table_caption(&mut self, layout_context: &LayoutContext) {
- debug!("build_display_list_table_caption: same process as block flow");
- self.block_flow.build_display_list_block(layout_context)
- }
}
impl Flow for TableCaptionFlow {
@@ -73,6 +68,11 @@ impl Flow for TableCaptionFlow {
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ debug!("build_display_list_table_caption: same process as block flow");
+ self.block_flow.build_display_list(layout_context)
+ }
}
impl fmt::Show for TableCaptionFlow {
diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs
index 3e4bdc2d01d..02c0c4445ef 100644
--- a/components/layout/table_cell.rs
+++ b/components/layout/table_cell.rs
@@ -51,11 +51,6 @@ impl TableCellFlow {
fn assign_block_size_table_cell_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse)
}
-
- pub fn build_display_list_table_cell(&mut self, layout_context: &LayoutContext) {
- debug!("build_display_list_table: same process as block flow");
- self.block_flow.build_display_list_block(layout_context)
- }
}
impl Flow for TableCellFlow {
@@ -143,6 +138,10 @@ impl Flow for TableCellFlow {
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ self.block_flow.build_display_list(layout_context)
+ }
}
impl fmt::Show for TableCellFlow {
diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs
index 5db1dd3ab2a..96cec13c5aa 100644
--- a/components/layout/table_colgroup.rs
+++ b/components/layout/table_colgroup.rs
@@ -85,6 +85,9 @@ impl Flow for TableColGroupFlow {
fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {}
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
+
+ // Table columns are invisible.
+ fn build_display_list(&mut self, _: &LayoutContext) {}
}
impl fmt::Show for TableColGroupFlow {
diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs
index ea3395704d4..c4c26281e20 100644
--- a/components/layout/table_row.rs
+++ b/components/layout/table_row.rs
@@ -126,11 +126,6 @@ impl TableRowFlow {
child_node.position.size.block = block_size;
}
}
-
- pub fn build_display_list_table_row(&mut self, layout_context: &LayoutContext) {
- debug!("build_display_list_table_row: same process as block flow");
- self.block_flow.build_display_list_block(layout_context)
- }
}
impl Flow for TableRowFlow {
@@ -246,6 +241,10 @@ impl Flow for TableRowFlow {
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ self.block_flow.build_display_list(layout_context)
+ }
}
impl fmt::Show for TableRowFlow {
diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs
index f0a6483515e..e21aedfc5ab 100644
--- a/components/layout/table_rowgroup.rs
+++ b/components/layout/table_rowgroup.rs
@@ -86,11 +86,6 @@ impl TableRowGroupFlow {
self.block_flow.fragment.border_box = position;
self.block_flow.base.position.size.block = block_size;
}
-
- pub fn build_display_list_table_rowgroup(&mut self, layout_context: &LayoutContext) {
- debug!("build_display_list_table_rowgroup: same process as block flow");
- self.block_flow.build_display_list_block(layout_context)
- }
}
impl Flow for TableRowGroupFlow {
@@ -205,6 +200,11 @@ impl Flow for TableRowGroupFlow {
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ debug!("build_display_list_table_rowgroup: same process as block flow");
+ self.block_flow.build_display_list(layout_context)
+ }
}
impl fmt::Show for TableRowGroupFlow {
diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs
index 060e78ecf5b..9acc65d672f 100644
--- a/components/layout/table_wrapper.rs
+++ b/components/layout/table_wrapper.rs
@@ -109,11 +109,6 @@ impl TableWrapperFlow {
}
}
- pub fn build_display_list_table_wrapper(&mut self, layout_context: &LayoutContext) {
- debug!("build_display_list_table_wrapper: same process as block flow");
- self.block_flow.build_display_list_block(layout_context);
- }
-
/// Calculates table column sizes for automatic layout per INTRINSIC § 4.3.
fn calculate_table_column_sizes_for_automatic_layout(&mut self) {
// Find the padding and border of our first child, which is the table itself.
@@ -338,6 +333,10 @@ impl Flow for TableWrapperFlow {
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
}
+
+ fn build_display_list(&mut self, layout_context: &LayoutContext) {
+ self.block_flow.build_display_list(layout_context)
+ }
}
impl fmt::Show for TableWrapperFlow {