Add flows if requested to the display list info.

This will be used for hit testing.
This commit is contained in:
Patrick Walton 2013-05-30 16:10:35 -07:00
parent e2bcd3648e
commit 2e4cecc718
8 changed files with 112 additions and 72 deletions

View file

@ -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<E> {
priv list: ~[DisplayItem<E>]
}
impl DisplayList {
impl<E> DisplayList<E> {
/// Creates a new display list.
pub fn new() -> DisplayList {
pub fn new() -> DisplayList<E> {
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<E>) {
// 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<E> {
SolidColorDisplayItemClass(~SolidColorDisplayItem<E>),
TextDisplayItemClass(~TextDisplayItem<E>),
ImageDisplayItemClass(~ImageDisplayItem<E>),
BorderDisplayItemClass(~BorderDisplayItem<E>),
}
/// Information common to all display items.
pub struct BaseDisplayItem {
pub struct BaseDisplayItem<E> {
/// The boundaries of the display item.
///
/// TODO: Which coordinate system should this use?
bounds: Rect<Au>,
/// 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<E> {
base: BaseDisplayItem<E>,
color: Color,
}
/// Renders text.
pub struct TextDisplayItem {
base: BaseDisplayItem,
pub struct TextDisplayItem<E> {
base: BaseDisplayItem<E>,
text_run: ~SendableTextRun,
range: Range,
color: Color,
}
/// Renders an image.
pub struct ImageDisplayItem {
base: BaseDisplayItem,
pub struct ImageDisplayItem<E> {
base: BaseDisplayItem<E>,
image: ARC<~Image>,
}
/// Renders a border.
pub struct BorderDisplayItem {
base: BaseDisplayItem,
pub struct BorderDisplayItem<E> {
base: BaseDisplayItem<E>,
/// The width of the border.
width: Au,
/// The color of the border.
color: Color,
}
impl DisplayItem {
impl<E> DisplayItem<E> {
/// Renders this display item into the given render context.
fn draw_into_context(&self, render_context: &RenderContext) {
match *self {

View file

@ -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<Nothing>,
size: Size2D<uint>
}

View file

@ -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<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList>) {
pub fn build_display_list_block<E:ExtraDisplayListData>(@mut self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList<E>>) {
// add box that starts block context
self.box.map(|&box| {
box.build_display_list(builder, dirty, offset, list)
@ -195,3 +196,4 @@ impl BlockFlowData {
}
}
}

View file

@ -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<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList>) {
fn build_display_list<E:ExtraDisplayListData>(&self,
_: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList<E>>) {
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<DisplayList>,
absolute_bounds: &Rect<Au>) {
fn paint_background_if_applicable<E:ExtraDisplayListData>(&self,
list: &Cell<DisplayList<E>>,
absolute_bounds: &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
@ -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(),
};

View file

@ -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<Au>, c: &Cell<DisplayList>);
fn build_display_list_for_child(&self,
a: &DisplayListBuilder,
b: FlowContext,
c: &Rect<Au>,
d: &Point2D<Au>,
e: &Cell<DisplayList>);
fn build_display_list<E:ExtraDisplayListData>(&self,
a: &DisplayListBuilder,
b: &Rect<Au>,
c: &Cell<DisplayList<E>>);
fn build_display_list_for_child<E:ExtraDisplayListData>(&self,
a: &DisplayListBuilder,
b: FlowContext,
c: &Rect<Au>,
d: &Point2D<Au>,
e: &Cell<DisplayList<E>>);
}
impl FlowDisplayListBuilderMethods for FlowContext {
fn build_display_list(&self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
list: &Cell<DisplayList>) {
fn build_display_list<E:ExtraDisplayListData>(&self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
list: &Cell<DisplayList<E>>) {
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<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList>) {
fn build_display_list_for_child<E:ExtraDisplayListData>(&self,
builder: &DisplayListBuilder,
child_flow: FlowContext,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList<E>>) {
// 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);

View file

@ -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<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList>) {
pub fn build_display_list_recurse<E:ExtraDisplayListData>(&self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList<E>>) {
do self.with_base |info| {
debug!("FlowContext::build_display_list at %?: %s", info.position, self.debug_str());
}

View file

@ -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<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList>) {
pub fn build_display_list_inline<E:ExtraDisplayListData>(&self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: &Point2D<Au>,
list: &Cell<DisplayList<E>>) {
// 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",

View file

@ -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<DisplayList>, abs_bounds: &Rect<Au>) {
pub fn paint_borders_if_applicable<E:ExtraDisplayListData>(&self,
list: &Cell<DisplayList<E>>,
abs_bounds: &Rect<Au>) {
// 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,