servo: Merge #11398 - script: Keep the DOM-side viewport up to date when scrolling happens in WebRender (from pcwalton:webrender-viewport); r=glennw
authorPatrick Walton <pcwalton@mimiga.net>
Tue, 31 May 2016 20:54:29 -0500
changeset 338968 f728a22bff8d6fd27c38a952b9142db0d243005a
parent 338967 b7afa397804274b71efaf09a8745c84d2a80811c
child 338969 5e36f837a50a0ffeefba5153dc5350b60b8a8561
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglennw
servo: Merge #11398 - script: Keep the DOM-side viewport up to date when scrolling happens in WebRender (from pcwalton:webrender-viewport); r=glennw This happens asynchronously, just as it does in non-WebRender mode. This functionality is a prerequisite for doing proper display-list-based hit testing in WebRender, since it moves the scroll offsets into Servo (and, specifically, into the script thread, enabling iframe event forwarding) instead of keeping them private to WebRender. Requires servo/webrender_traits#55 and servo/webrender#277. Partially addresses #11108. r? @glennw Source-Repo: https://github.com/servo/servo Source-Revision: 27d1f182713077395426a53a9c91ec35c95887ee
servo/components/compositing/compositor.rs
servo/components/gfx/display_list/mod.rs
servo/components/gfx/paint_thread.rs
servo/components/gfx_traits/lib.rs
servo/components/layout/block.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/flex.rs
servo/components/layout/flow.rs
servo/components/layout/fragment.rs
servo/components/layout/inline.rs
servo/components/layout/layout_thread.rs
servo/components/layout/list_item.rs
servo/components/layout/multicol.rs
servo/components/layout/table.rs
servo/components/layout/table_caption.rs
servo/components/layout/table_cell.rs
servo/components/layout/table_colgroup.rs
servo/components/layout/table_row.rs
servo/components/layout/table_rowgroup.rs
servo/components/layout/table_wrapper.rs
servo/components/layout/webrender_helpers.rs
servo/components/profile/time.rs
servo/components/profile_traits/time.rs
servo/components/script/dom/window.rs
servo/components/script/layout_interface.rs
servo/components/script/script_runtime.rs
servo/components/script/script_thread.rs
servo/components/script_traits/lib.rs
servo/components/servo/Cargo.lock
servo/ports/cef/Cargo.lock
--- a/servo/components/compositing/compositor.rs
+++ b/servo/components/compositing/compositor.rs
@@ -10,17 +10,18 @@ use compositor_thread::{CompositorEventL
 use compositor_thread::{CompositorReceiver, InitialCompositorState, Msg, RenderListener};
 use delayed_composition::DelayedCompositionTimerProxy;
 use euclid::point::TypedPoint2D;
 use euclid::rect::TypedRect;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 use euclid::{Matrix4D, Point2D, Rect, Size2D};
 use gfx::paint_thread::{ChromeToPaintMsg, PaintRequest};
-use gfx_traits::{color, Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties, ScrollPolicy};
+use gfx_traits::{ScrollPolicy, StackingContextId};
+use gfx_traits::{color, Epoch, FrameTreeId, FragmentType, LayerId, LayerKind, LayerProperties};
 use gleam::gl;
 use gleam::gl::types::{GLint, GLsizei};
 use image::{DynamicImage, ImageFormat, RgbImage};
 use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
 use ipc_channel::router::ROUTER;
 use layers::geometry::{DevicePixel, LayerPixel};
 use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
 use layers::platform::surface::NativeDisplay;
@@ -30,18 +31,18 @@ use layers::scene::Scene;
 use msg::constellation_msg::{Image, PixelFormat};
 use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
 use msg::constellation_msg::{NavigationDirection, PipelineId, PipelineIndex, PipelineNamespaceId};
 use msg::constellation_msg::{WindowSizeData, WindowSizeType};
 use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
 use profile_traits::time::{self, ProfilerCategory, profile};
 use script_traits::CompositorEvent::{MouseMoveEvent, MouseButtonEvent, TouchEvent};
 use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg};
-use script_traits::{ConstellationMsg, LayoutControlMsg, MouseButton};
-use script_traits::{MouseEventType, TouchpadPressurePhase, TouchEventType, TouchId};
+use script_traits::{ConstellationMsg, LayoutControlMsg, MouseButton, MouseEventType};
+use script_traits::{StackingContextScrollState, TouchpadPressurePhase, TouchEventType, TouchId};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::collections::{HashMap, HashSet};
 use std::fs::File;
 use std::mem as std_mem;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
 use style_traits::viewport::ViewportConstraints;
 use surface_map::SurfaceMap;
@@ -86,16 +87,42 @@ impl ConvertPipelineIdFromWebRender for 
     fn from_webrender(&self) -> PipelineId {
         PipelineId {
             namespace_id: PipelineNamespaceId(self.0),
             index: PipelineIndex(self.1),
         }
     }
 }
 
+trait ConvertStackingContextFromWebRender {
+    fn from_webrender(&self) -> StackingContextId;
+}
+
+impl ConvertStackingContextFromWebRender for webrender_traits::ServoStackingContextId {
+    fn from_webrender(&self) -> StackingContextId {
+        StackingContextId::new_of_type(self.1, self.0.from_webrender())
+    }
+}
+
+trait ConvertFragmentTypeFromWebRender {
+    fn from_webrender(&self) -> FragmentType;
+}
+
+impl ConvertFragmentTypeFromWebRender for webrender_traits::FragmentType {
+    fn from_webrender(&self) -> FragmentType {
+        match *self {
+            webrender_traits::FragmentType::FragmentBody => FragmentType::FragmentBody,
+            webrender_traits::FragmentType::BeforePseudoContent => {
+                FragmentType::BeforePseudoContent
+            }
+            webrender_traits::FragmentType::AfterPseudoContent => FragmentType::AfterPseudoContent,
+        }
+    }
+}
+
 /// Holds the state when running reftests that determines when it is
 /// safe to save the output image.
 #[derive(Copy, Clone, PartialEq)]
 enum ReadyState {
     Unknown,
     WaitingForConstellationReply,
     ReadyToSaveImage,
 }
@@ -1615,21 +1642,21 @@ impl<Window: WindowMethods> IOCompositor
                             (self.viewport_zoom.get() * event.magnification)
                             .min(self.max_viewport_zoom.as_ref().map_or(MAX_ZOOM, ScaleFactor::get))
                             .max(self.min_viewport_zoom.as_ref().map_or(MIN_ZOOM, ScaleFactor::get)));
                         self.update_zoom_transform();
                     }
 
                     self.perform_updates_after_scroll();
                 }
+            }
+        }
 
