From a86f77e36d310737ce9e87e1ab49340cfdd89ed7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 24 May 2016 18:40:39 -0700 Subject: [PATCH] script: Keep the DOM-side viewport up to date when scrolling happens in WebRender. 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. --- components/compositing/compositor.rs | 78 ++++++++++++++++--- components/gfx/display_list/mod.rs | 33 +------- components/gfx/paint_thread.rs | 3 +- components/gfx_traits/lib.rs | 55 +++++++++++++ components/layout/block.rs | 4 +- components/layout/display_list_builder.rs | 11 ++- components/layout/flex.rs | 3 +- components/layout/flow.rs | 4 +- components/layout/fragment.rs | 4 +- components/layout/inline.rs | 3 +- components/layout/layout_thread.rs | 56 ++++++++----- components/layout/list_item.rs | 3 +- components/layout/multicol.rs | 3 +- components/layout/table.rs | 3 +- components/layout/table_caption.rs | 3 +- components/layout/table_cell.rs | 3 +- components/layout/table_colgroup.rs | 3 +- components/layout/table_row.rs | 3 +- components/layout/table_rowgroup.rs | 3 +- components/layout/table_wrapper.rs | 3 +- components/layout/webrender_helpers.rs | 47 +++++++++-- components/profile/time.rs | 1 + components/profile_traits/time.rs | 1 + components/script/dom/window.rs | 9 ++- components/script/layout_interface.rs | 5 +- components/script/script_runtime.rs | 1 + components/script/script_thread.rs | 23 ++++++ components/script_traits/lib.rs | 14 ++++ components/servo/Cargo.lock | 4 +- ports/cef/Cargo.lock | 4 +- tests/wpt/mozilla/meta/MANIFEST.json | 6 ++ tests/wpt/mozilla/tests/mozilla/scrollTo.html | 21 +++++ 32 files changed, 318 insertions(+), 99 deletions(-) create mode 100644 tests/wpt/mozilla/tests/mozilla/scrollTo.html diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index ed2f0879afa..d25fdb4b7d2 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -15,7 +15,8 @@ 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}; @@ -35,8 +36,8 @@ 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; @@ -91,6 +92,32 @@ impl ConvertPipelineIdFromWebRender for webrender_traits::PipelineId { } } +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)] @@ -1620,12 +1647,12 @@ impl IOCompositor { 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 @@ -1887,9 +1914,40 @@ impl IOCompositor { } 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); + } + } } } diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index d7463c31124..f60a5245cb1 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -22,7 +22,7 @@ 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}; @@ -1395,37 +1395,6 @@ impl fmt::Debug for DisplayItem { } } -#[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, diff --git a/components/gfx/paint_thread.rs b/components/gfx/paint_thread.rs index bafe17ce015..3f86acfb4d6 100644 --- a/components/gfx/paint_thread.rs +++ b/components/gfx/paint_thread.rs @@ -8,13 +8,14 @@ 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}; diff --git a/components/gfx_traits/lib.rs b/components/gfx_traits/lib.rs index 6065704648d..c1a8155a798 100644 --- a/components/gfx_traits/lib.rs +++ b/components/gfx_traits/lib.rs @@ -149,3 +149,58 @@ impl FrameTreeId { 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, + } + } +} + diff --git a/components/layout/block.rs b/components/layout/block.rs index d5decf50c8d..2e0794913d3 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -43,8 +43,8 @@ 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; diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 8e1d10424db..c5e32ab7782 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -21,17 +21,16 @@ 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; diff --git a/components/layout/flex.rs b/components/layout/flex.rs index 6d2a12fec62..5a89a627fbe 100644 --- a/components/layout/flex.rs +++ b/components/layout/flex.rs @@ -17,7 +17,8 @@ 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}; diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 05e5814d0e0..1267ed31cf1 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -34,8 +34,8 @@ 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}; diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 3a5d90201bd..9868e141df1 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -14,10 +14,10 @@ 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}; diff --git a/components/layout/inline.rs b/components/layout/inline.rs index 4615b728335..5ad86e54e05 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -17,9 +17,10 @@ use flow::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, IS_ABSOLUTELY_P 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; diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index 2509394db5a..779a23fba82 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -21,14 +21,13 @@ 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}; @@ -52,8 +51,8 @@ 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; @@ -559,6 +558,11 @@ impl LayoutThread { 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) }, @@ -644,6 +648,10 @@ impl LayoutThread { 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) @@ -883,19 +891,18 @@ impl LayoutThread { 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, @@ -1264,6 +1271,19 @@ impl LayoutThread { true } + fn set_stacking_context_scroll_states<'a, 'b>( + &mut self, + new_scroll_states: Vec, + _: &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); diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs index 9b44ed78640..d32c19d5c37 100644 --- a/components/layout/list_item.rs +++ b/components/layout/list_item.rs @@ -17,7 +17,8 @@ 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; diff --git a/components/layout/multicol.rs b/components/layout/multicol.rs index a4e532c3b0a..09f0efd1130 100644 --- a/components/layout/multicol.rs +++ b/components/layout/multicol.rs @@ -15,7 +15,8 @@ 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; diff --git a/components/layout/table.rs b/components/layout/table.rs index 9ed0dfd02d7..5b7f26eb9d9 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -16,7 +16,8 @@ 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}; diff --git a/components/layout/table_caption.rs b/components/layout/table_caption.rs index 2f26e7ea2ae..1c24491d06d 100644 --- a/components/layout/table_caption.rs +++ b/components/layout/table_caption.rs @@ -13,7 +13,8 @@ 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; diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 06cb1e31ecc..a579ecb6c12 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -14,7 +14,8 @@ use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, Dis 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; diff --git a/components/layout/table_colgroup.rs b/components/layout/table_colgroup.rs index 86192f75c52..6dce7bd56d1 100644 --- a/components/layout/table_colgroup.rs +++ b/components/layout/table_colgroup.rs @@ -12,7 +12,8 @@ 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; diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index ca5b5133984..42257ec5a76 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -15,7 +15,8 @@ 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}; diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index 202d604a758..e7e3e2fa938 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -13,7 +13,8 @@ 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; diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index 99bd3d29b64..9b3b6f5c062 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -22,7 +22,8 @@ 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; diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index 59329147bcb..d7fd26513e5 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -11,13 +11,13 @@ 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, @@ -315,8 +315,11 @@ impl WebRenderStackingContextConverter for StackingContext { 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(), @@ -514,7 +517,8 @@ impl WebRenderDisplayItemConverter for DisplayItem { } 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, @@ -536,7 +540,7 @@ impl WebRenderFrameBuilder { 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)); @@ -561,5 +565,32 @@ impl WebRenderFrameBuilder { 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, + } + } +} + diff --git a/components/profile/time.rs b/components/profile/time.rs index f45e7df8c71..6271c8745e1 100644 --- a/components/profile/time.rs +++ b/components/profile/time.rs @@ -143,6 +143,7 @@ impl Formattable for ProfilerCategory { 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", diff --git a/components/profile_traits/time.rs b/components/profile_traits/time.rs index 5d9a95ddd60..4083f3f3c14 100644 --- a/components/profile_traits/time.rs +++ b/components/profile_traits/time.rs @@ -73,6 +73,7 @@ pub enum ProfilerCategory { ScriptParseHTML, ScriptPlannedNavigation, ScriptResize, + ScriptSetScrollState, ScriptSetViewport, ScriptTimerEvent, ScriptStylesheetLoad, diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 4862cb83c9e..3d6695986ae 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -995,13 +995,18 @@ impl Window { }; // 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, Point2D) { let (send, recv) = ipc::channel::<(Size2D, Point2D)>().unwrap(); self.constellation_chan.send(ConstellationMsg::GetClientWindow(send)).unwrap(); diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index b0327305665..29dff179525 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -15,8 +15,8 @@ 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; @@ -85,6 +85,9 @@ pub enum Msg { /// Set the final Url. SetFinalUrl(Url), + + /// Tells layout about the new scrolling offsets of each scrollable stacking context. + SetStackingContextScrollStates(Vec), } /// Synchronous messages that script can send to layout. diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 543574ccc62..061b80502b8 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -62,6 +62,7 @@ pub enum ScriptThreadEventCategory { NetworkEvent, Resize, ScriptEvent, + SetScrollState, SetViewport, StylesheetLoad, TimerEvent, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 20a8602a249..b913c5bbae0 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -708,6 +708,11 @@ impl ScriptThread { 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) { @@ -850,6 +855,9 @@ impl ScriptThread { ScriptThreadEventCategory::NetworkEvent => ProfilerCategory::ScriptNetworkEvent, ScriptThreadEventCategory::Resize => ProfilerCategory::ScriptResize, ScriptThreadEventCategory::ScriptEvent => ProfilerCategory::ScriptEvent, + ScriptThreadEventCategory::SetScrollState => { + ProfilerCategory::ScriptSetScrollState + } ScriptThreadEventCategory::UpdateReplacedElement => { ProfilerCategory::ScriptUpdateReplacedElement } @@ -877,6 +885,8 @@ impl ScriptThread { 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(..) => @@ -1077,6 +1087,19 @@ impl ScriptThread { panic!("Page rect message sent to nonexistent pipeline"); } + fn handle_set_scroll_state(&self, id: PipelineId, scroll_state: &Point2D) { + 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, diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 529fc6ad715..da9c49f8834 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -39,6 +39,7 @@ 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}; @@ -76,6 +77,8 @@ pub enum LayoutControlMsg { TickAnimations, /// Informs layout as to which regions of the page are visible. SetVisibleRects(Vec<(LayerId, Rect)>), + /// Tells layout about the new scrolling offsets of each scrollable stacking context. + SetStackingContextScrollStates(Vec), /// 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), @@ -122,6 +125,8 @@ pub enum ConstellationControlMsg { SendEvent(PipelineId, CompositorEvent), /// Notifies script of the viewport. Viewport(PipelineId, Rect), + /// Notifies script of a new scroll offset. + SetScrollState(PipelineId, Point2D), /// Requests that the script thread immediately send the constellation the title of a pipeline. GetTitle(PipelineId), /// Notifies script thread to suspend all its timers @@ -463,6 +468,15 @@ pub enum AnimationTickType { 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, +} + /// Messages to the constellation. #[derive(Deserialize, Serialize)] pub enum ConstellationMsg { diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 53875b3957c..b2ebec2e9cc 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -2517,7 +2517,7 @@ dependencies = [ [[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)", @@ -2540,7 +2540,7 @@ dependencies = [ [[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)", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 9029fa2cbfd..0925f658c70 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -2378,7 +2378,7 @@ dependencies = [ [[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)", @@ -2401,7 +2401,7 @@ dependencies = [ [[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)", diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 05e8dc4ad7e..7fabf3c762c 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -6874,6 +6874,12 @@ "url": "/_mozilla/mozilla/script_type.html" } ], + "mozilla/scrollTo.html": [ + { + "path": "mozilla/scrollTo.html", + "url": "/_mozilla/mozilla/scrollTo.html" + } + ], "mozilla/send-arraybuffer.htm": [ { "path": "mozilla/send-arraybuffer.htm", diff --git a/tests/wpt/mozilla/tests/mozilla/scrollTo.html b/tests/wpt/mozilla/tests/mozilla/scrollTo.html new file mode 100644 index 00000000000..f1b4384e63b --- /dev/null +++ b/tests/wpt/mozilla/tests/mozilla/scrollTo.html @@ -0,0 +1,21 @@ + + + + + + +