diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 8b13157fce..cc971e11bd 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -7,7 +7,7 @@ use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, Fi use api::{DeviceIntPoint, LayerPoint, SubpixelDirection, YuvColorSpace, YuvFormat}; use api::{LayerToWorldTransform, WorldPixel}; use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind}; -use clip::{ClipSource, ClipStore}; +use clip::{ClipSource, ClipStore, ClipWorkItem}; use clip_scroll_tree::{CoordinateSystemId}; use euclid::{TypedTransform3D, vec3}; use glyph_rasterizer::GlyphFormat; @@ -20,9 +20,7 @@ use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive use plane_split::{BspSplitter, Polygon, Splitter}; use prim_store::{ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PrimitiveRun}; -use render_task::{ClipWorkItem}; -use render_task::{RenderTaskAddress, RenderTaskId}; -use render_task::{RenderTaskKind, RenderTaskTree}; +use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind}; use renderer::BLOCKS_PER_UV_RECT; use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache}; diff --git a/webrender/src/border.rs b/webrender/src/border.rs index 677b76b0b0..6e809bcd82 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -2,15 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ClipAndScrollInfo, ColorF}; -use api::{LayerPoint, LayerRect, LayerPrimitiveInfo, LayerSize}; -use api::{NormalBorder, RepeatMode, TexelRect}; +use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF, LayerPoint}; +use api::{LayerPrimitiveInfo, LayerRect, LayerSize, NormalBorder, RepeatMode, TexelRect}; use clip::ClipSource; use ellipse::Ellipse; use frame_builder::FrameBuilder; use gpu_cache::GpuDataRequest; -use prim_store::{BorderPrimitiveCpu, BrushSegment, BrushSegmentDescriptor}; -use prim_store::{BrushClipMaskKind, EdgeAaSegmentMask, PrimitiveContainer}; +use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushSegment, BrushSegmentDescriptor}; +use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain}; use util::{lerp, pack_as_float}; #[repr(u8)] @@ -286,7 +285,7 @@ impl FrameBuilder { info: &LayerPrimitiveInfo, border: &NormalBorder, widths: &BorderWidths, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, corner_instances: [BorderCornerInstance; 4], edges: [BorderEdgeKind; 4], clip_sources: Vec, @@ -354,7 +353,7 @@ impl FrameBuilder { info: &LayerPrimitiveInfo, border: &NormalBorder, widths: &BorderWidths, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, ) { // The border shader is quite expensive. For simple borders, we can just draw // the border with a few rectangles. This generally gives better batching, and diff --git a/webrender/src/box_shadow.rs b/webrender/src/box_shadow.rs index 3b47b21e68..9b66cf37ee 100644 --- a/webrender/src/box_shadow.rs +++ b/webrender/src/box_shadow.rs @@ -2,16 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{ColorF, LayerPoint, LayerRect, LayerSize, LayerVector2D}; -use api::{BorderRadius, BoxShadowClipMode, LayoutSize, LayerPrimitiveInfo}; -use api::{ClipMode, ClipAndScrollInfo, ComplexClipRegion, LocalClip}; -use api::{PipelineId}; +use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, ComplexClipRegion, LayerPoint}; +use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, LocalClip}; +use api::PipelineId; use app_units::Au; use clip::ClipSource; use frame_builder::FrameBuilder; use gpu_types::BrushImageKind; -use prim_store::{PrimitiveContainer}; -use prim_store::{BrushMaskKind, BrushKind, BrushPrimitive}; +use prim_store::{BrushKind, BrushMaskKind, BrushPrimitive, PrimitiveContainer}; +use prim_store::ScrollNodeAndClipChain; use picture::PicturePrimitive; use util::RectHelpers; use render_task::MAX_BLUR_STD_DEVIATION; @@ -53,7 +52,7 @@ impl FrameBuilder { pub fn add_box_shadow( &mut self, pipeline_id: PipelineId, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, box_offset: &LayerVector2D, color: &ColorF, diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index ead309140f..59ed948ac2 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -6,12 +6,15 @@ use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelS use api::{ImageRendering, LayerRect, LayerToWorldTransform, LayoutPoint, LayoutVector2D}; use api::LocalClip; use border::{BorderCornerClipSource, ensure_no_corner_overlap}; +use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId}; use ellipse::Ellipse; use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; +use gpu_types::ClipScrollNodeIndex; use prim_store::{ClipData, ImageMaskData}; use resource_cache::{ImageRequest, ResourceCache}; use util::{MaxRect, MatrixHelpers, calculate_screen_bounding_rect, extract_inner_rect_safe}; +use std::rc::Rc; pub type ClipStore = FreeList; pub type ClipSourcesHandle = FreeListHandle; @@ -349,3 +352,106 @@ pub fn rounded_rectangle_contains_point(point: &LayoutPoint, true } + +pub type ClipChainNodeRef = Option>; + +#[derive(Debug, Clone)] +pub struct ClipChainNode { + pub work_item: ClipWorkItem, + pub local_clip_rect: LayerRect, + pub screen_outer_rect: DeviceIntRect, + pub screen_inner_rect: DeviceIntRect, + pub prev: ClipChainNodeRef, +} + +#[derive(Debug, Clone)] +pub struct ClipChain { + pub parent_index: Option, + pub combined_outer_screen_rect: DeviceIntRect, + pub combined_inner_screen_rect: DeviceIntRect, + pub nodes: ClipChainNodeRef, +} + +impl ClipChain { + pub fn empty(screen_rect: &DeviceIntRect) -> ClipChain { + ClipChain { + parent_index: None, + combined_inner_screen_rect: *screen_rect, + combined_outer_screen_rect: *screen_rect, + nodes: None, + } + } + + pub fn new_with_added_node( + &self, + work_item: ClipWorkItem, + local_clip_rect: LayerRect, + screen_outer_rect: DeviceIntRect, + screen_inner_rect: DeviceIntRect, + ) -> ClipChain { + // If the new node's inner rectangle completely surrounds our outer rectangle, + // we can discard the new node entirely since it isn't going to affect anything. + if screen_inner_rect.contains_rect(&self.combined_outer_screen_rect) { + return self.clone(); + } + + let new_node = ClipChainNode { + work_item, + local_clip_rect, + screen_outer_rect, + screen_inner_rect, + prev: None, + }; + + let mut new_chain = self.clone(); + new_chain.add_node(new_node); + new_chain + } + + pub fn add_node(&mut self, mut new_node: ClipChainNode) { + new_node.prev = self.nodes.clone(); + + // If this clip's outer rectangle is completely enclosed by the clip + // chain's inner rectangle, then the only clip that matters from this point + // on is this clip. We can disconnect this clip from the parent clip chain. + if self.combined_inner_screen_rect.contains_rect(&new_node.screen_outer_rect) { + new_node.prev = None; + } + + self.combined_outer_screen_rect = + self.combined_outer_screen_rect.intersection(&new_node.screen_outer_rect) + .unwrap_or_else(DeviceIntRect::zero); + self.combined_inner_screen_rect = + self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect) + .unwrap_or_else(DeviceIntRect::zero); + + self.nodes = Some(Rc::new(new_node)); + } +} + +pub struct ClipChainNodeIter { + pub current: ClipChainNodeRef, +} + +impl Iterator for ClipChainNodeIter { + type Item = Rc; + + fn next(&mut self) -> ClipChainNodeRef { + let previous = self.current.clone(); + self.current = match self.current { + Some(ref item) => item.prev.clone(), + None => return None, + }; + previous + } +} + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct ClipWorkItem { + pub scroll_node_data_index: ClipScrollNodeIndex, + pub clip_sources: ClipSourcesWeakHandle, + pub coordinate_system_id: CoordinateSystemId, +} + diff --git a/webrender/src/clip_scroll_node.rs b/webrender/src/clip_scroll_node.rs index 7df3993107..4940f1a503 100644 --- a/webrender/src/clip_scroll_node.rs +++ b/webrender/src/clip_scroll_node.rs @@ -6,13 +6,12 @@ use api::{ClipId, DevicePixelScale, ExternalScrollId, LayerPixel, LayerPoint, La use api::{LayerSize, LayerToWorldTransform, LayerTransform, LayerVector2D, LayoutTransform}; use api::{LayoutVector2D, PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase}; use api::{ScrollLocation, ScrollNodeIdType, ScrollSensitivity, StickyOffsetBounds, WorldPoint}; -use clip::{ClipSourcesHandle, ClipStore}; -use clip_scroll_tree::{CoordinateSystemId, TransformUpdateState}; +use clip::{ClipChain, ClipSourcesHandle, ClipStore, ClipWorkItem}; +use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, TransformUpdateState}; use euclid::SideOffsets2D; use geometry::ray_intersects_rect; use gpu_cache::GpuCache; use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData}; -use render_task::{ClipChain, ClipWorkItem}; use resource_cache::ResourceCache; use scene::SceneProperties; use spring::{DAMPING, STIFFNESS, Spring}; @@ -56,7 +55,10 @@ pub enum NodeType { ReferenceFrame(ReferenceFrameInfo), /// Other nodes just do clipping, but no transformation. - Clip(ClipSourcesHandle), + Clip { + handle: ClipSourcesHandle, + clip_chain_index: ClipChainIndex + }, /// Transforms it's content, but doesn't clip it. Can also be adjusted /// by scroll events or setting scroll offsets. @@ -106,9 +108,6 @@ pub struct ClipScrollNode { /// The type of this node and any data associated with that node type. pub node_type: NodeType, - /// The ClipChain that will be used if this node is used as the 'clipping node.' - pub clip_chain: Option, - /// True if this node is transformed by an invertible transform. If not, display items /// transformed by this node will not be displayed and display items not transformed by this /// node will not be clipped by clips that are transformed by this node. @@ -128,7 +127,7 @@ pub struct ClipScrollNode { } impl ClipScrollNode { - fn new( + pub fn new( pipeline_id: PipelineId, parent_id: Option, rect: &LayerRect, @@ -142,7 +141,6 @@ impl ClipScrollNode { children: Vec::new(), pipeline_id, node_type: node_type, - clip_chain: None, invertible: true, coordinate_system_id: CoordinateSystemId(0), coordinate_system_relative_transform: TransformOrOffset::zero(), @@ -170,15 +168,6 @@ impl ClipScrollNode { Self::new(pipeline_id, Some(parent_id), frame_rect, node_type) } - pub fn new_clip_node( - pipeline_id: PipelineId, - parent_id: ClipId, - handle: ClipSourcesHandle, - clip_rect: LayerRect, - ) -> Self { - Self::new(pipeline_id, Some(parent_id), &clip_rect, NodeType::Clip(handle)) - } - pub fn new_reference_frame( parent_id: Option, frame_rect: &LayerRect, @@ -271,7 +260,6 @@ impl ClipScrollNode { self.invertible = false; self.world_content_transform = LayerToWorldTransform::identity(); self.world_viewport_transform = LayerToWorldTransform::identity(); - self.clip_chain = None; } pub fn push_gpu_node_data(&mut self, node_data: &mut Vec) { @@ -304,6 +292,7 @@ impl ClipScrollNode { resource_cache: &mut ResourceCache, gpu_cache: &mut GpuCache, scene_properties: &SceneProperties, + clip_chains: &mut Vec, ) { // If any of our parents was not rendered, we are not rendered either and can just // quit here. @@ -331,6 +320,7 @@ impl ClipScrollNode { clip_store, resource_cache, gpu_cache, + clip_chains, ); } @@ -341,11 +331,11 @@ impl ClipScrollNode { clip_store: &mut ClipStore, resource_cache: &mut ResourceCache, gpu_cache: &mut GpuCache, + clip_chains: &mut Vec, ) { - let clip_sources_handle = match self.node_type { - NodeType::Clip(ref handle) => handle, + let (clip_sources_handle, clip_chain_index) = match self.node_type { + NodeType::Clip { ref handle, clip_chain_index } => (handle, clip_chain_index), _ => { - self.clip_chain = Some(state.parent_clip_chain.clone()); self.invertible = true; return; } @@ -364,29 +354,22 @@ impl ClipScrollNode { "Clipping node didn't have outer rect." ); - // If this clip's inner rectangle completely surrounds the existing clip - // chain's outer rectangle, we can discard this clip entirely since it isn't - // going to affect anything. - if screen_inner_rect.contains_rect(&state.parent_clip_chain.combined_outer_screen_rect) { - self.clip_chain = Some(state.parent_clip_chain.clone()); - return; - } - let work_item = ClipWorkItem { scroll_node_data_index: self.node_data_index, clip_sources: clip_sources_handle.weak(), coordinate_system_id: state.current_coordinate_system_id, }; - let clip_chain = state.parent_clip_chain.new_with_added_node( + let mut clip_chain = clip_chains[state.parent_clip_chain_index.0].new_with_added_node( work_item, self.coordinate_system_relative_transform.apply(&local_outer_rect), screen_outer_rect, screen_inner_rect, ); - self.clip_chain = Some(clip_chain.clone()); - state.parent_clip_chain = clip_chain; + clip_chain.parent_index = Some(state.parent_clip_chain_index); + clip_chains[clip_chain_index.0] = clip_chain; + state.parent_clip_chain_index = clip_chain_index; } pub fn update_transform( @@ -621,7 +604,7 @@ impl ClipScrollNode { state.nearest_scrolling_ancestor_viewport .translate(&translation); } - NodeType::Clip(..) => { } + NodeType::Clip{ .. } => { } NodeType::ScrollFrame(ref scrolling) => { state.parent_accumulated_scroll_offset = scrolling.offset + state.parent_accumulated_scroll_offset; diff --git a/webrender/src/clip_scroll_tree.rs b/webrender/src/clip_scroll_tree.rs index c82bcb9278..89a0a85919 100644 --- a/webrender/src/clip_scroll_tree.rs +++ b/webrender/src/clip_scroll_tree.rs @@ -2,17 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{ClipChainId, ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint}; -use api::{LayerRect, LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping}; -use api::{ScrollEventPhase, ScrollLocation, ScrollNodeIdType}; -use api::{ScrollNodeState, WorldPoint}; -use clip::ClipStore; +use api::{ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint, LayerRect}; +use api::{LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase}; +use api::{ScrollLocation, ScrollNodeIdType, ScrollNodeState, WorldPoint}; +use clip::{ClipChain, ClipSourcesHandle, ClipStore}; use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo}; use gpu_cache::GpuCache; use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData}; use internal_types::{FastHashMap, FastHashSet}; use print_tree::{PrintTree, PrintTreePrinter}; -use render_task::ClipChain; use resource_cache::ResourceCache; use scene::SceneProperties; use util::TransformOrOffset; @@ -44,11 +42,14 @@ impl CoordinateSystemId { } pub struct ClipChainDescriptor { - pub id: ClipChainId, - pub parent: Option, + pub index: ClipChainIndex, + pub parent: Option, pub clips: Vec, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ClipChainIndex(pub usize); + pub struct ClipScrollTree { pub nodes: FastHashMap, @@ -57,8 +58,9 @@ pub struct ClipScrollTree { /// the children of ClipChains later in the list. pub clip_chains_descriptors: Vec, - /// A HashMap of built ClipChains that are described by `clip_chains_descriptors`. - pub clip_chains: FastHashMap, + /// A vector of all ClipChains in this ClipScrollTree including those from + /// ClipChainDescriptors and also those defined by the clipping node hierarchy. + pub clip_chains: Vec, pub pending_scroll_offsets: FastHashMap, @@ -90,7 +92,9 @@ pub struct TransformUpdateState { pub parent_accumulated_scroll_offset: LayerVector2D, pub nearest_scrolling_ancestor_offset: LayerVector2D, pub nearest_scrolling_ancestor_viewport: LayerRect, - pub parent_clip_chain: ClipChain, + + /// The index of the current parent's clip chain. + pub parent_clip_chain_index: ClipChainIndex, /// An id for keeping track of the axis-aligned space of this node. This is used in /// order to to track what kinds of clip optimizations can be done for a particular @@ -113,7 +117,7 @@ impl ClipScrollTree { ClipScrollTree { nodes: FastHashMap::default(), clip_chains_descriptors: Vec::new(), - clip_chains: FastHashMap::default(), + clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())], pending_scroll_offsets: FastHashMap::default(), currently_scrolling_node_id: None, root_reference_frame_id: ClipId::root_reference_frame(dummy_pipeline), @@ -211,7 +215,7 @@ impl ClipScrollTree { } self.pipelines_to_discard.clear(); - self.clip_chains.clear(); + self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())]; self.clip_chains_descriptors.clear(); scroll_states } @@ -321,6 +325,8 @@ impl ClipScrollTree { return; } + self.clip_chains[0] = ClipChain::empty(screen_rect); + let root_reference_frame_id = self.root_reference_frame_id(); let mut state = TransformUpdateState { parent_reference_frame_transform: LayerToWorldTransform::create_translation( @@ -331,7 +337,7 @@ impl ClipScrollTree { parent_accumulated_scroll_offset: LayerVector2D::zero(), nearest_scrolling_ancestor_offset: LayerVector2D::zero(), nearest_scrolling_ancestor_viewport: LayerRect::zero(), - parent_clip_chain: ClipChain::empty(screen_rect), + parent_clip_chain_index: ClipChainIndex(0), current_coordinate_system_id: CoordinateSystemId::root(), coordinate_system_relative_transform: TransformOrOffset::zero(), invertible: true, @@ -384,6 +390,7 @@ impl ClipScrollTree { resource_cache, gpu_cache, scene_properties, + &mut self.clip_chains, ); node.push_gpu_node_data(gpu_node_data); @@ -417,21 +424,28 @@ impl ClipScrollTree { // ClipScrollNode clipping nodes. Here we start the ClipChain with a clone of the // parent's node, if necessary. let mut chain = match descriptor.parent { - Some(id) => self.clip_chains[&id].clone(), + Some(index) => self.clip_chains[index.0].clone(), None => ClipChain::empty(screen_rect), }; // Now we walk through each ClipScrollNode in the vector of clip nodes and // extract their ClipChain nodes to construct the final list. for clip_id in &descriptor.clips { - if let Some(ref node_chain) = self.nodes[&clip_id].clip_chain { - if let Some(ref nodes) = node_chain.nodes { - chain.add_node((**nodes).clone()); + let node_clip_chain_index = match self.nodes[&clip_id].node_type { + NodeType::Clip { clip_chain_index, .. } => clip_chain_index, + _ => { + warn!("Tried to create a clip chain with non-clipping node."); + continue; } + }; + + if let Some(ref nodes) = self.clip_chains[node_clip_chain_index.0].nodes { + chain.add_node((**nodes).clone()); } } - self.clip_chains.insert(descriptor.id, chain); + chain.parent_index = descriptor.parent; + self.clip_chains[descriptor.index.0] = chain; } } @@ -466,6 +480,20 @@ impl ClipScrollTree { } } + pub fn add_clip_node( + &mut self, + id: ClipId, + parent_id: ClipId, + handle: ClipSourcesHandle, + clip_rect: LayerRect, + ) -> ClipChainIndex { + let clip_chain_index = self.allocate_clip_chain(); + let node_type = NodeType::Clip { handle, clip_chain_index }; + let node = ClipScrollNode::new(id.pipeline_id(), Some(parent_id), &clip_rect, node_type); + self.add_node(node, id); + clip_chain_index + } + pub fn add_sticky_frame( &mut self, id: ClipId, @@ -484,11 +512,12 @@ impl ClipScrollTree { pub fn add_clip_chain_descriptor( &mut self, - id: ClipChainId, - parent: Option, + parent: Option, clips: Vec - ) { - self.clip_chains_descriptors.push(ClipChainDescriptor { id, parent, clips }); + ) -> ClipChainIndex { + let index = self.allocate_clip_chain(); + self.clip_chains_descriptors.push(ClipChainDescriptor { index, parent, clips }); + index } pub fn add_node(&mut self, node: ClipScrollNode, id: ClipId) { @@ -515,11 +544,11 @@ impl ClipScrollTree { let node = self.nodes.get(id).unwrap(); match node.node_type { - NodeType::Clip(ref clip_sources_handle) => { + NodeType::Clip { ref handle, .. } => { pt.new_level("Clip".to_owned()); pt.add_item(format!("id: {:?}", id)); - let clips = clip_store.get(&clip_sources_handle).clips(); + let clips = clip_store.get(&handle).clips(); pt.new_level(format!("Clip Sources [{}]", clips.len())); for source in clips { pt.add_item(format!("{:?}", source)); @@ -581,11 +610,15 @@ impl ClipScrollTree { } } - pub fn get_clip_chain(&self, id: &ClipId) -> Option<&ClipChain> { - match id { - &ClipId::ClipChain(clip_chain_id) => Some(&self.clip_chains[&clip_chain_id]), - _ => self.nodes[id].clip_chain.as_ref(), - } + pub fn allocate_clip_chain(&mut self) -> ClipChainIndex { + debug_assert!(!self.clip_chains.is_empty()); + let new_clip_chain =self.clip_chains[0].clone(); + self.clip_chains.push(new_clip_chain); + ClipChainIndex(self.clip_chains.len() - 1) + } + + pub fn get_clip_chain(&self, index: ClipChainIndex) -> &ClipChain { + &self.clip_chains[index.0] } } diff --git a/webrender/src/frame.rs b/webrender/src/frame.rs index 2f7fff636c..99c948a5d6 100644 --- a/webrender/src/frame.rs +++ b/webrender/src/frame.rs @@ -3,21 +3,22 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{BuiltDisplayListIter, ClipAndScrollInfo, ClipId, ColorF, ComplexClipRegion}; -use api::{DevicePixelScale, DeviceUintRect, DeviceUintSize, DisplayItemRef, DocumentLayer, Epoch}; -use api::{ExternalScrollId, FilterOp, IframeDisplayItem, ImageDisplayItem, ItemRange, LayerPoint}; +use api::{BuiltDisplayListIter, ClipId, ColorF, ComplexClipRegion, DevicePixelScale}; +use api::{DeviceUintRect, DeviceUintSize, DisplayItemRef, DocumentLayer, Epoch, ExternalScrollId}; +use api::{FilterOp, IframeDisplayItem, ImageDisplayItem, ItemRange, LayerPoint}; use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, PipelineId}; use api::{ScrollClamping, ScrollEventPhase, ScrollFrameDisplayItem, ScrollLocation}; use api::{ScrollNodeIdType, ScrollNodeState, ScrollPolicy, ScrollSensitivity, SpecificDisplayItem}; use api::{StackingContext, TileOffset, TransformStyle, WorldPoint}; use clip::ClipRegion; use clip_scroll_node::StickyFrameInfo; -use clip_scroll_tree::{ClipScrollTree, ScrollStates}; +use clip_scroll_tree::{ClipChainIndex, ClipScrollTree, ScrollStates}; use euclid::rect; use frame_builder::{FrameBuilder, FrameBuilderConfig, ScrollbarInfo}; use gpu_cache::GpuCache; use hit_test::HitTester; use internal_types::{FastHashMap, FastHashSet, RenderedDocument}; +use prim_store::ScrollNodeAndClipChain; use profiler::{GpuCacheProfileCounters, TextureCacheProfileCounters}; use resource_cache::{FontInstanceMap,ResourceCache, TiledImageMap}; use scene::{Scene, StackingContextHelpers, ScenePipeline, SceneProperties}; @@ -36,6 +37,53 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { a: 0.6, }; +/// A data structure that keeps track of mapping between API clip ids and the indices +/// used internally in the ClipScrollTree to avoid having to do HashMap lookups. This +/// also includes a small LRU cache. Currently the cache is small (1 entry), but in the +/// future we could use uluru here to do something more involved. +pub struct ClipIdToIndexMapper { + map: FastHashMap, + cached_index: Option<(ClipId, ClipChainIndex)>, +} + +impl ClipIdToIndexMapper { + fn new() -> ClipIdToIndexMapper { + ClipIdToIndexMapper { + map: FastHashMap::default(), + cached_index: None, + } + } + + pub fn add(&mut self, id: ClipId, index: ClipChainIndex) { + debug_assert!(!self.map.contains_key(&id)); + self.map.insert(id, index); + } + + pub fn map_to_parent_clip_chain(&mut self, id: ClipId, parent_id: &ClipId) { + let parent_chain_index = self.map_clip_id(parent_id); + self.add(id, parent_chain_index); + } + + pub fn map_clip_id(&mut self, id: &ClipId) -> ClipChainIndex { + match self.cached_index { + Some((cached_id, cached_index)) if cached_id == *id => return cached_index, + _ => {} + } + + self.map[id] + } + + pub fn map_clip_id_and_cache_result(&mut self, id: &ClipId) -> ClipChainIndex { + let index = self.map_clip_id(id); + self.cached_index = Some((*id, index)); + index + } + + pub fn simple_scroll_and_clip_chain(&mut self, id: &ClipId) -> ScrollNodeAndClipChain { + ScrollNodeAndClipChain::new(*id, self.map_clip_id(&id)) + } +} + struct FlattenContext<'a> { scene: &'a Scene, builder: FrameBuilder, @@ -45,6 +93,7 @@ struct FlattenContext<'a> { pipeline_epochs: Vec<(PipelineId, Epoch)>, replacements: Vec<(ClipId, ClipId)>, output_pipelines: &'a FastHashSet, + id_to_index_mapper: ClipIdToIndexMapper, } impl<'a> FlattenContext<'a> { @@ -104,13 +153,23 @@ impl<'a> FlattenContext<'a> { let root_reference_frame_id = ClipId::root_reference_frame(pipeline_id); let root_scroll_frame_id = ClipId::root_scroll_node(pipeline_id); + let root_clip_chain_index = + self.id_to_index_mapper.map_clip_id_and_cache_result(&root_reference_frame_id); + let root_reference_frame_clip_and_scroll = ScrollNodeAndClipChain::new( + root_reference_frame_id, + root_clip_chain_index, + ); + self.builder.push_stacking_context( pipeline_id, CompositeOps::default(), TransformStyle::Flat, true, true, - ClipAndScrollInfo::simple(root_scroll_frame_id), + ScrollNodeAndClipChain::new( + ClipId::root_scroll_node(pipeline_id), + root_clip_chain_index, + ), self.output_pipelines, ); @@ -122,7 +181,7 @@ impl<'a> FlattenContext<'a> { let root_bounds = LayerRect::new(LayerPoint::zero(), *frame_size); let info = LayerPrimitiveInfo::new(root_bounds); self.builder.add_solid_rectangle( - ClipAndScrollInfo::simple(root_reference_frame_id), + root_reference_frame_clip_and_scroll, &info, bg_color, None, @@ -142,7 +201,7 @@ impl<'a> FlattenContext<'a> { let scrollbar_rect = LayerRect::new(LayerPoint::zero(), LayerSize::new(10.0, 70.0)); let container_rect = LayerRect::new(LayerPoint::zero(), *frame_size); self.builder.add_scroll_bar( - ClipAndScrollInfo::simple(root_reference_frame_id), + root_reference_frame_clip_and_scroll, &LayerPrimitiveInfo::new(scrollbar_rect), DEFAULT_SCROLLBAR_COLOR, ScrollbarInfo(root_scroll_frame_id, container_rect), @@ -184,19 +243,13 @@ impl<'a> FlattenContext<'a> { } } - fn flatten_clip( - &mut self, - pipeline_id: PipelineId, - parent_id: &ClipId, - new_clip_id: &ClipId, - clip_region: ClipRegion, - ) { + fn flatten_clip(&mut self, parent_id: &ClipId, new_clip_id: &ClipId, clip_region: ClipRegion) { self.builder.add_clip_node( *new_clip_id, *parent_id, - pipeline_id, clip_region, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); } @@ -205,7 +258,7 @@ impl<'a> FlattenContext<'a> { item: &DisplayItemRef, info: &ScrollFrameDisplayItem, pipeline_id: PipelineId, - clip_and_scroll: &ClipAndScrollInfo, + clip_and_scroll: &ScrollNodeAndClipChain, reference_frame_relative_offset: &LayerVector2D, ) { let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0); @@ -229,9 +282,9 @@ impl<'a> FlattenContext<'a> { self.builder.add_clip_node( info.clip_id, clip_and_scroll.scroll_node_id, - pipeline_id, clip_region, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.builder.add_scroll_frame( @@ -243,6 +296,7 @@ impl<'a> FlattenContext<'a> { &content_rect.size, info.scroll_sensitivity, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); } @@ -250,7 +304,8 @@ impl<'a> FlattenContext<'a> { &mut self, traversal: &mut BuiltDisplayListIter<'a>, pipeline_id: PipelineId, - context_scroll_node_id: ClipId, + unreplaced_scroll_id: ClipId, + clip_and_scroll: ScrollNodeAndClipChain, mut reference_frame_relative_offset: LayerVector2D, bounds: &LayerRect, stacking_context: &StackingContext, @@ -279,7 +334,7 @@ impl<'a> FlattenContext<'a> { if stacking_context.scroll_policy == ScrollPolicy::Fixed { self.replacements.push(( - context_scroll_node_id, + unreplaced_scroll_id, self.builder.current_reference_frame_id(), )); } @@ -296,30 +351,33 @@ impl<'a> FlattenContext<'a> { ); let reference_frame_bounds = LayerRect::new(LayerPoint::zero(), bounds.size); - let mut parent_id = self.apply_scroll_frame_id_replacement(context_scroll_node_id); self.builder.push_reference_frame( reference_frame_id, - Some(parent_id), + Some(clip_and_scroll.scroll_node_id), pipeline_id, &reference_frame_bounds, stacking_context.transform, stacking_context.perspective, reference_frame_relative_offset, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); - self.replacements.push((context_scroll_node_id, reference_frame_id)); + self.replacements.push((unreplaced_scroll_id, reference_frame_id)); reference_frame_relative_offset = LayerVector2D::zero(); } - let sc_scroll_node_id = self.apply_scroll_frame_id_replacement(context_scroll_node_id); - + // We apply the replacements one more time in case we need to set it to a replacement + // that we just pushed above. + let new_scroll_node = self.apply_scroll_frame_id_replacement(unreplaced_scroll_id); + let stacking_context_clip_and_scroll = + self.id_to_index_mapper.simple_scroll_and_clip_chain(&new_scroll_node); self.builder.push_stacking_context( pipeline_id, composition_operations, stacking_context.transform_style, is_backface_visible, false, - ClipAndScrollInfo::simple(sc_scroll_node_id), + stacking_context_clip_and_scroll, self.output_pipelines, ); @@ -345,8 +403,7 @@ impl<'a> FlattenContext<'a> { &mut self, item: &DisplayItemRef, info: &IframeDisplayItem, - parent_pipeline_id: PipelineId, - clip_and_scroll: &ClipAndScrollInfo, + clip_and_scroll: &ScrollNodeAndClipChain, reference_frame_relative_offset: &LayerVector2D, ) { let iframe_pipeline_id = info.pipeline_id; @@ -358,12 +415,12 @@ impl<'a> FlattenContext<'a> { self.builder.add_clip_node( info.clip_id, clip_and_scroll.scroll_node_id, - parent_pipeline_id, ClipRegion::create_for_clip_node_with_local_clip( &item.local_clip(), &reference_frame_relative_offset ), self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.pipeline_epochs.push((iframe_pipeline_id, pipeline.epoch)); @@ -380,6 +437,7 @@ impl<'a> FlattenContext<'a> { None, origin, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.builder.add_scroll_frame( @@ -391,6 +449,7 @@ impl<'a> FlattenContext<'a> { &pipeline.content_size, ScrollSensitivity::ScriptAndInputEvents, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.flatten_root(&mut pipeline.display_list.iter(), iframe_pipeline_id, &iframe_rect.size); @@ -404,7 +463,11 @@ impl<'a> FlattenContext<'a> { pipeline_id: PipelineId, reference_frame_relative_offset: LayerVector2D, ) -> Option> { - let mut clip_and_scroll = item.clip_and_scroll(); + let clip_and_scroll = item.clip_and_scroll(); + let mut clip_and_scroll = ScrollNodeAndClipChain::new( + clip_and_scroll.scroll_node_id, + self.id_to_index_mapper.map_clip_id_and_cache_result(&clip_and_scroll.clip_node_id()), + ); let unreplaced_scroll_id = clip_and_scroll.scroll_node_id; clip_and_scroll.scroll_node_id = @@ -557,6 +620,7 @@ impl<'a> FlattenContext<'a> { &mut subtraversal, pipeline_id, unreplaced_scroll_id, + clip_and_scroll, reference_frame_relative_offset, &item.rect(), &info.stacking_context, @@ -569,7 +633,6 @@ impl<'a> FlattenContext<'a> { self.flatten_iframe( &item, info, - pipeline_id, &clip_and_scroll, &reference_frame_relative_offset ); @@ -582,16 +645,16 @@ impl<'a> FlattenContext<'a> { info.image_mask, &reference_frame_relative_offset, ); - self.flatten_clip( - pipeline_id, - &clip_and_scroll.scroll_node_id, - &info.id, - clip_region, - ); + self.flatten_clip(&clip_and_scroll.scroll_node_id, &info.id, clip_region); } SpecificDisplayItem::ClipChain(ref info) => { let items = self.get_clip_chain_items(pipeline_id, item.clip_chain_items()); - self.clip_scroll_tree.add_clip_chain_descriptor(info.id, info.parent, items); + let parent = info.parent.map(|id| + self.id_to_index_mapper.map_clip_id(&ClipId::ClipChain(id)) + ); + let clip_chain_index = + self.clip_scroll_tree.add_clip_chain_descriptor(parent, items); + self.id_to_index_mapper.add(ClipId::ClipChain(info.id), clip_chain_index); }, SpecificDisplayItem::ScrollFrame(ref info) => { self.flatten_scroll_frame( @@ -610,12 +673,14 @@ impl<'a> FlattenContext<'a> { info.horizontal_offset_bounds, info.previously_applied_offset, ); + let parent_id = clip_and_scroll.scroll_node_id; self.clip_scroll_tree.add_sticky_frame( info.id, - clip_and_scroll.scroll_node_id, /* parent id */ + parent_id, frame_rect, sticky_frame_info ); + self.id_to_index_mapper.map_to_parent_clip_chain(info.id, &parent_id); } // Do nothing; these are dummy items for the display list parser @@ -650,7 +715,7 @@ impl<'a> FlattenContext<'a> { /// takes care of the decomposition required by the internal tiling of the image. fn decompose_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, image_size: DeviceUintSize, @@ -696,7 +761,7 @@ impl<'a> FlattenContext<'a> { fn decompose_image_row( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, image_size: DeviceUintSize, @@ -742,7 +807,7 @@ impl<'a> FlattenContext<'a> { fn decompose_tiled_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, image_size: DeviceUintSize, @@ -878,7 +943,7 @@ impl<'a> FlattenContext<'a> { fn add_tile_primitive( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, tile_offset: TileOffset, @@ -1056,6 +1121,7 @@ impl FrameContext { pipeline_epochs: Vec::new(), replacements: Vec::new(), output_pipelines, + id_to_index_mapper: ClipIdToIndexMapper::new(), }; roller.builder.push_root( @@ -1063,6 +1129,7 @@ impl FrameContext { &root_pipeline.viewport_size, &root_pipeline.content_size, roller.clip_scroll_tree, + &mut roller.id_to_index_mapper, ); roller.builder.setup_viewport_offset( diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index 8611d6e32d..a72fbb85c0 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -2,35 +2,34 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo}; -use api::{ClipId, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale}; -use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, Epoch, ExtendMode}; -use api::{ExternalScrollId, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop, ImageKey}; -use api::{ImageRendering, ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize}; -use api::{LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D, LineOrientation}; -use api::{LineStyle, LocalClip, PipelineId, PremultipliedColorF, PropertyBinding, RepeatMode}; -use api::{ScrollSensitivity, Shadow, TexelRect, TileOffset, TransformStyle, WorldPoint}; -use api::{WorldToLayerTransform, YuvColorSpace, YuvData}; +use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipId, ColorF}; +use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale, DeviceUintPoint}; +use api::{DeviceUintRect, DeviceUintSize, DocumentLayer, Epoch, ExtendMode, ExternalScrollId}; +use api::{FontRenderMode, GlyphInstance, GlyphOptions, GradientStop, ImageKey, ImageRendering}; +use api::{ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize, LayerTransform}; +use api::{LayerVector2D, LayoutTransform, LayoutVector2D, LineOrientation, LineStyle, LocalClip}; +use api::{PipelineId, PremultipliedColorF, PropertyBinding, RepeatMode, ScrollSensitivity, Shadow}; +use api::{TexelRect, TileOffset, TransformStyle, WorldPoint, WorldToLayerTransform, YuvColorSpace}; +use api::YuvData; use app_units::Au; use border::ImageBorderSegment; -use clip::{ClipRegion, ClipSource, ClipSources, ClipStore}; +use clip::{ClipChain, ClipRegion, ClipSource, ClipSources, ClipStore}; use clip_scroll_node::{ClipScrollNode, NodeType}; -use clip_scroll_tree::ClipScrollTree; +use clip_scroll_tree::{ClipScrollTree, ClipChainIndex}; use euclid::{SideOffsets2D, vec2}; -use frame::FrameId; +use frame::{FrameId, ClipIdToIndexMapper}; use glyph_rasterizer::FontInstance; use gpu_cache::GpuCache; use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType}; use hit_test::{HitTester, HitTestingItem, HitTestingRun}; use internal_types::{FastHashMap, FastHashSet}; use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface}; -use prim_store::{BrushKind, BrushPrimitive, ImageCacheKey}; -use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, ImageSource, PrimitiveKind}; -use prim_store::{PrimitiveContainer, PrimitiveIndex}; -use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu}; -use prim_store::{BrushSegmentDescriptor, PrimitiveRun, TextRunPrimitiveCpu}; +use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, GradientPrimitiveCpu}; +use prim_store::{ImageCacheKey, ImagePrimitiveCpu, ImageSource, PrimitiveContainer}; +use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveRun, PrimitiveStore}; +use prim_store::{RadialGradientPrimitiveCpu, ScrollNodeAndClipChain, TextRunPrimitiveCpu}; use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters}; -use render_task::{ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree}; +use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree}; use resource_cache::{ImageRequest, ResourceCache}; use scene::{ScenePipeline, SceneProperties}; use std::{mem, usize, f32}; @@ -90,10 +89,10 @@ pub struct FrameBuilder { // A stack of the current shadow primitives. // The sub-Vec stores a buffer of fast-path primitives to be appended on pop. - shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ClipAndScrollInfo)>)>, + shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ScrollNodeAndClipChain)>)>, // If we're doing any fast-path shadows, we buffer the "real" // content here, to be appended when the shadow stack is empty. - pending_shadow_contents: Vec<(PrimitiveIndex, ClipAndScrollInfo, LayerPrimitiveInfo)>, + pending_shadow_contents: Vec<(PrimitiveIndex, ScrollNodeAndClipChain, LayerPrimitiveInfo)>, scrollbar_prims: Vec, @@ -150,14 +149,14 @@ impl PictureState { } pub struct PrimitiveRunContext<'a> { - pub clip_chain: Option<&'a ClipChain>, + pub clip_chain: &'a ClipChain, pub scroll_node: &'a ClipScrollNode, pub clip_chain_rect_index: ClipChainRectIndex, } impl<'a> PrimitiveRunContext<'a> { pub fn new( - clip_chain: Option<&'a ClipChain>, + clip_chain: &'a ClipChain, scroll_node: &'a ClipScrollNode, clip_chain_rect_index: ClipChainRectIndex, ) -> Self { @@ -252,7 +251,7 @@ impl FrameBuilder { pub fn add_primitive_to_hit_testing_list( &mut self, info: &LayerPrimitiveInfo, - clip_and_scroll: ClipAndScrollInfo + clip_and_scroll: ScrollNodeAndClipChain ) { let tag = match info.tag { Some(tag) => tag, @@ -276,7 +275,7 @@ impl FrameBuilder { pub fn add_primitive_to_draw_list( &mut self, prim_index: PrimitiveIndex, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, ) { // Add primitive to the top-most Picture on the stack. // TODO(gw): Let's consider removing the extra indirection @@ -294,7 +293,7 @@ impl FrameBuilder { /// to the draw list. pub fn add_primitive( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, clip_sources: Vec, container: PrimitiveContainer, @@ -313,7 +312,7 @@ impl FrameBuilder { transform_style: TransformStyle, is_backface_visible: bool, is_pipeline_root: bool, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, output_pipelines: &FastHashSet, ) { // Construct the necessary set of Picture primitives @@ -640,6 +639,7 @@ impl FrameBuilder { source_perspective: Option, origin_in_parent_reference_frame: LayerVector2D, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) { let node = ClipScrollNode::new_reference_frame( parent_id, @@ -651,6 +651,12 @@ impl FrameBuilder { ); clip_scroll_tree.add_node(node, reference_frame_id); self.reference_frame_stack.push(reference_frame_id); + + match parent_id { + Some(ref parent_id) => + id_to_index_mapper.map_to_parent_clip_chain(reference_frame_id, parent_id), + _ => id_to_index_mapper.add(reference_frame_id, ClipChainIndex(0)), + } } pub fn current_reference_frame_id(&self) -> ClipId { @@ -682,6 +688,7 @@ impl FrameBuilder { viewport_size: &LayerSize, content_size: &LayerSize, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) -> ClipId { let viewport_rect = LayerRect::new(LayerPoint::zero(), *viewport_size); self.push_reference_frame( @@ -693,6 +700,7 @@ impl FrameBuilder { None, LayerVector2D::zero(), clip_scroll_tree, + id_to_index_mapper, ); let topmost_scrolling_node_id = ClipId::root_scroll_node(pipeline_id); @@ -707,6 +715,7 @@ impl FrameBuilder { content_size, ScrollSensitivity::ScriptAndInputEvents, clip_scroll_tree, + id_to_index_mapper, ); topmost_scrolling_node_id @@ -716,18 +725,23 @@ impl FrameBuilder { &mut self, new_node_id: ClipId, parent_id: ClipId, - pipeline_id: PipelineId, clip_region: ClipRegion, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) { let clip_rect = clip_region.main; let clip_sources = ClipSources::from(clip_region); - debug_assert!(clip_sources.has_clips()); + debug_assert!(clip_sources.has_clips()); let handle = self.clip_store.insert(clip_sources); - let node = ClipScrollNode::new_clip_node(pipeline_id, parent_id, handle, clip_rect); - clip_scroll_tree.add_node(node, new_node_id); + let clip_chain_index = clip_scroll_tree.add_clip_node( + new_node_id, + parent_id, + handle, + clip_rect + ); + id_to_index_mapper.add(new_node_id, clip_chain_index); } pub fn add_scroll_frame( @@ -740,6 +754,7 @@ impl FrameBuilder { content_size: &LayerSize, scroll_sensitivity: ScrollSensitivity, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) { let node = ClipScrollNode::new_scroll_frame( pipeline_id, @@ -751,6 +766,7 @@ impl FrameBuilder { ); clip_scroll_tree.add_node(node, new_node_id); + id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id); } pub fn pop_reference_frame(&mut self) { @@ -760,7 +776,7 @@ impl FrameBuilder { pub fn push_shadow( &mut self, shadow: Shadow, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, ) { let pipeline_id = self.sc_stack.last().unwrap().pipeline_id; @@ -804,7 +820,7 @@ impl FrameBuilder { pub fn add_solid_rectangle( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, color: ColorF, segments: Option, @@ -833,7 +849,7 @@ impl FrameBuilder { pub fn add_clear_rectangle( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, ) { let prim = BrushPrimitive::new( @@ -851,7 +867,7 @@ impl FrameBuilder { pub fn add_scroll_bar( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, color: ColorF, scrollbar_info: ScrollbarInfo, @@ -883,7 +899,7 @@ impl FrameBuilder { pub fn add_line( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, wavy_line_thickness: f32, orientation: LineOrientation, @@ -970,7 +986,7 @@ impl FrameBuilder { pub fn add_border( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, border_item: &BorderDisplayItem, gradient_stops: ItemRange, @@ -1222,7 +1238,7 @@ impl FrameBuilder { pub fn add_gradient( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, start_point: LayerPoint, end_point: LayerPoint, @@ -1292,7 +1308,7 @@ impl FrameBuilder { fn add_radial_gradient_impl( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, start_center: LayerPoint, start_radius: f32, @@ -1331,7 +1347,7 @@ impl FrameBuilder { pub fn add_radial_gradient( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, start_center: LayerPoint, start_radius: f32, @@ -1380,7 +1396,7 @@ impl FrameBuilder { pub fn add_text( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, run_offset: LayoutVector2D, info: &LayerPrimitiveInfo, font: &FontInstance, @@ -1536,7 +1552,7 @@ impl FrameBuilder { pub fn add_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, stretch_size: LayerSize, mut tile_spacing: LayerSize, @@ -1616,7 +1632,7 @@ impl FrameBuilder { pub fn add_yuv_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, yuv_data: YuvData, color_space: YuvColorSpace, diff --git a/webrender/src/hit_test.rs b/webrender/src/hit_test.rs index 55b9fa90b8..d4b7b2b689 100644 --- a/webrender/src/hit_test.rs +++ b/webrender/src/hit_test.rs @@ -2,13 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{BorderRadius, ClipAndScrollInfo, ClipId, ClipMode, HitTestFlags, HitTestItem}; -use api::{HitTestResult, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect}; -use api::{LayerToWorldTransform, LocalClip, PipelineId, WorldPoint}; +use api::{BorderRadius, ClipId, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag}; +use api::{LayerPoint, LayerPrimitiveInfo, LayerRect, LayerToWorldTransform, LocalClip, PipelineId}; +use api::WorldPoint; use clip::{ClipSource, ClipStore, Contains, rounded_rectangle_contains_point}; use clip_scroll_node::{ClipScrollNode, NodeType}; -use clip_scroll_tree::ClipScrollTree; +use clip_scroll_tree::{ClipChainIndex, ClipScrollTree}; use internal_types::FastHashMap; +use prim_store::ScrollNodeAndClipChain; /// A copy of important clip scroll node data to use during hit testing. This a copy of /// data from the ClipScrollTree that will persist as a new frame is under construction, @@ -33,11 +34,21 @@ pub struct HitTestClipScrollNode { /// handled the same way during hit testing. Once we represent all ClipChains /// using ClipChainDescriptors, we can get rid of this and just use the /// ClipChainDescriptor here. +#[derive(Clone)] struct HitTestClipChainDescriptor { - parent: Option, + parent: Option, clips: Vec, } +impl HitTestClipChainDescriptor { + fn empty() -> HitTestClipChainDescriptor { + HitTestClipChainDescriptor { + parent: None, + clips: Vec::new(), + } + } +} + #[derive(Clone)] pub struct HitTestingItem { rect: LayerRect, @@ -56,7 +67,7 @@ impl HitTestingItem { } #[derive(Clone)] -pub struct HitTestingRun(pub Vec, pub ClipAndScrollInfo); +pub struct HitTestingRun(pub Vec, pub ScrollNodeAndClipChain); enum HitTestRegion { Rectangle(LayerRect), @@ -78,7 +89,7 @@ impl HitTestRegion { pub struct HitTester { runs: Vec, nodes: FastHashMap, - clip_chains: FastHashMap, + clip_chains: Vec, } impl HitTester { @@ -90,7 +101,7 @@ impl HitTester { let mut hit_tester = HitTester { runs: runs.clone(), nodes: FastHashMap::default(), - clip_chains: FastHashMap::default(), + clip_chains: Vec::new(), }; hit_tester.read_clip_scroll_tree(clip_scroll_tree, clip_store); hit_tester @@ -102,6 +113,11 @@ impl HitTester { clip_store: &ClipStore ) { self.nodes.clear(); + self.clip_chains.clear(); + self.clip_chains.resize( + clip_scroll_tree.clip_chains.len(), + HitTestClipChainDescriptor::empty() + ); for (id, node) in &clip_scroll_tree.nodes { self.nodes.insert(*id, HitTestClipScrollNode { @@ -111,52 +127,50 @@ impl HitTester { node_origin: node.local_viewport_rect.origin, }); - self.clip_chains.insert(*id, HitTestClipChainDescriptor { - parent: node.parent, - clips: vec![*id], - }); + if let NodeType::Clip { clip_chain_index, .. } = node.node_type { + let clip_chain = self.clip_chains.get_mut(clip_chain_index.0).unwrap(); + clip_chain.parent = + clip_scroll_tree.get_clip_chain(clip_chain_index).parent_index; + clip_chain.clips = vec![*id]; + } } for descriptor in &clip_scroll_tree.clip_chains_descriptors { - self.clip_chains.insert( - ClipId::ClipChain(descriptor.id), - HitTestClipChainDescriptor { - parent: descriptor.parent.map(|id| ClipId::ClipChain(id)), - clips: descriptor.clips.clone(), - } - ); + let clip_chain = self.clip_chains.get_mut(descriptor.index.0).unwrap(); + clip_chain.parent = clip_scroll_tree.get_clip_chain(descriptor.index).parent_index; + clip_chain.clips = descriptor.clips.clone(); } } fn is_point_clipped_in_for_clip_chain( &self, point: WorldPoint, - chain_id: &ClipId, + clip_chain_index: ClipChainIndex, test: &mut HitTest ) -> bool { - if let Some(result) = test.clip_chain_cache.get(&chain_id) { - return *result; + if let Some(result) = test.get_from_clip_chain_cache(clip_chain_index) { + return result; } - let descriptor = &self.clip_chains[&chain_id]; + let descriptor = &self.clip_chains[clip_chain_index.0]; let parent_clipped_in = match descriptor.parent { None => true, - Some(ref parent) => self.is_point_clipped_in_for_clip_chain(point, parent, test), + Some(parent) => self.is_point_clipped_in_for_clip_chain(point, parent, test), }; if !parent_clipped_in { - test.clip_chain_cache.insert(*chain_id, false); + test.set_in_clip_chain_cache(clip_chain_index, false); return false; } for clip_node in &descriptor.clips { if !self.is_point_clipped_in_for_node(point, clip_node, test) { - test.clip_chain_cache.insert(*chain_id, false); + test.set_in_clip_chain_cache(clip_chain_index, false); return false; } } - test.clip_chain_cache.insert(*chain_id, true); + test.set_in_clip_chain_cache(clip_chain_index, true); true } @@ -197,7 +211,9 @@ impl HitTester { let mut result = HitTestResult::default(); for &HitTestingRun(ref items, ref clip_and_scroll) in self.runs.iter().rev() { - let scroll_node = &self.nodes[&clip_and_scroll.scroll_node_id]; + let scroll_node_id = clip_and_scroll.scroll_node_id; + let scroll_node = &self.nodes[&scroll_node_id]; + let pipeline_id = scroll_node_id.pipeline_id(); match (test.pipeline_id, clip_and_scroll.scroll_node_id.pipeline_id()) { (Some(id), node_id) if node_id != id => continue, _ => {}, @@ -215,12 +231,11 @@ impl HitTester { continue; } - let clip_id = &clip_and_scroll.clip_node_id(); + let clip_chain_index = clip_and_scroll.clip_chain_index; + clipped_in |= + self.is_point_clipped_in_for_clip_chain(point, clip_chain_index, &mut test); if !clipped_in { - clipped_in = self.is_point_clipped_in_for_clip_chain(point, clip_id, &mut test); - if !clipped_in { - break; - } + break; } // We need to trigger a lookup against the root reference frame here, because @@ -228,7 +243,7 @@ impl HitTester { // hierarchy. If we don't have a valid point for this test, we are likely // in a situation where the reference frame has an univertible transform, but the // item's clip does not. - let root_reference_frame = ClipId::root_reference_frame(clip_id.pipeline_id()); + let root_reference_frame = ClipId::root_reference_frame(pipeline_id); if !self.is_point_clipped_in_for_node(point, &root_reference_frame, &mut test) { continue; } @@ -238,7 +253,7 @@ impl HitTester { }; result.items.push(HitTestItem { - pipeline: clip_and_scroll.clip_node_id().pipeline_id(), + pipeline: pipeline_id, tag: item.tag, point_in_viewport, point_relative_to_item: point_in_layer - item.rect.origin.to_vector(), @@ -259,7 +274,7 @@ fn get_regions_for_clip_scroll_node( clip_store: &ClipStore ) -> Vec { let clips = match node.node_type { - NodeType::Clip(ref handle) => clip_store.get(handle).clips(), + NodeType::Clip{ ref handle, .. } => clip_store.get(handle).clips(), _ => return Vec::new(), }; @@ -280,7 +295,7 @@ pub struct HitTest { point: WorldPoint, flags: HitTestFlags, node_cache: FastHashMap>, - clip_chain_cache: FastHashMap, + clip_chain_cache: Vec>, } impl HitTest { @@ -294,8 +309,23 @@ impl HitTest { point, flags, node_cache: FastHashMap::default(), - clip_chain_cache: FastHashMap::default(), + clip_chain_cache: Vec::new(), + } + } + + pub fn get_from_clip_chain_cache(&mut self, index: ClipChainIndex) -> Option { + if index.0 >= self.clip_chain_cache.len() { + None + } else { + self.clip_chain_cache[index.0] + } + } + + pub fn set_in_clip_chain_cache(&mut self, index: ClipChainIndex, value: bool) { + if index.0 >= self.clip_chain_cache.len() { + self.clip_chain_cache.resize(index.0 + 1, None); } + self.clip_chain_cache[index.0] = Some(value); } pub fn get_absolute_point(&self, hit_tester: &HitTester) -> WorldPoint { diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index 2bc77803eb..8abf253d82 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -2,15 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{ColorF, ClipAndScrollInfo, FilterOp, MixBlendMode}; -use api::{DeviceIntPoint, DeviceIntRect, LayerToWorldScale, PipelineId}; -use api::{BoxShadowClipMode, LayerPoint, LayerRect, LayerVector2D, Shadow}; -use api::{ClipId, PremultipliedColorF}; +use api::{BoxShadowClipMode, ClipId, ColorF, DeviceIntPoint, DeviceIntRect, FilterOp, LayerPoint}; +use api::{LayerRect, LayerToWorldScale, LayerVector2D, MixBlendMode, PipelineId}; +use api::{PremultipliedColorF, Shadow}; use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowCacheKey}; use frame_builder::{FrameContext, FrameState, PictureState}; use gpu_cache::GpuDataRequest; use gpu_types::{BrushImageKind, PictureType}; use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect}; +use prim_store::ScrollNodeAndClipChain; use render_task::{ClearMode, RenderTask, RenderTaskCacheKey}; use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation}; use resource_cache::CacheItem; @@ -230,7 +230,7 @@ impl PicturePrimitive { pub fn add_primitive( &mut self, prim_index: PrimitiveIndex, - clip_and_scroll: ClipAndScrollInfo + clip_and_scroll: ScrollNodeAndClipChain ) { if let Some(ref mut run) = self.runs.last_mut() { if run.clip_and_scroll == clip_and_scroll && diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index df94e9bcf6..c153e5bd5a 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -2,25 +2,24 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipAndScrollInfo, ClipMode}; -use api::{ColorF, DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch}; -use api::{ComplexClipRegion, ExtendMode, FontRenderMode}; +use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipId, ClipMode, ColorF, ComplexClipRegion}; +use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode}; use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag}; use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation}; -use api::{LineStyle, PremultipliedColorF}; -use api::{WorldToLayerTransform, YuvColorSpace, YuvFormat}; +use api::{LineStyle, PremultipliedColorF, WorldToLayerTransform, YuvColorSpace, YuvFormat}; use border::{BorderCornerInstance, BorderEdgeKind}; -use clip_scroll_tree::{CoordinateSystemId}; +use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId}; use clip_scroll_node::ClipScrollNode; -use clip::{ClipSource, ClipSourcesHandle}; +use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource}; +use clip::{ClipSourcesHandle, ClipWorkItem}; use frame_builder::{FrameContext, FrameState, PictureContext, PictureState, PrimitiveRunContext}; use glyph_rasterizer::{FontInstance, FontTransform}; use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use gpu_types::{ClipChainRectIndex}; use picture::{PictureKind, PicturePrimitive}; -use render_task::{BlitSource, ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipWorkItem}; -use render_task::{RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId}; +use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind}; +use render_task::RenderTaskId; use renderer::{MAX_VERTEX_TEXTURE_WIDTH}; use resource_cache::{CacheItem, ImageProperties, ImageRequest, ResourceCache}; use segment::SegmentBuilder; @@ -32,11 +31,23 @@ use util::recycle_vec; const MIN_BRUSH_SPLIT_AREA: f32 = 128.0 * 128.0; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ScrollNodeAndClipChain { + pub scroll_node_id: ClipId, + pub clip_chain_index: ClipChainIndex, +} + +impl ScrollNodeAndClipChain { + pub fn new(scroll_node_id: ClipId, clip_chain_index: ClipChainIndex) -> ScrollNodeAndClipChain { + ScrollNodeAndClipChain { scroll_node_id, clip_chain_index } + } +} + #[derive(Debug)] pub struct PrimitiveRun { pub base_prim_index: PrimitiveIndex, pub count: usize, - pub clip_and_scroll: ClipAndScrollInfo, + pub clip_and_scroll: ScrollNodeAndClipChain, } #[derive(Debug, Copy, Clone)] @@ -1602,12 +1613,9 @@ impl PrimitiveStore { } }; - let mut combined_outer_rect = match prim_run_context.clip_chain { - Some(ref chain) => prim_screen_rect.intersection(&chain.combined_outer_screen_rect), - None => Some(prim_screen_rect), - }; - - let clip_chain = prim_run_context.clip_chain.map_or(None, |x| x.nodes.clone()); + let mut combined_outer_rect = + prim_screen_rect.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect); + let clip_chain = prim_run_context.clip_chain.nodes.clone(); let prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id; let transform = &prim_run_context.scroll_node.world_content_transform; @@ -1828,12 +1836,8 @@ impl PrimitiveStore { frame_context.device_pixel_scale, ); - let clip_bounds = match prim_run_context.clip_chain { - Some(ref node) => node.combined_outer_screen_rect, - None => frame_context.screen_rect, - }; metadata.screen_rect = screen_bounding_rect - .intersection(&clip_bounds) + .intersection(&prim_run_context.clip_chain.combined_outer_screen_rect) .map(|clipped| { ScreenRect { clipped, @@ -1903,7 +1907,7 @@ impl PrimitiveStore { .nodes[&run.clip_and_scroll.scroll_node_id]; let clip_chain = frame_context .clip_scroll_tree - .get_clip_chain(&run.clip_and_scroll.clip_node_id()); + .get_clip_chain(run.clip_and_scroll.clip_chain_index); if pic_context.perform_culling { if !scroll_node.invertible { @@ -1911,16 +1915,12 @@ impl PrimitiveStore { continue; } - match clip_chain { - Some(ref chain) if chain.combined_outer_screen_rect.is_empty() => { - debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id); - continue; - } - _ => {}, + if clip_chain.combined_outer_screen_rect.is_empty() { + debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id); + continue; } } - let parent_relative_transform = pic_context .inv_world_transform .map(|inv_parent| { @@ -2050,14 +2050,9 @@ fn convert_clip_chain_to_clip_vector( fn get_local_clip_rect_for_nodes( scroll_node: &ClipScrollNode, - clip_chain: Option<&ClipChain>, + clip_chain: &ClipChain, ) -> Option { - let clip_chain_nodes = match clip_chain { - Some(ref clip_chain) => clip_chain.nodes.clone(), - None => return None, - }; - - let local_rect = ClipChainNodeIter { current: clip_chain_nodes }.fold( + let local_rect = ClipChainNodeIter { current: clip_chain.nodes.clone() }.fold( None, |combined_local_clip_rect: Option, node| { if node.work_item.coordinate_system_id != scroll_node.coordinate_system_id { diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 5ec00d078b..c5a6824129 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -2,14 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; -use api::{ImageDescriptor, ImageFormat, LayerRect, PremultipliedColorF}; +use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, ImageDescriptor, ImageFormat}; +use api::PremultipliedColorF; use box_shadow::BoxShadowCacheKey; -use clip::{ClipSourcesWeakHandle}; +use clip::ClipWorkItem; use clip_scroll_tree::CoordinateSystemId; use device::TextureFilter; use gpu_cache::GpuCache; -use gpu_types::{ClipScrollNodeIndex, PictureType}; +use gpu_types::PictureType; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use picture::ContentOrigin; use prim_store::{PrimitiveIndex, ImageCacheKey}; @@ -17,7 +17,6 @@ use prim_store::{PrimitiveIndex, ImageCacheKey}; use print_tree::{PrintTreePrinter}; use resource_cache::CacheItem; use std::{cmp, ops, usize, f32, i32}; -use std::rc::Rc; use texture_cache::{TextureCache, TextureCacheHandle}; use tiling::{RenderPass, RenderTargetIndex}; use tiling::{RenderTargetKind}; @@ -46,91 +45,6 @@ pub struct RenderTaskTree { next_saved: SavedTargetIndex, } -pub type ClipChainNodeRef = Option>; - -#[derive(Debug, Clone)] -pub struct ClipChainNode { - pub work_item: ClipWorkItem, - pub local_clip_rect: LayerRect, - pub screen_outer_rect: DeviceIntRect, - pub screen_inner_rect: DeviceIntRect, - pub prev: ClipChainNodeRef, -} - -#[derive(Debug, Clone)] -pub struct ClipChain { - pub combined_outer_screen_rect: DeviceIntRect, - pub combined_inner_screen_rect: DeviceIntRect, - pub nodes: ClipChainNodeRef, -} - -impl ClipChain { - pub fn empty(screen_rect: &DeviceIntRect) -> ClipChain { - ClipChain { - combined_inner_screen_rect: *screen_rect, - combined_outer_screen_rect: *screen_rect, - nodes: None, - } - } - - pub fn new_with_added_node( - &self, - work_item: ClipWorkItem, - local_clip_rect: LayerRect, - screen_outer_rect: DeviceIntRect, - screen_inner_rect: DeviceIntRect, - ) -> ClipChain { - let new_node = ClipChainNode { - work_item, - local_clip_rect, - screen_outer_rect, - screen_inner_rect, - prev: None, - }; - - let mut new_chain = self.clone(); - new_chain.add_node(new_node); - new_chain - } - - pub fn add_node(&mut self, mut new_node: ClipChainNode) { - new_node.prev = self.nodes.clone(); - - // If this clip's outer rectangle is completely enclosed by the clip - // chain's inner rectangle, then the only clip that matters from this point - // on is this clip. We can disconnect this clip from the parent clip chain. - if self.combined_inner_screen_rect.contains_rect(&new_node.screen_outer_rect) { - new_node.prev = None; - } - - self.combined_outer_screen_rect = - self.combined_outer_screen_rect.intersection(&new_node.screen_outer_rect) - .unwrap_or_else(DeviceIntRect::zero); - self.combined_inner_screen_rect = - self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect) - .unwrap_or_else(DeviceIntRect::zero); - - self.nodes = Some(Rc::new(new_node)); - } -} - -pub struct ClipChainNodeIter { - pub current: ClipChainNodeRef, -} - -impl Iterator for ClipChainNodeIter { - type Item = Rc; - - fn next(&mut self) -> ClipChainNodeRef { - let previous = self.current.clone(); - self.current = match self.current { - Some(ref item) => item.prev.clone(), - None => return None, - }; - previous - } -} - impl RenderTaskTree { pub fn new() -> Self { RenderTaskTree { @@ -231,15 +145,6 @@ pub enum RenderTaskLocation { TextureCache(SourceTexture, i32, DeviceIntRect), } -#[derive(Debug, Clone)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct ClipWorkItem { - pub scroll_node_data_index: ClipScrollNodeIndex, - pub clip_sources: ClipSourcesWeakHandle, - pub coordinate_system_id: CoordinateSystemId, -} - #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))]