-                if had_events {
-                    self.send_viewport_rects_for_all_layers();
-                }
-            }
+        if had_events {
+            self.send_viewport_rects_for_all_layers();
         }
     }
 
     /// Computes new display ports for each layer, taking the scroll position into account, and
     /// sends them to layout as necessary. This ultimately triggers a rerender of the content.
     fn send_updated_display_ports_to_layout(&mut self) {
         fn process_layer(layer: &Layer<CompositorData>,
                          window_size: &TypedSize2D<LayerPixel, f32>,
@@ -1882,19 +1909,50 @@ impl<Window: WindowMethods> IOCompositor
         }
 
         for kid in &*layer.children() {
             self.send_viewport_rect_for_layer(kid.clone());
         }
     }
 
     fn send_viewport_rects_for_all_layers(&self) {
-        match self.scene.root {
-            Some(ref root) => self.send_viewport_rect_for_layer(root.clone()),
-            None => {},
+        if opts::get().use_webrender {
+            return self.send_webrender_viewport_rects()
+        }
+
+        if let Some(ref root) = self.scene.root {
+            self.send_viewport_rect_for_layer(root.clone())
+        }
+    }
+
+    fn send_webrender_viewport_rects(&self) {
+        let mut stacking_context_scroll_states_per_pipeline = HashMap::new();
+        if let Some(ref webrender_api) = self.webrender_api {
+            for scroll_layer_state in webrender_api.get_scroll_layer_state() {
+                let stacking_context_scroll_state = StackingContextScrollState {
+                    stacking_context_id: scroll_layer_state.stacking_context_id.from_webrender(),
+                    scroll_offset: scroll_layer_state.scroll_offset,
+                };
+                let pipeline_id = scroll_layer_state.pipeline_id;
+                match stacking_context_scroll_states_per_pipeline.entry(pipeline_id) {
+                    Vacant(mut entry) => {
+                        entry.insert(vec![stacking_context_scroll_state]);
+                    }
+                    Occupied(mut entry) => entry.get_mut().push(stacking_context_scroll_state),
+                }
+            }
+
+            for (pipeline_id, stacking_context_scroll_states) in
+                    stacking_context_scroll_states_per_pipeline {
+                if let Some(pipeline) = self.pipeline(pipeline_id.from_webrender()) {
+                    let msg = LayoutControlMsg::SetStackingContextScrollStates(
+                        stacking_context_scroll_states);
+                    let _ = pipeline.layout_chan.send(msg);
+                }
+            }
         }
     }
 
     /// Returns true if any buffer requests were sent or false otherwise.
     fn send_buffer_requests_for_all_layers(&mut self) -> bool {
         if self.webrender.is_some() {
             return false;
         }
--- a/servo/components/gfx/display_list/mod.rs
+++ b/servo/components/gfx/display_list/mod.rs
@@ -17,17 +17,17 @@
 use app_units::Au;
 use azure::azure::AzFloat;
 use azure::azure_hl::Color;
 use euclid::approxeq::ApproxEq;
 use euclid::num::Zero;
 use euclid::rect::TypedRect;
 use euclid::{Matrix2D, Matrix4D, Point2D, Rect, SideOffsets2D, Size2D};
 use fnv::FnvHasher;
-use gfx_traits::{LayerId, ScrollPolicy};
+use gfx_traits::{LayerId, ScrollPolicy, StackingContextId};
 use ipc_channel::ipc::IpcSharedMemory;
 use msg::constellation_msg::PipelineId;
 use net_traits::image::base::{Image, PixelFormat};
 use paint_context::PaintContext;
 use range::Range;
 use serde::de::{self, Deserialize, Deserializer, MapVisitor, Visitor};
 use serde::ser::impls::MapIteratorVisitor;
 use serde::ser::{Serialize, Serializer};
@@ -1390,47 +1390,16 @@ impl fmt::Debug for DisplayItem {
                 DisplayItem::IframeClass(_) => "Iframe".to_owned(),
             },
             self.bounds(),
             self.base().clip
         )
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf, RustcEncodable)]
-pub enum FragmentType {
-    /// A StackingContext for the fragment body itself.
-    FragmentBody,
-    /// A StackingContext created to contain ::before pseudo-element content.
-    BeforePseudoContent,
-    /// A StackingContext created to contain ::after pseudo-element content.
-    AfterPseudoContent,
-}
-
-/// A unique ID for every stacking context.
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, PartialEq, RustcEncodable, Serialize)]
-pub struct StackingContextId(
-    /// The identifier for this StackingContext, derived from the Flow's memory address
-    /// and fragment type.  As a space optimization, these are combined into a single word.
-    usize
-);
-
-impl StackingContextId {
-    #[inline(always)]
-    pub fn new(id: usize) -> StackingContextId {
-        StackingContextId::new_of_type(id, FragmentType::FragmentBody)
-    }
-
-    #[inline(always)]
-    pub fn new_of_type(id: usize, fragment_type: FragmentType) -> StackingContextId {
-        debug_assert_eq!(id & fragment_type as usize, 0);
-        StackingContextId(id | fragment_type as usize)
-    }
-}
-
 #[derive(Copy, Clone, HeapSizeOf, Deserialize, Serialize)]
 pub struct WebRenderImageInfo {
     pub width: u32,
     pub height: u32,
     pub format: PixelFormat,
     #[ignore_heap_size_of = "WebRender traits type, and tiny"]
     pub key: Option<webrender_traits::ImageKey>,
 }
--- a/servo/components/gfx/paint_thread.rs
+++ b/servo/components/gfx/paint_thread.rs
@@ -3,23 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The thread that handles all painting.
 
 use app_units::Au;
 use azure::AzFloat;
 use azure::azure_hl::{BackendType, Color, DrawTarget, SurfaceFormat};
 use display_list::{DisplayItem, DisplayList, DisplayListTraversal};
-use display_list::{LayerInfo, StackingContext, StackingContextId, StackingContextType};
+use display_list::{LayerInfo, StackingContext, StackingContextType};
 use euclid::Matrix4D;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::size::Size2D;
 use font_cache_thread::FontCacheThread;
 use font_context::FontContext;
+use gfx_traits::StackingContextId;
 use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties, PaintListener};
 use ipc_channel::ipc::IpcSender;
 use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet};
 use layers::platform::surface::{NativeDisplay, NativeSurface};
 use msg::constellation_msg::{PanicMsg, PipelineId};
 use paint_context::PaintContext;
 use profile_traits::mem::{self, ReportsChan};
 use profile_traits::time;
