aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/gfx/display_list/mod.rs205
-rw-r--r--components/gfx/display_list/optimizer.rs31
-rw-r--r--components/gfx/render_task.rs12
-rw-r--r--components/layout/block.rs38
-rw-r--r--components/layout/construct.rs1
-rw-r--r--components/layout/flow.rs34
-rw-r--r--components/layout/fragment.rs252
-rw-r--r--components/layout/inline.rs49
-rw-r--r--components/layout/layout_task.rs90
-rw-r--r--components/layout/parallel.rs56
-rw-r--r--components/layout/traversal.rs8
-rw-r--r--components/util/geometry.rs23
12 files changed, 312 insertions, 487 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs
index 0614fc24a76..afa80ca477a 100644
--- a/components/gfx/display_list/mod.rs
+++ b/components/gfx/display_list/mod.rs
@@ -196,93 +196,35 @@ impl StackingContext {
};
for item in list.into_iter() {
- match item {
- ClipDisplayItemClass(box ClipDisplayItem {
- base: base,
- children: sublist
- }) => {
- let sub_stacking_context = StackingContext::new(sublist);
- stacking_context.merge_with_clip(sub_stacking_context, &base.bounds, base.node)
+ match item.base().level {
+ BackgroundAndBordersStackingLevel => {
+ stacking_context.background_and_borders.push(item)
}
- item => {
- match item.base().level {
- BackgroundAndBordersStackingLevel => {
- stacking_context.background_and_borders.push(item)
- }
- BlockBackgroundsAndBordersStackingLevel => {
- stacking_context.block_backgrounds_and_borders.push(item)
- }
- FloatStackingLevel => stacking_context.floats.push(item),
- ContentStackingLevel => stacking_context.content.push(item),
- PositionedDescendantStackingLevel(z_index) => {
- match stacking_context.positioned_descendants
- .iter_mut()
- .find(|& &(z, _)| z_index == z) {
- Some(&(_, ref mut my_list)) => {
- my_list.push(item);
- continue
- }
- None => {}
- }
-
- let mut new_list = DisplayList::new();
- new_list.list.push(item);
- stacking_context.positioned_descendants.push((z_index, new_list))
+ BlockBackgroundsAndBordersStackingLevel => {
+ stacking_context.block_backgrounds_and_borders.push(item)
+ }
+ FloatStackingLevel => stacking_context.floats.push(item),
+ ContentStackingLevel => stacking_context.content.push(item),
+ PositionedDescendantStackingLevel(z_index) => {
+ match stacking_context.positioned_descendants
+ .iter_mut()
+ .find(|& &(z, _)| z_index == z) {
+ Some(&(_, ref mut my_list)) => {
+ my_list.push(item);
+ continue
}
+ None => {}
}
+
+ let mut new_list = DisplayList::new();
+ new_list.list.push(item);
+ stacking_context.positioned_descendants.push((z_index, new_list))
}
}
}
stacking_context
}
-
- /// Merges another stacking context into this one, with the given clipping rectangle and DOM
- /// node that supplies it.
- fn merge_with_clip(&mut self,
- other: StackingContext,
- clip_rect: &Rect<Au>,
- clipping_dom_node: OpaqueNode) {
- let StackingContext {
- background_and_borders,
- block_backgrounds_and_borders,
- floats,
- content,
- positioned_descendants: positioned_descendants
- } = other;
-
- let push = |destination: &mut DisplayList, source: DisplayList, level| {
- if !source.is_empty() {
- let base = BaseDisplayItem::new(*clip_rect, clipping_dom_node, level);
- destination.push(ClipDisplayItemClass(box ClipDisplayItem::new(base, source)))
- }
- };
-
- push(&mut self.background_and_borders,
- background_and_borders,
- BackgroundAndBordersStackingLevel);
- push(&mut self.block_backgrounds_and_borders,
- block_backgrounds_and_borders,
- BlockBackgroundsAndBordersStackingLevel);
- push(&mut self.floats, floats, FloatStackingLevel);
- push(&mut self.content, content, ContentStackingLevel);
-
- for (z_index, list) in positioned_descendants.into_iter() {
- match self.positioned_descendants
- .iter_mut()
- .find(|& &(existing_z_index, _)| z_index == existing_z_index) {
- Some(&(_, ref mut existing_list)) => {
- push(existing_list, list, PositionedDescendantStackingLevel(z_index));
- continue
- }
- None => {}
- }
-
- let mut new_list = DisplayList::new();
- push(&mut new_list, list, PositionedDescendantStackingLevel(z_index));
- self.positioned_descendants.push((z_index, new_list));
- }
- }
}
/// Which level to place backgrounds and borders in.
@@ -342,11 +284,13 @@ impl DisplayList {
/// Draws the display list into the given render context. The display list must be flattened
/// first for correct painting.
- pub fn draw_into_context(&self, render_context: &mut RenderContext,
- current_transform: &Matrix2D<AzFloat>) {
+ pub fn draw_into_context(&self,
+ render_context: &mut RenderContext,
+ current_transform: &Matrix2D<AzFloat>,
+ current_clip_rect: &Rect<Au>) {
debug!("Beginning display list.");
for item in self.list.iter() {
- item.draw_into_context(render_context, current_transform)
+ item.draw_into_context(render_context, current_transform, current_clip_rect)
}
debug!("Ending display list.");
}
@@ -356,12 +300,6 @@ impl DisplayList {
ParentDisplayItemIterator(self.list.iter())
}
- /// Returns true if this list is empty and false otherwise.
- #[inline]
- fn is_empty(&self) -> bool {
- self.list.is_empty()
- }
-
/// Flattens a display list into a display list with a single stacking level according to the
/// steps in CSS 2.1 § E.2.
///
@@ -421,10 +359,6 @@ impl DisplayList {
fn set_stacking_level(&mut self, new_level: StackingLevel) {
for item in self.list.iter_mut() {
item.mut_base().level = new_level;
- match item.mut_sublist() {
- None => {}
- Some(sublist) => sublist.set_stacking_level(new_level),
- }
}
}
}
@@ -437,7 +371,6 @@ pub enum DisplayItem {
ImageDisplayItemClass(Box<ImageDisplayItem>),
BorderDisplayItemClass(Box<BorderDisplayItem>),
LineDisplayItemClass(Box<LineDisplayItem>),
- ClipDisplayItemClass(Box<ClipDisplayItem>),
/// A pseudo-display item that exists only so that queries like `ContentBoxQuery` and
/// `ContentBoxesQuery` can be answered.
@@ -450,9 +383,7 @@ pub enum DisplayItem {
/// Information common to all display items.
#[deriving(Clone)]
pub struct BaseDisplayItem {
- /// The boundaries of the display item.
- ///
- /// TODO: Which coordinate system should this use?
+ /// The boundaries of the display item, in layer coordinates.
pub bounds: Rect<Au>,
/// The originating DOM node.
@@ -460,14 +391,22 @@ pub struct BaseDisplayItem {
/// The stacking level in which this display item lives.
pub level: StackingLevel,
+
+ /// The rectangle to clip to.
+ ///
+ /// TODO(pcwalton): Eventually, to handle `border-radius`, this will (at least) need to grow
+ /// the ability to describe rounded rectangles.
+ pub clip_rect: Rect<Au>,
}
impl BaseDisplayItem {
- pub fn new(bounds: Rect<Au>, node: OpaqueNode, level: StackingLevel) -> BaseDisplayItem {
+ pub fn new(bounds: Rect<Au>, node: OpaqueNode, level: StackingLevel, clip_rect: Rect<Au>)
+ -> BaseDisplayItem {
BaseDisplayItem {
bounds: bounds,
node: node,
level: level,
+ clip_rect: clip_rect,
}
}
}
@@ -544,25 +483,6 @@ pub struct LineDisplayItem {
pub style: border_style::T
}
-/// Clips a list of child display items to this display item's boundaries.
-#[deriving(Clone)]
-pub struct ClipDisplayItem {
- /// The base information.
- pub base: BaseDisplayItem,
-
- /// The child nodes.
- pub children: DisplayList,
-}
-
-impl ClipDisplayItem {
- pub fn new(base: BaseDisplayItem, children: DisplayList) -> ClipDisplayItem {
- ClipDisplayItem {
- base: base,
- children: children,
- }
- }
-}
-
pub enum DisplayItemIterator<'a> {
EmptyDisplayItemIterator,
ParentDisplayItemIterator(dlist::Items<'a,DisplayItem>),
@@ -580,24 +500,24 @@ impl<'a> Iterator<&'a DisplayItem> for DisplayItemIterator<'a> {
impl DisplayItem {
/// Renders this display item into the given render context.
- fn draw_into_context(&self, render_context: &mut RenderContext,
- current_transform: &Matrix2D<AzFloat>) {
+ fn draw_into_context(&self,
+ render_context: &mut RenderContext,
+ current_transform: &Matrix2D<AzFloat>,
+ current_clip_rect: &Rect<Au>) {
// This should have been flattened to the content stacking level first.
assert!(self.base().level == ContentStackingLevel);
+ let clip_rect = &self.base().clip_rect;
+ let need_to_clip = current_clip_rect != clip_rect;
+ if need_to_clip {
+ render_context.draw_push_clip(clip_rect);
+ }
+
match *self {
SolidColorDisplayItemClass(ref solid_color) => {
render_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
}
- ClipDisplayItemClass(ref clip) => {
- render_context.draw_push_clip(&clip.base.bounds);
- for item in clip.children.iter() {
- (*item).draw_into_context(render_context, current_transform);
- }
- render_context.draw_pop_clip();
- }
-
TextDisplayItemClass(ref text) => {
debug!("Drawing text at {}.", text.base.bounds);
@@ -688,6 +608,10 @@ impl DisplayItem {
PseudoDisplayItemClass(_) => {}
}
+
+ if need_to_clip {
+ render_context.draw_pop_clip();
+ }
}
pub fn base<'a>(&'a self) -> &'a BaseDisplayItem {
@@ -697,7 +621,6 @@ impl DisplayItem {
ImageDisplayItemClass(ref image_item) => &image_item.base,
BorderDisplayItemClass(ref border) => &border.base,
LineDisplayItemClass(ref line) => &line.base,
- ClipDisplayItemClass(ref clip) => &clip.base,
PseudoDisplayItemClass(ref base) => &**base,
}
}
@@ -709,7 +632,6 @@ impl DisplayItem {
ImageDisplayItemClass(ref mut image_item) => &mut image_item.base,
BorderDisplayItemClass(ref mut border) => &mut border.base,
LineDisplayItemClass(ref mut line) => &mut line.base,
- ClipDisplayItemClass(ref mut clip) => &mut clip.base,
PseudoDisplayItemClass(ref mut base) => &mut **base,
}
}
@@ -718,40 +640,12 @@ impl DisplayItem {
self.base().bounds
}
- pub fn children<'a>(&'a self) -> DisplayItemIterator<'a> {
- match *self {
- ClipDisplayItemClass(ref clip) => ParentDisplayItemIterator(clip.children.list.iter()),
- SolidColorDisplayItemClass(..) |
- TextDisplayItemClass(..) |
- ImageDisplayItemClass(..) |
- BorderDisplayItemClass(..) |
- LineDisplayItemClass(..) |
- PseudoDisplayItemClass(..) => EmptyDisplayItemIterator,
- }
- }
-
- /// Returns a mutable reference to the sublist contained within this display list item, if any.
- fn mut_sublist<'a>(&'a mut self) -> Option<&'a mut DisplayList> {
- match *self {
- ClipDisplayItemClass(ref mut clip) => Some(&mut clip.children),
- SolidColorDisplayItemClass(..) |
- TextDisplayItemClass(..) |
- ImageDisplayItemClass(..) |
- BorderDisplayItemClass(..) |
- LineDisplayItemClass(..) |
- PseudoDisplayItemClass(..) => None,
- }
- }
-
pub fn debug_with_level(&self, level: uint) {
let mut indent = String::new();
for _ in range(0, level) {
indent.push_str("| ")
}
debug!("{}+ {}", indent, self);
- for child in self.children() {
- child.debug_with_level(level + 1);
- }
}
}
@@ -764,7 +658,6 @@ impl fmt::Show for DisplayItem {
ImageDisplayItemClass(_) => "Image",
BorderDisplayItemClass(_) => "Border",
LineDisplayItemClass(_) => "Line",
- ClipDisplayItemClass(_) => "Clip",
PseudoDisplayItemClass(_) => "Pseudo",
},
self.base().bounds,
diff --git a/components/gfx/display_list/optimizer.rs b/components/gfx/display_list/optimizer.rs
index 5e32238704c..e508e351010 100644
--- a/components/gfx/display_list/optimizer.rs
+++ b/components/gfx/display_list/optimizer.rs
@@ -2,9 +2,7 @@
* 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/. */
-use display_list::{BorderDisplayItemClass, ClipDisplayItem, ClipDisplayItemClass, DisplayItem};
-use display_list::{DisplayList, ImageDisplayItemClass, LineDisplayItemClass};
-use display_list::{PseudoDisplayItemClass, SolidColorDisplayItemClass, TextDisplayItemClass};
+use display_list::{DisplayItem, DisplayList};
use collections::dlist::DList;
use geom::rect::Rect;
@@ -45,28 +43,11 @@ impl DisplayListOptimizer {
fn process_display_item(&self, display_item: &DisplayItem) -> Option<DisplayItem> {
// Eliminate display items outside the visible region.
- if !self.visible_rect.intersects(&display_item.base().bounds) {
- return None
- }
-
- // Recur.
- match *display_item {
- ClipDisplayItemClass(ref clip) => {
- let new_children = self.process_display_list(&clip.children);
- if new_children.is_empty() {
- return None
- }
- Some(ClipDisplayItemClass(box ClipDisplayItem {
- base: clip.base.clone(),
- children: new_children,
- }))
- }
-
- BorderDisplayItemClass(_) | ImageDisplayItemClass(_) | LineDisplayItemClass(_) |
- PseudoDisplayItemClass(_) | SolidColorDisplayItemClass(_) |
- TextDisplayItemClass(_) => {
- Some((*display_item).clone())
- }
+ if !self.visible_rect.intersects(&display_item.base().bounds) ||
+ !self.visible_rect.intersects(&display_item.base().clip_rect) {
+ None
+ } else {
+ Some((*display_item).clone())
}
}
}
diff --git a/components/gfx/render_task.rs b/components/gfx/render_task.rs
index 92d9a2de2b0..8ddc5f232b2 100644
--- a/components/gfx/render_task.rs
+++ b/components/gfx/render_task.rs
@@ -25,13 +25,14 @@ use servo_msg::compositor_msg::{LayerMetadata, RenderListener, RenderingRenderSt
use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineId};
use servo_msg::constellation_msg::{RendererReadyMsg};
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
-use servo_util::geometry;
+use servo_util::geometry::{Au, mod};
use servo_util::opts::Opts;
use servo_util::smallvec::{SmallVec, SmallVec1};
use servo_util::task::spawn_named_with_send_on_failure;
use servo_util::time::{TimeProfilerChan, profile};
use servo_util::time;
use std::comm::{Receiver, Sender, channel};
+use std::i32;
use sync::Arc;
use font_cache_task::FontCacheTask;
@@ -356,8 +357,13 @@ impl<C:RenderListener + Send> RenderTask<C> {
ctx.clear();
// Draw the display list.
- profile(time::RenderingDrawingCategory, None, self.time_profiler_chan.clone(), || {
- display_list.draw_into_context(&mut ctx, &matrix);
+ profile(time::RenderingDrawingCategory,
+ None,
+ self.time_profiler_chan.clone(),
+ || {
+ let clip_rect = Rect(Point2D(Au(i32::MIN), Au(i32::MIN)),
+ Size2D(Au(i32::MAX), Au(i32::MAX)));
+ display_list.draw_into_context(&mut ctx, &matrix, &clip_rect);
ctx.draw_target.flush();
});
}
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 5fe80ecc8ab..53eecad09b6 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -37,7 +37,7 @@ use gfx::display_list::{RootOfStackingContextLevel};
use gfx::render_task::RenderLayer;
use serialize::{Encoder, Encodable};
use servo_msg::compositor_msg::{FixedPosition, LayerId, Scrollable};
-use servo_util::geometry::{Au, MAX_AU};
+use servo_util::geometry::{Au, MAX_AU, MAX_RECT};
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use std::cmp::{max, min};
use std::fmt;
@@ -1078,18 +1078,19 @@ impl BlockFlow {
fn build_display_list_block_common(&mut self,
layout_context: &LayoutContext,
background_border_level: BackgroundAndBorderLevel) {
- let rel_offset =
+ let relative_offset =
self.fragment.relative_position(&self.base
- .absolute_position_info
- .relative_containing_block_size);
+ .absolute_position_info
+ .relative_containing_block_size);
// Add the box that starts the block context.
let mut display_list = DisplayList::new();
- let mut accumulator = self.fragment.build_display_list(
- &mut display_list,
- layout_context,
- self.base.abs_position.add_size(&rel_offset.to_physical(self.base.writing_mode)),
- background_border_level);
+ 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() {
@@ -1098,19 +1099,21 @@ impl BlockFlow {
continue
}
- accumulator.push_child(&mut display_list, kid);
+ 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.
- accumulator.push_child(&mut display_list, abs_descendant_link);
+ 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()));
}
- accumulator.finish(&mut display_list);
self.base.display_list = display_list;
self.base.layers = child_layers
}
@@ -1696,6 +1699,10 @@ 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.is_absolutely_positioned() {
let position_start = self.base.position.start.to_physical(
self.base.writing_mode, container_size);
@@ -1737,8 +1744,11 @@ impl Flow for BlockFlow {
absolute_position_info.layers_needed_for_positioned_flows =
self.base.flags.layers_needed_for_descendants();
- // Process children.
+ // 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);
+
+ // Process children.
let writing_mode = self.base.writing_mode;
for kid in self.base.child_iter() {
if !kid.is_absolutely_positioned() {
@@ -1749,6 +1759,8 @@ impl Flow for BlockFlow {
container_size);
kid_base.absolute_position_info = absolute_position_info
}
+
+ flow::mut_base(kid).clip_rect = clip_rect
}
// Process absolute descendant links.
diff --git a/components/layout/construct.rs b/components/layout/construct.rs
index c45c26d781c..ffdf535874e 100644
--- a/components/layout/construct.rs
+++ b/components/layout/construct.rs
@@ -1204,7 +1204,6 @@ impl FlowConstructionUtils for FlowRef {
base.children.push_back(new_child);
let _ = base.parallel.children_count.fetch_add(1, Relaxed);
- let _ = base.parallel.children_and_absolute_descendant_count.fetch_add(1, Relaxed);
}
/// Finishes a flow. Once a flow is finished, no more child flows or fragments may be added to
diff --git a/components/layout/flow.rs b/components/layout/flow.rs
index a8711f62965..4520bee4eff 100644
--- a/components/layout/flow.rs
+++ b/components/layout/flow.rs
@@ -46,7 +46,7 @@ use table_wrapper::TableWrapperFlow;
use wrapper::ThreadSafeLayoutNode;
use collections::dlist::DList;
-use geom::Point2D;
+use geom::{Point2D, Rect, Size2D};
use gfx::display_list::DisplayList;
use gfx::render_task::RenderLayer;
use serialize::{Encoder, Encodable};
@@ -59,7 +59,7 @@ use std::num::Zero;
use std::fmt;
use std::iter::Zip;
use std::raw;
-use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
+use std::sync::atomics::{AtomicUint, SeqCst};
use std::slice::MutItems;
use style::computed_values::{clear, float, position, text_align};
@@ -168,14 +168,14 @@ pub trait Flow: fmt::Show + ToString + Sync {
fail!("called col_inline_sizes() on an other flow than table-row/table-rowgroup/table")
}
- /// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
- /// Fails otherwise.
+ /// If this is a table row flow or table rowgroup flow or table flow, returns column min
+ /// inline-sizes. Fails otherwise.
fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
fail!("called col_min_inline_sizes() on an other flow than table-row/table-rowgroup/table")
}
- /// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
- /// Fails otherwise.
+ /// If this is a table row flow or table rowgroup flow or table flow, returns column min
+ /// inline-sizes. Fails otherwise.
fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
fail!("called col_pref_inline_sizes() on an other flow than table-row/table-rowgroup/table")
}
@@ -230,8 +230,8 @@ pub trait Flow: fmt::Show + ToString + Sync {
}
fn compute_collapsible_block_start_margin(&mut self,
- _layout_context: &mut LayoutContext,
- _margin_collapse_info: &mut MarginCollapseInfo) {
+ _layout_context: &mut LayoutContext,
+ _margin_collapse_info: &mut MarginCollapseInfo) {
// The default implementation is a no-op.
}
@@ -679,8 +679,10 @@ pub type DescendantOffsetIter<'a> = Zip<DescendantIter<'a>, MutItems<'a, Au>>;
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>,
+
/// Whether the absolute containing block forces positioned descendants to be layerized.
///
/// FIXME(pcwalton): Move into `FlowFlags`.
@@ -770,6 +772,12 @@ pub struct BaseFlow {
/// FIXME(pcwalton): Merge with `absolute_static_i_offset` and `fixed_static_i_offset` above?
pub absolute_position_info: AbsolutePositionInfo,
+ /// The clipping rectangle for this flow and its descendants, in layer coordinates.
+ ///
+ /// TODO(pcwalton): When we have `border-radius` this will need to at least support rounded
+ /// rectangles.
+ pub clip_rect: Rect<Au>,
+
/// The unflattened display items for this flow.
pub display_list: DisplayList,
@@ -785,11 +793,10 @@ pub struct BaseFlow {
impl fmt::Show for BaseFlow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
- "@ {}, CC {}, ADC {}, CADC {}",
+ "@ {}, CC {}, ADC {}",
self.position,
self.parallel.children_count.load(SeqCst),
- self.abs_descendants.len(),
- self.parallel.children_and_absolute_descendant_count.load(SeqCst))
+ self.abs_descendants.len())
}
}
@@ -851,6 +858,7 @@ impl BaseFlow {
display_list: DisplayList::new(),
layers: DList::new(),
absolute_position_info: AbsolutePositionInfo::new(writing_mode),
+ clip_rect: Rect(Zero::zero(), Size2D(Au(0), Au(0))),
flags: FlowFlags::new(),
writing_mode: writing_mode,
@@ -1210,10 +1218,6 @@ impl MutableOwnedFlowUtils for FlowRef {
let block = self.get_mut().as_block();
block.base.abs_descendants = abs_descendants;
- block.base
- .parallel
- .children_and_absolute_descendant_count
- .fetch_add(block.base.abs_descendants.len() as int, Relaxed);
for descendant_link in block.base.abs_descendants.iter() {
let base = mut_base(descendant_link);
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 87b9dded311..4853ded381b 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -11,7 +11,6 @@ use construct::FlowConstructor;
use context::LayoutContext;
use floats::{ClearBoth, ClearLeft, ClearRight, ClearType};
use flow::Flow;
-use flow;
use flow_ref::FlowRef;
use inline::{InlineFragmentContext, InlineMetrics};
use layout_debug;
@@ -25,13 +24,12 @@ 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, ClipDisplayItem, ClipDisplayItemClass};
-use gfx::display_list::{ContentStackingLevel, DisplayItem, DisplayList, ImageDisplayItem};
-use gfx::display_list::{ImageDisplayItemClass, LineDisplayItem};
+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::{SolidColorDisplayItem, SolidColorDisplayItemClass, StackingLevel};
-use gfx::display_list::{TextDisplayItem, TextDisplayItemClass};
-use gfx::display_list::{Upright, SidewaysLeft, SidewaysRight};
+use gfx::display_list::{SidewaysLeft, SidewaysRight, SolidColorDisplayItem};
+use gfx::display_list::{SolidColorDisplayItemClass, StackingLevel, TextDisplayItem};
+use gfx::display_list::{TextDisplayItemClass, Upright};
use gfx::font::FontStyle;
use gfx::text::glyph::CharIndex;
use gfx::text::text_run::TextRun;
@@ -40,7 +38,7 @@ use serialize::{Encodable, Encoder};
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
use servo_net::image::holder::ImageHolder;
use servo_net::local_image_cache::LocalImageCache;
-use servo_util::geometry::Au;
+use servo_util::geometry::{Au, ZERO_RECT};
use servo_util::geometry;
use servo_util::logical_geometry::{LogicalRect, LogicalSize, LogicalMargin, WritingMode};
use servo_util::range::*;
@@ -49,7 +47,6 @@ use servo_util::str::is_whitespace;
use std::cmp::{max, min};
use std::fmt;
use std::from_str::FromStr;
-use std::mem;
use std::num::Zero;
use style::{ComputedValues, TElement, TNode, cascade_anonymous, RGBA};
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto};
@@ -60,24 +57,26 @@ use style::computed_values::{text_decoration, vertical_align, visibility, white_
use sync::{Arc, Mutex};
use url::Url;
-/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position themselves. In
-/// general, fragments do not have a simple correspondence with CSS fragments in the specification:
+/// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position
+/// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the
+/// specification:
///
/// * Several fragments may correspond to the same CSS box or DOM node. For example, a CSS text box
/// broken across two lines is represented by two fragments.
///
-/// * Some CSS fragments are not created at all, such as some anonymous block fragments induced by inline
-/// fragments with block-level sibling fragments. In that case, Servo uses an `InlineFlow` with
-/// `BlockFlow` siblings; the `InlineFlow` is block-level, but not a block container. It is
-/// positioned as if it were a block fragment, but its children are positioned according to inline
-/// flow.
+/// * Some CSS fragments are not created at all, such as some anonymous block fragments induced by
+/// inline fragments with block-level sibling fragments. In that case, Servo uses an `InlineFlow`
+/// with `BlockFlow` siblings; the `InlineFlow` is block-level, but not a block container. It is
+/// positioned as if it were a block fragment, but its children are positioned according to
+/// inline flow.
///
/// A `GenericFragment` is an empty fragment that contributes only borders, margins, padding, and
/// backgrounds. It is analogous to a CSS nonreplaced content box.
///
-/// A fragment's type influences how its styles are interpreted during layout. For example, replaced
-/// content such as images are resized differently from tables, text, or other content. Different
-/// types of fragments may also contain custom data; for example, text fragments contain text.
+/// A fragment's type influences how its styles are interpreted during layout. For example,
+/// replaced content such as images are resized differently from tables, text, or other content.
+/// Different types of fragments may also contain custom data; for example, text fragments contain
+/// text.
///
/// FIXME(#2260, pcwalton): This can be slimmed down some.
#[deriving(Clone)]
@@ -787,7 +786,8 @@ impl Fragment {
list: &mut DisplayList,
layout_context: &LayoutContext,
level: StackingLevel,
- absolute_bounds: &Rect<Au>) {
+ 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
@@ -795,7 +795,7 @@ impl 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),
+ base: BaseDisplayItem::new(*absolute_bounds, self.node, level, *clip_rect),
color: background_color.to_gfx_color(),
};
@@ -828,12 +828,10 @@ impl Fragment {
let image_height = Au::from_px(image.height as int);
let mut bounds = *absolute_bounds;
- // Add clip item.
+ // Clip.
+ //
// TODO: Check the bounds to see if a clip item is actually required.
- let mut clip_display_item = box ClipDisplayItem {
- base: BaseDisplayItem::new(bounds, self.node, level),
- children: DisplayList::new(),
- };
+ 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 {
@@ -884,14 +882,12 @@ impl Fragment {
// Create the image display item.
let image_display_item = ImageDisplayItemClass(box ImageDisplayItem {
- base: BaseDisplayItem::new(bounds, self.node, level),
+ 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)),
});
-
- clip_display_item.children.push(image_display_item);
- list.push(ClipDisplayItemClass(clip_display_item))
+ list.push(image_display_item)
}
/// Adds the display items necessary to paint the borders of this fragment to a display list if
@@ -900,7 +896,8 @@ impl Fragment {
style: &ComputedValues,
list: &mut DisplayList,
abs_bounds: &Rect<Au>,
- level: StackingLevel) {
+ level: StackingLevel,
+ clip_rect: &Rect<Au>) {
let border = style.logical_border_width();
if border.is_zero() {
return
@@ -913,7 +910,7 @@ impl Fragment {
// Append the border to the display list.
let border_display_item = box BorderDisplayItem {
- base: BaseDisplayItem::new(*abs_bounds, self.node, level),
+ 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(),
@@ -929,9 +926,10 @@ impl Fragment {
}
fn build_debug_borders_around_text_fragments(&self,
- display_list: &mut DisplayList,
- flow_origin: Point2D<Au>,
- text_fragment: &ScannedTextFragmentInfo) {
+ 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.
@@ -942,7 +940,10 @@ impl Fragment {
// 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),
+ 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)
@@ -958,7 +959,7 @@ impl Fragment {
baseline.origin = baseline.origin + flow_origin;
let line_display_item = box LineDisplayItem {
- base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel),
+ base: BaseDisplayItem::new(baseline, self.node, ContentStackingLevel, *clip_rect),
color: rgb(0, 200, 0),
style: border_style::dashed,
};
@@ -966,8 +967,9 @@ impl Fragment {
}
fn build_debug_borders_around_fragment(&self,
- display_list: &mut DisplayList,
- flow_origin: Point2D<Au>) {
+ 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.
@@ -978,7 +980,10 @@ impl Fragment {
// 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),
+ 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)
@@ -994,12 +999,13 @@ impl Fragment {
/// * `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)
- -> ChildDisplayListAccumulator {
+ 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>| {
@@ -1016,22 +1022,13 @@ impl Fragment {
layout_context.shared.dirty,
flow_origin);
- let may_need_clip = match self.specific {
- ScannedTextFragment(_) => false,
- _ => true,
- };
- let mut accumulator = ChildDisplayListAccumulator::new(self.style(),
- absolute_fragment_bounds,
- self.node,
- ContentStackingLevel,
- may_need_clip);
if self.style().get_inheritedbox().visibility != visibility::visible {
- return accumulator
+ return
}
if !absolute_fragment_bounds.intersects(&layout_context.shared.dirty) {
debug!("Fragment::build_display_list: Did not intersect...");
- return accumulator
+ return
}
debug!("Fragment::build_display_list: intersected. Adding display item...");
@@ -1043,7 +1040,8 @@ impl 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);
+ level,
+ *clip_rect);
display_list.push(PseudoDisplayItemClass(base_display_item));
// Add the background to the list, if applicable.
@@ -1055,7 +1053,8 @@ impl Fragment {
display_list,
layout_context,
level,
- &absolute_fragment_bounds);
+ &absolute_fragment_bounds,
+ clip_rect);
}
}
None => {}
@@ -1068,7 +1067,8 @@ impl Fragment {
display_list,
layout_context,
level,
- &absolute_fragment_bounds);
+ &absolute_fragment_bounds,
+ clip_rect);
}
}
@@ -1082,7 +1082,8 @@ impl Fragment {
&**style,
display_list,
&absolute_fragment_bounds,
- level);
+ level,
+ clip_rect);
}
}
None => {}
@@ -1090,10 +1091,12 @@ impl Fragment {
match self.specific {
ScannedTextFragment(_) => {},
_ => {
- self.build_display_list_for_borders_if_applicable(&*self.style,
- display_list,
- &absolute_fragment_bounds,
- level);
+ self.build_display_list_for_borders_if_applicable(
+ &*self.style,
+ display_list,
+ &absolute_fragment_bounds,
+ level,
+ clip_rect);
}
}
}
@@ -1125,15 +1128,17 @@ impl Fragment {
};
let text_display_item = box TextDisplayItem {
- base: BaseDisplayItem::new(
- absolute_content_box, self.node, ContentStackingLevel),
+ 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,
};
- accumulator.push(display_list, TextDisplayItemClass(text_display_item));
+ display_list.push(TextDisplayItemClass(text_display_item));
// Create display items for text decoration
{
@@ -1141,14 +1146,17 @@ impl Fragment {
match maybe_color {
None => {},
Some(color) => {
- accumulator.push(display_list, SolidColorDisplayItemClass(
- box SolidColorDisplayItem {
- base: BaseDisplayItem::new(
- rect_to_absolute(self.style.writing_mode, rect()),
- self.node, ContentStackingLevel),
- color: color.to_gfx_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(),
+ }));
}
}
};
@@ -1181,15 +1189,19 @@ impl Fragment {
// FIXME(#2263, 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_text_fragments(display_list,
- flow_origin,
- text_fragment))
+ flow_origin,
+ text_fragment,
+ clip_rect))
}
GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment |
TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | InputFragment(_) |
InlineAbsoluteHypotheticalFragment(_) => {
// 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))
+ debug!("{:?}",
+ self.build_debug_borders_around_fragment(display_list,
+ flow_origin,
+ clip_rect))
}
ImageFragment(ref mut image_fragment) => {
let image_ref = &mut image_fragment.image;
@@ -1201,12 +1213,13 @@ impl Fragment {
let image_display_item = box ImageDisplayItem {
base: BaseDisplayItem::new(absolute_content_box,
self.node,
- ContentStackingLevel),
+ ContentStackingLevel,
+ *clip_rect),
image: image.clone(),
stretch_size: absolute_content_box.size,
};
- accumulator.push(display_list, ImageDisplayItemClass(image_display_item))
+ display_list.push(ImageDisplayItemClass(image_display_item))
}
None => {
// No image data at all? Do nothing.
@@ -1220,7 +1233,8 @@ impl Fragment {
// 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))
+ 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.
//
@@ -1240,8 +1254,6 @@ impl Fragment {
}
_ => {}
}
-
- accumulator
}
/// Returns the intrinsic inline-sizes of this fragment.
@@ -1800,6 +1812,28 @@ 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 {
@@ -1828,61 +1862,3 @@ impl fmt::Show for Fragment {
}
}
-/// An object that accumulates display lists of child flows, applying a clipping rect if necessary.
-pub struct ChildDisplayListAccumulator {
- clip_display_item: Option<Box<ClipDisplayItem>>,
-}
-
-impl ChildDisplayListAccumulator {
- /// Creates a `ChildDisplayListAccumulator` from the `overflow` property in the given style.
- fn new(style: &ComputedValues,
- bounds: Rect<Au>,
- node: OpaqueNode,
- level: StackingLevel,
- may_need_clip: bool)
- -> ChildDisplayListAccumulator {
- ChildDisplayListAccumulator {
- clip_display_item: match (may_need_clip, style.get_box().overflow) {
- (true, overflow::hidden) | (true, overflow::auto) | (true, overflow::scroll) => {
- Some(box ClipDisplayItem {
- base: BaseDisplayItem::new(bounds, node, level),
- children: DisplayList::new(),
- })
- },
- (false, _) | (_, overflow::visible) => None,
- }
- }
- }
-
- /// Pushes the given display item onto this display list.
- pub fn push(&mut self, parent_display_list: &mut DisplayList, item: DisplayItem) {
- match self.clip_display_item {
- None => parent_display_list.push(item),
- Some(ref mut clip_display_item) => clip_display_item.children.push(item),
- }
- }
-
- /// Pushes the display items from the given child onto this display list.
- pub fn push_child(&mut self, parent_display_list: &mut DisplayList, child: &mut Flow) {
- let kid_display_list = mem::replace(&mut flow::mut_base(child).display_list,
- DisplayList::new());
- match self.clip_display_item {
- None => parent_display_list.push_all_move(kid_display_list),
- Some(ref mut clip_display_item) => {
- clip_display_item.children.push_all_move(kid_display_list)
- }
- }
- }
-
- /// Consumes this accumulator and pushes the clipping item, if any, onto the given display
- /// list.
- pub fn finish(self, display_list: &mut DisplayList) {
- let ChildDisplayListAccumulator {
- clip_display_item
- } = self;
- match clip_display_item {
- None => {}
- Some(clip_display_item) => display_list.push(ClipDisplayItemClass(clip_display_item)),
- }
- }
-}
diff --git a/components/layout/inline.rs b/components/layout/inline.rs
index 527b6367c89..eaa9bc19aed 100644
--- a/components/layout/inline.rs
+++ b/components/layout/inline.rs
@@ -9,8 +9,8 @@ use context::LayoutContext;
use floats::{FloatLeft, Floats, PlacementInfo};
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils};
use flow;
-use fragment::{Fragment, InlineBlockFragment, ScannedTextFragment, ScannedTextFragmentInfo};
-use fragment::{SplitInfo};
+use fragment::{Fragment, InlineAbsoluteHypotheticalFragment, InlineBlockFragment};
+use fragment::{ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
use layout_debug;
use model::IntrinsicISizes;
use text;
@@ -18,7 +18,7 @@ use wrapper::ThreadSafeLayoutNode;
use collections::{Deque, RingBuf};
use geom::Rect;
-use gfx::display_list::ContentLevel;
+use gfx::display_list::{ContentLevel, DisplayList};
use gfx::font::FontMetrics;
use gfx::font_context::FontContext;
use geom::Size2D;
@@ -704,19 +704,20 @@ impl InlineFlow {
let fragment_position = self.base
.abs_position
.add_size(&rel_offset.to_physical(self.base.writing_mode));
- let mut accumulator = fragment.build_display_list(&mut self.base.display_list,
- layout_context,
- fragment_position,
- ContentLevel);
+ 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.get_mut();
- accumulator.push_child(&mut self.base.display_list, block_flow);
+ self.base.display_list.push_all_move(
+ mem::replace(&mut flow::mut_base(block_flow).display_list,
+ DisplayList::new()));
}
_ => {}
}
-
- accumulator.finish(&mut self.base.display_list);
}
}
@@ -1124,16 +1125,40 @@ impl Flow for InlineFlow {
fn compute_absolute_position(&mut self) {
for fragment in self.fragments.fragments.iter_mut() {
- match fragment.specific {
+ let absolute_position = match fragment.specific {
InlineBlockFragment(ref mut info) => {
let block_flow = info.flow_ref.get_mut().as_block();
-
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
block_flow.base.abs_position =
self.base.abs_position +
fragment.border_box.start.to_physical(self.base.writing_mode,
container_size);
+ block_flow.base.abs_position
+ }
+ InlineAbsoluteHypotheticalFragment(ref mut info) => {
+ let block_flow = info.flow_ref.get_mut().as_block();
+ // FIXME(#2795): Get the real container size
+ let container_size = Size2D::zero();
+ block_flow.base.abs_position =
+ self.base.abs_position +
+ fragment.border_box.start.to_physical(self.base.writing_mode,
+ container_size);
+ block_flow.base.abs_position
+
+ }
+ _ => continue,
+ };
+
+ let clip_rect = fragment.clip_rect_for_children(self.base.clip_rect,
+ absolute_position);
+
+ match fragment.specific {
+ InlineBlockFragment(ref mut info) => {
+ flow::mut_base(info.flow_ref.get_mut()).clip_rect = clip_rect
+ }
+ InlineAbsoluteHypotheticalFragment(ref mut info) => {
+ flow::mut_base(info.flow_ref.get_mut()).clip_rect = clip_rect
}
_ => {}
}
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs
index 22068ae460b..03ea97d8583 100644
--- a/components/layout/layout_task.rs
+++ b/components/layout/layout_task.rs
@@ -26,8 +26,8 @@ use encoding::all::UTF_8;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
-use gfx::display_list::{ClipDisplayItemClass, ContentStackingLevel, DisplayItem};
-use gfx::display_list::{DisplayItemIterator, DisplayList, OpaqueNode};
+use gfx::display_list::{ContentStackingLevel, DisplayItem, DisplayItemIterator, DisplayList};
+use gfx::display_list::{OpaqueNode};
use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer};
use gfx::{render_task, color};
use layout_traits;
@@ -852,7 +852,6 @@ impl LayoutRPC for LayoutRPCImpl {
mut iter: DisplayItemIterator,
node: OpaqueNode) {
for item in iter {
- union_boxes_for_node(accumulator, item.children(), node);
if item.base().node == node {
match *accumulator {
None => *accumulator = Some(item.base().bounds),
@@ -884,7 +883,6 @@ impl LayoutRPC for LayoutRPCImpl {
mut iter: DisplayItemIterator,
node: OpaqueNode) {
for item in iter {
- add_boxes_for_node(accumulator, item.children(), node);
if item.base().node == node {
accumulator.push(item.base().bounds)
}
@@ -907,47 +905,25 @@ impl LayoutRPC for LayoutRPCImpl {
/// Requests the node containing the point of interest
fn hit_test(&self, _: TrustedNodeAddress, point: Point2D<f32>) -> Result<HitTestResponse, ()> {
- fn hit_test<'a,I:Iterator<&'a DisplayItem>>(x: Au, y: Au, mut iterator: I)
- -> Option<HitTestResponse> {
+ fn hit_test<'a,I>(point: Point2D<Au>, mut iterator: I)
+ -> Option<HitTestResponse>
+ where I: Iterator<&'a DisplayItem> {
for item in iterator {
- match *item {
- ClipDisplayItemClass(ref cc) => {
- if geometry::rect_contains_point(cc.base.bounds, Point2D(x, y)) {
- let ret = hit_test(x, y, cc.children.list.iter().rev());
- if !ret.is_none() {
- return ret
- }
- }
- continue
- }
- _ => {}
- }
-
- let bounds = item.bounds();
-
- // TODO(tikue): This check should really be performed by a method of
- // DisplayItem.
- if x < bounds.origin.x + bounds.size.width &&
- bounds.origin.x <= x &&
- y < bounds.origin.y + bounds.size.height &&
- bounds.origin.y <= y {
- return Some(HitTestResponse(item.base()
- .node
- .to_untrusted_node_address()))
+ // 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()))
}
}
- let ret: Option<HitTestResponse> = None;
- ret
+ None
}
- let (x, y) = (Au::from_frac_px(point.x as f64),
- Au::from_frac_px(point.y as f64));
-
+ 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 => fail!("no display list!"),
- Some(ref display_list) => hit_test(x, y, display_list.list.iter().rev()),
+ Some(ref display_list) => hit_test(point, display_list.list.iter().rev()),
}
};
@@ -957,49 +933,29 @@ impl LayoutRPC for LayoutRPCImpl {
Err(())
}
- fn mouse_over(&self, _: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()> {
- fn mouse_over_test<'a,
- I:Iterator<&'a DisplayItem>>(
- x: Au,
- y: Au,
- mut iterator: I,
- result: &mut Vec<UntrustedNodeAddress>) {
+ 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 {
- match *item {
- ClipDisplayItemClass(ref cc) => {
- mouse_over_test(x, y, cc.children.list.iter().rev(), result);
- }
- _ => {
- let bounds = item.bounds();
-
- // TODO(tikue): This check should really be performed by a method
- // of DisplayItem.
- if x < bounds.origin.x + bounds.size.width &&
- bounds.origin.x <= x &&
- y < bounds.origin.y + bounds.size.height &&
- bounds.origin.y <= y {
- result.push(item.base()
- .node
- .to_untrusted_node_address());
- }
- }
+ // 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 (x, y) = (Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
-
+ 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 => fail!("no display list!"),
Some(ref display_list) => {
- mouse_over_test(x,
- y,
- display_list.list.iter().rev(),
- &mut mouse_over_list);
+ mouse_over_test(point, display_list.list.iter().rev(), &mut mouse_over_list);
}
};
}
diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs
index 90e19f6db76..fbb95ac8123 100644
--- a/components/layout/parallel.rs
+++ b/components/layout/parallel.rs
@@ -188,8 +188,6 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal {
pub struct FlowParallelInfo {
/// The number of children that still need work done.
pub children_count: AtomicInt,
- /// The number of children and absolute descendants that still need work done.
- pub children_and_absolute_descendant_count: AtomicInt,
/// The address of the parent flow.
pub parent: UnsafeFlow,
}
@@ -198,7 +196,6 @@ impl FlowParallelInfo {
pub fn new() -> FlowParallelInfo {
FlowParallelInfo {
children_count: AtomicInt::new(0),
- children_and_absolute_descendant_count: AtomicInt::new(0),
parent: null_unsafe_flow(),
}
}
@@ -382,39 +379,12 @@ fn compute_absolute_position(unsafe_flow: UnsafeFlow,
// Compute the absolute position for the flow.
flow.get_mut().compute_absolute_position();
- // If we are the containing block, count the number of absolutely-positioned children, so
- // that we don't double-count them in the `children_and_absolute_descendant_count`
- // reference count.
- let mut absolutely_positioned_child_count = 0u;
+ // Enqueue all children.
for kid in flow::child_iter(flow.get_mut()) {
- if kid.is_absolutely_positioned() {
- absolutely_positioned_child_count += 1;
- }
- }
-
- drop(flow::mut_base(flow.get_mut()).parallel
- .children_and_absolute_descendant_count
- .fetch_sub(absolutely_positioned_child_count as int,
- SeqCst));
-
- // Enqueue all non-absolutely-positioned children.
- for kid in flow::child_iter(flow.get_mut()) {
- if !kid.is_absolutely_positioned() {
- had_descendants = true;
- proxy.push(WorkUnit {
- fun: compute_absolute_position,
- data: borrowed_flow_to_unsafe_flow(kid),
- });
- }
- }
-
- // Possibly enqueue absolute descendants.
- for absolute_descendant_link in flow::mut_base(flow.get_mut()).abs_descendants.iter() {
had_descendants = true;
- let descendant = absolute_descendant_link;
proxy.push(WorkUnit {
fun: compute_absolute_position,
- data: borrowed_flow_to_unsafe_flow(descendant),
+ data: borrowed_flow_to_unsafe_flow(kid),
});
}
@@ -441,26 +411,12 @@ fn build_display_list(mut unsafe_flow: UnsafeFlow,
{
let base = flow::mut_base(flow.get_mut());
- // Reset the count of children and absolute descendants for the next layout
- // traversal.
- let children_and_absolute_descendant_count = base.children.len() +
- base.abs_descendants.len();
- base.parallel
- .children_and_absolute_descendant_count
- .store(children_and_absolute_descendant_count as int, Relaxed);
+ // Reset the count of children for the next layout traversal.
+ base.parallel.children_count.store(base.children.len() as int, Relaxed);
}
// Possibly enqueue the parent.
- let unsafe_parent = if flow.get().is_absolutely_positioned() {
- match *flow::mut_base(flow.get_mut()).absolute_cb.get() {
- None => fail!("no absolute containing block for absolutely positioned?!"),
- Some(ref mut absolute_cb) => {
- mut_borrowed_flow_to_unsafe_flow(absolute_cb.get_mut())
- }
- }
- } else {
- flow::mut_base(flow.get_mut()).parallel.parent
- };
+ let unsafe_parent = flow::mut_base(flow.get_mut()).parallel.parent;
if unsafe_parent == null_unsafe_flow() {
// We're done!
break
@@ -472,7 +428,7 @@ fn build_display_list(mut unsafe_flow: UnsafeFlow,
let parent: &mut FlowRef = mem::transmute(&unsafe_parent);
let parent_base = flow::mut_base(parent.get_mut());
if parent_base.parallel
- .children_and_absolute_descendant_count
+ .children_count
.fetch_sub(1, SeqCst) == 1 {
// We were the last child of our parent. Build display lists for our parent.
unsafe_flow = unsafe_parent
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index d217e785321..f7726c19a59 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -323,13 +323,7 @@ impl<'a> BuildDisplayList<'a> {
flow.compute_absolute_position();
for kid in flow::mut_base(flow).child_iter() {
- if !kid.is_absolutely_positioned() {
- self.process(kid)
- }
- }
-
- for absolute_descendant_link in flow::mut_base(flow).abs_descendants.iter() {
- self.process(absolute_descendant_link)
+ self.process(kid)
}
flow.build_display_list(self.layout_context)
diff --git a/components/util/geometry.rs b/components/util/geometry.rs
index d212992f6da..64d779d1f67 100644
--- a/components/util/geometry.rs
+++ b/components/util/geometry.rs
@@ -73,6 +73,29 @@ impl Default for Au {
}
}
+pub static ZERO_RECT: Rect<Au> = Rect {
+ origin: Point2D {
+ x: Au(0),
+ y: Au(0),
+ },
+ size: Size2D {
+ width: Au(0),
+ height: Au(0),
+ }
+};
+
+pub static MAX_RECT: Rect<Au> = Rect {
+ origin: Point2D {
+ x: Au(i32::MIN / 2),
+ y: Au(i32::MIN / 2),
+ },
+ size: Size2D {
+ width: MAX_AU,
+ height: MAX_AU,
+ }
+};
+
+pub static MIN_AU: Au = Au(i32::MIN);
pub static MAX_AU: Au = Au(i32::MAX);
impl<E, S: Encoder<E>> Encodable<S, E> for Au {