diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/gfx/display_list/mod.rs | 205 | ||||
-rw-r--r-- | components/gfx/display_list/optimizer.rs | 31 | ||||
-rw-r--r-- | components/gfx/render_task.rs | 12 | ||||
-rw-r--r-- | components/layout/block.rs | 38 | ||||
-rw-r--r-- | components/layout/construct.rs | 1 | ||||
-rw-r--r-- | components/layout/flow.rs | 34 | ||||
-rw-r--r-- | components/layout/fragment.rs | 252 | ||||
-rw-r--r-- | components/layout/inline.rs | 49 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 90 | ||||
-rw-r--r-- | components/layout/parallel.rs | 56 | ||||
-rw-r--r-- | components/layout/traversal.rs | 8 | ||||
-rw-r--r-- | components/util/geometry.rs | 23 |
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 { |