--- a/servo/components/gfx_traits/lib.rs
+++ b/servo/components/gfx_traits/lib.rs
@@ -144,8 +144,63 @@ impl Epoch {
 #[derive(PartialEq, Eq, Debug, Copy, Clone)]
 pub struct FrameTreeId(pub u32);
 
 impl FrameTreeId {
     pub fn next(&mut self) {
         self.0 += 1;
     }
 }
+
+/// A unique ID for every stacking context.
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, PartialEq, Serialize)]
+pub struct StackingContextId(
+    /// The identifier for this StackingContext, derived from the Flow's memory address
+    /// and fragment type.  As a space optimization, these are combined into a single word.
+    usize
+);
+
+impl StackingContextId {
+    #[inline(always)]
+    pub fn new(id: usize) -> StackingContextId {
+        StackingContextId::new_of_type(id, FragmentType::FragmentBody)
+    }
+
+    #[inline(always)]
+    pub fn new_of_type(id: usize, fragment_type: FragmentType) -> StackingContextId {
+        debug_assert_eq!(id & fragment_type as usize, 0);
+        StackingContextId(id | fragment_type as usize)
+    }
+
+    #[inline]
+    pub fn fragment_type(&self) -> FragmentType {
+        FragmentType::from_usize(self.0 & 3)
+    }
+
+    #[inline]
+    pub fn id(&self) -> usize {
+        self.0 & !3
+    }
+}
+
+
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf)]
+pub enum FragmentType {
+    /// A StackingContext for the fragment body itself.
+    FragmentBody,
+    /// A StackingContext created to contain ::before pseudo-element content.
+    BeforePseudoContent,
+    /// A StackingContext created to contain ::after pseudo-element content.
+    AfterPseudoContent,
+}
+
+impl FragmentType {
+    #[inline]
+    pub fn from_usize(n: usize) -> FragmentType {
+        debug_assert!(n < 3);
+        match n {
+            0 => FragmentType::FragmentBody,
+            1 => FragmentType::BeforePseudoContent,
+            _ => FragmentType::AfterPseudoContent,
+        }
+    }
+}
+
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -38,18 +38,18 @@ use flow::{BLOCK_POSITION_IS_STATIC, CLE
 use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, INLINE_POSITION_IS_STATIC};
 use flow::{ImmutableFlowUtils, LateAbsolutePositionInfo, MutableFlowUtils, OpaqueFlow};
 use flow::{NEEDS_LAYER, PreorderFlowTraversal, FragmentationContext};
 use flow::{self, BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ForceNonfloatedFlag};
 use flow_list::FlowList;
 use flow_ref::FlowRef;
 use fragment::SpecificFragmentInfo;
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, HAS_LAYER, Overflow};
-use gfx::display_list::{ClippingRegion, StackingContext, StackingContextId};
-use gfx_traits::LayerId;
+use gfx::display_list::{ClippingRegion, StackingContext};
+use gfx_traits::{LayerId, StackingContextId};
 use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT};
 use layout_debug;
 use layout_thread::DISPLAY_PORT_SIZE_FACTOR;
 use model::{CollapsibleMargins, MaybeAuto, specified, specified_or_none};
 use model::{self, IntrinsicISizes, MarginCollapseInfo};
 use rustc_serialize::{Encodable, Encoder};
 use std::cmp::{max, min};
 use std::fmt;
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -16,27 +16,26 @@ use block::{BlockFlow, BlockStackingCont
 use canvas_traits::{CanvasMsg, CanvasData, FromLayoutMsg};
 use context::LayoutContext;
 use euclid::{Matrix4D, Point2D, Point3D, Rect, SideOffsets2D, Size2D};
 use flex::FlexFlow;
 use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
 use flow_ref;
 use fragment::SpecificFragmentInfo;
 use fragment::{CoordinateSystem, Fragment, HAS_LAYER, ImageFragmentInfo, ScannedTextFragmentInfo};
-use gfx::display_list::GradientDisplayItem;
 use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
 use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
-use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayListSection};
-use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem, LayeredItem, LayerInfo};
-use gfx::display_list::{LineDisplayItem, OpaqueNode, SolidColorDisplayItem};
-use gfx::display_list::{StackingContext, StackingContextId, StackingContextType};
+use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayListSection, GradientDisplayItem};
+use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGLDisplayItem};
+use gfx::display_list::{LayeredItem, LayerInfo, LineDisplayItem, OpaqueNode};
+use gfx::display_list::{SolidColorDisplayItem, StackingContext, StackingContextType};
 use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo};
 use gfx::paint_thread::THREAD_TINT_COLORS;
 use gfx::text::glyph::ByteIndex;
-use gfx_traits::{color, ScrollPolicy};
+use gfx_traits::{color, ScrollPolicy, StackingContextId};
 use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
 use ipc_channel::ipc;
 use list_item::ListItemFlow;
 use model::{self, MaybeAuto, ToGfxMatrix};
 use net_traits::image::base::PixelFormat;
 use net_traits::image_cache_thread::UsePlaceholder;
 use range::Range;
 use std::default::Default;
--- a/servo/components/layout/flex.rs
+++ b/servo/components/layout/flex.rs
@@ -12,17 +12,18 @@ use context::LayoutContext;
 use display_list_builder::{DisplayListBuildState, FlexFlowDisplayListBuilding};
 use euclid::Point2D;
 use floats::FloatKind;
 use flow;
 use flow::{Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED};
 use flow_ref::{self, FlowRef};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
 use layout_debug;
 use model::{IntrinsicISizes, MaybeAuto, MinMaxConstraint};
 use std::cmp::max;
 use std::sync::Arc;
 use style::computed_values::flex_direction;
 use style::logical_geometry::LogicalSize;
 use style::properties::{ComputedValues, ServoComputedValues};
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -29,18 +29,18 @@ use app_units::Au;
 use block::{BlockFlow, FormattingContextType};
 use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::{Point2D, Rect, Size2D};
 use floats::{Floats, SpeculatedFloatPlacement};
 use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
 use flow_ref::{self, FlowRef, WeakFlowRef};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
-use gfx::display_list::{ClippingRegion, StackingContext, StackingContextId};
-use gfx_traits::{LayerId, LayerType};
+use gfx::display_list::{ClippingRegion, StackingContext};
+use gfx_traits::{LayerId, LayerType, StackingContextId};
 use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
 use inline::InlineFlow;
 use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
 use multicol::MulticolFlow;
 use parallel::FlowParallelInfo;
 use rustc_serialize::{Encodable, Encoder};
 use std::iter::Zip;
 use std::slice::IterMut;
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -9,20 +9,20 @@
 use app_units::Au;
 use canvas_traits::CanvasMsg;
 use context::LayoutContext;
 use euclid::{Point2D, Rect, Size2D};
 use floats::ClearType;
 use flow::{self, ImmutableFlowUtils};
 use flow_ref::{self, FlowRef};
 use gfx;
-use gfx::display_list::{BLUR_INFLATION_FACTOR, FragmentType, OpaqueNode, StackingContextId};
+use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode};
 use gfx::text::glyph::ByteIndex;
 use gfx::text::text_run::{TextRun, TextRunSlice};
-use gfx_traits::{LayerId, LayerType};
+use gfx_traits::{FragmentType, LayerId, LayerType, StackingContextId};
 use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
 use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFragmentContext, InlineFragmentNodeInfo};
 use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT};
 use ipc_channel::ipc::IpcSender;
 use layout_debug;
 use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
 use msg::constellation_msg::PipelineId;
 use net_traits::image::base::{Image, ImageMetadata};
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -12,19 +12,20 @@ use display_list_builder::{FragmentDispl
 use euclid::{Point2D, Size2D};
 use floats::{FloatKind, Floats, PlacementInfo};
 use flow::OpaqueFlow;
 use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, EarlyAbsolutePositionInfo, MutableFlowUtils};
 use flow::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED};
 use flow_ref;
 use fragment::SpecificFragmentInfo;
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{OpaqueNode, StackingContext, StackingContextId};
+use gfx::display_list::{OpaqueNode, StackingContext};
 use gfx::font::FontMetrics;
 use gfx::font_context::FontContext;
