mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
auto merge of #3990 : pcwalton/servo/stacking-contexts, r=glennw
This implements the scheme described here: https://groups.google.com/forum/#!topic/mozilla.dev.servo/sZVPSfPVfkg This commit changes Servo to generate one display list per stacking context instead of one display list per layer. This is purely a refactoring; there are no functional changes. Performance is essentially the same as before. However, there should be numerous future benefits that this is intended to allow for: * It makes the code simpler to understand because the "new layer needed" vs. "no new layer needed" code paths are more consolidated. * It makes it easy to support CSS properties that did not fit into our previous flat display list model (without unconditionally layerizing them): o `opacity` should be easy to support because the stacking context provides the higher-level grouping of display items to which opacity is to be applied. o `transform` can be easily supported because the stacking context provides a place to stash the transformation matrix. This has the side benefit of nicely separating the transformation matrix from the clipping regions. * The `flatten` logic is now O(1) instead of O(n) and now only needs to be invoked for pseudo-stacking contexts (right now: just floats), instead of for every stacking context. * Layers are now a proper tree instead of a flat list as far as layout is concerned, bringing us closer to a production-quality compositing/layers framework. * This commit opens the door to incremental display list construction at the level of stacking contexts. Future performance improvements could come from optimizing allocation of display list items, and, of course, incremental display list construction. r? @glennw f? @mrobinson @cgaebel
This commit is contained in:
commit
397d8138e7
13 changed files with 812 additions and 550 deletions
|
@ -30,9 +30,9 @@
|
|||
use construct::FlowConstructor;
|
||||
use context::LayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use display_list_builder::{BlockFlowDisplayListBuilding, FragmentDisplayListBuilding};
|
||||
use display_list_builder::{BlockFlowDisplayListBuilding, BlockLevel, FragmentDisplayListBuilding};
|
||||
use floats::{ClearBoth, ClearLeft, ClearRight, FloatKind, FloatLeft, Floats, PlacementInfo};
|
||||
use flow::{BaseFlow, BlockFlowClass, FlowClass, Flow, ImmutableFlowUtils};
|
||||
use flow::{AbsolutePositionInfo, BaseFlow, BlockFlowClass, FlowClass, Flow, ImmutableFlowUtils};
|
||||
use flow::{MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal, mut_base};
|
||||
use flow;
|
||||
use fragment::{Fragment, ImageFragment, InlineBlockFragment, FragmentBoundsIterator};
|
||||
|
@ -45,10 +45,9 @@ use table::ColumnInlineSize;
|
|||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::Size2D;
|
||||
use gfx::display_list::BlockLevel;
|
||||
use serialize::{Encoder, Encodable};
|
||||
use servo_msg::compositor_msg::LayerId;
|
||||
use servo_util::geometry::{Au, MAX_AU};
|
||||
use servo_util::geometry::{Au, MAX_AU, MAX_RECT, ZERO_POINT};
|
||||
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
|
||||
use servo_util::opts;
|
||||
use std::cmp::{max, min};
|
||||
|
@ -1665,24 +1664,26 @@ impl Flow for BlockFlow {
|
|||
// FIXME(#2795): Get the real container size
|
||||
let container_size = Size2D::zero();
|
||||
|
||||
if self.is_root() {
|
||||
self.base.clip_rect = MAX_RECT
|
||||
}
|
||||
|
||||
if self.base.flags.is_absolutely_positioned() {
|
||||
let position_start = self.base.position.start.to_physical(self.base.writing_mode,
|
||||
container_size);
|
||||
self.base.absolute_position_info.absolute_containing_block_position =
|
||||
if self.is_fixed() {
|
||||
// The viewport is initially at (0, 0).
|
||||
position_start
|
||||
} else {
|
||||
// Absolute position of the containing block + position of absolute
|
||||
// flow w.r.t. the containing block.
|
||||
self.base.absolute_position_info.absolute_containing_block_position
|
||||
+ position_start
|
||||
};
|
||||
|
||||
// Set the absolute position, which will be passed down later as part
|
||||
// of containing block details for absolute descendants.
|
||||
self.base.abs_position =
|
||||
self.base.absolute_position_info.absolute_containing_block_position;
|
||||
// Compute our position relative to the nearest ancestor stacking context. This will be
|
||||
// passed down later as part of containing block details for absolute descendants.
|
||||
self.base.stacking_relative_position = if self.is_fixed() {
|
||||
// The viewport is initially at (0, 0).
|
||||
position_start
|
||||
} else {
|
||||
// Absolute position of the containing block + position of absolute
|
||||
// flow w.r.t. the containing block.
|
||||
self.base
|
||||
.absolute_position_info
|
||||
.stacking_relative_position_of_absolute_containing_block + position_start
|
||||
}
|
||||
}
|
||||
|
||||
// For relatively-positioned descendants, the containing block formed by a block is just
|
||||
|
@ -1693,32 +1694,52 @@ impl Flow for BlockFlow {
|
|||
.absolute_position_info
|
||||
.relative_containing_block_size);
|
||||
if self.is_positioned() {
|
||||
self.base.absolute_position_info.absolute_containing_block_position =
|
||||
self.base.abs_position
|
||||
+ (self.generated_containing_block_rect().start
|
||||
+ relative_offset).to_physical(self.base.writing_mode, container_size)
|
||||
self.base
|
||||
.absolute_position_info
|
||||
.stacking_relative_position_of_absolute_containing_block =
|
||||
self.base.stacking_relative_position +
|
||||
(self.generated_containing_block_rect().start +
|
||||
relative_offset).to_physical(self.base.writing_mode, container_size)
|
||||
}
|
||||
|
||||
// Compute absolute position info for children.
|
||||
let mut absolute_position_info = self.base.absolute_position_info;
|
||||
absolute_position_info.relative_containing_block_size = self.fragment.content_box().size;
|
||||
absolute_position_info.layers_needed_for_positioned_flows =
|
||||
self.base.flags.layers_needed_for_descendants();
|
||||
let absolute_position_info_for_children = AbsolutePositionInfo {
|
||||
stacking_relative_position_of_absolute_containing_block:
|
||||
if self.fragment.establishes_stacking_context() {
|
||||
let logical_border_width = self.fragment.style().logical_border_width();
|
||||
LogicalPoint::new(self.base.writing_mode,
|
||||
logical_border_width.inline_start,
|
||||
logical_border_width.block_start).to_physical(
|
||||
self.base.writing_mode,
|
||||
container_size)
|
||||
} else {
|
||||
self.base
|
||||
.absolute_position_info
|
||||
.stacking_relative_position_of_absolute_containing_block
|
||||
},
|
||||
relative_containing_block_size: self.fragment.content_box().size,
|
||||
layers_needed_for_positioned_flows: self.base.flags.layers_needed_for_descendants(),
|
||||
};
|
||||
|
||||
// Compute the clipping rectangle for children.
|
||||
let this_position = self.base.abs_position;
|
||||
let clip_rect = self.fragment.clip_rect_for_children(self.base.clip_rect, this_position);
|
||||
// Compute the origin and clipping rectangle for children.
|
||||
let origin_for_children = if self.fragment.establishes_stacking_context() {
|
||||
ZERO_POINT
|
||||
} else {
|
||||
self.base.stacking_relative_position
|
||||
};
|
||||
let clip_rect = self.fragment.clip_rect_for_children(self.base.clip_rect,
|
||||
origin_for_children);
|
||||
|
||||
// Process children.
|
||||
let writing_mode = self.base.writing_mode;
|
||||
for kid in self.base.child_iter() {
|
||||
if !flow::base(kid).flags.is_absolutely_positioned() {
|
||||
let kid_base = flow::mut_base(kid);
|
||||
kid_base.abs_position =
|
||||
this_position +
|
||||
kid_base.stacking_relative_position =
|
||||
origin_for_children +
|
||||
(kid_base.position.start + relative_offset).to_physical(writing_mode,
|
||||
container_size);
|
||||
kid_base.absolute_position_info = absolute_position_info
|
||||
kid_base.absolute_position_info = absolute_position_info_for_children
|
||||
}
|
||||
|
||||
flow::mut_base(kid).clip_rect = clip_rect
|
||||
|
@ -1726,7 +1747,8 @@ impl Flow for BlockFlow {
|
|||
|
||||
// Process absolute descendant links.
|
||||
for absolute_descendant in self.base.abs_descendants.iter() {
|
||||
flow::mut_base(absolute_descendant).absolute_position_info = absolute_position_info
|
||||
flow::mut_base(absolute_descendant).absolute_position_info =
|
||||
absolute_position_info_for_children
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1816,9 +1838,10 @@ impl Flow for BlockFlow {
|
|||
|
||||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
if iterator.should_process(&self.fragment) {
|
||||
let fragment_origin = self.base.child_fragment_absolute_position(&self.fragment);
|
||||
let fragment_origin =
|
||||
self.base.stacking_relative_position_of_child_fragment(&self.fragment);
|
||||
iterator.process(&self.fragment,
|
||||
self.fragment.abs_bounds_from_origin(&fragment_origin));
|
||||
self.fragment.stacking_relative_bounds(&fragment_origin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,27 +21,22 @@ 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, GradientDisplayItem, GradientDisplayItemClass};
|
||||
use gfx::display_list::{GradientStop, ImageDisplayItem, ImageDisplayItemClass, LineDisplayItem};
|
||||
use gfx::display_list::{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::display_list::{BaseDisplayItem, BorderDisplayItem, BorderDisplayItemClass, DisplayItem};
|
||||
use gfx::display_list::{DisplayList, GradientDisplayItem, GradientDisplayItemClass, GradientStop};
|
||||
use gfx::display_list::{ImageDisplayItem, ImageDisplayItemClass, LineDisplayItem};
|
||||
use gfx::display_list::{LineDisplayItemClass, PseudoDisplayItemClass, SidewaysLeft, SidewaysRight};
|
||||
use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, StackingContext};
|
||||
use gfx::display_list::{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::dlist;
|
||||
use servo_util::geometry::{mod, Au, ZERO_RECT};
|
||||
use servo_util::geometry::{mod, Au, ZERO_POINT, ZERO_RECT};
|
||||
use servo_util::logical_geometry::{LogicalRect, WritingMode};
|
||||
use servo_util::opts;
|
||||
use std::mem;
|
||||
use style::computed::{AngleAoc, CornerAoc, LP_Length, LP_Percentage, LengthOrPercentage};
|
||||
use style::computed::{LinearGradient, LinearGradientImage, UrlImage};
|
||||
use style::computed_values::{background_attachment, background_repeat, border_style, overflow};
|
||||
|
@ -50,12 +45,36 @@ use style::{ComputedValues, Bottom, Left, RGBA, Right, Top};
|
|||
use sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
/// The results of display list building for a single flow.
|
||||
pub enum DisplayListBuildingResult {
|
||||
NoDisplayListBuildingResult,
|
||||
StackingContextResult(Arc<StackingContext>),
|
||||
DisplayListResult(Box<DisplayList>),
|
||||
}
|
||||
|
||||
impl DisplayListBuildingResult {
|
||||
/// Adds the display list items contained within this display list building result to the given
|
||||
/// display list, preserving stacking order. If this display list building result does not
|
||||
/// consist of an entire stacking context, it will be emptied.
|
||||
pub fn add_to(&mut self, display_list: &mut DisplayList) {
|
||||
match *self {
|
||||
NoDisplayListBuildingResult => return,
|
||||
StackingContextResult(ref mut stacking_context) => {
|
||||
display_list.children.push_back((*stacking_context).clone())
|
||||
}
|
||||
DisplayListResult(ref mut source_display_list) => {
|
||||
display_list.append_from(&mut **source_display_list)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
level: StackingLevel,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
|
@ -65,7 +84,7 @@ pub trait FragmentDisplayListBuilding {
|
|||
/// display list at the appropriate stacking level.
|
||||
fn build_display_list_for_background_image(&self,
|
||||
style: &ComputedValues,
|
||||
list: &mut DisplayList,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
level: StackingLevel,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
|
@ -75,7 +94,7 @@ pub trait FragmentDisplayListBuilding {
|
|||
/// Adds the display items necessary to paint the background linear gradient of this fragment
|
||||
/// to the display list at the appropriate stacking level.
|
||||
fn build_display_list_for_background_linear_gradient(&self,
|
||||
list: &mut DisplayList,
|
||||
display_list: &mut DisplayList,
|
||||
level: StackingLevel,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
clip_rect: &Rect<Au>,
|
||||
|
@ -86,7 +105,7 @@ pub trait FragmentDisplayListBuilding {
|
|||
/// necessary.
|
||||
fn build_display_list_for_borders_if_applicable(&self,
|
||||
style: &ComputedValues,
|
||||
list: &mut DisplayList,
|
||||
display_list: &mut DisplayList,
|
||||
abs_bounds: &Rect<Au>,
|
||||
level: StackingLevel,
|
||||
clip_rect: &Rect<Au>);
|
||||
|
@ -102,11 +121,11 @@ pub trait FragmentDisplayListBuilding {
|
|||
flow_origin: Point2D<Au>,
|
||||
clip_rect: &Rect<Au>);
|
||||
|
||||
/// Adds the display items for this fragment to the given stacking context.
|
||||
/// Adds the display items for this fragment to the given display list.
|
||||
///
|
||||
/// Arguments:
|
||||
///
|
||||
/// * `display_list`: The unflattened display list to add display items to.
|
||||
/// * `display_list`: The display list to add display items to.
|
||||
/// * `layout_context`: The layout context.
|
||||
/// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
|
||||
/// * `flow_origin`: Position of the origin of the owning flow wrt the display list root flow.
|
||||
|
@ -132,7 +151,7 @@ pub trait FragmentDisplayListBuilding {
|
|||
impl FragmentDisplayListBuilding for Fragment {
|
||||
fn build_display_list_for_background_if_applicable(&self,
|
||||
style: &ComputedValues,
|
||||
list: &mut DisplayList,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
level: StackingLevel,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
|
@ -143,10 +162,10 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
// doesn't have a fragment".
|
||||
let background_color = style.resolve_color(style.get_background().background_color);
|
||||
if !background_color.alpha.approx_eq(&0.0) {
|
||||
list.push(SolidColorDisplayItemClass(box SolidColorDisplayItem {
|
||||
base: BaseDisplayItem::new(*absolute_bounds, self.node, level, *clip_rect),
|
||||
display_list.push(SolidColorDisplayItemClass(box SolidColorDisplayItem {
|
||||
base: BaseDisplayItem::new(*absolute_bounds, self.node, *clip_rect),
|
||||
color: background_color.to_gfx_color(),
|
||||
}));
|
||||
}), level);
|
||||
}
|
||||
|
||||
// The background image is painted on top of the background color.
|
||||
|
@ -156,7 +175,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
match background.background_image {
|
||||
None => {}
|
||||
Some(LinearGradientImage(ref gradient)) => {
|
||||
self.build_display_list_for_background_linear_gradient(list,
|
||||
self.build_display_list_for_background_linear_gradient(display_list,
|
||||
level,
|
||||
absolute_bounds,
|
||||
clip_rect,
|
||||
|
@ -165,7 +184,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
Some(UrlImage(ref image_url)) => {
|
||||
self.build_display_list_for_background_image(style,
|
||||
list,
|
||||
display_list,
|
||||
layout_context,
|
||||
level,
|
||||
absolute_bounds,
|
||||
|
@ -177,7 +196,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
|
||||
fn build_display_list_for_background_image(&self,
|
||||
style: &ComputedValues,
|
||||
list: &mut DisplayList,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
level: StackingLevel,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
|
@ -255,16 +274,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
};
|
||||
|
||||
// Create the image display item.
|
||||
list.push(ImageDisplayItemClass(box ImageDisplayItem {
|
||||
base: BaseDisplayItem::new(bounds, self.node, level, clip_rect),
|
||||
display_list.push(ImageDisplayItemClass(box ImageDisplayItem {
|
||||
base: BaseDisplayItem::new(bounds, self.node, clip_rect),
|
||||
image: image.clone(),
|
||||
stretch_size: Size2D(Au::from_px(image.width as int),
|
||||
Au::from_px(image.height as int)),
|
||||
}));
|
||||
}), level);
|
||||
}
|
||||
|
||||
fn build_display_list_for_background_linear_gradient(&self,
|
||||
list: &mut DisplayList,
|
||||
display_list: &mut DisplayList,
|
||||
level: StackingLevel,
|
||||
absolute_bounds: &Rect<Au>,
|
||||
clip_rect: &Rect<Au>,
|
||||
|
@ -364,18 +383,18 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
absolute_bounds.origin.y + absolute_bounds.size.height / 2);
|
||||
|
||||
let gradient_display_item = GradientDisplayItemClass(box GradientDisplayItem {
|
||||
base: BaseDisplayItem::new(*absolute_bounds, self.node, level, clip_rect),
|
||||
base: BaseDisplayItem::new(*absolute_bounds, self.node, clip_rect),
|
||||
start_point: center - delta,
|
||||
end_point: center + delta,
|
||||
stops: stops,
|
||||
});
|
||||
|
||||
list.push(gradient_display_item)
|
||||
display_list.push(gradient_display_item, level)
|
||||
}
|
||||
|
||||
fn build_display_list_for_borders_if_applicable(&self,
|
||||
style: &ComputedValues,
|
||||
list: &mut DisplayList,
|
||||
display_list: &mut DisplayList,
|
||||
abs_bounds: &Rect<Au>,
|
||||
level: StackingLevel,
|
||||
clip_rect: &Rect<Au>) {
|
||||
|
@ -390,8 +409,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
let left_color = style.resolve_color(style.get_border().border_left_color);
|
||||
|
||||
// Append the border to the display list.
|
||||
list.push(BorderDisplayItemClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(*abs_bounds, self.node, level, *clip_rect),
|
||||
display_list.push(BorderDisplayItemClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(*abs_bounds, self.node, *clip_rect),
|
||||
border: border.to_physical(style.writing_mode),
|
||||
color: SideOffsets2D::new(top_color.to_gfx_color(),
|
||||
right_color.to_gfx_color(),
|
||||
|
@ -401,7 +420,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
style.get_border().border_right_style,
|
||||
style.get_border().border_bottom_style,
|
||||
style.get_border().border_left_style)
|
||||
}));
|
||||
}), level);
|
||||
}
|
||||
|
||||
fn build_debug_borders_around_text_fragments(&self,
|
||||
|
@ -418,11 +437,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
fragment_bounds.size);
|
||||
|
||||
// Compute the text fragment bounds and draw a border surrounding them.
|
||||
display_list.push(BorderDisplayItemClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_fragment_bounds,
|
||||
self.node,
|
||||
ContentStackingLevel,
|
||||
*clip_rect),
|
||||
display_list.content.push_back(BorderDisplayItemClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_fragment_bounds, self.node, *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)
|
||||
|
@ -437,11 +453,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
baseline.origin = baseline.origin + flow_origin;
|
||||
|
||||
let line_display_item = box LineDisplayItem {
|
||||
base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel, *clip_rect),
|
||||
base: BaseDisplayItem::new(baseline, self.node, *clip_rect),
|
||||
color: color::rgb(0, 200, 0),
|
||||
style: border_style::dashed,
|
||||
};
|
||||
display_list.push(LineDisplayItemClass(line_display_item));
|
||||
display_list.content.push_back(LineDisplayItemClass(line_display_item));
|
||||
}
|
||||
|
||||
fn build_debug_borders_around_fragment(&self,
|
||||
|
@ -457,11 +473,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
fragment_bounds.size);
|
||||
|
||||
// This prints a debug border around the border of this fragment.
|
||||
display_list.push(BorderDisplayItemClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_fragment_bounds,
|
||||
self.node,
|
||||
ContentStackingLevel,
|
||||
*clip_rect),
|
||||
display_list.content.push_back(BorderDisplayItemClass(box BorderDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_fragment_bounds, self.node, *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)
|
||||
|
@ -474,14 +487,24 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
flow_origin: Point2D<Au>,
|
||||
background_and_border_level: BackgroundAndBorderLevel,
|
||||
clip_rect: &Rect<Au>) {
|
||||
// Compute the fragment position relative to the parent stacking context. If the fragment
|
||||
// itself establishes a stacking context, then the origin of its position will be (0, 0)
|
||||
// for the purposes of this computation.
|
||||
let stacking_relative_flow_origin = if self.establishes_stacking_context() {
|
||||
ZERO_POINT
|
||||
} else {
|
||||
flow_origin
|
||||
};
|
||||
let absolute_fragment_bounds =
|
||||
self.stacking_relative_bounds(&stacking_relative_flow_origin);
|
||||
|
||||
// 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)
|
||||
Rect(physical_rect.origin + stacking_relative_flow_origin, physical_rect.size)
|
||||
};
|
||||
// Fragment position wrt to the owning flow.
|
||||
let absolute_fragment_bounds = self.abs_bounds_from_origin(&flow_origin);
|
||||
|
||||
debug!("Fragment::build_display_list at rel={}, abs={}: {}",
|
||||
self.border_box,
|
||||
absolute_fragment_bounds,
|
||||
|
@ -512,9 +535,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
// 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));
|
||||
display_list.push(PseudoDisplayItemClass(base_display_item), level);
|
||||
|
||||
// Add the background to the list, if applicable.
|
||||
match self.inline_context {
|
||||
|
@ -593,17 +615,15 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
};
|
||||
|
||||
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 baseline_origin = {
|
||||
let mut content_box_start = content_box.start;
|
||||
content_box_start.b = content_box_start.b + metrics.ascent;
|
||||
content_box_start.to_physical(self.style.writing_mode, container_size)
|
||||
+ flow_origin
|
||||
};
|
||||
|
||||
display_list.push(TextDisplayItemClass(box TextDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_content_box,
|
||||
self.node,
|
||||
ContentStackingLevel,
|
||||
*clip_rect),
|
||||
display_list.content.push_back(TextDisplayItemClass(box TextDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_content_box, self.node, *clip_rect),
|
||||
text_run: text_fragment.run.clone(),
|
||||
range: text_fragment.range,
|
||||
text_color: self.style().get_color().color.to_gfx_color(),
|
||||
|
@ -615,19 +635,14 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
{
|
||||
let line = |maybe_color: Option<RGBA>, rect: || -> LogicalRect<Au>| {
|
||||
match maybe_color {
|
||||
None => {},
|
||||
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 bounds = rect_to_absolute(self.style.writing_mode, rect());
|
||||
display_list.content.push_back(SolidColorDisplayItemClass(
|
||||
box SolidColorDisplayItem {
|
||||
base: BaseDisplayItem::new(bounds, self.node, *clip_rect),
|
||||
color: color.to_gfx_color(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -678,10 +693,9 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
debug!("(building display list) building image fragment");
|
||||
|
||||
// Place the image into the display list.
|
||||
display_list.push(ImageDisplayItemClass(box ImageDisplayItem {
|
||||
display_list.content.push_back(ImageDisplayItemClass(box ImageDisplayItem {
|
||||
base: BaseDisplayItem::new(absolute_content_box,
|
||||
self.node,
|
||||
ContentStackingLevel,
|
||||
*clip_rect),
|
||||
image: image.clone(),
|
||||
stretch_size: absolute_content_box.size,
|
||||
|
@ -698,7 +712,9 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
|
||||
if opts::get().show_debug_fragment_borders {
|
||||
self.build_debug_borders_around_fragment(display_list, flow_origin, clip_rect)
|
||||
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.
|
||||
|
@ -766,6 +782,10 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
}
|
||||
|
||||
pub trait BlockFlowDisplayListBuilding {
|
||||
fn build_display_list_for_block_base(&mut self,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
background_border_level: BackgroundAndBorderLevel);
|
||||
fn build_display_list_for_block(&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
background_border_level: BackgroundAndBorderLevel);
|
||||
|
@ -775,78 +795,93 @@ pub trait BlockFlowDisplayListBuilding {
|
|||
}
|
||||
|
||||
impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||
fn build_display_list_for_block(&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
background_border_level: BackgroundAndBorderLevel) {
|
||||
|
||||
fn build_display_list_for_block_base(&mut self,
|
||||
display_list: &mut DisplayList,
|
||||
layout_context: &LayoutContext,
|
||||
background_border_level: BackgroundAndBorderLevel) {
|
||||
// Add the box that starts the block context.
|
||||
let absolute_fragment_origin = self.base.child_fragment_absolute_position(&self.fragment);
|
||||
self.fragment.build_display_list(&mut self.base.display_list,
|
||||
let stacking_relative_fragment_origin =
|
||||
self.base.stacking_relative_position_of_child_fragment(&self.fragment);
|
||||
self.fragment.build_display_list(display_list,
|
||||
layout_context,
|
||||
absolute_fragment_origin,
|
||||
stacking_relative_fragment_origin,
|
||||
background_border_level,
|
||||
&self.base.clip_rect);
|
||||
|
||||
self.base.layers = DList::new();
|
||||
for kid in self.base.children.iter_mut() {
|
||||
if flow::base(kid).flags.is_absolutely_positioned() {
|
||||
// All absolute flows will be handled by their containing block.
|
||||
continue
|
||||
}
|
||||
|
||||
self.base.display_list.append_from(&mut flow::mut_base(kid).display_list);
|
||||
dlist::append_from(&mut self.base.layers, &mut flow::mut_base(kid).layers)
|
||||
flow::mut_base(kid).display_list_building_result.add_to(display_list);
|
||||
}
|
||||
|
||||
// Process absolute descendant links.
|
||||
for abs_descendant_link in self.base.abs_descendants.iter() {
|
||||
// TODO(pradeep): Send in our absolute position directly.
|
||||
self.base
|
||||
.display_list
|
||||
.append_from(&mut flow::mut_base(abs_descendant_link).display_list);
|
||||
dlist::append_from(&mut self.base.layers,
|
||||
&mut flow::mut_base(abs_descendant_link).layers)
|
||||
flow::mut_base(abs_descendant_link).display_list_building_result.add_to(display_list);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_for_block(&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
background_border_level: BackgroundAndBorderLevel) {
|
||||
let mut display_list = box DisplayList::new();
|
||||
self.build_display_list_for_block_base(&mut *display_list,
|
||||
layout_context,
|
||||
background_border_level);
|
||||
self.base.display_list_building_result = DisplayListResult(display_list);
|
||||
}
|
||||
|
||||
fn build_display_list_for_absolutely_positioned_block(&mut self,
|
||||
layout_context: &LayoutContext) {
|
||||
self.build_display_list_for_block(layout_context, RootOfStackingContextLevel);
|
||||
let mut display_list = box DisplayList::new();
|
||||
self.build_display_list_for_block_base(&mut *display_list,
|
||||
layout_context,
|
||||
RootOfStackingContextLevel);
|
||||
|
||||
let bounds = Rect(self.base.stacking_relative_position,
|
||||
self.base.overflow.size.to_physical(self.base.writing_mode));
|
||||
let z_index = self.fragment.style().get_box().z_index.number_or_zero();
|
||||
|
||||
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();
|
||||
self.base.display_list.flatten(PositionedDescendantStackingLevel(z_index));
|
||||
self.base.display_list_building_result =
|
||||
StackingContextResult(Arc::new(StackingContext::new(display_list,
|
||||
bounds,
|
||||
z_index,
|
||||
None)));
|
||||
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
|
||||
};
|
||||
self.base.display_list.flatten(ContentStackingLevel);
|
||||
let new_layer = RenderLayer {
|
||||
id: self.layer_id(0),
|
||||
display_list: Arc::new(mem::replace(&mut self.base.display_list, DisplayList::new())),
|
||||
position: Rect(origin, size),
|
||||
background_color: color::rgba(1.0, 1.0, 1.0, 0.0),
|
||||
scroll_policy: scroll_policy,
|
||||
};
|
||||
self.base.layers.push_back(new_layer)
|
||||
|
||||
let transparent = color::rgba(1.0, 1.0, 1.0, 0.0);
|
||||
let stacking_context =
|
||||
Arc::new(StackingContext::new(display_list,
|
||||
bounds,
|
||||
z_index,
|
||||
Some(Arc::new(RenderLayer::new(self.layer_id(0),
|
||||
transparent,
|
||||
scroll_policy)))));
|
||||
|
||||
self.base.display_list_building_result = StackingContextResult(stacking_context)
|
||||
}
|
||||
|
||||
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.flatten(FloatStackingLevel)
|
||||
let mut display_list = box DisplayList::new();
|
||||
self.build_display_list_for_block_base(&mut *display_list,
|
||||
layout_context,
|
||||
RootOfStackingContextLevel);
|
||||
display_list.form_float_pseudo_stacking_context();
|
||||
self.base.display_list_building_result = DisplayListResult(display_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -873,3 +908,51 @@ fn position_to_offset(position: LengthOrPercentage, Au(total_length): Au) -> f32
|
|||
}
|
||||
}
|
||||
|
||||
/// "Steps" as defined by CSS 2.1 § E.2.
|
||||
#[deriving(Clone, PartialEq, Show)]
|
||||
pub enum StackingLevel {
|
||||
/// The border and backgrounds for the root of this stacking context: steps 1 and 2.
|
||||
BackgroundAndBordersStackingLevel,
|
||||
/// Borders and backgrounds for block-level descendants: step 4.
|
||||
BlockBackgroundsAndBordersStackingLevel,
|
||||
/// All other content.
|
||||
ContentStackingLevel,
|
||||
}
|
||||
|
||||
impl StackingLevel {
|
||||
#[inline]
|
||||
pub fn from_background_and_border_level(level: BackgroundAndBorderLevel) -> StackingLevel {
|
||||
match level {
|
||||
RootOfStackingContextLevel => BackgroundAndBordersStackingLevel,
|
||||
BlockLevel => BlockBackgroundsAndBordersStackingLevel,
|
||||
ContentLevel => ContentStackingLevel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Which level to place backgrounds and borders in.
|
||||
pub enum BackgroundAndBorderLevel {
|
||||
RootOfStackingContextLevel,
|
||||
BlockLevel,
|
||||
ContentLevel,
|
||||
}
|
||||
|
||||
trait StackingContextConstruction {
|
||||
/// Adds the given display item at the specified level to this display list.
|
||||
fn push(&mut self, display_item: DisplayItem, level: StackingLevel);
|
||||
}
|
||||
|
||||
impl StackingContextConstruction for DisplayList {
|
||||
fn push(&mut self, display_item: DisplayItem, level: StackingLevel) {
|
||||
match level {
|
||||
BackgroundAndBordersStackingLevel => {
|
||||
self.background_and_borders.push_back(display_item)
|
||||
}
|
||||
BlockBackgroundsAndBordersStackingLevel => {
|
||||
self.block_backgrounds_and_borders.push_back(display_item)
|
||||
}
|
||||
ContentStackingLevel => self.content.push_back(display_item),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
use css::node_style::StyledNode;
|
||||
use block::BlockFlow;
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::{DisplayListBuildingResult, DisplayListResult};
|
||||
use display_list_builder::{NoDisplayListBuildingResult, StackingContextResult};
|
||||
use floats::Floats;
|
||||
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
|
||||
use flow_ref::FlowRef;
|
||||
|
@ -45,10 +47,7 @@ use table_rowgroup::TableRowGroupFlow;
|
|||
use table_wrapper::TableWrapperFlow;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use collections::dlist::DList;
|
||||
use geom::{Point2D, Rect, Size2D};
|
||||
use gfx::display_list::DisplayList;
|
||||
use gfx::render_task::RenderLayer;
|
||||
use serialize::{Encoder, Encodable};
|
||||
use servo_msg::compositor_msg::LayerId;
|
||||
use servo_util::geometry::Au;
|
||||
|
@ -681,8 +680,10 @@ pub struct AbsolutePositionInfo {
|
|||
/// The size of the containing block for relatively-positioned descendants.
|
||||
pub relative_containing_block_size: LogicalSize<Au>,
|
||||
|
||||
/// The position of the absolute containing block.
|
||||
pub absolute_containing_block_position: Point2D<Au>,
|
||||
/// The position of the absolute containing block relative to the nearest ancestor stacking
|
||||
/// context. If the absolute containing block establishes the stacking context for this flow,
|
||||
/// and this flow is not itself absolutely-positioned, then this is (0, 0).
|
||||
pub stacking_relative_position_of_absolute_containing_block: Point2D<Au>,
|
||||
|
||||
/// Whether the absolute containing block forces positioned descendants to be layerized.
|
||||
///
|
||||
|
@ -696,7 +697,7 @@ impl AbsolutePositionInfo {
|
|||
// of the root layer.
|
||||
AbsolutePositionInfo {
|
||||
relative_containing_block_size: LogicalSize::zero(writing_mode),
|
||||
absolute_containing_block_position: Zero::zero(),
|
||||
stacking_relative_position_of_absolute_containing_block: Zero::zero(),
|
||||
layers_needed_for_positioned_flows: false,
|
||||
}
|
||||
}
|
||||
|
@ -742,8 +743,9 @@ pub struct BaseFlow {
|
|||
/// The collapsible margins for this flow, if any.
|
||||
pub collapsible_margins: CollapsibleMargins,
|
||||
|
||||
/// The position of this flow in page coordinates, computed during display list construction.
|
||||
pub abs_position: Point2D<Au>,
|
||||
/// The position of this flow relative to the start of the nearest ancestor stacking context.
|
||||
/// This is computed during the top-down pass of display list construction.
|
||||
pub stacking_relative_position: Point2D<Au>,
|
||||
|
||||
/// Details about descendants with position 'absolute' or 'fixed' for which we are the
|
||||
/// containing block. This is in tree order. This includes any direct children.
|
||||
|
@ -779,11 +781,8 @@ pub struct BaseFlow {
|
|||
/// rectangles.
|
||||
pub clip_rect: Rect<Au>,
|
||||
|
||||
/// The unflattened display items for this flow.
|
||||
pub display_list: DisplayList,
|
||||
|
||||
/// Any layers that we're bubbling up, in a linked list.
|
||||
pub layers: DList<RenderLayer>,
|
||||
/// The results of display list building for this flow.
|
||||
pub display_list_building_result: DisplayListBuildingResult,
|
||||
|
||||
/// The writing mode for this flow.
|
||||
pub writing_mode: WritingMode,
|
||||
|
@ -806,8 +805,12 @@ impl<E, S: Encoder<E>> Encodable<S, E> for BaseFlow {
|
|||
fn encode(&self, e: &mut S) -> Result<(), E> {
|
||||
e.emit_struct("base", 0, |e| {
|
||||
try!(e.emit_struct_field("id", 0, |e| self.debug_id().encode(e)))
|
||||
try!(e.emit_struct_field("abs_position", 1, |e| self.abs_position.encode(e)))
|
||||
try!(e.emit_struct_field("intrinsic_inline_sizes", 2, |e| self.intrinsic_inline_sizes.encode(e)))
|
||||
try!(e.emit_struct_field("stacking_relative_position",
|
||||
1,
|
||||
|e| self.stacking_relative_position.encode(e)))
|
||||
try!(e.emit_struct_field("intrinsic_inline_sizes",
|
||||
2,
|
||||
|e| self.intrinsic_inline_sizes.encode(e)))
|
||||
try!(e.emit_struct_field("position", 3, |e| self.position.encode(e)))
|
||||
e.emit_struct_field("children", 4, |e| {
|
||||
e.emit_seq(self.children.len(), |e| {
|
||||
|
@ -893,15 +896,14 @@ impl BaseFlow {
|
|||
parallel: FlowParallelInfo::new(),
|
||||
floats: Floats::new(writing_mode),
|
||||
collapsible_margins: CollapsibleMargins::new(),
|
||||
abs_position: Zero::zero(),
|
||||
stacking_relative_position: Zero::zero(),
|
||||
abs_descendants: Descendants::new(),
|
||||
absolute_static_i_offset: Au(0),
|
||||
fixed_static_i_offset: Au(0),
|
||||
block_container_inline_size: Au(0),
|
||||
block_container_explicit_block_size: None,
|
||||
absolute_cb: ContainingBlockLink::new(),
|
||||
display_list: DisplayList::new(),
|
||||
layers: DList::new(),
|
||||
display_list_building_result: NoDisplayListBuildingResult,
|
||||
absolute_position_info: AbsolutePositionInfo::new(writing_mode),
|
||||
clip_rect: Rect(Zero::zero(), Size2D(Au(0), Au(0))),
|
||||
flags: flags,
|
||||
|
@ -922,13 +924,23 @@ impl BaseFlow {
|
|||
p as uint
|
||||
}
|
||||
|
||||
/// Ensures that all display list items generated by this flow are within the flow's overflow
|
||||
/// rect. This should only be used for debugging.
|
||||
pub fn validate_display_list_geometry(&self) {
|
||||
let position_with_overflow = self.position.union(&self.overflow);
|
||||
let bounds = Rect(self.abs_position,
|
||||
let bounds = Rect(self.stacking_relative_position,
|
||||
Size2D(position_with_overflow.size.inline,
|
||||
position_with_overflow.size.block));
|
||||
|
||||
for item in self.display_list.iter() {
|
||||
let all_items = match self.display_list_building_result {
|
||||
NoDisplayListBuildingResult => Vec::new(),
|
||||
StackingContextResult(ref stacking_context) => {
|
||||
stacking_context.display_list.all_display_items()
|
||||
}
|
||||
DisplayListResult(ref display_list) => display_list.all_display_items(),
|
||||
};
|
||||
|
||||
for item in all_items.iter() {
|
||||
let paint_bounds = match item.base().bounds.intersection(&item.base().clip_rect) {
|
||||
None => continue,
|
||||
Some(rect) => rect,
|
||||
|
@ -944,12 +956,15 @@ impl BaseFlow {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn child_fragment_absolute_position(&self, fragment: &Fragment) -> Point2D<Au> {
|
||||
/// Returns the position of the given fragment relative to the start of the nearest ancestor
|
||||
/// stacking context. The fragment must be a child fragment of this flow.
|
||||
pub fn stacking_relative_position_of_child_fragment(&self, fragment: &Fragment)
|
||||
-> Point2D<Au> {
|
||||
let relative_offset =
|
||||
fragment.relative_position(&self
|
||||
.absolute_position_info
|
||||
.relative_containing_block_size);
|
||||
self.abs_position.add_size(&relative_offset.to_physical(self.writing_mode))
|
||||
self.stacking_relative_position.add_size(&relative_offset.to_physical(self.writing_mode))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1481,11 +1481,31 @@ impl Fragment {
|
|||
self.style = (*new_style).clone()
|
||||
}
|
||||
|
||||
pub fn abs_bounds_from_origin(&self, fragment_origin: &Point2D<Au>) -> Rect<Au> {
|
||||
/// Given the stacking-context-relative position of the containing flow, returns the boundaries
|
||||
/// of this fragment relative to the parent stacking context.
|
||||
pub fn stacking_relative_bounds(&self, stacking_relative_flow_origin: &Point2D<Au>)
|
||||
-> Rect<Au> {
|
||||
// FIXME(#2795): Get the real container size
|
||||
let container_size = Size2D::zero();
|
||||
self.border_box.to_physical(self.style.writing_mode, container_size)
|
||||
.translate(fragment_origin)
|
||||
self.border_box
|
||||
.to_physical(self.style.writing_mode, container_size)
|
||||
.translate(stacking_relative_flow_origin)
|
||||
}
|
||||
|
||||
/// Returns true if this fragment establishes a new stacking context and false otherwise.
|
||||
pub fn establishes_stacking_context(&self) -> bool {
|
||||
match self.style().get_box().position {
|
||||
position::absolute | position::fixed => {
|
||||
// FIXME(pcwalton): This should only establish a new stacking context when
|
||||
// `z-index` is not `auto`. But this matches what we did before.
|
||||
true
|
||||
}
|
||||
position::relative | position::static_ => {
|
||||
// FIXME(pcwalton): `position: relative` establishes a new stacking context if
|
||||
// `z-index` is not `auto`. But this matches what we did before.
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use css::node_style::StyledNode;
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::FragmentDisplayListBuilding;
|
||||
use display_list_builder::{ContentLevel, DisplayListResult, FragmentDisplayListBuilding};
|
||||
use floats::{FloatLeft, Floats, PlacementInfo};
|
||||
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils};
|
||||
use flow;
|
||||
|
@ -20,7 +20,7 @@ use text;
|
|||
|
||||
use collections::{RingBuf};
|
||||
use geom::{Rect, Size2D};
|
||||
use gfx::display_list::ContentLevel;
|
||||
use gfx::display_list::DisplayList;
|
||||
use gfx::font::FontMetrics;
|
||||
use gfx::font_context::FontContext;
|
||||
use gfx::text::glyph::CharIndex;
|
||||
|
@ -1136,34 +1136,34 @@ impl Flow for InlineFlow {
|
|||
|
||||
fn compute_absolute_position(&mut self) {
|
||||
for fragment in self.fragments.fragments.iter_mut() {
|
||||
let absolute_position = match fragment.specific {
|
||||
let stacking_relative_position = match fragment.specific {
|
||||
InlineBlockFragment(ref mut info) => {
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
// FIXME(#2795): Get the real container size
|
||||
let container_size = Size2D::zero();
|
||||
|
||||
block_flow.base.abs_position =
|
||||
self.base.abs_position +
|
||||
block_flow.base.stacking_relative_position =
|
||||
self.base.stacking_relative_position +
|
||||
fragment.border_box.start.to_physical(self.base.writing_mode,
|
||||
container_size);
|
||||
block_flow.base.abs_position
|
||||
block_flow.base.stacking_relative_position
|
||||
}
|
||||
InlineAbsoluteHypotheticalFragment(ref mut info) => {
|
||||
let block_flow = info.flow_ref.as_block();
|
||||
// FIXME(#2795): Get the real container size
|
||||
let container_size = Size2D::zero();
|
||||
block_flow.base.abs_position =
|
||||
self.base.abs_position +
|
||||
block_flow.base.stacking_relative_position =
|
||||
self.base.stacking_relative_position +
|
||||
fragment.border_box.start.to_physical(self.base.writing_mode,
|
||||
container_size);
|
||||
block_flow.base.abs_position
|
||||
block_flow.base.stacking_relative_position
|
||||
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let clip_rect = fragment.clip_rect_for_children(self.base.clip_rect,
|
||||
absolute_position);
|
||||
stacking_relative_position);
|
||||
|
||||
match fragment.specific {
|
||||
InlineBlockFragment(ref mut info) => {
|
||||
|
@ -1183,11 +1183,11 @@ impl Flow for InlineFlow {
|
|||
|
||||
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);
|
||||
if !Rect(self.base.stacking_relative_position, size).intersects(&layout_context.shared
|
||||
.dirty) {
|
||||
debug!("inline block (stacking relative pos {}, size {}) didn't intersect dirty rect",
|
||||
self.base.stacking_relative_position,
|
||||
size);
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1195,9 +1195,10 @@ impl Flow for InlineFlow {
|
|||
// not recurse on a line if nothing in it can intersect the dirty region.
|
||||
debug!("Flow: building display list for {:u} inline fragments", self.fragments.len());
|
||||
|
||||
let mut display_list = box DisplayList::new();
|
||||
for fragment in self.fragments.fragments.iter_mut() {
|
||||
let fragment_origin = self.base.child_fragment_absolute_position(fragment);
|
||||
fragment.build_display_list(&mut self.base.display_list,
|
||||
let fragment_origin = self.base.stacking_relative_position_of_child_fragment(fragment);
|
||||
fragment.build_display_list(&mut *display_list,
|
||||
layout_context,
|
||||
fragment_origin,
|
||||
ContentLevel,
|
||||
|
@ -1205,14 +1206,15 @@ impl Flow for InlineFlow {
|
|||
match fragment.specific {
|
||||
InlineBlockFragment(ref mut block_flow) => {
|
||||
let block_flow = block_flow.flow_ref.deref_mut();
|
||||
self.base
|
||||
.display_list
|
||||
.append_from(&mut flow::mut_base(block_flow).display_list)
|
||||
flow::mut_base(block_flow).display_list_building_result
|
||||
.add_to(&mut *display_list)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.base.display_list_building_result = DisplayListResult(display_list);
|
||||
|
||||
if opts::get().validate_display_list_geometry {
|
||||
self.base.validate_display_list_geometry();
|
||||
}
|
||||
|
@ -1223,8 +1225,9 @@ impl Flow for InlineFlow {
|
|||
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) {
|
||||
for fragment in self.fragments.fragments.iter() {
|
||||
if iterator.should_process(fragment) {
|
||||
let fragment_origin = self.base.child_fragment_absolute_position(fragment);
|
||||
iterator.process(fragment, fragment.abs_bounds_from_origin(&fragment_origin));
|
||||
let fragment_origin =
|
||||
self.base.stacking_relative_position_of_child_fragment(fragment);
|
||||
iterator.process(fragment, fragment.stacking_relative_bounds(&fragment_origin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,13 @@ use sequential;
|
|||
use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor};
|
||||
use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
|
||||
|
||||
use collections::dlist::DList;
|
||||
use encoding::EncodingRef;
|
||||
use encoding::all::UTF_8;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use gfx::display_list::{ContentStackingLevel, DisplayItem, DisplayList};
|
||||
use gfx::display_list::{OpaqueNode};
|
||||
use gfx::display_list::{DisplayList, OpaqueNode, StackingContext};
|
||||
use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer};
|
||||
use gfx::{render_task, color};
|
||||
use layout_traits;
|
||||
|
@ -51,7 +49,6 @@ use gfx::font_cache_task::{FontCacheTask};
|
|||
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
||||
use servo_net::resource_task::{ResourceTask, load_bytes_iter};
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry;
|
||||
use servo_util::logical_geometry::LogicalPoint;
|
||||
use servo_util::opts;
|
||||
use servo_util::smallvec::{SmallVec, SmallVec1, VecLike};
|
||||
|
@ -79,8 +76,8 @@ pub struct LayoutTaskData {
|
|||
/// The size of the viewport.
|
||||
pub screen_size: Size2D<Au>,
|
||||
|
||||
/// A cached display list.
|
||||
pub display_list: Option<Arc<DisplayList>>,
|
||||
/// The root stacking context.
|
||||
pub stacking_context: Option<Arc<StackingContext>>,
|
||||
|
||||
pub stylist: Box<Stylist>,
|
||||
|
||||
|
@ -277,7 +274,7 @@ impl LayoutTask {
|
|||
LayoutTaskData {
|
||||
local_image_cache: local_image_cache,
|
||||
screen_size: screen_size,
|
||||
display_list: None,
|
||||
stacking_context: None,
|
||||
stylist: box Stylist::new(device),
|
||||
parallel_traversal: parallel_traversal,
|
||||
dirty: Rect::zero(),
|
||||
|
@ -621,7 +618,7 @@ impl LayoutTask {
|
|||
shared_layout_ctx.dirty =
|
||||
flow::base(layout_root.deref()).position.to_physical(writing_mode,
|
||||
rw_data.screen_size);
|
||||
flow::mut_base(layout_root.deref_mut()).abs_position =
|
||||
flow::mut_base(layout_root.deref_mut()).stacking_relative_position =
|
||||
LogicalPoint::zero(writing_mode).to_physical(writing_mode,
|
||||
rw_data.screen_size);
|
||||
|
||||
|
@ -643,13 +640,7 @@ impl LayoutTask {
|
|||
}
|
||||
}
|
||||
|
||||
debug!("Done building display list. Display List = {}",
|
||||
flow::base(layout_root.deref()).display_list);
|
||||
|
||||
flow::mut_base(layout_root.deref_mut()).display_list.flatten(ContentStackingLevel);
|
||||
let display_list =
|
||||
Arc::new(mem::replace(&mut flow::mut_base(layout_root.deref_mut()).display_list,
|
||||
DisplayList::new()));
|
||||
debug!("Done building display list.");
|
||||
|
||||
// FIXME(pcwalton): This is really ugly and can't handle overflow: scroll. Refactor
|
||||
// it with extreme prejudice.
|
||||
|
@ -678,31 +669,23 @@ impl LayoutTask {
|
|||
let root_flow = flow::base(layout_root.deref());
|
||||
root_flow.position.size.to_physical(root_flow.writing_mode)
|
||||
};
|
||||
let root_size = Size2D(root_size.width.to_nearest_px() as uint,
|
||||
root_size.height.to_nearest_px() as uint);
|
||||
let render_layer = RenderLayer {
|
||||
id: layout_root.layer_id(0),
|
||||
display_list: display_list.clone(),
|
||||
position: Rect(Point2D(0u, 0u), root_size),
|
||||
background_color: color,
|
||||
scroll_policy: Scrollable,
|
||||
};
|
||||
let mut display_list = box DisplayList::new();
|
||||
flow::mut_base(layout_root.deref_mut()).display_list_building_result
|
||||
.add_to(&mut *display_list);
|
||||
let render_layer = Arc::new(RenderLayer::new(layout_root.layer_id(0),
|
||||
color,
|
||||
Scrollable));
|
||||
let origin = Rect(Point2D(Au(0), Au(0)), root_size);
|
||||
let stacking_context = Arc::new(StackingContext::new(display_list,
|
||||
origin,
|
||||
0,
|
||||
Some(render_layer)));
|
||||
|
||||
rw_data.display_list = Some(display_list);
|
||||
|
||||
// TODO(pcwalton): Eventually, when we have incremental reflow, this will have to
|
||||
// be smarter in order to handle retained layer contents properly from reflow to
|
||||
// reflow.
|
||||
let mut layers = SmallVec1::new();
|
||||
layers.push(render_layer);
|
||||
for layer in mem::replace(&mut flow::mut_base(layout_root.deref_mut()).layers,
|
||||
DList::new()).into_iter() {
|
||||
layers.push(layer)
|
||||
}
|
||||
rw_data.stacking_context = Some(stacking_context.clone());
|
||||
|
||||
debug!("Layout done!");
|
||||
|
||||
self.render_chan.send(RenderInitMsg(layers));
|
||||
self.render_chan.send(RenderInitMsg(stacking_context));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -933,27 +916,23 @@ impl LayoutRPC for LayoutRPCImpl {
|
|||
ContentBoxesResponse(rw_data.content_boxes_response.clone())
|
||||
}
|
||||
|
||||
/// Requests the node containing the point of interest
|
||||
/// Requests the node containing the point of interest.
|
||||
fn hit_test(&self, _: TrustedNodeAddress, point: Point2D<f32>) -> Result<HitTestResponse, ()> {
|
||||
fn hit_test<'a,I>(point: Point2D<Au>, mut iterator: I)
|
||||
-> Option<HitTestResponse>
|
||||
where I: Iterator<&'a DisplayItem> {
|
||||
for item in iterator {
|
||||
// TODO(tikue): This check should really be performed by a method of `DisplayItem`.
|
||||
if geometry::rect_contains_point(item.base().clip_rect, point) &&
|
||||
geometry::rect_contains_point(item.bounds(), point) {
|
||||
return Some(HitTestResponse(item.base().node.to_untrusted_node_address()))
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
let point = Point2D(Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
|
||||
let resp = {
|
||||
let &LayoutRPCImpl(ref rw_data) = self;
|
||||
let rw_data = rw_data.lock();
|
||||
match rw_data.display_list {
|
||||
None => panic!("no display list!"),
|
||||
Some(ref display_list) => hit_test(point, display_list.list.iter().rev()),
|
||||
match rw_data.stacking_context {
|
||||
None => panic!("no root stacking context!"),
|
||||
Some(ref stacking_context) => {
|
||||
let mut result = Vec::new();
|
||||
stacking_context.hit_test(point, &mut result, true);
|
||||
if !result.is_empty() {
|
||||
Some(HitTestResponse(result[0]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -965,29 +944,17 @@ impl LayoutRPC for LayoutRPCImpl {
|
|||
|
||||
fn mouse_over(&self, _: TrustedNodeAddress, point: Point2D<f32>)
|
||||
-> Result<MouseOverResponse, ()> {
|
||||
fn mouse_over_test<'a,I>(point: Point2D<Au>,
|
||||
mut iterator: I,
|
||||
result: &mut Vec<UntrustedNodeAddress>)
|
||||
where I: Iterator<&'a DisplayItem> {
|
||||
for item in iterator {
|
||||
// TODO(tikue): This check should really be performed by a method of `DisplayItem`.
|
||||
if geometry::rect_contains_point(item.bounds(), point) {
|
||||
result.push(item.base().node.to_untrusted_node_address())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut mouse_over_list: Vec<UntrustedNodeAddress> = vec!();
|
||||
let point = Point2D(Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
|
||||
{
|
||||
let &LayoutRPCImpl(ref rw_data) = self;
|
||||
let rw_data = rw_data.lock();
|
||||
match rw_data.display_list {
|
||||
None => panic!("no display list!"),
|
||||
Some(ref display_list) => {
|
||||
mouse_over_test(point, display_list.list.iter().rev(), &mut mouse_over_list);
|
||||
match rw_data.stacking_context {
|
||||
None => panic!("no root stacking context!"),
|
||||
Some(ref stacking_context) => {
|
||||
stacking_context.hit_test(point, &mut mouse_over_list, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if mouse_over_list.is_empty() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue