servo: Merge #5913 - Various fixes to getClientBoundingRect() (from glennw:bounding-rect); r=pcwalton
authorGlenn Watson <gw@intuitionlibrary.com>
Fri, 01 May 2015 13:15:23 -0500
changeset 385274 3ba4c5400aed0424dbf0258f24a6b8c86837b0df
parent 385273 83c7ed4a1f92a1d55f365ee835d3cc466357e8e2
child 385275 8a4f1dbfeb2a1dd198b834bb10a8683570c79a7f
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton
servo: Merge #5913 - Various fixes to getClientBoundingRect() (from glennw:bounding-rect); r=pcwalton * Fix queries involving stacking contexts * The code was double accumulating stacking context origins. * Handle queries of inline elements. * The node addresses being compared were incorrect (CharacterData vs. Span) * Handle ScriptQuery reflows correctly. * The layout task was skipping the compute absolute positions traversal, so failed before window.onload. Source-Repo: https://github.com/servo/servo Source-Revision: 5f6a740190e1e5912d84162c92c6b79365df165a
servo/components/gfx/display_list/mod.rs
servo/components/layout/block.rs
servo/components/layout/construct.rs
servo/components/layout/context.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/fragment.rs
servo/components/layout/inline.rs
servo/components/layout/layout_task.rs
servo/components/layout/list_item.rs
servo/components/layout/traversal.rs
servo/components/script/layout_interface.rs
--- a/servo/components/gfx/display_list/mod.rs
+++ b/servo/components/gfx/display_list/mod.rs
@@ -59,17 +59,17 @@ pub mod optimizer;
 pub static BLUR_INFLATION_FACTOR: i32 = 3;
 
 /// An opaque handle to a node. The only safe operation that can be performed on this node is to
 /// compare it to another opaque handle or to another node.
 ///
 /// Because the script task's GC does not trace layout, node data cannot be safely stored in layout
 /// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for
 /// locality reasons. Using `OpaqueNode` enforces this invariant.
-#[derive(Clone, PartialEq, Copy)]
+#[derive(Clone, PartialEq, Copy, Debug)]
 pub struct OpaqueNode(pub uintptr_t);
 
 impl OpaqueNode {
     /// Returns the address of this node, for debugging purposes.
     pub fn id(&self) -> uintptr_t {
         let OpaqueNode(pointer) = *self;
         pointer
     }
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -1909,17 +1909,17 @@ impl Flow for BlockFlow {
                          &self.fragment
                               .stacking_relative_border_box(&self.base.stacking_relative_position,
                                                             &self.base
                                                                  .absolute_position_info
                                                                  .relative_containing_block_size,
                                                             self.base
                                                                 .absolute_position_info
                                                                 .relative_containing_block_mode,
-                                                            CoordinateSystem::Parent)
+                                                            CoordinateSystem::Own)
                               .translate(stacking_context_position));
     }
 
     fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
         (*mutator)(&mut self.fragment)
     }
 }
 
--- a/servo/components/layout/construct.rs
+++ b/servo/components/layout/construct.rs
@@ -26,17 +26,17 @@ use flow_ref::FlowRef;
 use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
 use fragment::CanvasFragmentInfo;
 use fragment::ImageFragmentInfo;
 use fragment::InlineAbsoluteHypotheticalFragmentInfo;
 use fragment::TableColumnFragmentInfo;
 use fragment::UnscannedTextFragmentInfo;
 use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo};
 use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
-use inline::InlineFlow;
+use inline::{InlineFlow, InlineFragmentNodeInfo};
 use list_item::{ListItemFlow, ListStyleTypeContent};
 use multicol::MulticolFlow;
 use opaque_node::OpaqueNodeMethods;
 use parallel;
 use table::TableFlow;
 use table_caption::TableCaptionFlow;
 use table_cell::TableCellFlow;
 use table_colgroup::TableColGroupFlow;
@@ -164,58 +164,60 @@ pub struct InlineBlockSplit {
 
 /// Holds inline fragments that we're gathering for children of an inline node.
 struct InlineFragmentsAccumulator {
     /// The list of fragments.
     fragments: LinkedList<Fragment>,
 
     /// Whether we've created a range to enclose all the fragments. This will be Some() if the
     /// outer node is an inline and None otherwise.
-    enclosing_style: Option<Arc<ComputedValues>>,
+    enclosing_node: Option<InlineFragmentNodeInfo>,
 }
 
 impl InlineFragmentsAccumulator {
     fn new() -> InlineFragmentsAccumulator {
         InlineFragmentsAccumulator {
             fragments: LinkedList::new(),
-            enclosing_style: None,
+            enclosing_node: None,
         }
     }
 
     fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
         let fragments = LinkedList::new();
         InlineFragmentsAccumulator {
             fragments: fragments,
-            enclosing_style: Some(node.style().clone()),
+            enclosing_node: Some(InlineFragmentNodeInfo {
+                                    address: OpaqueNodeMethods::from_thread_safe_layout_node(node),
+                                    style: node.style().clone() }),
         }
     }
 
     fn push_all(&mut self, mut fragments: LinkedList<Fragment>) {
         if fragments.len() == 0 {
             return
         }
 
         self.fragments.append(&mut fragments)
     }
 
     fn to_dlist(self) -> LinkedList<Fragment> {
         let InlineFragmentsAccumulator {
             mut fragments,
-            enclosing_style
+            enclosing_node,
         } = self;
-        if let Some(enclosing_style) = enclosing_style {
+        if let Some(enclosing_node) = enclosing_node {
             let frag_len = fragments.len();
             for (idx, frag) in fragments.iter_mut().enumerate() {
 
                 // frag is first inline fragment in the inline node
                 let is_first = idx == 0;
                 // frag is the last inline fragment in the inline node
                 let is_last = idx == frag_len - 1;
 
-                frag.add_inline_context_style(enclosing_style.clone(), is_first, is_last);
+                frag.add_inline_context_style(enclosing_node.clone(), is_first, is_last);
             }
         }
         fragments
     }
 }
 
 enum WhitespaceStrippingMode {
     None,
--- a/servo/components/layout/context.rs
+++ b/servo/components/layout/context.rs
@@ -10,17 +10,17 @@ use css::matching::{ApplicableDeclaratio
 
 use geom::{Rect, Size2D};
 use gfx::display_list::OpaqueNode;
 use gfx::font_cache_task::FontCacheTask;
 use gfx::font_context::FontContext;
 use msg::constellation_msg::ConstellationChan;
 use net_traits::image::base::Image;
 use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageState};
-use script::layout_interface::{Animation, LayoutChan};
+use script::layout_interface::{Animation, LayoutChan, ReflowGoal};
 use std::boxed;
 use std::cell::Cell;
 use std::ptr;
 use std::sync::Arc;
 use std::sync::mpsc::{channel, Sender};
 use style::selector_matching::Stylist;
 use url::Url;
 use util::geometry::Au;
@@ -93,16 +93,19 @@ pub struct SharedLayoutContext {
 
     /// Starts at zero, and increased by one every time a layout completes.
     /// This can be used to easily check for invalid stale data.
     pub generation: u32,
 
     /// A channel on which new animations that have been triggered by style recalculation can be
     /// sent.
     pub new_animations_sender: Sender<Animation>,
+
+    /// Why is this reflow occurring
+    pub goal: ReflowGoal,
 }
 
 pub struct SharedLayoutContextWrapper(pub *const SharedLayoutContext);
 
 unsafe impl Send for SharedLayoutContextWrapper {}
 
 pub struct LayoutContext<'a> {
     pub shared: &'a SharedLayoutContext,
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -862,40 +862,40 @@ impl FragmentDisplayListBuilding for Fra
         debug!("Fragment::build_display_list: intersected. Adding display item...");
 
         if self.is_primary_fragment() {
             let level =
                 StackingLevel::from_background_and_border_level(background_and_border_level);
 
             // Add shadows, background, borders, and outlines, if applicable.
             if let Some(ref inline_context) = self.inline_context {
-                for style in inline_context.styles.iter().rev() {
+                for node in inline_context.nodes.iter().rev() {
                     self.build_display_list_for_box_shadow_if_applicable(
-                        &**style,
+                        &*node.style,
                         display_list,
                         layout_context,
                         level,
                         &stacking_relative_border_box,
                         &clip);
                     self.build_display_list_for_background_if_applicable(
-                        &**style,
+                        &*node.style,
                         display_list,
                         layout_context,
                         level,
                         &stacking_relative_border_box,
                         &clip);
                     self.build_display_list_for_borders_if_applicable(
-                        &**style,
+                        &*node.style,
                         border_painting_mode,
                         display_list,
                         &stacking_relative_border_box,
                         level,
                         &clip);
                     self.build_display_list_for_outline_if_applicable(
-                        &**style,
+                        &*node.style,
                         display_list,
                         &stacking_relative_border_box,
                         &clip);
                 }
             }
             if !self.is_scanned_text_fragment() {
                 self.build_display_list_for_box_shadow_if_applicable(&*self.style,
                                                                      display_list,
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -9,17 +9,17 @@
 use canvas::canvas_msg::CanvasMsg;
 use css::node_style::StyledNode;
 use context::LayoutContext;
 use floats::ClearType;
 use flow;
 use flow::Flow;
 use flow_ref::FlowRef;
 use incremental::{self, RestyleDamage};
-use inline::{InlineFragmentContext, InlineMetrics};
+use inline::{InlineFragmentContext, InlineFragmentNodeInfo, InlineMetrics};
 use layout_debug;
 use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
 use text;
 use opaque_node::OpaqueNodeMethods;
 use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
 
 use geom::num::Zero;
 use geom::{Point2D, Rect, Size2D};
@@ -835,42 +835,47 @@ impl Fragment {
         debug_assert!(ellipsis_fragments.len() == 1);
         ellipsis_fragments.fragments.into_iter().next().unwrap()
     }
 
     pub fn restyle_damage(&self) -> RestyleDamage {
         self.restyle_damage | self.specific.restyle_damage()
     }
 
+    pub fn contains_node(&self, node_address: OpaqueNode) -> bool {
+        node_address == self.node ||
+        self.inline_context.as_ref().map_or(false, |ctx| {
+            ctx.contains_node(node_address)
+        })
+    }
+
     /// Adds a style to the inline context for this fragment. If the inline context doesn't exist
     /// yet, it will be created.
     pub fn add_inline_context_style(&mut self,
-                                    style: Arc<ComputedValues>,
+                                    mut node_info: InlineFragmentNodeInfo,
                                     first_frag: bool,
                                     last_frag: bool) {
         if self.inline_context.is_none() {
             self.inline_context = Some(InlineFragmentContext::new());
         }
-        let frag_style = if first_frag && last_frag {
-            style.clone()
-        } else {
+        if !first_frag || !last_frag {
             // Set the border width to zero and the border style to none on
             // border sides that are not the outermost for a node container.
             // Because with multiple inline fragments they don't have interior
             // borders separating each other.
-            let mut border_width = style.logical_border_width();
+            let mut border_width = node_info.style.logical_border_width();
             if !last_frag {
-                border_width.set_right(style.writing_mode, Zero::zero());
+                border_width.set_right(node_info.style.writing_mode, Zero::zero());
             }
             if !first_frag {
-                border_width.set_left(style.writing_mode, Zero::zero());
+                border_width.set_left(node_info.style.writing_mode, Zero::zero());
             }
-            Arc::new(make_border(&*style, border_width))
+            node_info.style = Arc::new(make_border(&*node_info.style, border_width))
         };
-        self.inline_context.as_mut().unwrap().styles.push(frag_style);
+        self.inline_context.as_mut().unwrap().nodes.push(node_info);
     }
 
     /// Determines which quantities (border/padding/margin/specified) should be included in the
     /// intrinsic inline size of this fragment.
     fn quantities_included_in_intrinsic_inline_size(&self)
                                                     -> QuantitiesIncludedInIntrinsicInlineSizes {
         match self.specific {
             SpecificFragmentInfo::Canvas(_) |
@@ -995,20 +1000,20 @@ impl Fragment {
         let style_border_width = match self.specific {
             SpecificFragmentInfo::ScannedText(_) => LogicalMargin::zero(self.style.writing_mode),
             _ => self.style().logical_border_width(),
         };
 
         match self.inline_context {
             None => style_border_width,
             Some(ref inline_fragment_context) => {
-                inline_fragment_context.styles
+                inline_fragment_context.nodes
                                        .iter()
                                        .fold(style_border_width,
-                                             |acc, style| acc + style.logical_border_width())
+                                             |acc, node| acc + node.style.logical_border_width())
             }
         }
     }
 
     /// Computes the margins in the inline direction from the containing block inline-size and the
     /// style. After this call, the inline direction of the `margin` field will be correct.
     ///
     /// Do not use this method if the inline direction margins are to be computed some other way
@@ -1087,20 +1092,20 @@ impl Fragment {
                         LogicalMargin::zero(self.style.writing_mode)
                     }
                     _ => model::padding_from_style(self.style(), containing_block_inline_size),
                 };
 
                 match self.inline_context {
                     None => style_padding,
                     Some(ref inline_fragment_context) => {
-                        inline_fragment_context.styles
+                        inline_fragment_context.nodes
                                                .iter()
-                                               .fold(style_padding, |acc, style| {
-                                                   acc + model::padding_from_style(&**style,
+                                               .fold(style_padding, |acc, node| {
+                                                   acc + model::padding_from_style(&*node.style,
                                                                                    Au(0))
                                                })
                     }
                 }
             }
         };
 
         self.border_padding = border + padding
@@ -1131,19 +1136,19 @@ impl Fragment {
         // Go over the ancestor fragments and add all relative offsets (if any).
         let mut rel_pos = if self.style().get_box().position == position::T::relative {
             from_style(self.style(), containing_block_size)
         } else {
             LogicalSize::zero(self.style.writing_mode)
         };
 
         if let Some(ref inline_fragment_context) = self.inline_context {
-            for style in inline_fragment_context.styles.iter() {
-                if style.get_box().position == position::T::relative {
-                    rel_pos = rel_pos + from_style(&**style, containing_block_size);
+            for node in inline_fragment_context.nodes.iter() {
+                if node.style.get_box().position == position::T::relative {
+                    rel_pos = rel_pos + from_style(&*node.style, containing_block_size);
                 }
             }
         }
 
         rel_pos
     }
 
     /// Always inline for SCCP.
@@ -1277,20 +1282,20 @@ impl Fragment {
             SpecificFragmentInfo::UnscannedText(..) => {
                 panic!("Unscanned text fragments should have been scanned by now!")
             }
         };
 
         // Take borders and padding for parent inline fragments into account, if necessary.
         if self.is_primary_fragment() {
             if let Some(ref context) = self.inline_context {
-                for style in context.styles.iter() {
-                    let border_width = style.logical_border_width().inline_start_end();
+                for node in context.nodes.iter() {
+                    let border_width = node.style.logical_border_width().inline_start_end();
                     let padding_inline_size =
-                        model::padding_from_style(&**style, Au(0)).inline_start_end();
+                        model::padding_from_style(&*node.style, Au(0)).inline_start_end();
                     result.surrounding_size = result.surrounding_size + border_width +
                         padding_inline_size;
                 }
             }
         }
 
         result
     }
@@ -2092,21 +2097,21 @@ impl<'a> Iterator for InlineStyleIterato
             self.primary_style_yielded = true;
             return Some(&*self.fragment.style)
         }
         let inline_context = match self.fragment.inline_context {
             None => return None,
             Some(ref inline_context) => inline_context,
         };
         let inline_style_index = self.inline_style_index;
-        if inline_style_index == inline_context.styles.len() {
+        if inline_style_index == inline_context.nodes.len() {
             return None
         }
         self.inline_style_index += 1;
-        Some(&*inline_context.styles[inline_style_index])
+        Some(&*inline_context.nodes[inline_style_index].style)
     }
 }
 
 impl<'a> InlineStyleIterator<'a> {
     fn new<'b>(fragment: &'b Fragment) -> InlineStyleIterator<'b> {
         InlineStyleIterator {
             fragment: fragment,
             inline_style_index: 0,
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -12,16 +12,17 @@ use flow::{self, BaseFlow, FlowClass, Fl
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
 use incremental::{REFLOW, REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT};
 use layout_debug;
 use model::IntrinsicISizesContribution;
 use text;
 
 use collections::VecDeque;
 use geom::{Point2D, Rect};
+use gfx::display_list::OpaqueNode;
 use gfx::font::FontMetrics;
 use gfx::font_context::FontContext;
 use gfx::text::glyph::CharIndex;
 use gfx::text::text_run::TextRun;
 use std::cmp::max;
 use std::fmt;
 use std::mem;
 use std::num::ToPrimitive;
@@ -1083,20 +1084,20 @@ impl InlineFlow {
         let mut block_size_above_baseline = inline_metrics.block_size_above_baseline;
         let mut depth_below_baseline = inline_metrics.depth_below_baseline;
 
         // According to CSS 2.1 ยง 10.8, `line-height` of any inline element specifies the minimal
         // height of line boxes within the element.
         for frag in self.fragments.fragments.iter() {
             match frag.inline_context {
                 Some(ref inline_context) => {
-                    for style in inline_context.styles.iter() {
-                        let font_style = style.get_font_arc();
+                    for node in inline_context.nodes.iter() {
+                        let font_style = node.style.get_font_arc();
                         let font_metrics = text::font_metrics_for_style(font_context, font_style);
-                        let line_height = text::line_height_from_style(&**style, &font_metrics);
+                        let line_height = text::line_height_from_style(&*node.style, &font_metrics);
                         let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics,
                                                                               line_height);
                         block_size_above_baseline = max(block_size_above_baseline,
                                                         inline_metrics.block_size_above_baseline);
                         depth_below_baseline = max(depth_below_baseline,
                                                    inline_metrics.depth_below_baseline);
                     }
                 }
@@ -1471,17 +1472,17 @@ impl Flow for InlineFlow {
             let relative_containing_block_size =
                 &self.base.absolute_position_info.relative_containing_block_size;
             let relative_containing_block_mode =
                 self.base.absolute_position_info.relative_containing_block_mode;
             iterator.process(fragment,
                              &fragment.stacking_relative_border_box(stacking_relative_position,
                                                                     relative_containing_block_size,
                                                                     relative_containing_block_mode,
-                                                                    CoordinateSystem::Parent)
+                                                                    CoordinateSystem::Own)
                                       .translate(stacking_context_position))
         }
     }
 
     fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
         for fragment in self.fragments.fragments.iter_mut() {
             (*mutator)(fragment)
         }
@@ -1490,33 +1491,44 @@ impl Flow for InlineFlow {
 
 impl fmt::Debug for InlineFlow {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{:?} - {:x} - {:?}", self.class(), self.base.debug_id(), self.fragments)
     }
 }
 
 #[derive(Clone)]
+pub struct InlineFragmentNodeInfo {
+    pub address: OpaqueNode,
+    pub style: Arc<ComputedValues>,
+}
+
+#[derive(Clone)]
 pub struct InlineFragmentContext {
-    pub styles: Vec<Arc<ComputedValues>>,
+    pub nodes: Vec<InlineFragmentNodeInfo>,
 }
 
 impl InlineFragmentContext {
     pub fn new() -> InlineFragmentContext {
         InlineFragmentContext {
-            styles: vec!()
+            nodes: vec!(),
         }
     }
 
+    #[inline]
+    pub fn contains_node(&self, node_address: OpaqueNode) -> bool {
+        self.nodes.iter().position(|node| node.address == node_address).is_some()
+    }
+
     fn ptr_eq(&self, other: &InlineFragmentContext) -> bool {
-        if self.styles.len() != other.styles.len() {
+        if self.nodes.len() != other.nodes.len() {
             return false
         }
-        for (this_style, other_style) in self.styles.iter().zip(other.styles.iter()) {
-            if !util::arc_ptr_eq(this_style, other_style) {
+        for (this_node, other_node) in self.nodes.iter().zip(other.nodes.iter()) {
+            if !util::arc_ptr_eq(&this_node.style, &other_node.style) {
                 return false
             }
         }
         true
     }
 }
 
 fn inline_contexts_are_equal(inline_context_a: &Option<InlineFragmentContext>,
--- a/servo/components/layout/layout_task.rs
+++ b/servo/components/layout/layout_task.rs
@@ -345,32 +345,34 @@ impl LayoutTask {
         }
     }
 
     // Create a layout context for use in building display lists, hit testing, &c.
     fn build_shared_layout_context(&self,
                                    rw_data: &LayoutTaskData,
                                    screen_size_changed: bool,
                                    reflow_root: Option<&LayoutNode>,
-                                   url: &Url)
+                                   url: &Url,
+                                   goal: ReflowGoal)
                                    -> SharedLayoutContext {
         SharedLayoutContext {
             image_cache_task: rw_data.image_cache_task.clone(),
             image_cache_sender: self.image_cache_sender.clone(),
             screen_size: rw_data.screen_size.clone(),
             screen_size_changed: screen_size_changed,
             constellation_chan: rw_data.constellation_chan.clone(),
             layout_chan: self.chan.clone(),
             font_cache_task: self.font_cache_task.clone(),
             stylist: &*rw_data.stylist,
             url: (*url).clone(),
             reflow_root: reflow_root.map(|node| OpaqueNodeMethods::from_layout_node(node)),
             dirty: Rect::zero(),
             generation: rw_data.generation,
             new_animations_sender: rw_data.new_animations_sender.clone(),
+            goal: goal,
         }
     }
 
     /// Receives and dispatches messages from the script and constellation tasks
     fn handle_request<'a>(&'a self,
                           possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>)
                           -> bool {
         enum PortToRead {
@@ -462,17 +464,18 @@ impl LayoutTask {
         let reflow_info = Reflow {
             goal: ReflowGoal::ForDisplay,
             page_clip_rect: MAX_RECT,
         };
 
         let mut layout_context = self.build_shared_layout_context(&*rw_data,
                                                                   false,
                                                                   None,
-                                                                  &self.url);
+                                                                  &self.url,
+                                                                  reflow_info.goal);
 
         self.perform_post_style_recalc_layout_passes(&reflow_info,
                                                      &mut *rw_data,
                                                      &mut layout_context);
 
 
         true
     }
@@ -746,21 +749,21 @@ impl LayoutTask {
         // FIXME(pcwalton): This has not been updated to handle the stacking context relative
         // stuff. So the position is wrong in most cases.
         let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node);
         let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node);
         sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator);
         rw_data.content_boxes_response = iterator.rects;
     }
 
-    fn build_display_list_for_reflow<'a>(&'a self,
-                                         data: &Reflow,
-                                         layout_root: &mut FlowRef,
-                                         shared_layout_context: &mut SharedLayoutContext,
-                                         rw_data: &mut LayoutTaskData) {
+    fn compute_abs_pos_and_build_display_list<'a>(&'a self,
+                                                  data: &Reflow,
+                                                  layout_root: &mut FlowRef,
+                                                  shared_layout_context: &mut SharedLayoutContext,
+                                                  rw_data: &mut LayoutTaskData) {
         let writing_mode = flow::base(&**layout_root).writing_mode;
         profile(time::ProfilerCategory::LayoutDispListBuild,
                 self.profiler_metadata(),
                 self.time_profiler_chan.clone(),
                 || {
             shared_layout_context.dirty =
                 flow::base(&**layout_root).position.to_physical(writing_mode,
                                                                      rw_data.screen_size);
@@ -768,61 +771,64 @@ impl LayoutTask {
                 LogicalPoint::zero(writing_mode).to_physical(writing_mode,
                                                              rw_data.screen_size);
 
             flow::mut_base(&mut **layout_root).clip =
                 ClippingRegion::from_rect(&data.page_clip_rect);
 
             match rw_data.parallel_traversal {
                 None => {
-                    sequential::build_display_list_for_subtree(layout_root, shared_layout_context);
+                    sequential::build_display_list_for_subtree(layout_root,
+                                                               shared_layout_context);
                 }
                 Some(ref mut traversal) => {
                     parallel::build_display_list_for_subtree(layout_root,
                                                              self.profiler_metadata(),
                                                              self.time_profiler_chan.clone(),
                                                              shared_layout_context,
                                                              traversal);
                 }
             }
 
-            debug!("Done building display list.");
+            if data.goal == ReflowGoal::ForDisplay {
+                debug!("Done building display list.");
 
-            let root_background_color = get_root_flow_background_color(&mut **layout_root);
-            let root_size = {
-                let root_flow = flow::base(&**layout_root);
-                root_flow.position.size.to_physical(root_flow.writing_mode)
-            };
-            let mut display_list = box DisplayList::new();
-            flow::mut_base(&mut **layout_root).display_list_building_result
-                                              .add_to(&mut *display_list);
-            let paint_layer = Arc::new(PaintLayer::new(layout_root.layer_id(0),
-                                                       root_background_color,
-                                                       ScrollPolicy::Scrollable));
-            let origin = Rect(Point2D(Au(0), Au(0)), root_size);
+                let root_background_color = get_root_flow_background_color(&mut **layout_root);
+                let root_size = {
+                    let root_flow = flow::base(&**layout_root);
+                    root_flow.position.size.to_physical(root_flow.writing_mode)
+                };
+                let mut display_list = box DisplayList::new();
+                flow::mut_base(&mut **layout_root).display_list_building_result
+                                                  .add_to(&mut *display_list);
+                let paint_layer = Arc::new(PaintLayer::new(layout_root.layer_id(0),
+                                                           root_background_color,
+                                                           ScrollPolicy::Scrollable));
+                let origin = Rect(Point2D(Au(0), Au(0)), root_size);
 
-            if opts::get().dump_display_list {
-                println!("#### start printing display list.");
-                display_list.print_items(String::from_str("#"));
-            }
+                if opts::get().dump_display_list {
+                    println!("#### start printing display list.");
+                    display_list.print_items(String::from_str("#"));
+                }
 
-            let stacking_context = Arc::new(StackingContext::new(display_list,
-                                                                 &origin,
-                                                                 &origin,
-                                                                 0,
-                                                                 &Matrix2D::identity(),
-                                                                 filter::T::new(Vec::new()),
-                                                                 mix_blend_mode::T::normal,
-                                                                 Some(paint_layer)));
+                let stacking_context = Arc::new(StackingContext::new(display_list,
+                                                                     &origin,
+                                                                     &origin,
+                                                                     0,
+                                                                     &Matrix2D::identity(),
+                                                                     filter::T::new(Vec::new()),
+                                                                     mix_blend_mode::T::normal,
+                                                                     Some(paint_layer)));
 
-            rw_data.stacking_context = Some(stacking_context.clone());
+                rw_data.stacking_context = Some(stacking_context.clone());
 
-            debug!("Layout done!");
+                debug!("Layout done!");
 
-            self.paint_chan.send(PaintMsg::PaintInit(stacking_context));
+                self.paint_chan.send(PaintMsg::PaintInit(stacking_context));
+            }
         });
     }
 
     /// The high-level routine that performs layout tasks.
     fn handle_reflow<'a>(&'a self,
                          data: &ScriptReflow,
                          possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) {
         // FIXME: Isolate this transmutation into a "bridge" module.
@@ -873,17 +879,18 @@ impl LayoutTask {
                 }
             }
         }
 
         // Create a layout context for use throughout the following passes.
         let mut shared_layout_context = self.build_shared_layout_context(&*rw_data,
                                                                          screen_size_changed,
                                                                          Some(&node),
-                                                                         &self.url);
+                                                                         &self.url,
+                                                                         data.reflow_info.goal);
 
         // Recalculate CSS styles and rebuild flows and fragments.
         profile(time::ProfilerCategory::LayoutStyleRecalc,
                 self.profiler_metadata(),
                 self.time_profiler_chan.clone(),
                 || {
             // Perform CSS selector matching and flow construction.
             let rw_data = &mut *rw_data;
@@ -941,17 +948,18 @@ impl LayoutTask {
             goal: ReflowGoal::ForDisplay,
             page_clip_rect: MAX_RECT,
         };
 
         // Perform an abbreviated style recalc that operates without access to the DOM.
         let mut layout_context = self.build_shared_layout_context(&*rw_data,
                                                                   false,
                                                                   None,
-                                                                  &self.url);
+                                                                  &self.url,
+                                                                  reflow_info.goal);
         let mut root_flow = (*rw_data.root_flow.as_ref().unwrap()).clone();
         profile(time::ProfilerCategory::LayoutStyleRecalc,
                 self.profiler_metadata(),
                 self.time_profiler_chan.clone(),
                 || animation::recalc_style_for_animation(root_flow.deref_mut(), &animation));
 
         self.perform_post_style_recalc_layout_passes(&reflow_info,
                                                      &mut *rw_data,
@@ -1005,26 +1013,20 @@ impl LayoutTask {
                     self.solve_constraints_parallel(rw_data,
                                                     &mut root_flow,
                                                     &mut *layout_context);
                 }
             }
         });
 
         // Build the display list if necessary, and send it to the painter.
-        match data.goal {
-            ReflowGoal::ForDisplay => {
-                self.build_display_list_for_reflow(data,
-                                                   &mut root_flow,
-                                                   &mut *layout_context,
-                                                   rw_data);
-            }
-            ReflowGoal::ForScriptQuery => {}
-        }
-
+        self.compute_abs_pos_and_build_display_list(data,
+                                                    &mut root_flow,
+                                                    &mut *layout_context,
+                                                    rw_data);
         self.first_reflow.set(false);
 
         if opts::get().trace_layout {
             layout_debug::end_trace();
         }
 
         if opts::get().dump_flow_tree {
             root_flow.dump();
@@ -1177,17 +1179,17 @@ impl FragmentBorderBoxIterator for Union
             }
             None => {
                 Some(*border_box)
             }
         };
     }
 
     fn should_process(&mut self, fragment: &Fragment) -> bool {
-        self.node_address == fragment.node
+        fragment.contains_node(self.node_address)
     }
 }
 
 struct CollectingFragmentBorderBoxIterator {
     node_address: OpaqueNode,
     rects: Vec<Rect<Au>>,
 }
 
@@ -1201,17 +1203,17 @@ impl CollectingFragmentBorderBoxIterator
 }
 
 impl FragmentBorderBoxIterator for CollectingFragmentBorderBoxIterator {
     fn process(&mut self, _: &Fragment, border_box: &Rect<Au>) {
         self.rects.push(*border_box);
     }
 
     fn should_process(&mut self, fragment: &Fragment) -> bool {
-        self.node_address == fragment.node
+        fragment.contains_node(self.node_address)
     }
 }
 
 // The default computed value for background-color is transparent (see
 // http://dev.w3.org/csswg/css-backgrounds/#background-color). However, we
 // need to propagate the background color from the root HTML/Body
 // element (http://dev.w3.org/csswg/css-backgrounds/#special-backgrounds) if
 // it is non-transparent. The phrase in the spec "If the canvas background
--- a/servo/components/layout/list_item.rs
+++ b/servo/components/layout/list_item.rs
@@ -167,17 +167,17 @@ impl Flow for ListItemFlow {
                                                          &self.block_flow
                                                               .base
                                                               .absolute_position_info
                                                               .relative_containing_block_size,
                                                          self.block_flow
                                                              .base
                                                              .absolute_position_info
                                                              .relative_containing_block_mode,
-                                                         CoordinateSystem::Parent)
+                                                         CoordinateSystem::Own)
                            .translate(stacking_context_position));
             }
         }
     }
 
     fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
         self.block_flow.mutate_fragments(mutator);
 
--- a/servo/components/layout/traversal.rs
+++ b/servo/components/layout/traversal.rs
@@ -9,16 +9,17 @@
 use css::node_style::StyledNode;
 use css::matching::{ApplicableDeclarations, MatchMethods, StyleSharingResult};
 use construct::FlowConstructor;
 use context::LayoutContext;
 use flow::{Flow, MutableFlowUtils};
 use flow::{PreorderFlowTraversal, PostorderFlowTraversal};
 use flow;
 use incremental::{self, BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage};
+use script::layout_interface::ReflowGoal;
 use wrapper::{layout_node_to_unsafe_layout_node, LayoutNode};
 use wrapper::{PostorderNodeMutTraversal, ThreadSafeLayoutNode, UnsafeLayoutNode};
 use wrapper::{PreorderDomTraversal, PostorderDomTraversal};
 
 use selectors::bloom::BloomFilter;
 use util::opts;
 use util::tid::tid;
 use style::node::TNode;
@@ -373,10 +374,14 @@ pub struct BuildDisplayList<'a> {
     pub layout_context: &'a LayoutContext<'a>,
 }
 
 impl<'a> PostorderFlowTraversal for BuildDisplayList<'a> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         flow.build_display_list(self.layout_context);
     }
+
+    #[inline]
+    fn should_process(&self, _: &mut Flow) -> bool {
+        self.layout_context.shared.goal == ReflowGoal::ForDisplay
+    }
 }
-
--- a/servo/components/script/layout_interface.rs
+++ b/servo/components/script/layout_interface.rs
@@ -83,17 +83,17 @@ pub trait LayoutRPC {
 }
 
 pub struct ContentBoxResponse(pub Rect<Au>);
 pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
 pub struct HitTestResponse(pub UntrustedNodeAddress);
 pub struct MouseOverResponse(pub Vec<UntrustedNodeAddress>);
 
 /// Why we're doing reflow.
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Copy, Debug)]
 pub enum ReflowGoal {
     /// We're reflowing in order to send a display list to the screen.
     ForDisplay,
     /// We're reflowing in order to satisfy a script query. No display list will be created.
     ForScriptQuery,
 }
 
 /// Any query to perform with this reflow.