+use gfx_traits::StackingContextId;
 use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RESOLVE_GENERATED_CONTENT};
 use layout_debug;
 use model::IntrinsicISizesContribution;
 use range::{Range, RangeIndex};
 use std::cmp::max;
 use std::collections::VecDeque;
 use std::sync::Arc;
 use std::{fmt, i32, isize, mem};
--- a/servo/components/layout/layout_thread.rs
+++ b/servo/components/layout/layout_thread.rs
@@ -16,24 +16,23 @@ use display_list_builder::ToGfxColor;
 use euclid::Matrix4D;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::scale_factor::ScaleFactor;
 use euclid::size::Size2D;
 use flow::{self, Flow, ImmutableFlowUtils, MutableOwnedFlowUtils};
 use flow_ref::{self, FlowRef};
 use fnv::FnvHasher;
-use gfx::display_list::WebRenderImageInfo;
 use gfx::display_list::{ClippingRegion, DisplayItemMetadata, DisplayList, LayerInfo};
-use gfx::display_list::{OpaqueNode, StackingContext, StackingContextId, StackingContextType};
+use gfx::display_list::{OpaqueNode, StackingContext, StackingContextType, WebRenderImageInfo};
 use gfx::font;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::font_context;
 use gfx::paint_thread::LayoutToPaintMsg;
-use gfx_traits::{color, Epoch, LayerId, ScrollPolicy};
+use gfx_traits::{color, Epoch, LayerId, ScrollPolicy, StackingContextId};
 use heapsize::HeapSizeOf;
 use incremental::LayoutDamageComputation;
 use incremental::{REPAINT, STORE_OVERFLOW, REFLOW_OUT_OF_FLOW, REFLOW, REFLOW_ENTIRE_DOCUMENT};
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
 use layout_debug;
 use layout_traits::LayoutThreadFactory;
 use log;
@@ -47,18 +46,18 @@ use profile_traits::time::{self, TimerMe
 use query::process_offset_parent_query;
 use query::{LayoutRPCImpl, process_content_box_request, process_content_boxes_request};
 use query::{process_node_geometry_request, process_node_layer_id_request, process_node_scroll_area_request};
 use query::{process_node_overflow_request, process_resolved_style_request, process_margin_style_query};
 use script::dom::node::OpaqueStyleAndLayoutData;
 use script::layout_interface::{LayoutRPC, OffsetParentResponse, NodeOverflowResponse, MarginStyleResponse};
 use script::layout_interface::{Msg, NewLayoutThreadInfo, Reflow, ReflowQueryType, ScriptReflow};
 use script::reporter::CSSErrorReporter;
-use script_traits::ConstellationControlMsg;
-use script_traits::{LayoutControlMsg, LayoutMsg as ConstellationMsg};
+use script_traits::StackingContextScrollState;
+use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
 use sequential;
 use serde_json;
 use std::borrow::ToOwned;
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use std::ops::{Deref, DerefMut};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::mpsc::{channel, Sender, Receiver};
@@ -554,16 +553,21 @@ impl LayoutThread {
             }
         };
 
         match request {
             Request::FromPipeline(LayoutControlMsg::SetVisibleRects(new_visible_rects)) => {
                 self.handle_request_helper(Msg::SetVisibleRects(new_visible_rects),
                                            possibly_locked_rw_data)
             },
+            Request::FromPipeline(LayoutControlMsg::SetStackingContextScrollStates(
+                    new_scroll_states)) => {
+                self.handle_request_helper(Msg::SetStackingContextScrollStates(new_scroll_states),
+                                           possibly_locked_rw_data)
+            },
             Request::FromPipeline(LayoutControlMsg::TickAnimations) => {
                 self.handle_request_helper(Msg::TickAnimations, possibly_locked_rw_data)
             },
             Request::FromPipeline(LayoutControlMsg::GetCurrentEpoch(sender)) => {
                 self.handle_request_helper(Msg::GetCurrentEpoch(sender), possibly_locked_rw_data)
             },
             Request::FromPipeline(LayoutControlMsg::GetWebFontLoadState(sender)) => {
                 self.handle_request_helper(Msg::GetWebFontLoadState(sender),
@@ -639,16 +643,20 @@ impl LayoutThread {
             },
             Msg::TickAnimations => self.tick_all_animations(possibly_locked_rw_data),
             Msg::ReflowWithNewlyLoadedWebFont => {
                 self.reflow_with_newly_loaded_web_font(possibly_locked_rw_data)
             }
             Msg::SetVisibleRects(new_visible_rects) => {
                 self.set_visible_rects(new_visible_rects, possibly_locked_rw_data);
             }
+            Msg::SetStackingContextScrollStates(new_scroll_states) => {
+                self.set_stacking_context_scroll_states(new_scroll_states,
+                                                        possibly_locked_rw_data);
+            }
             Msg::ReapStyleAndLayoutData(dead_data) => {
                 unsafe {
                     self.handle_reap_style_and_layout_data(dead_data)
                 }
             }
             Msg::CollectReports(reports_chan) => {
                 self.collect_reports(reports_chan, possibly_locked_rw_data);
             },
@@ -878,29 +886,28 @@ impl LayoutThread {
                 LogicalPoint::zero(writing_mode).to_physical(writing_mode,
                                                              self.viewport_size);
 
             flow::mut_base(flow_ref::deref_mut(layout_root)).clip =
                 ClippingRegion::from_rect(&data.page_clip_rect);
 
             if flow::base(&**layout_root).restyle_damage.contains(REPAINT) ||
                     rw_data.display_list.is_none() {
-                let mut root_stacking_context =
-                    StackingContext::new(StackingContextId::new(0),
-                                         StackingContextType::Real,
-                                         &Rect::zero(),
-                                         &Rect::zero(),
-                                         0,
-                                         filter::T::new(Vec::new()),
-                                         mix_blend_mode::T::normal,
-                                         Matrix4D::identity(),
-                                         Matrix4D::identity(),
-                                         true,
-                                         false,
-                                         None);
+                let mut root_stacking_context = StackingContext::new(StackingContextId::new(0),
+                                                                     StackingContextType::Real,
+                                                                     &Rect::zero(),
+                                                                     &Rect::zero(),
+                                                                     0,
+                                                                     filter::T::new(Vec::new()),
+                                                                     mix_blend_mode::T::normal,
+                                                                     Matrix4D::identity(),
+                                                                     Matrix4D::identity(),
+                                                                     true,
+                                                                     false,
+                                                                     None);
 
                 let display_list_entries =
                     sequential::build_display_list_for_subtree(layout_root,
                                                                &mut root_stacking_context,
                                                                shared_layout_context);
 
                 debug!("Done building display list.");
 
@@ -1259,16 +1266,29 @@ impl LayoutThread {
         let mut layout_context = self.build_shared_layout_context(&*rw_data,
                                                                   false,
                                                                   reflow_info.goal);
 
         self.perform_post_main_layout_passes(&reflow_info, &mut *rw_data, &mut layout_context);
         true
     }
 
+    fn set_stacking_context_scroll_states<'a, 'b>(
+            &mut self,
+            new_scroll_states: Vec<StackingContextScrollState>,
+            _: &mut RwData<'a, 'b>) {
+        for new_scroll_state in &new_scroll_states {
+            if self.root_flow.is_some() && new_scroll_state.stacking_context_id.id() == 0 {
+                let _ = self.script_chan.send(ConstellationControlMsg::SetScrollState(
+                        self.id,
+                        new_scroll_state.scroll_offset));
+            }
+        }
+    }
+
     fn tick_all_animations<'a, 'b>(&mut self, possibly_locked_rw_data: &mut RwData<'a, 'b>) {
         let mut rw_data = possibly_locked_rw_data.lock();
         self.tick_animations(&mut rw_data);
     }
 
     pub fn tick_animations(&mut self, rw_data: &mut LayoutThreadData) {
         let reflow_info = Reflow {
             goal: ReflowGoal::ForDisplay,
--- a/servo/components/layout/list_item.rs
+++ b/servo/components/layout/list_item.rs
@@ -12,17 +12,18 @@ use block::BlockFlow;
 use context::LayoutContext;
 use display_list_builder::{DisplayListBuildState, ListItemFlowDisplayListBuilding};
 use euclid::Point2D;
 use floats::FloatKind;
 use flow::{Flow, FlowClass, OpaqueFlow};
 use fragment::Overflow;
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo};
 use generated_content;
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use incremental::RESOLVE_GENERATED_CONTENT;
 use inline::InlineMetrics;
 use std::sync::Arc;
 use style::computed_values::{list_style_type, position};
 use style::logical_geometry::LogicalSize;
 use style::properties::{ComputedValues, ServoComputedValues};
 use text;
 
--- a/servo/components/layout/multicol.rs
+++ b/servo/components/layout/multicol.rs
@@ -10,17 +10,18 @@ use app_units::Au;
 use block::BlockFlow;
 use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use floats::FloatKind;
 use flow::{Flow, FlowClass, OpaqueFlow, mut_base, FragmentationContext};
 use flow_ref::{self, FlowRef};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use std::cmp::{min, max};
 use std::fmt;
 use std::sync::Arc;
 use style::context::StyleContext;
 use style::logical_geometry::LogicalSize;
 use style::properties::{ComputedValues, ServoComputedValues};
 use style::values::computed::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
 use util::print_tree::PrintTree;
--- a/servo/components/layout/table.rs
+++ b/servo/components/layout/table.rs
@@ -11,17 +11,18 @@ use block::{BlockFlow, CandidateBSizeIte
 use block::{ISizeConstraintInput, ISizeConstraintSolution};
 use context::LayoutContext;
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::Point2D;
 use flow;
 use flow::{BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow_list::MutFlowListIterator;
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
 use layout_debug;
 use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
 use std::cmp;
 use std::fmt;
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_spacing, table_layout};
 use style::logical_geometry::LogicalSize;
--- a/servo/components/layout/table_caption.rs
+++ b/servo/components/layout/table_caption.rs
@@ -8,17 +8,18 @@
 
 use app_units::Au;
 use block::BlockFlow;
 use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use flow::{Flow, FlowClass, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use std::fmt;
 use std::sync::Arc;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 use util::print_tree::PrintTree;
 
 /// A table formatting context.
 pub struct TableCaptionFlow {
--- a/servo/components/layout/table_cell.rs
+++ b/servo/components/layout/table_cell.rs
@@ -9,17 +9,18 @@
 use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
 use context::LayoutContext;
 use cssparser::Color;
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
 use flow::{self, Flow, FlowClass, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use incremental::REFLOW;
 use layout_debug;
 use model::MaybeAuto;
 use std::fmt;
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_top_style, vertical_align};
 use style::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
 use style::properties::{ComputedValues, ServoComputedValues};
--- a/servo/components/layout/table_colgroup.rs
+++ b/servo/components/layout/table_colgroup.rs
@@ -7,17 +7,18 @@
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use flow::{BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use layout_debug;
 use std::cmp::max;
 use std::fmt;
 use std::sync::Arc;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 use style::values::computed::LengthOrPercentageOrAuto;
 
--- a/servo/components/layout/table_row.rs
+++ b/servo/components/layout/table_row.rs
@@ -10,17 +10,18 @@ use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer};
 use context::LayoutContext;
 use cssparser::{Color, RGBA};
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::Point2D;
 use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow_list::MutFlowListIterator;
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use layout_debug;
 use model::MaybeAuto;
 use rustc_serialize::{Encodable, Encoder};
 use std::cmp::max;
 use std::fmt;
 use std::iter::{Enumerate, IntoIterator, Peekable};
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_spacing, border_top_style};
--- a/servo/components/layout/table_rowgroup.rs
+++ b/servo/components/layout/table_rowgroup.rs
@@ -8,17 +8,18 @@
 
 use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer};
 use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use flow::{Flow, FlowClass, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use layout_debug;
 use rustc_serialize::{Encodable, Encoder};
 use std::fmt;
 use std::iter::{IntoIterator, Iterator, Peekable};
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_spacing};
 use style::logical_geometry::{LogicalSize, WritingMode};
 use style::properties::{ComputedValues, ServoComputedValues};
--- a/servo/components/layout/table_wrapper.rs
+++ b/servo/components/layout/table_wrapper.rs
@@ -17,17 +17,18 @@ use app_units::Au;
 use block::{AbsoluteNonReplaced, BlockFlow, FloatNonReplaced, ISizeAndMarginsComputer, ISizeConstraintInput};
 use block::{ISizeConstraintSolution, MarginsMayCollapseFlag};
 use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use floats::FloatKind;
 use flow::{Flow, FlowClass, ImmutableFlowUtils, INLINE_POSITION_IS_STATIC, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
-use gfx::display_list::{StackingContext, StackingContextId};
+use gfx::display_list::StackingContext;
+use gfx_traits::StackingContextId;
 use model::MaybeAuto;
 use std::cmp::{max, min};
 use std::fmt;
 use std::ops::Add;
 use std::sync::Arc;
 use style::computed_values::{border_collapse, table_layout};
 use style::logical_geometry::LogicalSize;
 use style::properties::{ComputedValues, ServoComputedValues};
--- a/servo/components/layout/webrender_helpers.rs
+++ b/servo/components/layout/webrender_helpers.rs
@@ -6,23 +6,23 @@
 //           into WebRender display lists. In the future, this step should be completely removed.
 //           This might be achieved by sharing types between WR and Servo display lists, or
 //           completely converting layout to directly generate WebRender display lists, for example.
 
 use app_units::Au;
 use azure::azure_hl::Color;
 use euclid::{Point2D, Rect, Size2D};
 use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion};
-use gfx::display_list::{DisplayItem, DisplayList};
-use gfx::display_list::{DisplayListTraversal, GradientStop, StackingContext, StackingContextType};
-use gfx_traits::ScrollPolicy;
+use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal};
+use gfx::display_list::{GradientStop, StackingContext, StackingContextType};
+use gfx_traits::{FragmentType, ScrollPolicy, StackingContextId};
 use style::computed_values::filter::{self, Filter};
 use style::computed_values::{image_rendering, mix_blend_mode};
 use style::values::computed::BorderStyle;
-use webrender_traits::{self, AuxiliaryListsBuilder, DisplayListId, PipelineId, StackingContextId};
+use webrender_traits::{self, AuxiliaryListsBuilder, DisplayListId, PipelineId};
 
 trait WebRenderStackingContextConverter {
     fn convert_to_webrender<'a>(&self,
                                 traversal: &mut DisplayListTraversal<'a>,
                                 api: &mut webrender_traits::RenderApi,
                                 pipeline_id: webrender_traits::PipelineId,
                                 epoch: webrender_traits::Epoch,
                                 scroll_layer_id: Option<webrender_traits::ScrollLayerId>,
@@ -310,18 +310,21 @@ impl WebRenderStackingContextConverter f
             scroll_policy = layer_info.scroll_policy
         }
 
         let webrender_scroll_policy = match scroll_policy {
             ScrollPolicy::Scrollable => webrender_traits::ScrollPolicy::Scrollable,
             ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed,
         };
 
+        let webrender_stacking_context_id = self.id.convert_to_webrender();
+
         let mut sc =
-            webrender_traits::StackingContext::new(scroll_layer_id,
+            webrender_traits::StackingContext::new(webrender_stacking_context_id,
+                                                   scroll_layer_id,
                                                    webrender_scroll_policy,
                                                    self.bounds.to_rectf(),
                                                    self.overflow.to_rectf(),
                                                    self.z_index,
                                                    &self.transform,
                                                    &self.perspective,
                                                    self.establishes_3d_context,
                                                    self.blend_mode.to_blend_mode(),
@@ -509,17 +512,18 @@ impl WebRenderDisplayItemConverter for D
                                     item.base.clip.to_clip_region(frame_builder),
                                     pipeline_id);
             }
         }
     }
 }
 
 pub struct WebRenderFrameBuilder {
-    pub stacking_contexts: Vec<(StackingContextId, webrender_traits::StackingContext)>,
+    pub stacking_contexts: Vec<(webrender_traits::StackingContextId,
+                                webrender_traits::StackingContext)>,
     pub display_lists: Vec<(DisplayListId, webrender_traits::BuiltDisplayList)>,
     pub auxiliary_lists_builder: AuxiliaryListsBuilder,
     pub root_pipeline_id: PipelineId,
     pub next_scroll_layer_id: usize,
 }
 
 impl WebRenderFrameBuilder {
     pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
@@ -531,17 +535,17 @@ impl WebRenderFrameBuilder {
             next_scroll_layer_id: 0,
         }
     }
 
     pub fn add_stacking_context(&mut self,
                                 api: &mut webrender_traits::RenderApi,
                                 pipeline_id: PipelineId,
                                 stacking_context: webrender_traits::StackingContext)
-                                -> StackingContextId {
+                                -> webrender_traits::StackingContextId {
         assert!(pipeline_id == self.root_pipeline_id);
         let id = api.next_stacking_context_id();
         self.stacking_contexts.push((id, stacking_context));
         id
     }
 
     pub fn add_display_list(&mut self,
                             api: &mut webrender_traits::RenderApi,
@@ -556,10 +560,37 @@ impl WebRenderFrameBuilder {
         id
     }
 
     pub fn next_scroll_layer_id(&mut self) -> webrender_traits::ScrollLayerId {
         let scroll_layer_id = self.next_scroll_layer_id;
         self.next_scroll_layer_id += 1;
         webrender_traits::ScrollLayerId::new(self.root_pipeline_id, scroll_layer_id)
     }
+}
 
+trait WebRenderStackingContextIdConverter {
+    fn convert_to_webrender(&self) -> webrender_traits::ServoStackingContextId;
 }
+
+impl WebRenderStackingContextIdConverter for StackingContextId {
+    fn convert_to_webrender(&self) -> webrender_traits::ServoStackingContextId {
+        webrender_traits::ServoStackingContextId(self.fragment_type().convert_to_webrender(),
+                                                 self.id())
+    }
+}
+
+trait WebRenderFragmentTypeConverter {
+    fn convert_to_webrender(&self) -> webrender_traits::FragmentType;
+}
+
+impl WebRenderFragmentTypeConverter for FragmentType {
+    fn convert_to_webrender(&self) -> webrender_traits::FragmentType {
+        match *self {
+            FragmentType::FragmentBody => webrender_traits::FragmentType::FragmentBody,
+            FragmentType::BeforePseudoContent => {
+                webrender_traits::FragmentType::BeforePseudoContent
+            }
+            FragmentType::AfterPseudoContent => webrender_traits::FragmentType::AfterPseudoContent,
+        }
+    }
+}
+
--- a/servo/components/profile/time.rs
+++ b/servo/components/profile/time.rs
@@ -138,16 +138,17 @@ impl Formattable for ProfilerCategory {
             ProfilerCategory::ScriptImageCacheMsg => "Script Image Cache Msg",
             ProfilerCategory::ScriptInputEvent => "Script Input Event",
             ProfilerCategory::ScriptNetworkEvent => "Script Network Event",
             ProfilerCategory::ScriptParseHTML => "Script Parse HTML",
             ProfilerCategory::ScriptPlannedNavigation => "Script Planned Navigation",
             ProfilerCategory::ScriptResize => "Script Resize",
             ProfilerCategory::ScriptEvent => "Script Event",
             ProfilerCategory::ScriptUpdateReplacedElement => "Script Update Replaced Element",
+            ProfilerCategory::ScriptSetScrollState => "Script Set Scroll State",
             ProfilerCategory::ScriptSetViewport => "Script Set Viewport",
             ProfilerCategory::ScriptTimerEvent => "Script Timer Event",
             ProfilerCategory::ScriptStylesheetLoad => "Script Stylesheet Load",
             ProfilerCategory::ScriptWebSocketEvent => "Script Web Socket Event",
             ProfilerCategory::ScriptWorkerEvent => "Script Worker Event",
             ProfilerCategory::ApplicationHeartbeat => "Application Heartbeat",
         };
         format!("{}{}", padding, name)
--- a/servo/components/profile_traits/time.rs
+++ b/servo/components/profile_traits/time.rs
@@ -68,16 +68,17 @@ pub enum ProfilerCategory {
     ScriptEvent,
     ScriptFileRead,
     ScriptImageCacheMsg,
     ScriptInputEvent,
     ScriptNetworkEvent,
     ScriptParseHTML,
     ScriptPlannedNavigation,
     ScriptResize,
+    ScriptSetScrollState,
     ScriptSetViewport,
     ScriptTimerEvent,
     ScriptStylesheetLoad,
     ScriptUpdateReplacedElement,
     ScriptWebSocketEvent,
     ScriptWorkerEvent,
     ApplicationHeartbeat,
 }
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -990,23 +990,28 @@ impl Window {
                     true
                 })
             }
             ScrollBehavior::Instant => false,
             ScrollBehavior::Smooth => true
         };
 
         // TODO (farodin91): Raise an event to stop the current_viewport
-        let size = self.current_viewport.get().size;
-        self.current_viewport.set(Rect::new(Point2D::new(Au::from_f32_px(x), Au::from_f32_px(y)), size));
+        self.update_viewport_for_scroll(x, y);
 
         let message = ConstellationMsg::ScrollFragmentPoint(self.pipeline(), layer_id, point, smooth);
         self.constellation_chan.send(message).unwrap();
     }
 
