From 2e4cecc71827e799a4576835776535a2af8e87f3 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 30 May 2013 16:10:35 -0700 Subject: [PATCH] Add flows if requested to the display list info. This will be used for hit testing. --- src/components/gfx/display_list.rs | 43 ++++++------ src/components/gfx/render_layers.rs | 6 +- src/components/main/layout/block.rs | 14 ++-- src/components/main/layout/box.rs | 23 ++++--- .../main/layout/display_list_builder.rs | 67 +++++++++++++------ src/components/main/layout/flow.rs | 12 ++-- src/components/main/layout/inline.rs | 12 ++-- src/components/main/layout/model.rs | 7 +- 8 files changed, 112 insertions(+), 72 deletions(-) diff --git a/src/components/gfx/display_list.rs b/src/components/gfx/display_list.rs index 6ceeef76a9c..1583b1fcf6d 100644 --- a/src/components/gfx/display_list.rs +++ b/src/components/gfx/display_list.rs @@ -26,20 +26,20 @@ use std::arc::ARC; use std::arc; /// A list of rendering operations to be performed. -pub struct DisplayList { - priv list: ~[DisplayItem] +pub struct DisplayList { + priv list: ~[DisplayItem] } -impl DisplayList { +impl DisplayList { /// Creates a new display list. - pub fn new() -> DisplayList { + pub fn new() -> DisplayList { DisplayList { list: ~[] } } /// Appends the given item to the display list. - pub fn append_item(&mut self, item: DisplayItem) { + pub fn append_item(&mut self, item: DisplayItem) { // FIXME(Issue #150): crashes //debug!("Adding display item %u: %?", self.len(), item); self.list.push(item) @@ -58,51 +58,54 @@ impl DisplayList { } /// One drawing command in the list. -pub enum DisplayItem { - SolidColorDisplayItemClass(~SolidColorDisplayItem), - TextDisplayItemClass(~TextDisplayItem), - ImageDisplayItemClass(~ImageDisplayItem), - BorderDisplayItemClass(~BorderDisplayItem), +pub enum DisplayItem { + SolidColorDisplayItemClass(~SolidColorDisplayItem), + TextDisplayItemClass(~TextDisplayItem), + ImageDisplayItemClass(~ImageDisplayItem), + BorderDisplayItemClass(~BorderDisplayItem), } /// Information common to all display items. -pub struct BaseDisplayItem { +pub struct BaseDisplayItem { /// The boundaries of the display item. /// /// TODO: Which coordinate system should this use? bounds: Rect, + + /// Extra data: either the originating flow (for hit testing) or nothing (for rendering). + extra: E, } /// Renders a solid color. -pub struct SolidColorDisplayItem { - base: BaseDisplayItem, +pub struct SolidColorDisplayItem { + base: BaseDisplayItem, color: Color, } /// Renders text. -pub struct TextDisplayItem { - base: BaseDisplayItem, +pub struct TextDisplayItem { + base: BaseDisplayItem, text_run: ~SendableTextRun, range: Range, color: Color, } /// Renders an image. -pub struct ImageDisplayItem { - base: BaseDisplayItem, +pub struct ImageDisplayItem { + base: BaseDisplayItem, image: ARC<~Image>, } /// Renders a border. -pub struct BorderDisplayItem { - base: BaseDisplayItem, +pub struct BorderDisplayItem { + base: BaseDisplayItem, /// The width of the border. width: Au, /// The color of the border. color: Color, } -impl DisplayItem { +impl DisplayItem { /// Renders this display item into the given render context. fn draw_into_context(&self, render_context: &RenderContext) { match *self { diff --git a/src/components/gfx/render_layers.rs b/src/components/gfx/render_layers.rs index 93c1bc59e80..a2cab09e2c1 100644 --- a/src/components/gfx/render_layers.rs +++ b/src/components/gfx/render_layers.rs @@ -14,8 +14,12 @@ use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; +/// The type representing the lack of extra display list data. This is used when sending display +/// list data off to be rendered. +pub type Nothing = (); + pub struct RenderLayer { - display_list: DisplayList, + display_list: DisplayList, size: Size2D } diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs index ac980be4bb6..95872a3273c 100644 --- a/src/components/main/layout/block.rs +++ b/src/components/main/layout/block.rs @@ -6,7 +6,8 @@ use layout::box::{RenderBox}; use layout::context::LayoutContext; -use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods}; +use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; +use layout::display_list_builder::{FlowDisplayListBuilderMethods}; use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow}; use layout::inline::InlineLayout; @@ -175,11 +176,11 @@ impl BlockFlowData { }); } - pub fn build_display_list_block(@mut self, - builder: &DisplayListBuilder, - dirty: &Rect, - offset: &Point2D, - list: &Cell) { + pub fn build_display_list_block(@mut self, + builder: &DisplayListBuilder, + dirty: &Rect, + offset: &Point2D, + list: &Cell>) { // add box that starts block context self.box.map(|&box| { box.build_display_list(builder, dirty, offset, list) @@ -195,3 +196,4 @@ impl BlockFlowData { } } } + diff --git a/src/components/main/layout/box.rs b/src/components/main/layout/box.rs index f5cac35f568..53b8826657b 100644 --- a/src/components/main/layout/box.rs +++ b/src/components/main/layout/box.rs @@ -6,7 +6,7 @@ use css::node_style::StyledNode; use layout::context::LayoutContext; -use layout::display_list_builder::{DisplayListBuilder, ToGfxColor}; +use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor}; use layout::flow::FlowContext; use layout::model::BoxModel; use layout::text; @@ -550,11 +550,11 @@ pub impl RenderBox { /// representing the box's stacking context. When asked to construct its constituent display /// items, each box puts its display items into the correct stack layer according to CSS 2.1 /// Appendix E. Finally, the builder flattens the list. - fn build_display_list(&self, - _: &DisplayListBuilder, - dirty: &Rect, - offset: &Point2D, - list: &Cell) { + fn build_display_list(&self, + _: &DisplayListBuilder, + dirty: &Rect, + offset: &Point2D, + list: &Cell>) { let box_bounds = self.position(); let absolute_box_bounds = box_bounds.translate(offset); debug!("RenderBox::build_display_list at rel=%?, abs=%?: %s", @@ -582,6 +582,7 @@ pub impl RenderBox { let text_display_item = ~TextDisplayItem { base: BaseDisplayItem { bounds: absolute_box_bounds, + extra: ExtraDisplayListData::new(*self), }, // FIXME(pcwalton): Allocation? Why?! text_run: ~text_box.run.serialize(), @@ -602,6 +603,7 @@ pub impl RenderBox { let border_display_item = ~BorderDisplayItem { base: BaseDisplayItem { bounds: absolute_box_bounds, + extra: ExtraDisplayListData::new(*self), }, width: Au::from_px(1), color: rgb(0, 0, 200).to_gfx_color(), @@ -621,6 +623,7 @@ pub impl RenderBox { let border_display_item = ~BorderDisplayItem { base: BaseDisplayItem { bounds: baseline, + extra: ExtraDisplayListData::new(*self), }, width: Au::from_px(1), color: rgb(0, 200, 0).to_gfx_color(), @@ -644,6 +647,7 @@ pub impl RenderBox { let image_display_item = ~ImageDisplayItem { base: BaseDisplayItem { bounds: absolute_box_bounds, + extra: ExtraDisplayListData::new(*self), }, image: image.clone(), }; @@ -668,9 +672,9 @@ pub impl RenderBox { /// Adds the display items necessary to paint the background of this render box to the display /// list if necessary. - fn paint_background_if_applicable(&self, - list: &Cell, - absolute_bounds: &Rect) { + fn paint_background_if_applicable(&self, + list: &Cell>, + absolute_bounds: &Rect) { // 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 @@ -683,6 +687,7 @@ pub impl RenderBox { let solid_color_display_item = ~SolidColorDisplayItem { base: BaseDisplayItem { bounds: *absolute_bounds, + extra: ExtraDisplayListData::new(*self), }, color: background_color.to_gfx_color(), }; diff --git a/src/components/main/layout/display_list_builder.rs b/src/components/main/layout/display_list_builder.rs index 1d0ea27b7e5..02173ef7517 100644 --- a/src/components/main/layout/display_list_builder.rs +++ b/src/components/main/layout/display_list_builder.rs @@ -2,15 +2,13 @@ * 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/. */ -/// -/// Constructs display lists from render boxes. -/// - -use core::cell::Cell; +//! Constructs display lists from render boxes. +use layout::box::RenderBox; use layout::context::LayoutContext; use layout::flow::FlowContext; +use core::cell::Cell; use geom::point::Point2D; use geom::rect::Rect; use gfx::display_list::DisplayList; @@ -19,6 +17,28 @@ use gfx; use newcss; use servo_util::tree::TreeNodeRef; +/// Extra display list data is either nothing (if the display list is to be rendered) or the +/// originating render box (if the display list is generated for hit testing). +pub trait ExtraDisplayListData { + fn new(box: RenderBox) -> Self; +} + +/// The type representing the lack of extra display list data. This is used when sending display +/// list data off to be rendered. +pub type Nothing = (); + +impl ExtraDisplayListData for Nothing { + fn new(_: RenderBox) -> Nothing { + () + } +} + +impl ExtraDisplayListData for RenderBox { + fn new(box: RenderBox) -> RenderBox { + box + } +} + /// A builder object that manages display list builder should mainly hold information about the /// initial request and desired result--for example, whether the `DisplayList` is to be used for /// painting or hit testing. This can affect which boxes are created. @@ -30,30 +50,33 @@ pub struct DisplayListBuilder<'self> { } pub trait FlowDisplayListBuilderMethods { - fn build_display_list(&self, a: &DisplayListBuilder, b: &Rect, c: &Cell); - fn build_display_list_for_child(&self, - a: &DisplayListBuilder, - b: FlowContext, - c: &Rect, - d: &Point2D, - e: &Cell); + fn build_display_list(&self, + a: &DisplayListBuilder, + b: &Rect, + c: &Cell>); + fn build_display_list_for_child(&self, + a: &DisplayListBuilder, + b: FlowContext, + c: &Rect, + d: &Point2D, + e: &Cell>); } impl FlowDisplayListBuilderMethods for FlowContext { - fn build_display_list(&self, - builder: &DisplayListBuilder, - dirty: &Rect, - list: &Cell) { + fn build_display_list(&self, + builder: &DisplayListBuilder, + dirty: &Rect, + list: &Cell>) { let zero = gfx::geometry::zero_point(); self.build_display_list_recurse(builder, dirty, &zero, list); } - fn build_display_list_for_child(&self, - builder: &DisplayListBuilder, - child_flow: FlowContext, - dirty: &Rect, - offset: &Point2D, - list: &Cell) { + fn build_display_list_for_child(&self, + builder: &DisplayListBuilder, + child_flow: FlowContext, + dirty: &Rect, + offset: &Point2D, + list: &Cell>) { // Adjust the dirty rect to child flow context coordinates. do child_flow.with_base |child_node| { let abs_flow_bounds = child_node.position.translate(offset); diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs index c840a204d7f..4a9a6f9dd62 100644 --- a/src/components/main/layout/flow.rs +++ b/src/components/main/layout/flow.rs @@ -28,7 +28,7 @@ use layout::block::BlockFlowData; use layout::box::RenderBox; use layout::context::LayoutContext; -use layout::display_list_builder::DisplayListBuilder; +use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; use layout::inline::{InlineFlowData}; use core::cell::Cell; @@ -284,11 +284,11 @@ impl<'self> FlowContext { } } - pub fn build_display_list_recurse(&self, - builder: &DisplayListBuilder, - dirty: &Rect, - offset: &Point2D, - list: &Cell) { + pub fn build_display_list_recurse(&self, + builder: &DisplayListBuilder, + dirty: &Rect, + offset: &Point2D, + list: &Cell>) { do self.with_base |info| { debug!("FlowContext::build_display_list at %?: %s", info.position, self.debug_str()); } diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs index 3db7e23e34e..704c62c20c4 100644 --- a/src/components/main/layout/inline.rs +++ b/src/components/main/layout/inline.rs @@ -7,7 +7,7 @@ use core; use layout::box::{CannotSplit, GenericRenderBoxClass, ImageRenderBoxClass, RenderBox}; use layout::box::{SplitDidFit, SplitDidNotFit, TextRenderBoxClass, UnscannedTextRenderBoxClass}; use layout::context::LayoutContext; -use layout::display_list_builder::DisplayListBuilder; +use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; use layout::flow::{FlowContext, FlowData, InlineFlow}; use layout::text::{UnscannedMethods, adapt_textbox_with_range}; @@ -864,11 +864,11 @@ impl InlineFlowData { self.common.position.size.height = cur_y; } - pub fn build_display_list_inline(&self, - builder: &DisplayListBuilder, - dirty: &Rect, - offset: &Point2D, - list: &Cell) { + pub fn build_display_list_inline(&self, + builder: &DisplayListBuilder, + dirty: &Rect, + offset: &Point2D, + list: &Cell>) { // TODO(#228): Once we form line boxes 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!("FlowContext[%d]: building display list for %u inline boxes", diff --git a/src/components/main/layout/model.rs b/src/components/main/layout/model.rs index 35b545baebf..da92788a338 100644 --- a/src/components/main/layout/model.rs +++ b/src/components/main/layout/model.rs @@ -4,7 +4,7 @@ //! Borders, padding, and margins. -use layout::display_list_builder::ToGfxColor; +use layout::display_list_builder::{ExtraDisplayListData, ToGfxColor}; use layout::box::RenderBox; use core::cell::Cell; @@ -76,7 +76,9 @@ impl BoxModel { impl RenderBox { /// Adds the display items necessary to paint the borders of this render box to a display list /// if necessary. - pub fn paint_borders_if_applicable(&self, list: &Cell, abs_bounds: &Rect) { + pub fn paint_borders_if_applicable(&self, + list: &Cell>, + abs_bounds: &Rect) { // Fast path. let border = do self.with_imm_base |base| { base.model.border @@ -109,6 +111,7 @@ impl RenderBox { let border_display_item = ~BorderDisplayItem { base: BaseDisplayItem { bounds: bounds, + extra: ExtraDisplayListData::new(*self), }, width: border_width, color: color,