+    pub fn update_viewport_for_scroll(&self, x: f32, y: f32) {
+        let size = self.current_viewport.get().size;
+        let new_viewport = Rect::new(Point2D::new(Au::from_f32_px(x), Au::from_f32_px(y)), size);
+        self.current_viewport.set(new_viewport)
+    }
+
     pub fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
         let (send, recv) = ipc::channel::<(Size2D<u32>, Point2D<i32>)>().unwrap();
         self.constellation_chan.send(ConstellationMsg::GetClientWindow(send)).unwrap();
         recv.recv().unwrap_or((Size2D::zero(), Point2D::zero()))
     }
 
     /// Reflows the page unconditionally if possible and not suppressed. This
     /// method will wait for the layout thread to complete (but see the `TODO`
--- a/servo/components/script/layout_interface.rs
+++ b/servo/components/script/layout_interface.rs
@@ -10,18 +10,18 @@ use app_units::Au;
 use dom::node::OpaqueStyleAndLayoutData;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use gfx_traits::{Epoch, LayerId};
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
 use msg::constellation_msg::{PanicMsg, PipelineId, WindowSizeData};
 use net_traits::image_cache_thread::ImageCacheThread;
 use profile_traits::mem::ReportsChan;
-use script_traits::UntrustedNodeAddress;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
+use script_traits::{StackingContextScrollState, UntrustedNodeAddress};
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender};
 use string_cache::Atom;
 use style::context::ReflowGoal;
 use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left, overflow_x};
 use style::selector_impl::PseudoElement;
 use style::servo::Stylesheet;
 use url::Url;
@@ -80,16 +80,19 @@ pub enum Msg {
 
     /// Creates a new layout thread.
     ///
     /// This basically exists to keep the script-layout dependency one-way.
     CreateLayoutThread(NewLayoutThreadInfo),
 
     /// Set the final Url.
     SetFinalUrl(Url),
+
+    /// Tells layout about the new scrolling offsets of each scrollable stacking context.
+    SetStackingContextScrollStates(Vec<StackingContextScrollState>),
 }
 
 /// Synchronous messages that script can send to layout.
 ///
 /// In general, you should use messages to talk to Layout. Use the RPC interface
 /// if and only if the work is
 ///
 ///   1) read-only with respect to LayoutThreadData,
--- a/servo/components/script/script_runtime.rs
+++ b/servo/components/script/script_runtime.rs
@@ -57,16 +57,17 @@ pub enum ScriptThreadEventCategory {
     DomEvent,
     FileRead,
     FormPlannedNavigation,
     ImageCacheMsg,
     InputEvent,
     NetworkEvent,
     Resize,
     ScriptEvent,
+    SetScrollState,
     SetViewport,
     StylesheetLoad,
     TimerEvent,
     UpdateReplacedElement,
     WebSocketEvent,
     WorkerEvent,
 }
 
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -703,16 +703,21 @@ impl ScriptThread {
                         self.handle_resize(id, size, size_type);
                     })
                 }
                 FromConstellation(ConstellationControlMsg::Viewport(id, rect)) => {
                     self.profile_event(ScriptThreadEventCategory::SetViewport, || {
                         self.handle_viewport(id, rect);
                     })
                 }
+                FromConstellation(ConstellationControlMsg::SetScrollState(id, scroll_offset)) => {
+                    self.profile_event(ScriptThreadEventCategory::SetScrollState, || {
+                        self.handle_set_scroll_state(id, &scroll_offset);
+                    })
+                }
                 FromConstellation(ConstellationControlMsg::TickAllAnimations(
                         pipeline_id)) => {
                     if !animation_ticks.contains(&pipeline_id) {
                         animation_ticks.insert(pipeline_id);
                         sequential.push(event);
                     }
                 }
                 FromConstellation(ConstellationControlMsg::SendEvent(
@@ -845,16 +850,19 @@ impl ScriptThread {
                 ScriptThreadEventCategory::DomEvent => ProfilerCategory::ScriptDomEvent,
                 ScriptThreadEventCategory::FileRead => ProfilerCategory::ScriptFileRead,
                 ScriptThreadEventCategory::FormPlannedNavigation => ProfilerCategory::ScriptPlannedNavigation,
                 ScriptThreadEventCategory::ImageCacheMsg => ProfilerCategory::ScriptImageCacheMsg,
                 ScriptThreadEventCategory::InputEvent => ProfilerCategory::ScriptInputEvent,
                 ScriptThreadEventCategory::NetworkEvent => ProfilerCategory::ScriptNetworkEvent,
                 ScriptThreadEventCategory::Resize => ProfilerCategory::ScriptResize,
                 ScriptThreadEventCategory::ScriptEvent => ProfilerCategory::ScriptEvent,
+                ScriptThreadEventCategory::SetScrollState => {
+                    ProfilerCategory::ScriptSetScrollState
+                }
                 ScriptThreadEventCategory::UpdateReplacedElement => {
                     ProfilerCategory::ScriptUpdateReplacedElement
                 }
                 ScriptThreadEventCategory::StylesheetLoad => ProfilerCategory::ScriptStylesheetLoad,
                 ScriptThreadEventCategory::SetViewport => ProfilerCategory::ScriptSetViewport,
                 ScriptThreadEventCategory::TimerEvent => ProfilerCategory::ScriptTimerEvent,
                 ScriptThreadEventCategory::WebSocketEvent => ProfilerCategory::ScriptWebSocketEvent,
                 ScriptThreadEventCategory::WorkerEvent => ProfilerCategory::ScriptWorkerEvent,
@@ -872,16 +880,18 @@ impl ScriptThread {
             ConstellationControlMsg::Navigate(pipeline_id, subpage_id, load_data) =>
                 self.handle_navigate(pipeline_id, Some(subpage_id), load_data),
             ConstellationControlMsg::SendEvent(id, event) =>
                 self.handle_event(id, event),
             ConstellationControlMsg::ResizeInactive(id, new_size) =>
                 self.handle_resize_inactive_msg(id, new_size),
             ConstellationControlMsg::Viewport(..) =>
                 panic!("should have handled Viewport already"),
+            ConstellationControlMsg::SetScrollState(..) =>
+                panic!("should have handled SetScrollState already"),
             ConstellationControlMsg::Resize(..) =>
                 panic!("should have handled Resize already"),
             ConstellationControlMsg::ExitPipeline(..) =>
                 panic!("should have handled ExitPipeline already"),
             ConstellationControlMsg::GetTitle(pipeline_id) =>
                 self.handle_get_title_msg(pipeline_id),
             ConstellationControlMsg::Freeze(pipeline_id) =>
                 self.handle_freeze_msg(pipeline_id),
@@ -1072,16 +1082,29 @@ impl ScriptThread {
         let mut loads = self.incomplete_loads.borrow_mut();
         if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) {
             load.clip_rect = Some(rect);
             return;
         }
         panic!("Page rect message sent to nonexistent pipeline");
     }
 
+    fn handle_set_scroll_state(&self, id: PipelineId, scroll_state: &Point2D<f32>) {
+        let context = self.browsing_context.get();
+        if let Some(context) = context {
+            if let Some(inner_context) = context.find(id) {
+                let window = inner_context.active_window();
+                window.update_viewport_for_scroll(-scroll_state.x, -scroll_state.y);
+                return
+            }
+        }
+
+        panic!("Set scroll state message message sent to nonexistent pipeline: {:?}", id);
+    }
+
     fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
         let NewLayoutInfo {
             containing_pipeline_id,
             new_pipeline_id,
             subpage_id,
             load_data,
             paint_chan,
             panic_chan,
--- a/servo/components/script_traits/lib.rs
+++ b/servo/components/script_traits/lib.rs
@@ -34,16 +34,17 @@ mod script_msg;
 use app_units::Au;
 use devtools_traits::ScriptToDevtoolsControlMsg;
 use euclid::Size2D;
 use euclid::length::Length;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use gfx_traits::Epoch;
 use gfx_traits::LayerId;
+use gfx_traits::StackingContextId;
 use ipc_channel::ipc::{IpcReceiver, IpcSender};
 use libc::c_void;
 use msg::constellation_msg::{FrameId, FrameType, Key, KeyModifiers, KeyState, LoadData};
 use msg::constellation_msg::{NavigationDirection, PanicMsg, PipelineId};
 use msg::constellation_msg::{PipelineNamespaceId, SubpageId, WindowSizeData};
 use msg::constellation_msg::{WebDriverCommandMsg, WindowSizeType};
 use msg::webdriver_msg::WebDriverScriptCommand;
 use net_traits::ResourceThreads;
@@ -71,16 +72,18 @@ pub enum LayoutControlMsg {
     /// Requests that this layout thread exit.
     ExitNow,
     /// Requests the current epoch (layout counter) from this layout.
     GetCurrentEpoch(IpcSender<Epoch>),
     /// Asks layout to run another step in its animation.
     TickAnimations,
     /// Informs layout as to which regions of the page are visible.
     SetVisibleRects(Vec<(LayerId, Rect<Au>)>),
+    /// Tells layout about the new scrolling offsets of each scrollable stacking context.
+    SetStackingContextScrollStates(Vec<StackingContextScrollState>),
     /// Requests the current load state of Web fonts. `true` is returned if fonts are still loading
     /// and `false` is returned if all fonts have loaded.
     GetWebFontLoadState(IpcSender<bool>),
 }
 
 /// The initial data associated with a newly-created framed pipeline.
 #[derive(Deserialize, Serialize)]
 pub struct NewLayoutInfo {
@@ -117,16 +120,18 @@ pub enum ConstellationControlMsg {
     /// Notifies script that window has been resized but to not take immediate action.
     ResizeInactive(PipelineId, WindowSizeData),
     /// Notifies the script that a pipeline should be closed.
     ExitPipeline(PipelineId),
     /// Sends a DOM event.
     SendEvent(PipelineId, CompositorEvent),
     /// Notifies script of the viewport.
     Viewport(PipelineId, Rect<f32>),
+    /// Notifies script of a new scroll offset.
+    SetScrollState(PipelineId, Point2D<f32>),
     /// Requests that the script thread immediately send the constellation the title of a pipeline.
     GetTitle(PipelineId),
     /// Notifies script thread to suspend all its timers
     Freeze(PipelineId),
     /// Notifies script thread to resume all its timers
     Thaw(PipelineId),
     /// Notifies script thread that a url should be loaded in this iframe.
     Navigate(PipelineId, SubpageId, LoadData),
@@ -458,16 +463,25 @@ impl MozBrowserErrorType {
 #[derive(Deserialize, Serialize)]
 pub enum AnimationTickType {
     /// The script thread.
     Script,
     /// The layout thread.
     Layout,
 }
 
+/// The scroll state of a stacking context.
+#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
+pub struct StackingContextScrollState {
+    /// The ID of the stacking context.
+    pub stacking_context_id: StackingContextId,
+    /// The scrolling offset of this stacking context.
+    pub scroll_offset: Point2D<f32>,
+}
+
 /// Messages to the constellation.
 #[derive(Deserialize, Serialize)]
 pub enum ConstellationMsg {
     /// Exit the constellation.
     Exit,
     /// Inform the constellation of the size of the viewport.
     FrameSize(PipelineId, Size2D<f32>),
     /// Request that the constellation send the FrameId corresponding to the document
--- a/servo/components/servo/Cargo.lock
+++ b/servo/components/servo/Cargo.lock
@@ -2512,17 +2512,17 @@ dependencies = [
  "util 0.0.1",
  "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "webdriver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender"
 version = "0.1.0"
-source = "git+https://github.com/servo/webrender#02bfa59b3f15145cfc559684deba8153dc33a5af"
+source = "git+https://github.com/servo/webrender#4ee826b19c23e63ecab7f5a8d0a68faa1f05b70c"
 dependencies = [
  "app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
@@ -2535,17 +2535,17 @@ dependencies = [
  "scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.1.0 (git+https://github.com/servo/webrender_traits)",
 ]
 
 [[package]]
 name = "webrender_traits"
 version = "0.1.0"
-source = "git+https://github.com/servo/webrender_traits#f74a744614b4c0c2fc64d39916386848124f4d52"
+source = "git+https://github.com/servo/webrender_traits#e4cbde9880d118e50de425d37bd93d4e7c866e44"
 dependencies = [
  "app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.2.2 (git+https://github.com/servo/ipc-channel)",
  "offscreen_gl_context 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -2373,17 +2373,17 @@ dependencies = [
  "util 0.0.1",
  "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "webdriver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender"
 version = "0.1.0"
-source = "git+https://github.com/servo/webrender#02bfa59b3f15145cfc559684deba8153dc33a5af"
+source = "git+https://github.com/servo/webrender#4ee826b19c23e63ecab7f5a8d0a68faa1f05b70c"
 dependencies = [
  "app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
@@ -2396,17 +2396,17 @@ dependencies = [
  "scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.1.0 (git+https://github.com/servo/webrender_traits)",
 ]
 
 [[package]]
 name = "webrender_traits"
 version = "0.1.0"
-source = "git+https://github.com/servo/webrender_traits#f74a744614b4c0c2fc64d39916386848124f4d52"
+source = "git+https://github.com/servo/webrender_traits#e4cbde9880d118e50de425d37bd93d4e7c866e44"
 dependencies = [
  "app_units 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.2.2 (git+https://github.com/servo/ipc-channel)",
  "offscreen_gl_context 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",