diff --git a/direct-composition/src/main_windows.rs b/direct-composition/src/main_windows.rs index b025f8f176..d4255c0c03 100644 --- a/direct-composition/src/main_windows.rs +++ b/direct-composition/src/main_windows.rs @@ -142,12 +142,21 @@ impl Rectangle { api::BorderRadius::uniform(20.), api::ClipMode::Clip ); - let clip_id = builder.define_clip(rect, vec![region], None); - builder.push_clip_id(clip_id); - - builder.push_rect(&api::PrimitiveInfo::new(rect), self.color); + let clip_id = builder.define_clip( + &api::SpaceAndClipInfo::root_scroll(pipeline_id), + rect, + vec![region], + None, + ); - builder.pop_clip_id(); + builder.push_rect( + &api::PrimitiveInfo::new(rect), + &api::SpaceAndClipInfo { + spatial_id: api::SpatialId::root_scroll_node(pipeline_id), + clip_id, + }, + self.color, + ); let mut transaction = api::Transaction::new(); transaction.set_display_list( diff --git a/examples/alpha_perf.rs b/examples/alpha_perf.rs index 1c6e5389a7..f668d618a4 100644 --- a/examples/alpha_perf.rs +++ b/examples/alpha_perf.rs @@ -26,14 +26,16 @@ impl Example for App { builder: &mut DisplayListBuilder, _txn: &mut Transaction, _framebuffer_size: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let bounds = (0, 0).to(1920, 1080); let info = LayoutPrimitiveInfo::new(bounds); + let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -42,7 +44,7 @@ impl Example for App { ); for _ in 0 .. self.rect_count { - builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 0.05)); + builder.push_rect(&info, &space_and_clip, ColorF::new(1.0, 1.0, 1.0, 0.05)); } builder.pop_stacking_context(); diff --git a/examples/animation.rs b/examples/animation.rs index c2b625cca4..88afd8f370 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -40,6 +40,7 @@ impl App { bounds: LayoutRect, color: ColorF, builder: &mut DisplayListBuilder, + pipeline_id: PipelineId, property_key: PropertyBindingKey<LayoutTransform>, opacity_key: Option<PropertyBindingKey<f32>>, ) { @@ -54,17 +55,17 @@ impl App { } }; - let reference_frame_id = builder.push_reference_frame( + let spatial_id = builder.push_reference_frame( &LayoutRect::new(bounds.origin, LayoutSize::zero()), + SpatialId::root_scroll_node(pipeline_id), TransformStyle::Flat, Some(PropertyBinding::Binding(property_key, LayoutTransform::identity())), None, ); - builder.push_clip_id(reference_frame_id); - builder.push_stacking_context( &LayoutPrimitiveInfo::new(LayoutRect::zero()), + spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -72,26 +73,29 @@ impl App { RasterSpace::Screen, ); + let space_and_clip = SpaceAndClipInfo { + spatial_id, + clip_id: ClipId::root(pipeline_id), + }; let clip_bounds = LayoutRect::new(LayoutPoint::zero(), bounds.size); let complex_clip = ComplexClipRegion { rect: clip_bounds, radii: BorderRadius::uniform(30.0), mode: ClipMode::Clip, }; - let clip_id = builder.define_clip(clip_bounds, vec![complex_clip], None); - builder.push_clip_id(clip_id); + let clip_id = builder.define_clip(&space_and_clip, clip_bounds, vec![complex_clip], None); // Fill it with a white rect builder.push_rect( &LayoutPrimitiveInfo::new(LayoutRect::new(LayoutPoint::zero(), bounds.size)), + &SpaceAndClipInfo { + spatial_id, + clip_id, + }, color, ); - builder.pop_clip_id(); - builder.pop_stacking_context(); - - builder.pop_clip_id(); builder.pop_reference_frame(); } } @@ -106,22 +110,22 @@ impl Example for App { builder: &mut DisplayListBuilder, _txn: &mut Transaction, _framebuffer_size: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let opacity_key = self.opacity_key; let bounds = (150, 150).to(250, 250); let key0 = self.property_key0; - self.add_rounded_rect(bounds, ColorF::new(1.0, 0.0, 0.0, 0.5), builder, key0, Some(opacity_key)); + self.add_rounded_rect(bounds, ColorF::new(1.0, 0.0, 0.0, 0.5), builder, pipeline_id, key0, Some(opacity_key)); let bounds = (400, 400).to(600, 600); let key1 = self.property_key1; - self.add_rounded_rect(bounds, ColorF::new(0.0, 1.0, 0.0, 0.5), builder, key1, None); + self.add_rounded_rect(bounds, ColorF::new(0.0, 1.0, 0.0, 0.5), builder, pipeline_id, key1, None); let bounds = (200, 500).to(350, 580); let key2 = self.property_key2; - self.add_rounded_rect(bounds, ColorF::new(0.0, 0.0, 1.0, 0.5), builder, key2, None); + self.add_rounded_rect(bounds, ColorF::new(0.0, 0.0, 1.0, 0.5), builder, pipeline_id, key2, None); } fn on_event(&mut self, win_event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool { diff --git a/examples/basic.rs b/examples/basic.rs index af7994af5a..6bd63834fa 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -186,13 +186,17 @@ impl Example for App { builder: &mut DisplayListBuilder, txn: &mut Transaction, _: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size()); let info = LayoutPrimitiveInfo::new(bounds); + let root_space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); + let spatial_id = root_space_and_clip.spatial_id; + builder.push_stacking_context( &info, + spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -217,14 +221,19 @@ impl Example for App { BorderRadius::uniform(20.0), ClipMode::Clip ); - let id = builder.define_clip(bounds, vec![complex], Some(mask)); - builder.push_clip_id(id); + let clip_id = builder.define_clip(&root_space_and_clip, bounds, vec![complex], Some(mask)); - let info = LayoutPrimitiveInfo::new((100, 100).to(200, 200)); - builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0)); + builder.push_rect( + &LayoutPrimitiveInfo::new((100, 100).to(200, 200)), + &SpaceAndClipInfo { spatial_id, clip_id }, + ColorF::new(0.0, 1.0, 0.0, 1.0), + ); - let info = LayoutPrimitiveInfo::new((250, 100).to(350, 200)); - builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0)); + builder.push_rect( + &LayoutPrimitiveInfo::new((250, 100).to(350, 200)), + &SpaceAndClipInfo { spatial_id, clip_id }, + ColorF::new(0.0, 1.0, 0.0, 1.0), + ); let border_side = BorderSide { color: ColorF::new(0.0, 0.0, 1.0, 1.0), style: BorderStyle::Groove, @@ -239,9 +248,12 @@ impl Example for App { do_aa: true, }); - let info = LayoutPrimitiveInfo::new((100, 100).to(200, 200)); - builder.push_border(&info, border_widths, border_details); - builder.pop_clip_id(); + builder.push_border( + &LayoutPrimitiveInfo::new((100, 100).to(200, 200)), + &SpaceAndClipInfo { spatial_id, clip_id }, + border_widths, + border_details, + ); if false { // draw box shadow? @@ -253,10 +265,10 @@ impl Example for App { let spread_radius = 0.0; let simple_border_radius = 8.0; let box_shadow_type = BoxShadowClipMode::Inset; - let info = LayoutPrimitiveInfo::with_clip_rect(rect, bounds); builder.push_box_shadow( - &info, + &LayoutPrimitiveInfo::with_clip_rect(rect, bounds), + &root_space_and_clip, simple_box_bounds, offset, color, diff --git a/examples/blob.rs b/examples/blob.rs index 384df8ac06..5f7f856919 100644 --- a/examples/blob.rs +++ b/examples/blob.rs @@ -17,7 +17,7 @@ use rayon::prelude::*; use std::collections::HashMap; use std::sync::Arc; use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, RenderApi, Transaction}; -use webrender::api::ColorF; +use webrender::api::{ColorF, SpaceAndClipInfo}; use webrender::euclid::size2; // This example shows how to implement a very basic BlobImageHandler that can only render @@ -200,7 +200,7 @@ impl Example for App { builder: &mut DisplayListBuilder, txn: &mut Transaction, _framebuffer_size: api::DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let blob_img1 = api.generate_blob_image_key(); @@ -220,9 +220,11 @@ impl Example for App { ); let bounds = api::LayoutRect::new(api::LayoutPoint::zero(), builder.content_size()); - let info = api::LayoutPrimitiveInfo::new(bounds); + let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); + builder.push_stacking_context( - &info, + &api::LayoutPrimitiveInfo::new(bounds), + space_and_clip.spatial_id, None, api::TransformStyle::Flat, api::MixBlendMode::Normal, @@ -230,9 +232,9 @@ impl Example for App { api::RasterSpace::Screen, ); - let info = api::LayoutPrimitiveInfo::new((30, 30).by(500, 500)); builder.push_image( - &info, + &api::LayoutPrimitiveInfo::new((30, 30).by(500, 500)), + &space_and_clip, api::LayoutSize::new(500.0, 500.0), api::LayoutSize::new(0.0, 0.0), api::ImageRendering::Auto, @@ -241,9 +243,9 @@ impl Example for App { ColorF::WHITE, ); - let info = api::LayoutPrimitiveInfo::new((600, 600).by(200, 200)); builder.push_image( - &info, + &api::LayoutPrimitiveInfo::new((600, 600).by(200, 200)), + &space_and_clip, api::LayoutSize::new(200.0, 200.0), api::LayoutSize::new(0.0, 0.0), api::ImageRendering::Auto, diff --git a/examples/document.rs b/examples/document.rs index affa33600d..b62744cd0c 100644 --- a/examples/document.rs +++ b/examples/document.rs @@ -90,7 +90,7 @@ impl Example for App { base_builder: &mut DisplayListBuilder, _txn: &mut Transaction, framebuffer_size: DeviceIntSize, - _: PipelineId, + _pipeline_id: PipelineId, _: DocumentId, ) { if self.documents.is_empty() { @@ -102,6 +102,7 @@ impl Example for App { } for doc in &self.documents { + let space_and_clip = SpaceAndClipInfo::root_scroll(doc.pipeline_id); let mut builder = DisplayListBuilder::new( doc.pipeline_id, doc.content_rect.size, @@ -113,6 +114,7 @@ impl Example for App { builder.push_stacking_context( &LayoutPrimitiveInfo::new(doc.content_rect), + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -121,6 +123,7 @@ impl Example for App { ); builder.push_rect( &LayoutPrimitiveInfo::new(local_rect), + &space_and_clip, doc.color, ); builder.pop_stacking_context(); diff --git a/examples/frame_output.rs b/examples/frame_output.rs index 84bc51dd9c..9a5962f518 100644 --- a/examples/frame_output.rs +++ b/examples/frame_output.rs @@ -107,6 +107,7 @@ impl App { ); let info = LayoutPrimitiveInfo::new(document.content_rect); + let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); let mut builder = DisplayListBuilder::new( document.pipeline_id, document.content_rect.size, @@ -114,6 +115,7 @@ impl App { builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -121,7 +123,7 @@ impl App { RasterSpace::Screen, ); - builder.push_rect(&info, ColorF::new(1.0, 1.0, 0.0, 1.0)); + builder.push_rect(&info, &space_and_clip, ColorF::new(1.0, 1.0, 0.0, 1.0)); builder.pop_stacking_context(); txn.set_root_pipeline(pipeline_id); @@ -145,7 +147,7 @@ impl Example for App { builder: &mut DisplayListBuilder, _txn: &mut Transaction, framebuffer_size: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { if self.output_document.is_none() { @@ -155,8 +157,11 @@ impl Example for App { } let info = LayoutPrimitiveInfo::new((100, 100).to(200, 200)); + let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); + builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -166,6 +171,7 @@ impl Example for App { builder.push_image( &info, + &space_and_clip, info.rect.size, LayoutSize::zero(), ImageRendering::Auto, diff --git a/examples/iframe.rs b/examples/iframe.rs index 82728a61df..484fdb5b82 100644 --- a/examples/iframe.rs +++ b/examples/iframe.rs @@ -35,10 +35,12 @@ impl Example for App { let sub_pipeline_id = PipelineId(pipeline_id.0, 42); let mut sub_builder = DisplayListBuilder::new(sub_pipeline_id, sub_bounds.size); + let mut space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); let info = LayoutPrimitiveInfo::new(sub_bounds); sub_builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -47,7 +49,7 @@ impl Example for App { ); // green rect visible == success - sub_builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0)); + sub_builder.push_rect(&info, &space_and_clip, ColorF::new(0.0, 1.0, 0.0, 1.0)); sub_builder.pop_stacking_context(); let mut txn = Transaction::new(); @@ -60,19 +62,19 @@ impl Example for App { ); api.send_transaction(document_id, txn); - let info = LayoutPrimitiveInfo::new(sub_bounds); - let reference_frame_id = builder.push_reference_frame( + space_and_clip.spatial_id = builder.push_reference_frame( &sub_bounds, + space_and_clip.spatial_id, TransformStyle::Flat, Some(PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity())), None, ); - builder.push_clip_id(reference_frame_id); - // And this is for the root pipeline + let info = LayoutPrimitiveInfo::new(sub_bounds); builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -80,11 +82,9 @@ impl Example for App { RasterSpace::Screen, ); // red rect under the iframe: if this is visible, things have gone wrong - builder.push_rect(&info, ColorF::new(1.0, 0.0, 0.0, 1.0)); - builder.push_iframe(&info, sub_pipeline_id, false); + builder.push_rect(&info, &space_and_clip, ColorF::new(1.0, 0.0, 0.0, 1.0)); + builder.push_iframe(&info, &space_and_clip, sub_pipeline_id, false); builder.pop_stacking_context(); - - builder.pop_clip_id(); builder.pop_reference_frame(); } } diff --git a/examples/image_resize.rs b/examples/image_resize.rs index 7a667b7eac..fbeec2c53f 100644 --- a/examples/image_resize.rs +++ b/examples/image_resize.rs @@ -26,7 +26,7 @@ impl Example for App { builder: &mut DisplayListBuilder, txn: &mut Transaction, _framebuffer_size: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let (image_descriptor, image_data) = image_helper::make_checkerboard(32, 32); @@ -39,8 +39,11 @@ impl Example for App { let bounds = (0, 0).to(512, 512); let info = LayoutPrimitiveInfo::new(bounds); + let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); + builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -56,6 +59,7 @@ impl Example for App { ); builder.push_image( &info, + &space_and_clip, image_size, LayoutSize::zero(), ImageRendering::Auto, @@ -70,6 +74,7 @@ impl Example for App { ); builder.push_image( &info, + &space_and_clip, image_size, LayoutSize::zero(), ImageRendering::Pixelated, diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 9b2df6d7b5..c88ef0fead 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -187,11 +187,13 @@ impl Window { let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio); let mut txn = Transaction::new(); let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id); let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size()); let info = LayoutPrimitiveInfo::new(bounds); builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -203,7 +205,7 @@ impl Window { LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 200.0) )); - builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0)); + builder.push_rect(&info, &space_and_clip, ColorF::new(0.0, 1.0, 0.0, 1.0)); let text_bounds = LayoutRect::new( LayoutPoint::new(100.0, 50.0), @@ -263,6 +265,7 @@ impl Window { let info = LayoutPrimitiveInfo::new(text_bounds); builder.push_text( &info, + &space_and_clip, &glyphs, self.font_instance_key, ColorF::new(1.0, 1.0, 0.0, 1.0), diff --git a/examples/scrolling.rs b/examples/scrolling.rs index 3575c081c5..86b1c6bc7d 100644 --- a/examples/scrolling.rs +++ b/examples/scrolling.rs @@ -27,14 +27,16 @@ impl Example for App { builder: &mut DisplayListBuilder, _txn: &mut Transaction, _framebuffer_size: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let info = LayoutPrimitiveInfo::new( LayoutRect::new(LayoutPoint::zero(), builder.content_size()) ); + let root_space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); builder.push_stacking_context( &info, + root_space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -48,6 +50,7 @@ impl Example for App { let scrollbox = (0, 0).to(300, 400); builder.push_stacking_context( &LayoutPrimitiveInfo::new((10, 10).by(0, 0)), + root_space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -55,7 +58,8 @@ impl Example for App { RasterSpace::Screen, ); // set the scrolling clip - let clip_id = builder.define_scroll_frame( + let space_and_clip1 = builder.define_scroll_frame( + &root_space_and_clip, None, (0, 0).by(1000, 1000), scrollbox, @@ -63,30 +67,30 @@ impl Example for App { None, ScrollSensitivity::ScriptAndInputEvents, ); - builder.push_clip_id(clip_id); // now put some content into it. // start with a white background let mut info = LayoutPrimitiveInfo::new((0, 0).to(1000, 1000)); info.tag = Some((0, 1)); - builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0)); + builder.push_rect(&info, &space_and_clip1, ColorF::new(1.0, 1.0, 1.0, 1.0)); // let's make a 50x50 blue square as a visual reference let mut info = LayoutPrimitiveInfo::new((0, 0).to(50, 50)); info.tag = Some((0, 2)); - builder.push_rect(&info, ColorF::new(0.0, 0.0, 1.0, 1.0)); + builder.push_rect(&info, &space_and_clip1, ColorF::new(0.0, 0.0, 1.0, 1.0)); // and a 50x50 green square next to it with an offset clip // to see what that looks like let mut info = LayoutPrimitiveInfo::with_clip_rect((50, 0).to(100, 50), (60, 10).to(110, 60)); info.tag = Some((0, 3)); - builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0)); + builder.push_rect(&info, &space_and_clip1, ColorF::new(0.0, 1.0, 0.0, 1.0)); // Below the above rectangles, set up a nested scrollbox. It's still in // the same stacking context, so note that the rects passed in need to // be relative to the stacking context. - let nested_clip_id = builder.define_scroll_frame( + let space_and_clip2 = builder.define_scroll_frame( + &space_and_clip1, None, (0, 100).to(300, 1000), (0, 100).to(200, 300), @@ -94,25 +98,25 @@ impl Example for App { None, ScrollSensitivity::ScriptAndInputEvents, ); - builder.push_clip_id(nested_clip_id); // give it a giant gray background just to distinguish it and to easily // visually identify the nested scrollbox let mut info = LayoutPrimitiveInfo::new((-1000, -1000).to(5000, 5000)); info.tag = Some((0, 4)); - builder.push_rect(&info, ColorF::new(0.5, 0.5, 0.5, 1.0)); + builder.push_rect(&info, &space_and_clip2, ColorF::new(0.5, 0.5, 0.5, 1.0)); // add a teal square to visualize the scrolling/clipping behaviour // as you scroll the nested scrollbox let mut info = LayoutPrimitiveInfo::new((0, 200).to(50, 250)); info.tag = Some((0, 5)); - builder.push_rect(&info, ColorF::new(0.0, 1.0, 1.0, 1.0)); + builder.push_rect(&info, &space_and_clip2, ColorF::new(0.0, 1.0, 1.0, 1.0)); // Add a sticky frame. It will "stick" twice while scrolling, once // at a margin of 10px from the bottom, for 40 pixels of scrolling, // and once at a margin of 10px from the top, for 60 pixels of // scrolling. let sticky_id = builder.define_sticky_frame( + space_and_clip2.spatial_id, (50, 350).by(50, 50), SideOffsets2D::new(Some(10.0), None, Some(10.0), None), StickyOffsetBounds::new(-40.0, 60.0), @@ -120,21 +124,23 @@ impl Example for App { LayoutVector2D::new(0.0, 0.0) ); - builder.push_clip_id(sticky_id); let mut info = LayoutPrimitiveInfo::new((50, 350).by(50, 50)); info.tag = Some((0, 6)); - builder.push_rect(&info, ColorF::new(0.5, 0.5, 1.0, 1.0)); - builder.pop_clip_id(); // sticky_id + builder.push_rect( + &info, + &SpaceAndClipInfo { + spatial_id: sticky_id, + clip_id: space_and_clip2.clip_id, + }, + ColorF::new(0.5, 0.5, 1.0, 1.0), + ); // just for good measure add another teal square further down and to // the right, which can be scrolled into view by the user let mut info = LayoutPrimitiveInfo::new((250, 350).to(300, 400)); info.tag = Some((0, 7)); - builder.push_rect(&info, ColorF::new(0.0, 1.0, 1.0, 1.0)); - - builder.pop_clip_id(); // nested_clip_id + builder.push_rect(&info, &space_and_clip2, ColorF::new(0.0, 1.0, 1.0, 1.0)); - builder.pop_clip_id(); // clip_id builder.pop_stacking_context(); } diff --git a/examples/texture_cache_stress.rs b/examples/texture_cache_stress.rs index 2eee1b3a8f..e8fb94a435 100644 --- a/examples/texture_cache_stress.rs +++ b/examples/texture_cache_stress.rs @@ -91,13 +91,16 @@ impl Example for App { builder: &mut DisplayListBuilder, txn: &mut Transaction, _framebuffer_size: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let bounds = (0, 0).to(512, 512); let info = LayoutPrimitiveInfo::new(bounds); + let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); + builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -146,6 +149,7 @@ impl Example for App { builder.push_image( &info, + &space_and_clip, image_size, LayoutSize::zero(), ImageRendering::Auto, @@ -163,6 +167,7 @@ impl Example for App { ); builder.push_image( &info, + &space_and_clip, image_size, LayoutSize::zero(), ImageRendering::Auto, @@ -180,6 +185,7 @@ impl Example for App { ); builder.push_image( &info, + &space_and_clip, image_size, LayoutSize::zero(), ImageRendering::Auto, diff --git a/examples/yuv.rs b/examples/yuv.rs index b5370376ca..86d2b41247 100644 --- a/examples/yuv.rs +++ b/examples/yuv.rs @@ -88,13 +88,16 @@ impl Example for App { builder: &mut DisplayListBuilder, txn: &mut Transaction, _framebuffer_size: DeviceIntSize, - _pipeline_id: PipelineId, + pipeline_id: PipelineId, _document_id: DocumentId, ) { let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size()); let info = LayoutPrimitiveInfo::new(bounds); + let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id); + builder.push_stacking_context( &info, + space_and_clip.spatial_id, None, TransformStyle::Flat, MixBlendMode::Normal, @@ -161,6 +164,7 @@ impl Example for App { ); builder.push_yuv_image( &info, + &space_and_clip, YuvData::NV12(yuv_chanel1, yuv_chanel2), ColorDepth::Color8, YuvColorSpace::Rec601, @@ -173,6 +177,7 @@ impl Example for App { ); builder.push_yuv_image( &info, + &space_and_clip, YuvData::PlanarYCbCr(yuv_chanel1, yuv_chanel2_1, yuv_chanel3), ColorDepth::Color8, YuvColorSpace::Rec601, diff --git a/webrender/doc/CLIPPING_AND_POSITIONING.md b/webrender/doc/CLIPPING_AND_POSITIONING.md index b6fd527fba..084dfebdd6 100644 --- a/webrender/doc/CLIPPING_AND_POSITIONING.md +++ b/webrender/doc/CLIPPING_AND_POSITIONING.md @@ -108,7 +108,7 @@ performance impacts on WebRender. # Clipping and Positioning in the Display List Each non-structural WebRender display list item has - * A `ClipId` of a `SpatialNode` or `ClipNode` for positioning + * A `SpatialId` of a `SpatialNode` for positioning * A `ClipId` of a `ClipNode` or a `ClipChain` for clipping * An item-specific rectangular clip rectangle @@ -120,28 +120,13 @@ independent of how the node is positioned and items can be clipped by any the item-specific clipping rectangle is applied directly to the item and should never result in the creation of a clip mask itself. -Perhaps the most inconvenient holdover from the previous single-tree -hierarchical design is that `SpatialNodes`, `ClipNodes`, and `ClipChains` all -share a single `ClipId` id type. This means that the client must be a bit -careful when using the API. For instance, when specifying the parent of -`ClipNode` one can use the `ClipId` or another `ClipNode` or a `SpatialNode`, -but not one for a `ClipChain`. - -WebRender's internal representation of clipping and positioning is not a perfect -match to the display list representation of these concepts. This is due, again, -to the evolutionary nature of the design. The general trend is that the display -list gradually moves toward the internal representation. The most important of -these incongruities is that while `ClipNodes`, sticky frames, and scroll frames -are defined and simply return a `ClipId`, reference frames return a `ClipId` and -also are pushed and popped like stacking contexts. - -## Converting `ClipId` to global `ClipScrollTree` indices +## Converting user-exposed `ClipId`/`SpatialId` to internal indices WebRender must access `ClipNodes` and `SpatialNodes` quite a bit when building -scenes and frames, so it tries to convert `ClipIds`, which are already +scenes and frames, so it tries to convert `ClipId`/`SpatialId`, which are already per-pipeline indices, to global scene-wide indices. Internally this is a -conversion from `ClipId` into `SpatialNodeIndex` or -`ClipChainIndex`. In order to make this conversion cheaper, the +conversion from `ClipId` into `ClipNodeIndex` or `ClipChainIndex`, and from +`SpatialId` into `SpatialNodeIndex`. In order to make this conversion cheaper, the `DisplayListFlattner` assigns offsets for each pipeline and node type in the scene-wide `ClipScrollTree`. @@ -160,8 +145,7 @@ structure copies information necessary for hit testing from the new `ClipScrollTree` is under construction. # Ideas for the Future -1. Expose the difference between ids for `SpatialNodes`, `ClipNodes`, and - `ClipChains` in the API. +1. Expose the difference between `ClipId` and `ClipChainId` in the API. 2. Prevent having to duplicate the `ClipScrollTree` for hit testing. 3. Avoid having to create placeholder nodes in the `ClipScrollTree` while processing iframes. diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index 42a0e0eadb..bfba1ad729 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -204,6 +204,7 @@ pub struct ClipChainId(pub u32); // node, a bounds error will occur. impl ClipChainId { pub const NONE: Self = ClipChainId(u32::MAX); + pub const INVALID: Self = ClipChainId(0xDEADBEEF); } // A clip chain node is an id for a range of clip sources, diff --git a/webrender/src/clip_scroll_tree.rs b/webrender/src/clip_scroll_tree.rs index 51c1099955..726b21453b 100644 --- a/webrender/src/clip_scroll_tree.rs +++ b/webrender/src/clip_scroll_tree.rs @@ -3,8 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D}; -use api::{PipelineId, ScrollClamping, ScrollNodeState, ScrollLocation}; -use api::{TransformStyle, LayoutSize, LayoutTransform, PropertyBinding, ScrollSensitivity, WorldPoint}; +use api::{PipelineId, ScrollClamping, ScrollNodeState, ScrollLocation, ScrollSensitivity}; +use api::{LayoutSize, LayoutTransform, PropertyBinding, TransformStyle, WorldPoint}; use gpu_types::TransformPalette; use internal_types::{FastHashMap, FastHashSet}; use print_tree::{PrintTree, PrintTreePrinter}; @@ -46,6 +46,7 @@ impl CoordinateSystem { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct SpatialNodeIndex(pub u32); +//Note: these have to match ROOT_REFERENCE_FRAME_SPATIAL_ID and ROOT_SCROLL_NODE_SPATIAL_ID pub const ROOT_SPATIAL_NODE_INDEX: SpatialNodeIndex = SpatialNodeIndex(0); const TOPMOST_SCROLL_NODE_INDEX: SpatialNodeIndex = SpatialNodeIndex(1); diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 8707bf4f78..9531b2eb7c 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, ClipAndScrollInfo}; +use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter}; use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use api::{DisplayItemRef, ExtendMode, ExternalScrollId, AuHelpers}; use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop}; @@ -10,7 +10,7 @@ use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, C use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D}; use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId}; use api::{PropertyBinding, ReferenceFrame, ScrollFrameDisplayItem, ScrollSensitivity}; -use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect}; +use api::{Shadow, SpaceAndClipInfo, SpatialId, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect}; use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData}; use app_units::Au; use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore}; @@ -49,7 +49,7 @@ struct ClipNode { } impl ClipNode { - fn new(id: ClipChainId, count: usize) -> ClipNode { + fn new(id: ClipChainId, count: usize) -> Self { ClipNode { id, count, @@ -57,16 +57,16 @@ impl ClipNode { } } -/// A data structure that keeps track of mapping between API ClipIds and the indices used -/// internally in the ClipScrollTree to avoid having to do HashMap lookups. ClipIdToIndexMapper is -/// responsible for mapping both ClipId to ClipChainIndex and ClipId to SpatialNodeIndex. +/// A data structure that keeps track of mapping between API Ids for clips/spatials and the indices +/// used internally in the ClipScrollTree to avoid having to do HashMap lookups. NodeIdToIndexMapper +/// is responsible for mapping both ClipId to ClipChainIndex and SpatialId to SpatialNodeIndex. #[derive(Default)] -pub struct ClipIdToIndexMapper { +pub struct NodeIdToIndexMapper { clip_node_map: FastHashMap<ClipId, ClipNode>, - spatial_node_map: FastHashMap<ClipId, SpatialNodeIndex>, + spatial_node_map: FastHashMap<SpatialId, SpatialNodeIndex>, } -impl ClipIdToIndexMapper { +impl NodeIdToIndexMapper { pub fn add_clip_chain( &mut self, id: ClipId, @@ -77,16 +77,7 @@ impl ClipIdToIndexMapper { debug_assert!(_old_value.is_none()); } - pub fn map_to_parent_clip_chain( - &mut self, - id: ClipId, - parent_id: &ClipId, - ) { - let parent_node = self.clip_node_map[parent_id]; - self.add_clip_chain(id, parent_node.id, parent_node.count); - } - - pub fn map_spatial_node(&mut self, id: ClipId, index: SpatialNodeIndex) { + pub fn map_spatial_node(&mut self, id: SpatialId, index: SpatialNodeIndex) { let _old_value = self.spatial_node_map.insert(id, index); debug_assert!(_old_value.is_none()); } @@ -95,18 +86,12 @@ impl ClipIdToIndexMapper { self.clip_node_map[id] } - pub fn get_clip_chain_id(&self, id: &ClipId) -> ClipChainId { - self.clip_node_map[id].id + pub fn get_clip_chain_id(&self, id: ClipId) -> ClipChainId { + self.clip_node_map[&id].id } - pub fn get_spatial_node_index(&self, id: ClipId) -> SpatialNodeIndex { - match id { - ClipId::Clip(..) | - ClipId::Spatial(..) => { - self.spatial_node_map[&id] - } - ClipId::ClipChain(_) => panic!("Tried to use ClipChain as scroll node."), - } + pub fn get_spatial_node_index(&self, id: SpatialId) -> SpatialNodeIndex { + self.spatial_node_map[&id] } } @@ -127,9 +112,9 @@ pub struct DisplayListFlattener<'a> { /// output textures. output_pipelines: &'a FastHashSet<PipelineId>, - /// The data structure that converting between ClipId and the various index - /// types that the ClipScrollTree uses. - id_to_index_mapper: ClipIdToIndexMapper, + /// The data structure that converting between ClipId/SpatialId and the various + /// index types that the ClipScrollTree uses. + id_to_index_mapper: NodeIdToIndexMapper, /// A stack of stacking context properties. sc_stack: Vec<FlattenedStackingContext>, @@ -188,7 +173,7 @@ impl<'a> DisplayListFlattener<'a> { font_instances, config: *frame_builder_config, output_pipelines, - id_to_index_mapper: ClipIdToIndexMapper::default(), + id_to_index_mapper: NodeIdToIndexMapper::default(), hit_testing_runs: Vec::new(), pending_shadow_items: VecDeque::new(), sc_stack: Vec::new(), @@ -453,11 +438,6 @@ impl<'a> DisplayListFlattener<'a> { frame_size: &LayoutSize, ) { let pipeline_id = pipeline.pipeline_id; - let reference_frame_info = self.simple_scroll_and_clip_chain( - &ClipId::root_reference_frame(pipeline_id), - ); - - let root_scroll_node = ClipId::root_scroll_node(pipeline_id); self.push_stacking_context( pipeline_id, @@ -465,8 +445,8 @@ impl<'a> DisplayListFlattener<'a> { TransformStyle::Flat, true, true, - root_scroll_node, - None, + ROOT_SPATIAL_NODE_INDEX, + ClipChainId::NONE, RasterSpace::Screen, ); @@ -477,6 +457,10 @@ impl<'a> DisplayListFlattener<'a> { if self.scene.root_pipeline_id != Some(pipeline_id) { if let Some(pipeline) = self.scene.pipelines.get(&pipeline_id) { if let Some(bg_color) = pipeline.background_color { + let reference_frame_info = ScrollNodeAndClipChain::new( + self.id_to_index_mapper.get_spatial_node_index(SpatialId::root_reference_frame(pipeline_id)), + ClipChainId::NONE, + ); let root_bounds = LayoutRect::new(LayoutPoint::zero(), *frame_size); let info = LayoutPrimitiveInfo::new(root_bounds); self.add_solid_rectangle( @@ -488,7 +472,11 @@ impl<'a> DisplayListFlattener<'a> { } } - self.flatten_items(&mut pipeline.display_list.iter(), pipeline_id, LayoutVector2D::zero()); + self.flatten_items( + &mut pipeline.display_list.iter(), + pipeline_id, + LayoutVector2D::zero(), + ); self.pop_stacking_context(); } @@ -506,12 +494,10 @@ impl<'a> DisplayListFlattener<'a> { None => break, }; - if SpecificDisplayItem::PopReferenceFrame == *item.item() { - return; - } - - if SpecificDisplayItem::PopStackingContext == *item.item() { - return; + match item.item() { + SpecificDisplayItem::PopReferenceFrame | + SpecificDisplayItem::PopStackingContext => return, + _ => (), } self.flatten_item( @@ -533,8 +519,7 @@ impl<'a> DisplayListFlattener<'a> { &mut self, item: &DisplayItemRef, info: &StickyFrameDisplayItem, - clip_and_scroll: &ScrollNodeAndClipChain, - parent_id: &ClipId, + parent_node_index: SpatialNodeIndex, reference_frame_relative_offset: &LayoutVector2D, ) { let frame_rect = item.rect().translate(reference_frame_relative_offset); @@ -547,20 +532,19 @@ impl<'a> DisplayListFlattener<'a> { ); let index = self.clip_scroll_tree.add_sticky_frame( - clip_and_scroll.spatial_node_index, /* parent id */ + parent_node_index, sticky_frame_info, info.id.pipeline_id(), ); self.id_to_index_mapper.map_spatial_node(info.id, index); - self.id_to_index_mapper.map_to_parent_clip_chain(info.id, parent_id); } fn flatten_scroll_frame( &mut self, item: &DisplayItemRef, info: &ScrollFrameDisplayItem, + parent_node_index: SpatialNodeIndex, pipeline_id: PipelineId, - clip_and_scroll_ids: &ClipAndScrollInfo, reference_frame_relative_offset: &LayoutVector2D, ) { let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0); @@ -574,20 +558,18 @@ impl<'a> DisplayListFlattener<'a> { // This is useful when calculating scroll extents for the // SpatialNode::scroll(..) API as well as for properly setting sticky // positioning offsets. - let frame_rect = item.clip_rect().translate(reference_frame_relative_offset); - let content_rect = item.rect().translate(reference_frame_relative_offset); + let frame_rect = clip_region.main.translate(reference_frame_relative_offset); + let content_size = item.rect().size; - debug_assert!(info.clip_id != info.scroll_frame_id); - - self.add_clip_node(info.clip_id, clip_and_scroll_ids, clip_region); + self.add_clip_node(info.clip_id, item.space_and_clip_info(), clip_region); self.add_scroll_frame( info.scroll_frame_id, - info.clip_id, + parent_node_index, info.external_id, pipeline_id, &frame_rect, - &content_rect.size, + &content_size, info.scroll_sensitivity, ScrollFrameKind::Explicit, ); @@ -597,33 +579,34 @@ impl<'a> DisplayListFlattener<'a> { &mut self, traversal: &mut BuiltDisplayListIter<'a>, pipeline_id: PipelineId, - item: &DisplayItemRef, + parent_spatial_node: SpatialNodeIndex, + origin: LayoutPoint, reference_frame: &ReferenceFrame, - clip_and_scroll_ids: &ClipAndScrollInfo, reference_frame_relative_offset: LayoutVector2D, ) { self.push_reference_frame( reference_frame.id, - Some(clip_and_scroll_ids.scroll_node_id), - clip_and_scroll_ids.clip_node_id, + Some(parent_spatial_node), pipeline_id, reference_frame.transform_style, reference_frame.transform, reference_frame.perspective, - reference_frame_relative_offset + item.rect().origin.to_vector(), + reference_frame_relative_offset + origin.to_vector(), ); self.flatten_items(traversal, pipeline_id, LayoutVector2D::zero()); } + fn flatten_stacking_context( &mut self, traversal: &mut BuiltDisplayListIter<'a>, pipeline_id: PipelineId, - item: &DisplayItemRef, stacking_context: &StackingContext, - scroll_node_id: ClipId, - reference_frame_relative_offset: LayoutVector2D, + spatial_node_index: SpatialNodeIndex, + origin: LayoutPoint, + filters: ItemRange<FilterOp>, + reference_frame_relative_offset: &LayoutVector2D, is_backface_visible: bool, ) { // Avoid doing unnecessary work for empty stacking contexts. @@ -636,26 +619,31 @@ impl<'a> DisplayListFlattener<'a> { // TODO(optimization?): self.traversal.display_list() let display_list = self.scene.get_display_list_for_pipeline(pipeline_id); CompositeOps::new( - stacking_context.filter_ops_for_compositing(display_list, item.filters()), + stacking_context.filter_ops_for_compositing(display_list, filters), stacking_context.mix_blend_mode_for_compositing(), ) }; + let clip_chain_id = match stacking_context.clip_id { + Some(clip_id) => self.id_to_index_mapper.get_clip_chain_id(clip_id), + None => ClipChainId::NONE, + }; + self.push_stacking_context( pipeline_id, composition_operations, stacking_context.transform_style, is_backface_visible, false, - scroll_node_id, - stacking_context.clip_node_id, + spatial_node_index, + clip_chain_id, stacking_context.raster_space, ); self.flatten_items( traversal, pipeline_id, - reference_frame_relative_offset + item.rect().origin.to_vector(), + *reference_frame_relative_offset + origin.to_vector(), ); self.pop_stacking_context(); @@ -665,7 +653,7 @@ impl<'a> DisplayListFlattener<'a> { &mut self, item: &DisplayItemRef, info: &IframeDisplayItem, - clip_and_scroll_ids: &ClipAndScrollInfo, + spatial_node_index: SpatialNodeIndex, reference_frame_relative_offset: &LayoutVector2D, ) { let iframe_pipeline_id = info.pipeline_id; @@ -678,21 +666,20 @@ impl<'a> DisplayListFlattener<'a> { }; let clip_chain_index = self.add_clip_node( - info.clip_id, - clip_and_scroll_ids, + ClipId::root(iframe_pipeline_id), + item.space_and_clip_info(), ClipRegion::create_for_clip_node_with_local_clip( item.clip_rect(), - reference_frame_relative_offset + reference_frame_relative_offset, ), ); self.pipeline_clip_chain_stack.push(clip_chain_index); let bounds = item.rect(); let origin = *reference_frame_relative_offset + bounds.origin.to_vector(); - self.push_reference_frame( - ClipId::root_reference_frame(iframe_pipeline_id), - Some(info.clip_id), - None, + let spatial_node_index = self.push_reference_frame( + SpatialId::root_reference_frame(iframe_pipeline_id), + Some(spatial_node_index), iframe_pipeline_id, TransformStyle::Flat, None, @@ -702,8 +689,8 @@ impl<'a> DisplayListFlattener<'a> { let iframe_rect = LayoutRect::new(LayoutPoint::zero(), bounds.size); self.add_scroll_frame( - ClipId::root_scroll_node(iframe_pipeline_id), - ClipId::root_reference_frame(iframe_pipeline_id), + SpatialId::root_scroll_node(iframe_pipeline_id), + spatial_node_index, Some(ExternalScrollId(0, iframe_pipeline_id)), iframe_pipeline_id, &iframe_rect, @@ -726,10 +713,17 @@ impl<'a> DisplayListFlattener<'a> { pipeline_id: PipelineId, reference_frame_relative_offset: LayoutVector2D, ) -> Option<BuiltDisplayListIter<'a>> { - let clip_and_scroll_ids = item.clip_and_scroll(); - let clip_and_scroll = self.map_clip_and_scroll(&clip_and_scroll_ids); - + let space_and_clip = item.space_and_clip_info(); + let clip_and_scroll = ScrollNodeAndClipChain::new( + self.id_to_index_mapper.get_spatial_node_index(space_and_clip.spatial_id), + if space_and_clip.clip_id.is_valid() { + self.id_to_index_mapper.get_clip_chain_id(space_and_clip.clip_id) + } else { + ClipChainId::INVALID + }, + ); let prim_info = item.get_layout_primitive_info(&reference_frame_relative_offset); + match *item.item() { SpecificDisplayItem::Image(ref info) => { self.add_image( @@ -861,10 +855,11 @@ impl<'a> DisplayListFlattener<'a> { self.flatten_stacking_context( &mut subtraversal, pipeline_id, - &item, &info.stacking_context, - clip_and_scroll_ids.scroll_node_id, - reference_frame_relative_offset, + clip_and_scroll.spatial_node_index, + item.rect().origin, + item.filters(), + &reference_frame_relative_offset, prim_info.is_backface_visible, ); return Some(subtraversal); @@ -874,20 +869,19 @@ impl<'a> DisplayListFlattener<'a> { self.flatten_reference_frame( &mut subtraversal, pipeline_id, - &item, + clip_and_scroll.spatial_node_index, + item.rect().origin, &info.reference_frame, - &clip_and_scroll_ids, reference_frame_relative_offset, ); return Some(subtraversal); - } SpecificDisplayItem::Iframe(ref info) => { self.flatten_iframe( &item, info, - &clip_and_scroll_ids, - &reference_frame_relative_offset + clip_and_scroll.spatial_node_index, + &reference_frame_relative_offset, ); } SpecificDisplayItem::Clip(ref info) => { @@ -898,7 +892,7 @@ impl<'a> DisplayListFlattener<'a> { info.image_mask, &reference_frame_relative_offset, ); - self.add_clip_node(info.id, &clip_and_scroll_ids, clip_region); + self.add_clip_node(info.id, space_and_clip, clip_region); } SpecificDisplayItem::ClipChain(ref info) => { // For a user defined clip-chain the parent (if specified) must @@ -907,7 +901,7 @@ impl<'a> DisplayListFlattener<'a> { // is used to provide a root clip chain for iframes. let mut parent_clip_chain_id = match info.parent { Some(id) => { - self.id_to_index_mapper.get_clip_chain_id(&ClipId::ClipChain(id)) + self.id_to_index_mapper.get_clip_chain_id(ClipId::ClipChain(id)) } None => { self.pipeline_clip_chain_stack.last().cloned().unwrap() @@ -923,11 +917,11 @@ impl<'a> DisplayListFlattener<'a> { let mut clip_chain_id = parent_clip_chain_id; // For each specified clip id - for item in self.get_clip_chain_items(pipeline_id, item.clip_chain_items()) { + for clip_item in self.get_clip_chain_items(pipeline_id, item.clip_chain_items()) { // Map the ClipId to an existing clip chain node. let item_clip_node = self .id_to_index_mapper - .get_clip_node(&item); + .get_clip_node(&clip_item); let mut clip_node_clip_chain_id = item_clip_node.id; @@ -973,25 +967,25 @@ impl<'a> DisplayListFlattener<'a> { self.flatten_scroll_frame( &item, info, + clip_and_scroll.spatial_node_index, pipeline_id, - &clip_and_scroll_ids, - &reference_frame_relative_offset + &reference_frame_relative_offset, ); } SpecificDisplayItem::StickyFrame(ref info) => { self.flatten_sticky_frame( &item, info, - &clip_and_scroll, - &clip_and_scroll_ids.scroll_node_id, - &reference_frame_relative_offset + clip_and_scroll.spatial_node_index, + &reference_frame_relative_offset, ); } // Do nothing; these are dummy items for the display list parser SpecificDisplayItem::SetGradientStops => {} - SpecificDisplayItem::PopStackingContext | SpecificDisplayItem::PopReferenceFrame => { + SpecificDisplayItem::PopReferenceFrame | + SpecificDisplayItem::PopStackingContext => { unreachable!("Should have returned in parent method.") } SpecificDisplayItem::PushShadow(shadow) => { @@ -1030,13 +1024,12 @@ impl<'a> DisplayListFlattener<'a> { .clip_interner .intern(&item, || ()); - clip_chain_id = self.clip_store - .add_clip_chain_node( - handle, - local_pos, - spatial_node_index, - clip_chain_id, - ); + clip_chain_id = self.clip_store.add_clip_chain_node( + handle, + local_pos, + spatial_node_index, + clip_chain_id, + ); } clip_chain_id @@ -1218,16 +1211,10 @@ impl<'a> DisplayListFlattener<'a> { transform_style: TransformStyle, is_backface_visible: bool, is_pipeline_root: bool, - spatial_node: ClipId, - clipping_node: Option<ClipId>, + spatial_node_index: SpatialNodeIndex, + clip_chain_id: ClipChainId, requested_raster_space: RasterSpace, ) { - let spatial_node_index = self.id_to_index_mapper.get_spatial_node_index(spatial_node); - let clip_chain_id = match clipping_node { - Some(ref clipping_node) => self.id_to_index_mapper.get_clip_chain_id(clipping_node), - None => ClipChainId::NONE, - }; - // Check if this stacking context is the root of a pipeline, and the caller // has requested it as an output frame. let frame_output_pipeline_id = if is_pipeline_root && self.output_pipelines.contains(&pipeline_id) { @@ -1294,7 +1281,7 @@ impl<'a> DisplayListFlattener<'a> { // has a clip node. In the future, we may decide during // prepare step to skip the intermediate surface if the // clip node doesn't affect the stacking context rect. - let should_isolate = clipping_node.is_some(); + let should_isolate = clip_chain_id != ClipChainId::NONE; // Push the SC onto the stack, so we know how to handle things in // pop_stacking_context. @@ -1586,16 +1573,14 @@ impl<'a> DisplayListFlattener<'a> { pub fn push_reference_frame( &mut self, - reference_frame_id: ClipId, - parent_scroll_id: Option<ClipId>, - parent_clip_id: Option<ClipId>, + reference_frame_id: SpatialId, + parent_index: Option<SpatialNodeIndex>, pipeline_id: PipelineId, transform_style: TransformStyle, source_transform: Option<PropertyBinding<LayoutTransform>>, source_perspective: Option<LayoutTransform>, origin_in_parent_reference_frame: LayoutVector2D, ) -> SpatialNodeIndex { - let parent_index = parent_scroll_id.map(|id| self.id_to_index_mapper.get_spatial_node_index(id)); let index = self.clip_scroll_tree.add_reference_frame( parent_index, transform_style, @@ -1606,11 +1591,6 @@ impl<'a> DisplayListFlattener<'a> { ); self.id_to_index_mapper.map_spatial_node(reference_frame_id, index); - match parent_clip_id.or(parent_scroll_id) { - Some(ref parent_id) => - self.id_to_index_mapper.map_to_parent_clip_chain(reference_frame_id, parent_id), - _ => self.id_to_index_mapper.add_clip_chain(reference_frame_id, ClipChainId::NONE, 0), - } index } @@ -1625,9 +1605,10 @@ impl<'a> DisplayListFlattener<'a> { register_prim_chase_id(id); } - self.push_reference_frame( - ClipId::root_reference_frame(pipeline_id), - None, + self.id_to_index_mapper.add_clip_chain(ClipId::root(pipeline_id), ClipChainId::NONE, 0); + + let spatial_node_index = self.push_reference_frame( + SpatialId::root_reference_frame(pipeline_id), None, pipeline_id, TransformStyle::Flat, @@ -1637,8 +1618,8 @@ impl<'a> DisplayListFlattener<'a> { ); self.add_scroll_frame( - ClipId::root_scroll_node(pipeline_id), - ClipId::root_reference_frame(pipeline_id), + SpatialId::root_scroll_node(pipeline_id), + spatial_node_index, Some(ExternalScrollId(0, pipeline_id)), pipeline_id, &LayoutRect::new(LayoutPoint::zero(), *viewport_size), @@ -1651,7 +1632,7 @@ impl<'a> DisplayListFlattener<'a> { pub fn add_clip_node<I>( &mut self, new_node_id: ClipId, - parent: &ClipAndScrollInfo, + space_and_clip: &SpaceAndClipInfo, clip_region: ClipRegion<I>, ) -> ClipChainId where @@ -1661,15 +1642,9 @@ impl<'a> DisplayListFlattener<'a> { // and the positioning node associated with those clip sources. // Map from parent ClipId to existing clip-chain. - let mut parent_clip_chain_index = self - .id_to_index_mapper - .get_clip_chain_id(&parent.clip_node_id()); + let mut parent_clip_chain_index = self.id_to_index_mapper.get_clip_chain_id(space_and_clip.clip_id); // Map the ClipId for the positioning node to a spatial node index. - let spatial_node = self.id_to_index_mapper.get_spatial_node_index(parent.scroll_node_id); - - // Add a mapping for this ClipId in case it's referenced as a positioning node. - self.id_to_index_mapper - .map_spatial_node(new_node_id, spatial_node); + let spatial_node = self.id_to_index_mapper.get_spatial_node_index(space_and_clip.spatial_id); let mut clip_count = 0; @@ -1740,8 +1715,8 @@ impl<'a> DisplayListFlattener<'a> { pub fn add_scroll_frame( &mut self, - new_node_id: ClipId, - parent_id: ClipId, + new_node_id: SpatialId, + parent_node_index: SpatialNodeIndex, external_id: Option<ExternalScrollId>, pipeline_id: PipelineId, frame_rect: &LayoutRect, @@ -1749,7 +1724,6 @@ impl<'a> DisplayListFlattener<'a> { scroll_sensitivity: ScrollSensitivity, frame_kind: ScrollFrameKind, ) -> SpatialNodeIndex { - let parent_node_index = self.id_to_index_mapper.get_spatial_node_index(parent_id); let node_index = self.clip_scroll_tree.add_scroll_frame( parent_node_index, external_id, @@ -1760,7 +1734,6 @@ impl<'a> DisplayListFlattener<'a> { frame_kind, ); self.id_to_index_mapper.map_spatial_node(new_node_id, node_index); - self.id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id); node_index } @@ -2477,17 +2450,6 @@ impl<'a> DisplayListFlattener<'a> { ); } - pub fn map_clip_and_scroll(&mut self, info: &ClipAndScrollInfo) -> ScrollNodeAndClipChain { - ScrollNodeAndClipChain::new( - self.id_to_index_mapper.get_spatial_node_index(info.scroll_node_id), - self.id_to_index_mapper.get_clip_chain_id(&info.clip_node_id()) - ) - } - - pub fn simple_scroll_and_clip_chain(&mut self, id: &ClipId) -> ScrollNodeAndClipChain { - self.map_clip_and_scroll(&ClipAndScrollInfo::simple(*id)) - } - pub fn add_primitive_instance_to_3d_root(&mut self, instance: PrimitiveInstance) { // find the 3D root and append to the children list for sc in self.sc_stack.iter_mut().rev() { diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index db99871cfd..2bcc88b09c 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -1589,8 +1589,8 @@ impl ToDebugString for SpecificDisplayItem { SpecificDisplayItem::PopAllShadows => String::from("pop_all_shadows"), SpecificDisplayItem::PopReferenceFrame => String::from("pop_reference_frame"), SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"), - SpecificDisplayItem::PushReferenceFrame(..) => String::from("push_reference_frame"), SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"), + SpecificDisplayItem::PushReferenceFrame(..) => String::from("push_reference_frame"), SpecificDisplayItem::PushStackingContext(..) => String::from("push_stacking_context"), SpecificDisplayItem::RadialGradient(..) => String::from("radial_gradient"), SpecificDisplayItem::Rectangle(..) => String::from("rectangle"), diff --git a/webrender_api/src/display_item.rs b/webrender_api/src/display_item.rs index abfc78b505..72dec8dce6 100644 --- a/webrender_api/src/display_item.rs +++ b/webrender_api/src/display_item.rs @@ -20,32 +20,6 @@ pub const MAX_BLUR_RADIUS: f32 = 300.; // a list of values nearby that this item consumes. The traversal // iterator should handle finding these. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct ClipAndScrollInfo { - pub scroll_node_id: ClipId, - pub clip_node_id: Option<ClipId>, -} - -impl ClipAndScrollInfo { - pub fn simple(node_id: ClipId) -> ClipAndScrollInfo { - ClipAndScrollInfo { - scroll_node_id: node_id, - clip_node_id: None, - } - } - - pub fn new(scroll_node_id: ClipId, clip_node_id: ClipId) -> ClipAndScrollInfo { - ClipAndScrollInfo { - scroll_node_id, - clip_node_id: Some(clip_node_id), - } - } - - pub fn clip_node_id(&self) -> ClipId { - self.clip_node_id.unwrap_or(self.scroll_node_id) - } -} - /// A tag that can be used to identify items during hit testing. If the tag /// is missing then the item doesn't take part in hit testing at all. This /// is composed of two numbers. In Servo, the first is an identifier while the @@ -60,8 +34,8 @@ pub type ItemTag = (u64, u16); #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct GenericDisplayItem<T> { pub item: T, - pub clip_and_scroll: ClipAndScrollInfo, pub layout: LayoutPrimitiveInfo, + pub space_and_clip: SpaceAndClipInfo, } pub type DisplayItem = GenericDisplayItem<SpecificDisplayItem>; @@ -71,8 +45,8 @@ pub type DisplayItem = GenericDisplayItem<SpecificDisplayItem>; #[derive(Serialize)] pub struct SerializedDisplayItem<'a> { pub item: &'a SpecificDisplayItem, - pub clip_and_scroll: &'a ClipAndScrollInfo, pub layout: &'a LayoutPrimitiveInfo, + pub space_and_clip: &'a SpaceAndClipInfo, } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] @@ -103,6 +77,29 @@ impl LayoutPrimitiveInfo { pub type LayoutPrimitiveInfo = PrimitiveInfo<LayoutPixel>; +/// Per-primitive information about the nodes in the clip tree and +/// the spatial tree that the primitive belongs to. +/// +/// Note: this is a separate struct from `PrimitiveInfo` because +/// it needs indirectional mapping during the DL flattening phase, +/// turning into `ScrollNodeAndClipChain`. +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +pub struct SpaceAndClipInfo { + pub spatial_id: SpatialId, + pub clip_id: ClipId, +} + +impl SpaceAndClipInfo { + /// Create a new space/clip info associated with the root + /// scroll frame. + pub fn root_scroll(pipeline_id: PipelineId) -> Self { + SpaceAndClipInfo { + spatial_id: SpatialId::root_scroll_node(pipeline_id), + clip_id: ClipId::root(pipeline_id), + } + } +} + #[repr(u64)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub enum SpecificDisplayItem { @@ -121,10 +118,10 @@ pub enum SpecificDisplayItem { RadialGradient(RadialGradientDisplayItem), ClipChain(ClipChainItem), Iframe(IframeDisplayItem), + PushReferenceFrame(ReferenceFrameDisplayListItem), + PopReferenceFrame, PushStackingContext(PushStackingContextDisplayItem), PopStackingContext, - PushReferenceFrame(PushReferenceFrameDisplayListItem), - PopReferenceFrame, SetGradientStops, PushShadow(Shadow), PopAllShadows, @@ -154,10 +151,10 @@ pub enum CompletelySpecificDisplayItem { Gradient(GradientDisplayItem), RadialGradient(RadialGradientDisplayItem), Iframe(IframeDisplayItem), + PushReferenceFrame(ReferenceFrameDisplayListItem), + PopReferenceFrame, PushStackingContext(PushStackingContextDisplayItem, Vec<FilterOp>), PopStackingContext, - PushReferenceFrame(PushReferenceFrameDisplayListItem), - PopReferenceFrame, SetGradientStops(Vec<GradientStop>), PushShadow(Shadow), PopAllShadows, @@ -194,7 +191,7 @@ impl StickyOffsetBounds { #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct StickyFrameDisplayItem { - pub id: ClipId, + pub id: SpatialId, /// The margins that should be maintained between the edge of the parent viewport and this /// sticky frame. A margin of None indicates that the sticky frame should not stick at all @@ -230,7 +227,7 @@ pub enum ScrollSensitivity { #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct ScrollFrameDisplayItem { pub clip_id: ClipId, - pub scroll_frame_id: ClipId, + pub scroll_frame_id: SpatialId, pub external_id: Option<ExternalScrollId>, pub image_mask: Option<ImageMask>, pub scroll_sensitivity: ScrollSensitivity, @@ -517,7 +514,7 @@ pub struct RadialGradientDisplayItem { } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] -pub struct PushReferenceFrameDisplayListItem { +pub struct ReferenceFrameDisplayListItem { pub reference_frame: ReferenceFrame, } @@ -532,7 +529,7 @@ pub struct ReferenceFrame { pub transform_style: TransformStyle, pub transform: Option<PropertyBinding<LayoutTransform>>, pub perspective: Option<LayoutTransform>, - pub id: ClipId, + pub id: SpatialId, } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] @@ -544,7 +541,7 @@ pub struct PushStackingContextDisplayItem { pub struct StackingContext { pub transform_style: TransformStyle, pub mix_blend_mode: MixBlendMode, - pub clip_node_id: Option<ClipId>, + pub clip_id: Option<ClipId>, pub raster_space: RasterSpace, } // IMPLICIT: filters: Vec<FilterOp> @@ -646,7 +643,6 @@ impl FilterOp { #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct IframeDisplayItem { - pub clip_id: ClipId, pub pipeline_id: PipelineId, pub ignore_missing_pipeline: bool, } @@ -856,48 +852,82 @@ impl ComplexClipRegion { #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct ClipChainId(pub u64, pub PipelineId); +/// A reference to a clipping node defining how an item is clipped. #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum ClipId { - Spatial(usize, PipelineId), Clip(usize, PipelineId), ClipChain(ClipChainId), } -const ROOT_REFERENCE_FRAME_CLIP_ID: usize = 0; -const ROOT_SCROLL_NODE_CLIP_ID: usize = 1; +const ROOT_CLIP_ID: usize = 0; impl ClipId { - pub fn root_scroll_node(pipeline_id: PipelineId) -> ClipId { - ClipId::Spatial(ROOT_SCROLL_NODE_CLIP_ID, pipeline_id) + /// Return the root clip ID - effectively doing no clipping. + pub fn root(pipeline_id: PipelineId) -> Self { + ClipId::Clip(ROOT_CLIP_ID, pipeline_id) } - pub fn root_reference_frame(pipeline_id: PipelineId) -> ClipId { - ClipId::Spatial(ROOT_REFERENCE_FRAME_CLIP_ID, pipeline_id) + /// Return an invalid clip ID - needed in places where we carry + /// one but need to not attempt to use it. + pub fn invalid() -> Self { + ClipId::Clip(!0, PipelineId::dummy()) } pub fn pipeline_id(&self) -> PipelineId { match *self { - ClipId::Spatial(_, pipeline_id) | ClipId::Clip(_, pipeline_id) | ClipId::ClipChain(ClipChainId(_, pipeline_id)) => pipeline_id, } } - pub fn is_root_scroll_node(&self) -> bool { + pub fn is_root(&self) -> bool { match *self { - ClipId::Spatial(ROOT_SCROLL_NODE_CLIP_ID, _) => true, - _ => false, + ClipId::Clip(id, _) => id == ROOT_CLIP_ID, + ClipId::ClipChain(_) => false, } } - pub fn is_root_reference_frame(&self) -> bool { + pub fn is_valid(&self) -> bool { match *self { - ClipId::Spatial(ROOT_REFERENCE_FRAME_CLIP_ID, _) => true, - _ => false, + ClipId::Clip(id, _) => id != !0, + _ => true, } } } +/// A reference to a spatial node defining item positioning. +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct SpatialId(pub usize, PipelineId); + +const ROOT_REFERENCE_FRAME_SPATIAL_ID: usize = 0; +const ROOT_SCROLL_NODE_SPATIAL_ID: usize = 1; + +impl SpatialId { + pub fn new(spatial_node_index: usize, pipeline_id: PipelineId) -> Self { + SpatialId(spatial_node_index, pipeline_id) + } + + pub fn root_reference_frame(pipeline_id: PipelineId) -> Self { + SpatialId(ROOT_REFERENCE_FRAME_SPATIAL_ID, pipeline_id) + } + + pub fn root_scroll_node(pipeline_id: PipelineId) -> Self { + SpatialId(ROOT_SCROLL_NODE_SPATIAL_ID, pipeline_id) + } + + pub fn pipeline_id(&self) -> PipelineId { + self.1 + } + + pub fn is_root_reference_frame(&self) -> bool { + self.0 == ROOT_REFERENCE_FRAME_SPATIAL_ID + } + + pub fn is_root_scroll_node(&self) -> bool { + self.0 == ROOT_SCROLL_NODE_SPATIAL_ID + } +} + /// An external identifier that uniquely identifies a scroll frame independent of its ClipId, which /// may change from frame to frame. This should be unique within a pipeline. WebRender makes no /// attempt to ensure uniqueness. The zero value is reserved for use by the root scroll node of diff --git a/webrender_api/src/display_list.rs b/webrender_api/src/display_list.rs index e88bf5c804..f96db40ea3 100644 --- a/webrender_api/src/display_list.rs +++ b/webrender_api/src/display_list.rs @@ -15,16 +15,16 @@ use std::ops::Range; use std::{io, mem, ptr, slice}; use time::precise_time_ns; use {AlphaType, BorderDetails, BorderDisplayItem, BorderRadius, BoxShadowClipMode, CacheMarkerDisplayItem}; -use {BoxShadowDisplayItem, ClipAndScrollInfo, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId}; +use {BoxShadowDisplayItem, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId}; use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, ExternalScrollId, FilterOp}; use {FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, Gradient, GradientBuilder}; use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask}; use {ImageRendering, LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSideOffsets, LayoutSize}; use {LayoutTransform, LayoutVector2D, LineDisplayItem, LineOrientation, LineStyle, MixBlendMode}; -use {PipelineId, PropertyBinding, PushReferenceFrameDisplayListItem}; +use {PipelineId, PropertyBinding, ReferenceFrameDisplayListItem}; use {PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem}; use {RectangleDisplayItem, ReferenceFrame, ScrollFrameDisplayItem, ScrollSensitivity}; -use {SerializedDisplayItem, Shadow, SpecificDisplayItem}; +use {SerializedDisplayItem, Shadow, SpaceAndClipInfo, SpatialId, SpecificDisplayItem}; use {StackingContext, StickyFrameDisplayItem, StickyOffsetBounds}; use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayItem, ColorDepth}; @@ -32,13 +32,13 @@ use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayIte // This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_TEXT_RUN) * 2 pub const MAX_TEXT_RUN_LENGTH: usize = 2040; -// We start at 2, because the root reference is always 0 and the root scroll node is always 1. +// See ROOT_REFERENCE_FRAME_SPATIAL_ID and ROOT_SCROLL_NODE_SPATIAL_ID // TODO(mrobinson): It would be a good idea to eliminate the root scroll frame which is only // used by Servo. const FIRST_SPATIAL_NODE_INDEX: usize = 2; -// There are no default clips, so we start at the 0 index for clips. -const FIRST_CLIP_NODE_INDEX: usize = 0; +// See ROOT_SCROLL_NODE_SPATIAL_ID +const FIRST_CLIP_NODE_INDEX: usize = 1; #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] @@ -213,9 +213,8 @@ impl<'a> BuiltDisplayListIter<'a> { cur_item: DisplayItem { // Dummy data, will be overwritten by `next` item: SpecificDisplayItem::PopStackingContext, - clip_and_scroll: - ClipAndScrollInfo::simple(ClipId::root_scroll_node(PipelineId::dummy())), layout: LayoutPrimitiveInfo::new(LayoutRect::zero()), + space_and_clip: SpaceAndClipInfo::root_scroll(PipelineId::dummy()) }, cur_stops: ItemRange::default(), cur_glyphs: ItemRange::default(), @@ -370,8 +369,8 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> { &self.iter.cur_item.layout.clip_rect } - pub fn clip_and_scroll(&self) -> ClipAndScrollInfo { - self.iter.cur_item.clip_and_scroll + pub fn space_and_clip_info(&self) -> &SpaceAndClipInfo { + &self.iter.cur_item.space_and_clip } pub fn item(&self) -> &SpecificDisplayItem { @@ -490,13 +489,13 @@ impl Serialize for BuiltDisplayList { SpecificDisplayItem::Gradient(v) => Gradient(v), SpecificDisplayItem::RadialGradient(v) => RadialGradient(v), SpecificDisplayItem::Iframe(v) => Iframe(v), + SpecificDisplayItem::PushReferenceFrame(v) => PushReferenceFrame(v), + SpecificDisplayItem::PopReferenceFrame => PopReferenceFrame, SpecificDisplayItem::PushStackingContext(v) => PushStackingContext( v, item.iter.list.get(item.iter.cur_filters).collect() ), SpecificDisplayItem::PopStackingContext => PopStackingContext, - SpecificDisplayItem::PushReferenceFrame(v) => PushReferenceFrame(v), - SpecificDisplayItem::PopReferenceFrame => PopReferenceFrame, SpecificDisplayItem::SetGradientStops => SetGradientStops( item.iter.list.get(item.iter.cur_stops).collect() ), @@ -505,8 +504,8 @@ impl Serialize for BuiltDisplayList { SpecificDisplayItem::PushCacheMarker(m) => PushCacheMarker(m), SpecificDisplayItem::PopCacheMarker => PopCacheMarker, }, - clip_and_scroll: display_item.clip_and_scroll, layout: display_item.layout, + space_and_clip: display_item.space_and_clip, }; seq.serialize_element(&serial_di)? } @@ -551,7 +550,7 @@ impl<'de> Deserialize<'de> for BuiltDisplayList { total_clip_nodes += 1; DisplayListBuilder::push_iter_impl(&mut temp, complex_clips); SpecificDisplayItem::ScrollFrame(specific_item) - }, + } StickyFrame(specific_item) => { total_spatial_nodes += 1; SpecificDisplayItem::StickyFrame(specific_item) @@ -574,16 +573,16 @@ impl<'de> Deserialize<'de> for BuiltDisplayList { total_clip_nodes += 1; SpecificDisplayItem::Iframe(specific_item) } + PushReferenceFrame(v) => { + total_spatial_nodes += 1; + SpecificDisplayItem::PushReferenceFrame(v) + } + PopReferenceFrame => SpecificDisplayItem::PopReferenceFrame, PushStackingContext(specific_item, filters) => { DisplayListBuilder::push_iter_impl(&mut temp, filters); SpecificDisplayItem::PushStackingContext(specific_item) }, PopStackingContext => SpecificDisplayItem::PopStackingContext, - PushReferenceFrame(specific_item) => { - total_spatial_nodes += 1; - SpecificDisplayItem::PushReferenceFrame(specific_item) - } - PopReferenceFrame => SpecificDisplayItem::PopReferenceFrame, SetGradientStops(stops) => { DisplayListBuilder::push_iter_impl(&mut temp, stops); SpecificDisplayItem::SetGradientStops @@ -593,8 +592,8 @@ impl<'de> Deserialize<'de> for BuiltDisplayList { PushCacheMarker(marker) => SpecificDisplayItem::PushCacheMarker(marker), PopCacheMarker => SpecificDisplayItem::PopCacheMarker, }, - clip_and_scroll: complete.clip_and_scroll, layout: complete.layout, + space_and_clip: complete.space_and_clip, }; serialize_fast(&mut data, &item); // the aux data is serialized after the item, hence the temporary @@ -832,7 +831,6 @@ impl<'a, 'b> Read for UnsafeReader<'a, 'b> { #[derive(Clone, Debug)] pub struct SaveState { dl_len: usize, - clip_stack_len: usize, next_clip_index: usize, next_spatial_index: usize, next_clip_chain_id: u64, @@ -842,7 +840,6 @@ pub struct SaveState { pub struct DisplayListBuilder { pub data: Vec<u8>, pub pipeline_id: PipelineId, - clip_stack: Vec<ClipAndScrollInfo>, next_clip_index: usize, next_spatial_index: usize, next_clip_chain_id: u64, @@ -869,9 +866,6 @@ impl DisplayListBuilder { DisplayListBuilder { data: Vec::with_capacity(capacity), pipeline_id, - clip_stack: vec![ - ClipAndScrollInfo::simple(ClipId::root_scroll_node(pipeline_id)), - ], next_clip_index: FIRST_CLIP_NODE_INDEX, next_spatial_index: FIRST_SPATIAL_NODE_INDEX, next_clip_chain_id: 0, @@ -897,7 +891,6 @@ impl DisplayListBuilder { assert!(self.save_state.is_none(), "DisplayListBuilder doesn't support nested saves"); self.save_state = Some(SaveState { - clip_stack_len: self.clip_stack.len(), dl_len: self.data.len(), next_clip_index: self.next_clip_index, next_spatial_index: self.next_spatial_index, @@ -909,7 +902,6 @@ impl DisplayListBuilder { pub fn restore(&mut self) { let state = self.save_state.take().expect("No save to restore DisplayListBuilder from"); - self.clip_stack.truncate(state.clip_stack_len); self.data.truncate(state.dl_len); self.next_clip_index = state.next_clip_index; self.next_spatial_index = state.next_spatial_index; @@ -969,36 +961,31 @@ impl DisplayListBuilder { /// NOTE: It is usually preferable to use the specialized methods to push /// display items. Pushing unexpected or invalid items here may /// result in WebRender panicking or behaving in unexpected ways. - pub fn push_item(&mut self, item: &SpecificDisplayItem, layout: &LayoutPrimitiveInfo) { - serialize_fast( - &mut self.data, - SerializedDisplayItem { - item, - clip_and_scroll: self.clip_stack.last().unwrap(), - layout, - }, - ) - } - - fn push_item_with_clip_scroll_info( + #[inline] + pub fn push_item( &mut self, item: &SpecificDisplayItem, layout: &LayoutPrimitiveInfo, - clip_and_scroll: &ClipAndScrollInfo + space_and_clip: &SpaceAndClipInfo, ) { serialize_fast( &mut self.data, SerializedDisplayItem { item, - clip_and_scroll, layout, + space_and_clip, }, ) } + #[inline] fn push_new_empty_item(&mut self, item: &SpecificDisplayItem) { - let layout = &LayoutPrimitiveInfo::new(LayoutRect::zero()); - self.push_item(item, layout) + let pipeline_id = self.pipeline_id; + self.push_item( + item, + &LayoutPrimitiveInfo::new(LayoutRect::zero()), + &SpaceAndClipInfo::root_scroll(pipeline_id), + ) } fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I) @@ -1046,18 +1033,28 @@ impl DisplayListBuilder { Self::push_iter_impl(&mut self.data, iter); } - pub fn push_rect(&mut self, layout: &LayoutPrimitiveInfo, color: ColorF) { + pub fn push_rect( + &mut self, + layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, + color: ColorF, + ) { let item = SpecificDisplayItem::Rectangle(RectangleDisplayItem { color }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } - pub fn push_clear_rect(&mut self, layout: &LayoutPrimitiveInfo) { - self.push_item(&SpecificDisplayItem::ClearRectangle, layout); + pub fn push_clear_rect( + &mut self, + layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, + ) { + self.push_item(&SpecificDisplayItem::ClearRectangle, layout, space_and_clip); } pub fn push_line( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, wavy_line_thickness: f32, orientation: LineOrientation, color: &ColorF, @@ -1070,12 +1067,13 @@ impl DisplayListBuilder { style, }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } pub fn push_image( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, stretch_size: LayoutSize, tile_spacing: LayoutSize, image_rendering: ImageRendering, @@ -1092,13 +1090,14 @@ impl DisplayListBuilder { color, }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } /// Push a yuv image. All planar data in yuv image should use the same buffer type. pub fn push_yuv_image( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, yuv_data: YuvData, color_depth: ColorDepth, color_space: YuvColorSpace, @@ -1110,12 +1109,13 @@ impl DisplayListBuilder { color_space, image_rendering, }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } pub fn push_text( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, glyphs: &[GlyphInstance], font_key: FontInstanceKey, color: ColorF, @@ -1128,7 +1128,7 @@ impl DisplayListBuilder { }); for split_glyphs in glyphs.chunks(MAX_TEXT_RUN_LENGTH) { - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); self.push_iter(split_glyphs); } } @@ -1166,17 +1166,19 @@ impl DisplayListBuilder { pub fn push_border( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, widths: LayoutSideOffsets, details: BorderDetails, ) { let item = SpecificDisplayItem::Border(BorderDisplayItem { details, widths }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } pub fn push_box_shadow( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, box_bounds: LayoutRect, offset: LayoutVector2D, color: ColorF, @@ -1195,7 +1197,7 @@ impl DisplayListBuilder { clip_mode, }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } /// Pushes a linear gradient to be displayed. @@ -1215,6 +1217,7 @@ impl DisplayListBuilder { pub fn push_gradient( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, gradient: Gradient, tile_size: LayoutSize, tile_spacing: LayoutSize, @@ -1225,7 +1228,7 @@ impl DisplayListBuilder { tile_spacing, }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } /// Pushes a radial gradient to be displayed. @@ -1234,6 +1237,7 @@ impl DisplayListBuilder { pub fn push_radial_gradient( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, gradient: RadialGradient, tile_size: LayoutSize, tile_spacing: LayoutSize, @@ -1244,18 +1248,20 @@ impl DisplayListBuilder { tile_spacing, }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } pub fn push_reference_frame( &mut self, rect: &LayoutRect, + parent: SpatialId, transform_style: TransformStyle, transform: Option<PropertyBinding<LayoutTransform>>, perspective: Option<LayoutTransform>, - ) -> ClipId { + ) -> SpatialId { let id = self.generate_spatial_index(); - let item = SpecificDisplayItem::PushReferenceFrame(PushReferenceFrameDisplayListItem { + + let item = SpecificDisplayItem::PushReferenceFrame(ReferenceFrameDisplayListItem { reference_frame: ReferenceFrame { transform_style, transform, @@ -1263,7 +1269,12 @@ impl DisplayListBuilder { id, }, }); - self.push_item(&item, &LayoutPrimitiveInfo::new(*rect)); + + let layout = LayoutPrimitiveInfo::new(*rect); + self.push_item(&item, &layout, &SpaceAndClipInfo { + spatial_id: parent, + clip_id: ClipId::invalid(), + }); id } @@ -1287,7 +1298,8 @@ impl DisplayListBuilder { pub fn push_stacking_context( &mut self, layout: &LayoutPrimitiveInfo, - clip_node_id: Option<ClipId>, + spatial_id: SpatialId, + clip_id: Option<ClipId>, transform_style: TransformStyle, mix_blend_mode: MixBlendMode, filters: &[FilterOp], @@ -1297,12 +1309,15 @@ impl DisplayListBuilder { stacking_context: StackingContext { transform_style, mix_blend_mode, - clip_node_id, + clip_id, raster_space, }, }); - self.push_item(&item, layout); + self.push_item(&item, layout, &SpaceAndClipInfo { + spatial_id, + clip_id: ClipId::invalid(), + }); self.push_iter(filters); } @@ -1323,9 +1338,9 @@ impl DisplayListBuilder { ClipId::Clip(self.next_clip_index - 1, self.pipeline_id) } - fn generate_spatial_index(&mut self) -> ClipId { + fn generate_spatial_index(&mut self) -> SpatialId { self.next_spatial_index += 1; - ClipId::Spatial(self.next_spatial_index - 1, self.pipeline_id) + SpatialId::new(self.next_spatial_index - 1, self.pipeline_id) } fn generate_clip_chain_id(&mut self) -> ClipChainId { @@ -1335,38 +1350,14 @@ impl DisplayListBuilder { pub fn define_scroll_frame<I>( &mut self, + parent_space_and_clip: &SpaceAndClipInfo, external_id: Option<ExternalScrollId>, content_rect: LayoutRect, clip_rect: LayoutRect, complex_clips: I, image_mask: Option<ImageMask>, scroll_sensitivity: ScrollSensitivity, - ) -> ClipId - where - I: IntoIterator<Item = ComplexClipRegion>, - I::IntoIter: ExactSizeIterator + Clone, - { - let parent = self.clip_stack.last().unwrap().scroll_node_id; - self.define_scroll_frame_with_parent( - parent, - external_id, - content_rect, - clip_rect, - complex_clips, - image_mask, - scroll_sensitivity) - } - - pub fn define_scroll_frame_with_parent<I>( - &mut self, - parent: ClipId, - external_id: Option<ExternalScrollId>, - content_rect: LayoutRect, - clip_rect: LayoutRect, - complex_clips: I, - image_mask: Option<ImageMask>, - scroll_sensitivity: ScrollSensitivity, - ) -> ClipId + ) -> SpaceAndClipInfo where I: IntoIterator<Item = ComplexClipRegion>, I::IntoIter: ExactSizeIterator + Clone, @@ -1381,14 +1372,17 @@ impl DisplayListBuilder { scroll_sensitivity, }); - self.push_item_with_clip_scroll_info( + self.push_item( &item, &LayoutPrimitiveInfo::with_clip_rect(content_rect, clip_rect), - &ClipAndScrollInfo::simple(parent), + parent_space_and_clip, ); self.push_iter(complex_clips); - scroll_frame_id + SpaceAndClipInfo { + spatial_id: scroll_frame_id, + clip_id, + } } pub fn define_clip_chain<I>( @@ -1408,45 +1402,7 @@ impl DisplayListBuilder { pub fn define_clip<I>( &mut self, - clip_rect: LayoutRect, - complex_clips: I, - image_mask: Option<ImageMask>, - ) -> ClipId - where - I: IntoIterator<Item = ComplexClipRegion>, - I::IntoIter: ExactSizeIterator + Clone, - { - let clip_and_scroll = self.clip_stack.last().unwrap().clone(); - self.define_clip_impl( - clip_and_scroll, - clip_rect, - complex_clips, - image_mask, - ) - } - - pub fn define_clip_with_parent<I>( - &mut self, - parent: ClipId, - clip_rect: LayoutRect, - complex_clips: I, - image_mask: Option<ImageMask>, - ) -> ClipId - where - I: IntoIterator<Item = ComplexClipRegion>, - I::IntoIter: ExactSizeIterator + Clone, - { - self.define_clip_impl( - ClipAndScrollInfo::simple(parent), - clip_rect, - complex_clips, - image_mask, - ) - } - - fn define_clip_impl<I>( - &mut self, - scrollinfo: ClipAndScrollInfo, + parent_space_and_clip: &SpaceAndClipInfo, clip_rect: LayoutRect, complex_clips: I, image_mask: Option<ImageMask>, @@ -1461,21 +1417,24 @@ impl DisplayListBuilder { image_mask, }); - let layout = LayoutPrimitiveInfo::new(clip_rect); - - self.push_item_with_clip_scroll_info(&item, &layout, &scrollinfo); + self.push_item( + &item, + &LayoutPrimitiveInfo::new(clip_rect), + parent_space_and_clip, + ); self.push_iter(complex_clips); id } pub fn define_sticky_frame( &mut self, + parent_spatial_id: SpatialId, frame_rect: LayoutRect, margins: SideOffsets2D<Option<f32>>, vertical_offset_bounds: StickyOffsetBounds, horizontal_offset_bounds: StickyOffsetBounds, previously_applied_offset: LayoutVector2D, - ) -> ClipId { + ) -> SpatialId { let id = self.generate_spatial_index(); let item = SpecificDisplayItem::StickyFrame(StickyFrameDisplayItem { id, @@ -1485,44 +1444,38 @@ impl DisplayListBuilder { previously_applied_offset, }); - let layout = LayoutPrimitiveInfo::new(frame_rect); - self.push_item(&item, &layout); + self.push_item( + &item, + &LayoutPrimitiveInfo::new(frame_rect), + &SpaceAndClipInfo { + spatial_id: parent_spatial_id, + clip_id: ClipId::invalid(), + }, + ); id } - pub fn push_clip_id(&mut self, id: ClipId) { - self.clip_stack.push(ClipAndScrollInfo::simple(id)); - } - - pub fn push_clip_and_scroll_info(&mut self, layout: ClipAndScrollInfo) { - self.clip_stack.push(layout); - } - - pub fn pop_clip_id(&mut self) { - self.clip_stack.pop(); - if let Some(save_state) = self.save_state.as_ref() { - assert!(self.clip_stack.len() >= save_state.clip_stack_len, - "Cannot pop clips that were pushed before the DisplayListBuilder save."); - } - assert!(!self.clip_stack.is_empty()); - } - pub fn push_iframe( &mut self, layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, pipeline_id: PipelineId, ignore_missing_pipeline: bool ) { let item = SpecificDisplayItem::Iframe(IframeDisplayItem { - clip_id: self.generate_clip_index(), pipeline_id, ignore_missing_pipeline, }); - self.push_item(&item, layout); + self.push_item(&item, layout, space_and_clip); } - pub fn push_shadow(&mut self, layout: &LayoutPrimitiveInfo, shadow: Shadow) { - self.push_item(&SpecificDisplayItem::PushShadow(shadow), layout); + pub fn push_shadow( + &mut self, + layout: &LayoutPrimitiveInfo, + space_and_clip: &SpaceAndClipInfo, + shadow: Shadow, + ) { + self.push_item(&SpecificDisplayItem::PushShadow(shadow), layout, space_and_clip); } pub fn pop_all_shadows(&mut self) { @@ -1533,6 +1486,7 @@ impl DisplayListBuilder { assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save"); let end_time = precise_time_ns(); + ( self.pipeline_id, self.content_size, diff --git a/wrench/reftests/scrolling/fixed-position-scrolling-clip.yaml b/wrench/reftests/scrolling/fixed-position-scrolling-clip.yaml index fe012db818..63573e5742 100644 --- a/wrench/reftests/scrolling/fixed-position-scrolling-clip.yaml +++ b/wrench/reftests/scrolling/fixed-position-scrolling-clip.yaml @@ -7,22 +7,22 @@ root: scroll-offset: [0, 50] items: # The rectangles below should stay in place even when the parent scroll area scrolls, - # because they are use the root reference frame as their scroll node (fixed position). + # because they use the root reference frame as their scroll node (fixed position). # On the other hand, the clip item here will scroll with its parent scroll area. Normally # fixed position items would only be clipped by their reference frame (in this case the - # root), but ince these items specify an auxiliary clip, they will be clipped by their + # root), but since these items specify an auxiliary clip, they will be clipped by their # sibling clip (42). - - type: clip - bounds: [10, 60, 50, 50] - id: 42 - - type: stacking-context - bounds: [10, 10, 100, 100] - items: - - type: rect - bounds: [0, 0, 100, 50] - color: green - clip-and-scroll: [root-reference-frame, 42] - - type: rect - bounds: [0, 50, 100, 50] - color: red - clip-and-scroll: [root-reference-frame, 42] + - type: clip + bounds: [10, 60, 50, 50] + id: 42 + - type: stacking-context + bounds: [10, 10, 100, 100] + items: + - type: rect + bounds: [0, 0, 100, 50] + color: green + clip-and-scroll: [root-reference-frame, 42] + - type: rect + bounds: [0, 50, 100, 50] + color: red + clip-and-scroll: [root-reference-frame, 42] diff --git a/wrench/reftests/scrolling/fixed-position.yaml b/wrench/reftests/scrolling/fixed-position.yaml index 540267c5b3..6fa099b5e3 100644 --- a/wrench/reftests/scrolling/fixed-position.yaml +++ b/wrench/reftests/scrolling/fixed-position.yaml @@ -2,18 +2,14 @@ root: bounds: [0, 0, 1024, 10000] scroll-offset: [0, 100] items: - # This stacking context should not scroll out of view because it is fixed position. - type: stacking-context bounds: [0, 0, 50, 50] items: + # This item should not scroll out of view because it is fixed position. - type: rect bounds: [0, 0, 50, 50] color: green clip-and-scroll: root-reference-frame - # Even though there is a fixed position stacking context, it should scroll, - # because it is fixed relative to its reference frame. The reference frame - # of this stacking context is the stacking context parent because it has - # a transformation. - type: stacking-context bounds: [0, 0, 50, 50] transform: translate(60, 100) @@ -22,17 +18,21 @@ root: - type: stacking-context bounds: [0, 0, 50, 50] items: + # Even though there is a custom clip-scroll ID, it should scroll, + # because it is fixed relative to its reference frame. The reference frame + # of this stacking context is the stacking context parent because it has + # a transformation. - type: rect bounds: [0, 0, 50, 50] color: green clip-and-scroll: 100 - # This is similar to the previous case, but ensures that this still works - # even with an identity transform. - type: stacking-context bounds: [120, 0, 50, 200] transform: translate(0, 0) id: 101 items: + # This is similar to the previous case, but ensures that this still works + # even with an identity transform. - type: stacking-context bounds: [0, 0, 50, 200] items: @@ -40,12 +40,12 @@ root: bounds: [0, 100, 50, 50] color: green clip-and-scroll: 101 - # This is similar to the previous case, but for perspective. - type: stacking-context bounds: [180, 0, 50, 200] perspective: 1 id: 102 items: + # This is similar to the previous case, but for perspective. - type: stacking-context bounds: [0, 0, 50, 200] items: diff --git a/wrench/reftests/scrolling/scroll-layer-with-mask.yaml b/wrench/reftests/scrolling/scroll-layer-with-mask.yaml index dc4ee4410f..77cee7abe6 100644 --- a/wrench/reftests/scrolling/scroll-layer-with-mask.yaml +++ b/wrench/reftests/scrolling/scroll-layer-with-mask.yaml @@ -6,7 +6,6 @@ root: # ensure that offsets within reference frames are handled # properly when drawing the mask. bounds: [10, 10, 100, 100] - scroll-policy: scrollable items: - type: scroll-frame bounds: [0, 0, 100, 100] @@ -15,15 +14,14 @@ root: rect: [0, 0, 100, 100] repeat: false items: - - type: rect - bounds: [0, 0, 100, 100] - color: green + - type: rect + bounds: [0, 0, 100, 100] + color: green # The same test, but this time ensure that scroll offsets don't affect the masking. - type: stacking-context bounds: [100, 0, 100, 100] - scroll-policy: scrollable items: - type: scroll-frame bounds: [10, 10, 100, 300] diff --git a/wrench/reftests/scrolling/translate-nested.yaml b/wrench/reftests/scrolling/translate-nested.yaml index 8337379deb..74bd647aa7 100644 --- a/wrench/reftests/scrolling/translate-nested.yaml +++ b/wrench/reftests/scrolling/translate-nested.yaml @@ -1,28 +1,28 @@ --- -root: - items: - - +root: + items: + - bounds: [8, 8, 500, 500] type: "stacking-context" - items: - - + items: + - bounds: [0, 0, 200, 200] type: clip id: 2 items: - - - bounds: [0, 0, 200, 200] - type: rect - color: red - - - bounds: [0, 0, 200, 200] - type: "stacking-context" - transform: translate(100, 0) - items: - - - bounds: [-100, 0, 200, 200] - clip-rect: [-300, -300, 900, 900] - type: rect - color: green + - + bounds: [0, 0, 200, 200] + type: rect + color: red + - + bounds: [0, 0, 200, 200] + type: "stacking-context" + transform: translate(100, 0) + items: + - + bounds: [-100, 0, 200, 200] + clip-rect: [-300, -300, 900, 900] + type: rect + color: green id: [0, 0] pipelines: [] diff --git a/wrench/script/headless.py b/wrench/script/headless.py index 3052ea2be2..ced6c1a133 100755 --- a/wrench/script/headless.py +++ b/wrench/script/headless.py @@ -49,27 +49,6 @@ def is_linux(): return sys.platform.startswith('linux') -def debugger(): - if "DEBUGGER" in os.environ: - return os.environ["DEBUGGER"] - return None - - -def use_gdb(): - return debugger() in ['gdb', 'cgdb', 'rust-gdb'] - - -def use_rr(): - return debugger() == 'rr' - - -def optimized_build(): - if "OPTIMIZED" in os.environ: - opt = os.environ["OPTIMIZED"] - return opt not in ["0", "false"] - return True - - def set_osmesa_env(bin_path): """Set proper LD_LIBRARY_PATH and DRIVE for software rendering on Linux and OSX""" if is_linux(): @@ -88,34 +67,11 @@ def set_osmesa_env(bin_path): extra_flags = os.getenv('CARGOFLAGS', None) extra_flags = extra_flags.split(' ') if extra_flags else [] -build_cmd = ['cargo', 'build'] + extra_flags + ['--verbose', '--features', 'headless'] -if optimized_build(): - build_cmd += ['--release'] - -objdir = '' -if optimized_build(): - objdir = '../target/release/' -else: - objdir = '../target/debug/' - -subprocess.check_call(build_cmd) - -set_osmesa_env(objdir) - -dbg_cmd = [] -if use_rr(): - dbg_cmd = ['rr', 'record'] -elif use_gdb(): - dbg_cmd = [debugger(), '--args'] -elif debugger(): - print("Unknown debugger: " + debugger()) - sys.exit(1) - +subprocess.check_call(['cargo', 'build'] + extra_flags + ['--release', '--verbose', '--features', 'headless']) +set_osmesa_env('../target/release/') # TODO(gw): We have an occasional accuracy issue or bug (could be WR or OSMesa) # where the output of a previous test that uses intermediate targets can # cause 1.0 / 255.0 pixel differences in a subsequent test. For now, we # run tests with no-scissor mode, which ensures a complete target clear # between test runs. But we should investigate this further... -cmd = dbg_cmd + [objdir + '/wrench', '--no-scissor', '-h'] + sys.argv[1:] -print('Running: `' + ' '.join(cmd) + '`') -subprocess.check_call(cmd) +subprocess.check_call(['../target/release/wrench', '--no-scissor', '-h'] + sys.argv[1:]) diff --git a/wrench/src/rawtest.rs b/wrench/src/rawtest.rs index 343f2e13fe..5063e49c39 100644 --- a/wrench/src/rawtest.rs +++ b/wrench/src/rawtest.rs @@ -109,6 +109,7 @@ impl<'a> RawtestHarness<'a> { // setup some malicious image size parameters builder.push_image( &info, + &SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id), size(151., 56.0), size(151.0, 56.0), ImageRendering::Auto, @@ -170,12 +171,18 @@ impl<'a> RawtestHarness<'a> { let image_size = size(1510., 111256.); - let clip_id = builder.define_clip(rect(40., 41., 200., 201.), vec![], None); + let root_space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); + let clip_id = builder.define_clip( + &root_space_and_clip, + rect(40., 41., 200., 201.), + vec![], + None, + ); - builder.push_clip_id(clip_id); // setup some malicious image size parameters builder.push_image( &info, + &SpaceAndClipInfo { clip_id, spatial_id: root_space_and_clip.spatial_id }, image_size * 2., image_size, ImageRendering::Auto, @@ -191,8 +198,6 @@ impl<'a> RawtestHarness<'a> { } ); - builder.pop_clip_id(); - let mut epoch = Epoch(0); self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates); @@ -242,7 +247,7 @@ impl<'a> RawtestHarness<'a> { } fn test_insufficient_blob_visible_area(&mut self) { - println!("\tinsufficient blob visible area."); + println!("\tinsufficient blob visible area..."); // This test compares two almost identical display lists containing the a blob // image. The only difference is that one of the display lists specifies a visible @@ -261,6 +266,7 @@ impl<'a> RawtestHarness<'a> { let layout_size = LayoutSize::new(800.0, 800.0); let image_size = size(800.0, 800.0); let info = LayoutPrimitiveInfo::new(rect(0.0, 0.0, 800.0, 800.0)); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); let mut txn = Transaction::new(); @@ -281,6 +287,7 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, + &space_and_clip, image_size, image_size, ImageRendering::Auto, @@ -317,6 +324,7 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, + &space_and_clip, image_size, image_size, ImageRendering::Auto, @@ -349,6 +357,7 @@ impl<'a> RawtestHarness<'a> { DeviceIntPoint::new(0, window_size.height - test_size.height), test_size, ); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); // This exposes a crash in tile decomposition let mut txn = Transaction::new(); @@ -371,6 +380,7 @@ impl<'a> RawtestHarness<'a> { // setup some malicious image size parameters builder.push_image( &info, + &space_and_clip, image_size, image_size, ImageRendering::Auto, @@ -396,6 +406,7 @@ impl<'a> RawtestHarness<'a> { // setup some malicious image size parameters builder.push_image( &info, + &space_and_clip, image_size, image_size, ImageRendering::Auto, @@ -426,6 +437,7 @@ impl<'a> RawtestHarness<'a> { // setup some malicious image size parameters builder.push_image( &info, + &space_and_clip, image_size, image_size, ImageRendering::Auto, @@ -461,6 +473,8 @@ impl<'a> RawtestHarness<'a> { test_size, ); let layout_size = LayoutSize::new(400., 400.); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); + let mut txn = Transaction::new(); { let api = &self.wrench.api; @@ -487,6 +501,7 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, + &space_and_clip, size(200.0, 200.0), size(0.0, 0.0), ImageRendering::Auto, @@ -510,6 +525,7 @@ impl<'a> RawtestHarness<'a> { let info = LayoutPrimitiveInfo::new(rect(1.0, 60.0, 200.0, 200.0)); builder.push_image( &info, + &space_and_clip, size(200.0, 200.0), size(0.0, 0.0), ImageRendering::Auto, @@ -534,10 +550,6 @@ impl<'a> RawtestHarness<'a> { assert!(pixels_first != pixels_second); // cleanup - txn = Transaction::new(); - txn.delete_blob_image(blob_img); - self.wrench.api.update_resources(txn.resource_updates); - *self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new(); } @@ -553,6 +565,8 @@ impl<'a> RawtestHarness<'a> { test_size, ); let layout_size = LayoutSize::new(400., 400.); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); + let mut txn = Transaction::new(); let (blob_img, blob_img2) = { let api = &self.wrench.api; @@ -599,6 +613,7 @@ impl<'a> RawtestHarness<'a> { let push_images = |builder: &mut DisplayListBuilder| { builder.push_image( &info, + &space_and_clip, size(200.0, 200.0), size(0.0, 0.0), ImageRendering::Auto, @@ -608,6 +623,7 @@ impl<'a> RawtestHarness<'a> { ); builder.push_image( &info2, + &space_and_clip, size(200.0, 200.0), size(0.0, 0.0), ImageRendering::Auto, @@ -666,11 +682,6 @@ impl<'a> RawtestHarness<'a> { assert_eq!(img2_requested.load(Ordering::SeqCst), 2); // cleanup - txn = Transaction::new(); - txn.delete_blob_image(blob_img); - txn.delete_blob_image(blob_img2); - self.wrench.api.update_resources(txn.resource_updates); - *self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new(); } @@ -685,6 +696,7 @@ impl<'a> RawtestHarness<'a> { test_size, ); let layout_size = LayoutSize::new(400., 400.); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); let mut txn = Transaction::new(); let blob_img = { @@ -704,6 +716,7 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &info, + &space_and_clip, size(200.0, 200.0), size(0.0, 0.0), ImageRendering::Auto, @@ -731,6 +744,7 @@ impl<'a> RawtestHarness<'a> { let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0)); builder.push_image( &info, + &space_and_clip, size(200.0, 200.0), size(0.0, 0.0), ImageRendering::Auto, @@ -756,6 +770,7 @@ impl<'a> RawtestHarness<'a> { let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0)); builder.push_image( &info, + &space_and_clip, size(200.0, 200.0), size(0.0, 0.0), ImageRendering::Auto, @@ -769,11 +784,6 @@ impl<'a> RawtestHarness<'a> { assert!(pixels_first == pixels_second); assert!(pixels_first != pixels_third); - - // cleanup - txn = Transaction::new(); - txn.delete_blob_image(blob_img); - self.wrench.api.update_resources(txn.resource_updates); } // Ensures that content doing a save-restore produces the same results as not @@ -792,54 +802,71 @@ impl<'a> RawtestHarness<'a> { let mut do_test = |should_try_and_fail| { let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); - let clip = builder.define_clip( + let spatial_id = SpatialId::root_scroll_node(self.wrench.root_pipeline_id); + let clip_id = builder.define_clip( + &SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id), rect(110., 120., 200., 200.), None::<ComplexClipRegion>, None ); - builder.push_clip_id(clip); - builder.push_rect(&PrimitiveInfo::new(rect(100., 100., 100., 100.)), - ColorF::new(0.0, 0.0, 1.0, 1.0)); + builder.push_rect( + &PrimitiveInfo::new(rect(100., 100., 100., 100.)), + &SpaceAndClipInfo { spatial_id, clip_id }, + ColorF::new(0.0, 0.0, 1.0, 1.0), + ); if should_try_and_fail { builder.save(); - let clip = builder.define_clip( + let clip_id = builder.define_clip( + &SpaceAndClipInfo { spatial_id, clip_id }, rect(80., 80., 90., 90.), None::<ComplexClipRegion>, None ); - builder.push_clip_id(clip); - builder.push_rect(&PrimitiveInfo::new(rect(110., 110., 50., 50.)), - ColorF::new(0.0, 1.0, 0.0, 1.0)); - builder.push_shadow(&PrimitiveInfo::new(rect(100., 100., 100., 100.)), - Shadow { - offset: LayoutVector2D::new(1.0, 1.0), - blur_radius: 1.0, - color: ColorF::new(0.0, 0.0, 0.0, 1.0), - }); - builder.push_line(&PrimitiveInfo::new(rect(110., 110., 50., 2.)), - 0.0, LineOrientation::Horizontal, - &ColorF::new(0.0, 0.0, 0.0, 1.0), LineStyle::Solid); + let space_and_clip = SpaceAndClipInfo { + spatial_id, + clip_id + }; + builder.push_rect( + &PrimitiveInfo::new(rect(110., 110., 50., 50.)), + &space_and_clip, + ColorF::new(0.0, 1.0, 0.0, 1.0), + ); + builder.push_shadow( + &PrimitiveInfo::new(rect(100., 100., 100., 100.)), + &space_and_clip, + Shadow { + offset: LayoutVector2D::new(1.0, 1.0), + blur_radius: 1.0, + color: ColorF::new(0.0, 0.0, 0.0, 1.0), + }, + ); + builder.push_line( + &PrimitiveInfo::new(rect(110., 110., 50., 2.)), + &space_and_clip, + 0.0, LineOrientation::Horizontal, + &ColorF::new(0.0, 0.0, 0.0, 1.0), + LineStyle::Solid, + ); builder.restore(); } { builder.save(); - let clip = builder.define_clip( + let clip_id = builder.define_clip( + &SpaceAndClipInfo { spatial_id, clip_id }, rect(80., 80., 100., 100.), None::<ComplexClipRegion>, None ); - builder.push_clip_id(clip); - builder.push_rect(&PrimitiveInfo::new(rect(150., 150., 100., 100.)), - ColorF::new(0.0, 0.0, 1.0, 1.0)); - - builder.pop_clip_id(); + builder.push_rect( + &PrimitiveInfo::new(rect(150., 150., 100., 100.)), + &SpaceAndClipInfo { spatial_id, clip_id }, + ColorF::new(0.0, 0.0, 1.0, 1.0), + ); builder.clear_save(); } - builder.pop_clip_id(); - let txn = Transaction::new(); self.submit_dl(&mut Epoch(0), layout_size, builder, &txn.resource_updates); @@ -866,6 +893,7 @@ impl<'a> RawtestHarness<'a> { test_size, ); let layout_size = LayoutSize::new(400., 400.); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); let mut do_test = |shadow_is_red| { let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); @@ -875,15 +903,22 @@ impl<'a> RawtestHarness<'a> { ColorF::new(0.0, 1.0, 0.0, 1.0) }; - builder.push_shadow(&PrimitiveInfo::new(rect(100., 100., 100., 100.)), + builder.push_shadow( + &PrimitiveInfo::new(rect(100., 100., 100., 100.)), + &space_and_clip, Shadow { offset: LayoutVector2D::new(1.0, 1.0), blur_radius: 1.0, color: shadow_color, - }); - builder.push_line(&PrimitiveInfo::new(rect(110., 110., 50., 2.)), - 0.0, LineOrientation::Horizontal, - &ColorF::new(0.0, 0.0, 0.0, 1.0), LineStyle::Solid); + }, + ); + builder.push_line( + &PrimitiveInfo::new(rect(110., 110., 50., 2.)), + &space_and_clip, + 0.0, LineOrientation::Horizontal, + &ColorF::new(0.0, 0.0, 0.0, 1.0), + LineStyle::Solid, + ); builder.pop_all_shadows(); let txn = Transaction::new(); @@ -923,6 +958,7 @@ impl<'a> RawtestHarness<'a> { builder.push_image( &LayoutPrimitiveInfo::new(rect(300.0, 70.0, 150.0, 50.0)), + &SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id), size(150.0, 50.0), size(0.0, 0.0), ImageRendering::Auto, @@ -991,7 +1027,11 @@ impl<'a> RawtestHarness<'a> { let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); let info = LayoutPrimitiveInfo::new(LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(100.0, 100.0))); - builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0)); + builder.push_rect( + &info, + &SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id), + ColorF::new(0.0, 1.0, 0.0, 1.0), + ); let mut txn = Transaction::new(); txn.set_root_pipeline(self.wrench.root_pipeline_id); @@ -1017,11 +1057,12 @@ impl<'a> RawtestHarness<'a> { let layout_size = LayoutSize::new(400., 400.); let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); + let space_and_clip = SpaceAndClipInfo::root_scroll(self.wrench.root_pipeline_id); + // Add a rectangle that covers the entire scene. let mut info = LayoutPrimitiveInfo::new(LayoutRect::new(LayoutPoint::zero(), layout_size)); info.tag = Some((0, 1)); - builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0)); - + builder.push_rect(&info, &space_and_clip, ColorF::new(1.0, 1.0, 1.0, 1.0)); // Add a simple 100x100 rectangle at 100,0. let mut info = LayoutPrimitiveInfo::new(LayoutRect::new( @@ -1029,7 +1070,7 @@ impl<'a> RawtestHarness<'a> { LayoutSize::new(100., 100.) )); info.tag = Some((0, 2)); - builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0)); + builder.push_rect(&info, &space_and_clip, ColorF::new(1.0, 1.0, 1.0, 1.0)); let make_rounded_complex_clip = |rect: &LayoutRect, radius: f32| -> ComplexClipRegion { ComplexClipRegion::new( @@ -1039,30 +1080,46 @@ impl<'a> RawtestHarness<'a> { ) }; - // Add a rectangle that is clipped by a rounded rect clip item. let rect = LayoutRect::new(LayoutPoint::new(100., 100.), LayoutSize::new(100., 100.)); - let clip_id = builder.define_clip(rect, vec![make_rounded_complex_clip(&rect, 20.)], None); - builder.push_clip_id(clip_id); - let mut info = LayoutPrimitiveInfo::new(rect); - info.tag = Some((0, 4)); - builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0)); - builder.pop_clip_id(); - + let temp_clip_id = builder.define_clip( + &space_and_clip, + rect, + vec![make_rounded_complex_clip(&rect, 20.)], + None, + ); + builder.push_rect( + &LayoutPrimitiveInfo { + tag: Some((0, 4)), + .. LayoutPrimitiveInfo::new(rect) + }, + &SpaceAndClipInfo { + clip_id: temp_clip_id, + spatial_id: space_and_clip.spatial_id, + }, + ColorF::new(1.0, 1.0, 1.0, 1.0), + ); // Add a rectangle that is clipped by a ClipChain containing a rounded rect. let rect = LayoutRect::new(LayoutPoint::new(200., 100.), LayoutSize::new(100., 100.)); - let clip_id = builder.define_clip(rect, vec![make_rounded_complex_clip(&rect, 20.)], None); + let clip_id = builder.define_clip( + &space_and_clip, + rect, + vec![make_rounded_complex_clip(&rect, 20.)], + None, + ); let clip_chain_id = builder.define_clip_chain(None, vec![clip_id]); - builder.push_clip_and_scroll_info(ClipAndScrollInfo::new( - ClipId::root_scroll_node(self.wrench.root_pipeline_id), - ClipId::ClipChain(clip_chain_id), - )); - let mut info = LayoutPrimitiveInfo::new(rect); - info.tag = Some((0, 5)); - builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0)); - builder.pop_clip_id(); - + builder.push_rect( + &LayoutPrimitiveInfo { + tag: Some((0, 5)), + .. LayoutPrimitiveInfo::new(rect) + }, + &SpaceAndClipInfo { + clip_id: ClipId::ClipChain(clip_chain_id), + spatial_id: space_and_clip.spatial_id, + }, + ColorF::new(1.0, 1.0, 1.0, 1.0), + ); let mut epoch = Epoch(0); let txn = Transaction::new(); diff --git a/wrench/src/yaml_frame_reader.rs b/wrench/src/yaml_frame_reader.rs index 9ba89e9d5d..fa16b8968e 100644 --- a/wrench/src/yaml_frame_reader.rs +++ b/wrench/src/yaml_frame_reader.rs @@ -224,7 +224,11 @@ pub struct YamlFrameReader { /// A HashMap that allows specifying a numeric id for clip and clip chains in YAML /// and having each of those ids correspond to a unique ClipId. - clip_id_map: HashMap<u64, ClipId>, + user_clip_id_map: HashMap<u64, ClipId>, + user_spatial_id_map: HashMap<u64, SpatialId>, + + clip_id_stack: Vec<ClipId>, + spatial_id_stack: Vec<SpatialId>, } impl YamlFrameReader { @@ -243,9 +247,12 @@ impl YamlFrameReader { fonts: HashMap::new(), font_instances: HashMap::new(), font_render_mode: None, - image_map: HashMap::new(), - clip_id_map: HashMap::new(), allow_mipmaps: false, + image_map: HashMap::new(), + user_clip_id_map: HashMap::new(), + user_spatial_id_map: HashMap::new(), + clip_id_stack: Vec::new(), + spatial_id_stack: Vec::new(), } } @@ -263,6 +270,13 @@ impl YamlFrameReader { wrench.api.update_resources(txn.resource_updates); } + fn top_space_and_clip(&self) -> SpaceAndClipInfo { + SpaceAndClipInfo { + spatial_id: *self.spatial_id_stack.last().unwrap(), + clip_id: *self.clip_id_stack.last().unwrap(), + } + } + pub fn yaml_path(&self) -> &PathBuf { &self.yaml_path } @@ -316,13 +330,21 @@ impl YamlFrameReader { yaml: &Yaml ) { // Don't allow referencing clips between pipelines for now. - self.clip_id_map.clear(); + self.user_clip_id_map.clear(); + self.user_spatial_id_map.clear(); + self.clip_id_stack.clear(); + self.clip_id_stack.push(ClipId::root(pipeline_id)); + self.spatial_id_stack.clear(); + self.spatial_id_stack.push(SpatialId::root_scroll_node(pipeline_id)); let content_size = self.get_root_size_from_yaml(wrench, yaml); let mut builder = DisplayListBuilder::new(pipeline_id, content_size); let mut info = LayoutPrimitiveInfo::new(LayoutRect::zero()); self.add_stacking_context_from_yaml(&mut builder, wrench, yaml, true, &mut info); self.display_lists.push(builder.finalize()); + + assert_eq!(self.clip_id_stack.len(), 1); + assert_eq!(self.spatial_id_stack.len(), 1); } fn to_complex_clip_region(&mut self, item: &Yaml) -> ComplexClipRegion { @@ -362,50 +384,84 @@ impl YamlFrameReader { } } - pub fn u64_to_clip_id(&self, number: u64, pipeline_id: PipelineId) -> ClipId { - match number { - 0 => ClipId::root_reference_frame(pipeline_id), - 1 => ClipId::root_scroll_node(pipeline_id), - _ => self.clip_id_map[&number], + pub fn to_clip_id(&self, item: &Yaml, pipeline_id: PipelineId) -> Option<ClipId> { + match *item { + Yaml::Integer(value) => Some(self.user_clip_id_map[&(value as u64)]), + Yaml::String(ref id_string) if id_string == "root_clip" => + Some(ClipId::root(pipeline_id)), + _ => None, } - } - pub fn to_clip_id(&self, item: &Yaml, pipeline_id: PipelineId) -> Option<ClipId> { + pub fn to_spatial_id(&self, item: &Yaml, pipeline_id: PipelineId) -> SpatialId { match *item { - Yaml::Integer(value) => Some(self.u64_to_clip_id(value as u64, pipeline_id)), + Yaml::Integer(value) => self.user_spatial_id_map[&(value as u64)], Yaml::String(ref id_string) if id_string == "root-reference-frame" => - Some(ClipId::root_reference_frame(pipeline_id)), + SpatialId::root_reference_frame(pipeline_id), Yaml::String(ref id_string) if id_string == "root-scroll-node" => - Some(ClipId::root_scroll_node(pipeline_id)), - _ => None, + SpatialId::root_scroll_node(pipeline_id), + _ => { + println!("Unable to parse SpatialId {:?}", item); + SpatialId::root_reference_frame(pipeline_id) + } } } pub fn add_clip_id_mapping(&mut self, numeric_id: u64, real_id: ClipId) { - assert!(numeric_id != 0, "id=0 is reserved for the root reference frame"); - assert!(numeric_id != 1, "id=1 is reserved for the root scroll node"); - self.clip_id_map.insert(numeric_id, real_id); + assert_ne!(numeric_id, 0, "id=0 is reserved for the root clip"); + self.user_clip_id_map.insert(numeric_id, real_id); + } + + pub fn add_spatial_id_mapping(&mut self, numeric_id: u64, real_id: SpatialId) { + assert_ne!(numeric_id, 0, "id=0 is reserved for the root reference frame"); + assert_ne!(numeric_id, 1, "id=1 is reserved for the root scroll node"); + self.user_spatial_id_map.insert(numeric_id, real_id); } fn to_clip_and_scroll_info( &self, item: &Yaml, pipeline_id: PipelineId - ) -> Option<ClipAndScrollInfo> { + ) -> (Option<ClipId>, Option<SpatialId>) { + // Note: this is tricky. In the old code the single ID could be used either way + // for clip/scroll. In the new code we are trying to reflect that and not break + // all the reftests. Ultimately we'd want the clip and scroll nodes to be + // provided separately in YAML. match *item { + Yaml::BadValue => (None, None), Yaml::Array(ref array) if array.len() == 2 => { - let scroll_id = match self.to_clip_id(&array[0], pipeline_id) { - Some(id) => id, - None => return None, - }; - let clip_id = match self.to_clip_id(&array[1], pipeline_id) { - Some(id) => id, - None => return None, - }; - Some(ClipAndScrollInfo::new(scroll_id, clip_id)) + let scroll_id = self.to_spatial_id(&array[0], pipeline_id); + let clip_id = self.to_clip_id(&array[1], pipeline_id); + (clip_id, Some(scroll_id)) + } + Yaml::String(ref id_string) if id_string == "root-reference-frame" => { + let scroll_id = SpatialId::root_reference_frame(pipeline_id); + let clip_id = ClipId::root(pipeline_id); + (Some(clip_id), Some(scroll_id)) + } + Yaml::String(ref id_string) if id_string == "root-scroll-node" => { + let scroll_id = SpatialId::root_scroll_node(pipeline_id); + (None, Some(scroll_id)) + } + Yaml::String(ref id_string) if id_string == "root_clip" => { + let clip_id = ClipId::root(pipeline_id); + (Some(clip_id), None) + } + Yaml::Integer(value) => { + let scroll_id = self.user_spatial_id_map + .get(&(value as u64)) + .cloned(); + let clip_id = self.user_clip_id_map + .get(&(value as u64)) + .cloned(); + assert!(scroll_id.is_some() || clip_id.is_some(), + "clip-and-scroll index not found: {}", value); + (clip_id, scroll_id) + } + _ => { + println!("Unable to parse clip/scroll {:?}", item); + (None, None) } - _ => self.to_clip_id(item, pipeline_id).map(|id| ClipAndScrollInfo::simple(id)), } } @@ -709,7 +765,7 @@ impl YamlFrameReader { .as_rect() .expect("rect type must have bounds"); let color = item["color"].as_colorf().unwrap_or(ColorF::WHITE); - dl.push_rect(&info, color); + dl.push_rect(&info, &self.top_space_and_clip(), color); } fn handle_clear_rect( @@ -721,7 +777,7 @@ impl YamlFrameReader { info.rect = item["bounds"] .as_rect() .expect("clear-rect type must have bounds"); - dl.push_clear_rect(&info); + dl.push_clear_rect(&info, &self.top_space_and_clip()); } fn handle_line( @@ -777,6 +833,7 @@ impl YamlFrameReader { dl.push_line( &info, + &self.top_space_and_clip(), wavy_line_thickness, orientation, &color, @@ -803,7 +860,7 @@ impl YamlFrameReader { let tile_size = item["tile-size"].as_size().unwrap_or(bounds.size); let tile_spacing = item["tile-spacing"].as_size().unwrap_or(LayoutSize::zero()); - dl.push_gradient(&info, gradient, tile_size, tile_spacing); + dl.push_gradient(&info, &self.top_space_and_clip(), gradient, tile_size, tile_spacing); } fn handle_radial_gradient( @@ -825,7 +882,13 @@ impl YamlFrameReader { let tile_size = item["tile-size"].as_size().unwrap_or(bounds.size); let tile_spacing = item["tile-spacing"].as_size().unwrap_or(LayoutSize::zero()); - dl.push_radial_gradient(&info, gradient, tile_size, tile_spacing); + dl.push_radial_gradient( + &info, + &self.top_space_and_clip(), + gradient, + tile_size, + tile_spacing, + ); } fn handle_border( @@ -987,7 +1050,7 @@ impl YamlFrameReader { None }; if let Some(details) = border_details { - dl.push_border(&info, widths, details); + dl.push_border(&info, &self.top_space_and_clip(), widths, details); } } @@ -1028,6 +1091,7 @@ impl YamlFrameReader { dl.push_box_shadow( &info, + &self.top_space_and_clip(), box_bounds, offset, color, @@ -1090,6 +1154,7 @@ impl YamlFrameReader { dl.push_yuv_image( &info, + &self.top_space_and_clip(), yuv_data, color_depth, color_space, @@ -1150,7 +1215,16 @@ impl YamlFrameReader { item ), }; - dl.push_image(&info, stretch_size, tile_spacing, rendering, alpha_type, image_key, ColorF::WHITE); + dl.push_image( + &info, + &self.top_space_and_clip(), + stretch_size, + tile_spacing, + rendering, + alpha_type, + image_key, + ColorF::WHITE, + ); } fn handle_text( @@ -1265,7 +1339,14 @@ impl YamlFrameReader { }; info.rect = rect; - dl.push_text(&info, &glyphs, font_instance_key, color, None); + dl.push_text( + &info, + &self.top_space_and_clip(), + &glyphs, + font_instance_key, + color, + None, + ); } fn handle_iframe( @@ -1277,7 +1358,7 @@ impl YamlFrameReader { info.rect = item["bounds"].as_rect().expect("iframe must have bounds"); let pipeline_id = item["id"].as_pipeline_id().unwrap(); let ignore = item["ignore_missing_pipeline"].as_bool().unwrap_or(true); - dl.push_iframe(&info, pipeline_id, ignore); + dl.push_iframe(&info, &self.top_space_and_clip(), pipeline_id, ignore); } pub fn get_complex_clip_for_item(&mut self, yaml: &Yaml) -> Option<ComplexClipRegion> { @@ -1332,12 +1413,15 @@ impl YamlFrameReader { continue; } - let clip_scroll_info = self.to_clip_and_scroll_info( + let (set_clip_id, set_scroll_id) = self.to_clip_and_scroll_info( &item["clip-and-scroll"], dl.pipeline_id ); - if let Some(clip_scroll_info) = clip_scroll_info { - dl.push_clip_and_scroll_info(clip_scroll_info); + if let Some(clip_id) = set_clip_id { + self.clip_id_stack.push(clip_id); + } + if let Some(scroll_id) = set_scroll_id { + self.spatial_id_stack.push(scroll_id); } let complex_clip = self.get_complex_clip_for_item(item); @@ -1348,8 +1432,13 @@ impl YamlFrameReader { match item_type { "clip" | "clip-chain" | "scroll-frame" => {}, _ => { - let id = dl.define_clip(clip_rect, vec![complex_clip], None); - dl.push_clip_id(id); + let id = dl.define_clip( + &self.top_space_and_clip(), + clip_rect, + vec![complex_clip], + None, + ); + self.clip_id_stack.push(id); pushed_clip = true; } } @@ -1385,14 +1474,14 @@ impl YamlFrameReader { } if pushed_clip { - dl.pop_clip_id(); - + self.clip_id_stack.pop().unwrap(); } - - if clip_scroll_info.is_some() { - dl.pop_clip_id(); + if set_clip_id.is_some() { + self.clip_id_stack.pop().unwrap(); + } + if set_scroll_id.is_some() { + self.spatial_id_stack.pop().unwrap(); } - } } @@ -1419,7 +1508,8 @@ impl YamlFrameReader { id }); - let real_id = dl.define_scroll_frame( + let space_and_clip = dl.define_scroll_frame( + &self.top_space_and_clip(), external_id, content_rect, clip_rect, @@ -1428,13 +1518,16 @@ impl YamlFrameReader { ScrollSensitivity::ScriptAndInputEvents, ); if let Some(numeric_id) = numeric_id { - self.add_clip_id_mapping(numeric_id, real_id); + self.add_spatial_id_mapping(numeric_id, space_and_clip.spatial_id); + self.add_clip_id_mapping(numeric_id, space_and_clip.clip_id); } if !yaml["items"].is_badvalue() { - dl.push_clip_id(real_id); + self.spatial_id_stack.push(space_and_clip.spatial_id); + self.clip_id_stack.push(space_and_clip.clip_id); self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]); - dl.pop_clip_id(); + self.clip_id_stack.pop().unwrap(); + self.spatial_id_stack.pop().unwrap(); } } @@ -1448,6 +1541,7 @@ impl YamlFrameReader { let numeric_id = yaml["id"].as_i64().map(|id| id as u64); let real_id = dl.define_sticky_frame( + *self.spatial_id_stack.last().unwrap(), bounds, SideOffsets2D::new( yaml["margin-top"].as_f32(), @@ -1461,13 +1555,13 @@ impl YamlFrameReader { ); if let Some(numeric_id) = numeric_id { - self.add_clip_id_mapping(numeric_id, real_id); + self.add_spatial_id_mapping(numeric_id, real_id); } if !yaml["items"].is_badvalue() { - dl.push_clip_id(real_id); + self.spatial_id_stack.push(real_id); self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]); - dl.pop_clip_id(); + self.spatial_id_stack.pop().unwrap(); } } @@ -1483,6 +1577,7 @@ impl YamlFrameReader { dl.push_shadow( &info, + &self.top_space_and_clip(), Shadow { blur_radius, offset, @@ -1499,8 +1594,9 @@ impl YamlFrameReader { let numeric_id = yaml["id"].as_i64().expect("clip chains must have an id"); let clip_ids: Vec<ClipId> = yaml["clips"] .as_vec_u64() - .unwrap_or_else(Vec::new) - .iter().map(|id| self.u64_to_clip_id(*id, builder.pipeline_id)) + .unwrap_or_default() + .iter() + .map(|id| self.user_clip_id_map[id]) .collect(); let parent = self.to_clip_id(&yaml["parent"], builder.pipeline_id); @@ -1520,15 +1616,22 @@ impl YamlFrameReader { let complex_clips = self.to_complex_clip_regions(&yaml["complex"]); let image_mask = self.to_image_mask(&yaml["image-mask"], wrench); - let real_id = dl.define_clip(clip_rect, complex_clips, image_mask); + let space_and_clip = self.top_space_and_clip(); + let real_id = dl.define_clip( + &space_and_clip, + clip_rect, + complex_clips, + image_mask, + ); if let Some(numeric_id) = numeric_id { self.add_clip_id_mapping(numeric_id as u64, real_id); + self.add_spatial_id_mapping(numeric_id as u64, space_and_clip.spatial_id); } if !yaml["items"].is_badvalue() { - dl.push_clip_id(real_id); + self.clip_id_stack.push(real_id); self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]); - dl.pop_clip_id(); + self.clip_id_stack.pop().unwrap(); } } @@ -1544,7 +1647,7 @@ impl YamlFrameReader { dl: &mut DisplayListBuilder, wrench: &mut Wrench, yaml: &Yaml, - ) -> ClipId { + ) -> SpatialId { let default_bounds = LayoutRect::new(LayoutPoint::zero(), wrench.window_size_f32()); let bounds = yaml["bounds"].as_rect().unwrap_or(default_bounds); let default_transform_origin = LayoutPoint::new( @@ -1578,6 +1681,7 @@ impl YamlFrameReader { let reference_frame_id = dl.push_reference_frame( &bounds, + *self.spatial_id_stack.last().unwrap(), transform_style, transform.into(), perspective, @@ -1585,7 +1689,7 @@ impl YamlFrameReader { let numeric_id = yaml["id"].as_i64(); if let Some(numeric_id) = numeric_id { - self.add_clip_id_mapping(numeric_id as u64, reference_frame_id); + self.add_spatial_id_mapping(numeric_id as u64, reference_frame_id); } reference_frame_id @@ -1597,14 +1701,14 @@ impl YamlFrameReader { wrench: &mut Wrench, yaml: &Yaml, ) { - let reference_frame_id = self.push_reference_frame(dl, wrench, yaml); + let real_id = self.push_reference_frame(dl, wrench, yaml); + self.spatial_id_stack.push(real_id); if !yaml["items"].is_badvalue() { - dl.push_clip_id(reference_frame_id); self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]); - dl.pop_clip_id(); } + self.spatial_id_stack.pop().unwrap(); dl.pop_reference_frame(); } @@ -1617,21 +1721,21 @@ impl YamlFrameReader { info: &mut LayoutPrimitiveInfo, ) { let default_bounds = LayoutRect::new(LayoutPoint::zero(), wrench.window_size_f32()); - let bounds = yaml["bounds"].as_rect().unwrap_or(default_bounds); - info.rect = bounds; - info.clip_rect = bounds; + let mut bounds = yaml["bounds"].as_rect().unwrap_or(default_bounds); let reference_frame_id = if !yaml["transform"].is_badvalue() || !yaml["perspective"].is_badvalue() { let reference_frame_id = self.push_reference_frame(dl, wrench, yaml); - info.rect.origin = LayoutPoint::zero(); - info.clip_rect.origin = LayoutPoint::zero(); + self.spatial_id_stack.push(reference_frame_id); + bounds.origin = LayoutPoint::zero(); Some(reference_frame_id) } else { None }; + // note: this API is deprecated, use the standard clip-and-scroll field instead let clip_node_id = self.to_clip_id(&yaml["clip-node"], dl.pipeline_id); + let transform_style = yaml["transform-style"] .as_transform_style() .unwrap_or(TransformStyle::Flat); @@ -1651,12 +1755,12 @@ impl YamlFrameReader { let filters = yaml["filters"].as_vec_filter_op().unwrap_or(vec![]); - if let Some(reference_frame_id) = reference_frame_id { - dl.push_clip_id(reference_frame_id); - } + info.rect = bounds; + info.clip_rect = bounds; dl.push_stacking_context( &info, + *self.spatial_id_stack.last().unwrap(), clip_node_id, transform_style, mix_blend_mode, @@ -1671,10 +1775,7 @@ impl YamlFrameReader { dl.pop_stacking_context(); if reference_frame_id.is_some() { - dl.pop_clip_id(); - } - - if reference_frame_id.is_some() { + self.spatial_id_stack.pop().unwrap(); dl.pop_reference_frame(); } } diff --git a/wrench/src/yaml_frame_writer.rs b/wrench/src/yaml_frame_writer.rs index 098dba158b..f514cef85f 100644 --- a/wrench/src/yaml_frame_writer.rs +++ b/wrench/src/yaml_frame_writer.rs @@ -17,7 +17,7 @@ use super::CURRENT_FRAME_NUMBER; use time; use webrender; use webrender::api::*; -use webrender::api::SpecificDisplayItem::*; +use webrender::api::SpecificDisplayItem as Sdi; use webrender::api::channel::Payload; use yaml_helper::StringEnum; use yaml_rust::{Yaml, YamlEmitter}; @@ -206,7 +206,7 @@ fn write_reference_frame( matrix4d_node(parent, "perspective", &perspective); } - usize_node(parent, "id", clip_id_mapper.add_id(reference_frame.id)); + usize_node(parent, "id", clip_id_mapper.add_spatial_id(reference_frame.id)); } fn write_stacking_context( @@ -214,7 +214,6 @@ fn write_stacking_context( sc: &StackingContext, properties: &SceneProperties, filter_iter: AuxIter<FilterOp>, - clip_id_mapper: &ClipIdMapper, ) { enum_node(parent, "transform-style", sc.transform_style); @@ -228,10 +227,6 @@ fn write_stacking_context( }; str_node(parent, "raster-space", &raster_space); - if let Some(clip_node_id) = sc.clip_node_id { - yaml_node(parent, "clip-node", clip_id_mapper.map_id(&clip_node_id)); - } - // mix_blend_mode if sc.mix_blend_mode != MixBlendMode::Normal { enum_node(parent, "mix-blend-mode", sc.mix_blend_mode) @@ -767,18 +762,22 @@ impl YamlFrameWriter { ); } - yaml_node(&mut v, "clip-and-scroll", clip_id_mapper.map_info(&base.clip_and_scroll())); + let space_and_clip = base.space_and_clip_info(); + let clip_id = if space_and_clip.clip_id.is_root() { None } else { Some(space_and_clip.clip_id) }; + yaml_node(&mut v, "clip-and-scroll", + clip_id_mapper.map_clip_and_scroll_ids(clip_id, space_and_clip.spatial_id) + ); bool_node(&mut v, "backface-visible", base.is_backface_visible()); match *base.item() { - Rectangle(item) => { + Sdi::Rectangle(item) => { str_node(&mut v, "type", "rect"); color_node(&mut v, "color", item.color); } - ClearRectangle => { + Sdi::ClearRectangle => { str_node(&mut v, "type", "clear-rect");; } - Line(item) => { + Sdi::Line(item) => { str_node(&mut v, "type", "line"); if let LineStyle::Wavy = item.style { f32_node(&mut v, "thickness", item.wavy_line_thickness); @@ -787,7 +786,7 @@ impl YamlFrameWriter { color_node(&mut v, "color", item.color); str_node(&mut v, "style", item.style.as_str()); } - Text(item) => { + Sdi::Text(item) => { let gi = display_list.get(base.glyphs()); let mut indices: Vec<u32> = vec![]; let mut offsets: Vec<f32> = vec![]; @@ -841,7 +840,7 @@ impl YamlFrameWriter { } } } - Image(item) => { + Sdi::Image(item) => { if let Some(path) = self.path_for_image(item.image_key) { path_node(&mut v, "image", &path); } @@ -864,12 +863,12 @@ impl YamlFrameWriter { AlphaType::Alpha => str_node(&mut v, "alpha-type", "alpha"), }; } - YuvImage(_) => { + Sdi::YuvImage(_) => { str_node(&mut v, "type", "yuv-image"); // TODO println!("TODO YAML YuvImage"); } - Border(item) => { + Sdi::Border(item) => { str_node(&mut v, "type", "border"); match item.details { BorderDetails::Normal(ref details) => { @@ -984,7 +983,7 @@ impl YamlFrameWriter { } } } - BoxShadow(item) => { + Sdi::BoxShadow(item) => { str_node(&mut v, "type", "box-shadow"); rect_node(&mut v, "box-bounds", &item.box_bounds); vector_node(&mut v, "offset", &item.offset); @@ -1000,7 +999,7 @@ impl YamlFrameWriter { }; str_node(&mut v, "clip-mode", clip_mode); } - Gradient(item) => { + Sdi::Gradient(item) => { str_node(&mut v, "type", "gradient"); point_node(&mut v, "start", &item.gradient.start_point); point_node(&mut v, "end", &item.gradient.end_point); @@ -1018,7 +1017,7 @@ impl YamlFrameWriter { item.gradient.extend_mode == ExtendMode::Repeat, ); } - RadialGradient(item) => { + Sdi::RadialGradient(item) => { str_node(&mut v, "type", "radial-gradient"); size_node(&mut v, "tile-size", &item.tile_size); size_node(&mut v, "tile-spacing", &item.tile_spacing); @@ -1029,12 +1028,12 @@ impl YamlFrameWriter { display_list ); } - Iframe(item) => { + Sdi::Iframe(item) => { str_node(&mut v, "type", "iframe"); u32_vec_node(&mut v, "id", &[item.pipeline_id.0, item.pipeline_id.1]); bool_node(&mut v, "ignore_missing_pipeline", item.ignore_missing_pipeline); } - PushStackingContext(item) => { + Sdi::PushStackingContext(item) => { str_node(&mut v, "type", "stacking-context"); let filters = display_list.get(base.filters()); write_stacking_context( @@ -1042,29 +1041,28 @@ impl YamlFrameWriter { &item.stacking_context, &scene.properties, filters, - clip_id_mapper, ); let mut sub_iter = base.sub_iter(); self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper); continue_traversal = Some(sub_iter); } - PushReferenceFrame(item) => { + Sdi::PushReferenceFrame(item) => { str_node(&mut v, "type", "reference-frame"); write_reference_frame( &mut v, &item.reference_frame, &scene.properties, - clip_id_mapper + clip_id_mapper, ); let mut sub_iter = base.sub_iter(); self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper); continue_traversal = Some(sub_iter); } - Clip(item) => { + Sdi::Clip(item) => { str_node(&mut v, "type", "clip"); - usize_node(&mut v, "id", clip_id_mapper.add_id(item.id)); + usize_node(&mut v, "id", clip_id_mapper.add_clip_id(item.id)); let (complex_clips, complex_clip_count) = base.complex_clip(); if let Some(complex) = self.make_complex_clips_node( @@ -1079,25 +1077,25 @@ impl YamlFrameWriter { yaml_node(&mut v, "image-mask", mask_yaml); } } - ClipChain(item) => { + Sdi::ClipChain(item) => { str_node(&mut v, "type", "clip-chain"); let id = ClipId::ClipChain(item.id); - u32_node(&mut v, "id", clip_id_mapper.add_id(id) as u32); + u32_node(&mut v, "id", clip_id_mapper.add_clip_id(id) as u32); let clip_ids = display_list.get(base.clip_chain_items()).map(|clip_id| { - clip_id_mapper.map_id(&clip_id) + clip_id_mapper.map_clip_id(&clip_id) }).collect(); yaml_node(&mut v, "clips", Yaml::Array(clip_ids)); if let Some(parent) = item.parent { let parent = ClipId::ClipChain(parent); - yaml_node(&mut v, "parent", clip_id_mapper.map_id(&parent)); + yaml_node(&mut v, "parent", clip_id_mapper.map_clip_id(&parent)); } } - ScrollFrame(item) => { + Sdi::ScrollFrame(item) => { str_node(&mut v, "type", "scroll-frame"); - usize_node(&mut v, "id", clip_id_mapper.add_id(item.scroll_frame_id)); + usize_node(&mut v, "id", clip_id_mapper.add_spatial_id(item.scroll_frame_id)); size_node(&mut v, "content-size", &base.rect().size); rect_node(&mut v, "bounds", &base.clip_rect()); @@ -1114,9 +1112,9 @@ impl YamlFrameWriter { yaml_node(&mut v, "image-mask", mask_yaml); } } - StickyFrame(item) => { + Sdi::StickyFrame(item) => { str_node(&mut v, "type", "sticky-frame"); - usize_node(&mut v, "id", clip_id_mapper.add_id(item.id)); + usize_node(&mut v, "id", clip_id_mapper.add_spatial_id(item.id)); rect_node(&mut v, "bounds", &base.clip_rect()); if let Some(margin) = item.margins.top { @@ -1151,21 +1149,22 @@ impl YamlFrameWriter { yaml_node(&mut v, "previously-applied-offset", Yaml::Array(applied)); } - PopCacheMarker => return, - PushCacheMarker(_) => { + Sdi::PopReferenceFrame | + Sdi::PopStackingContext => return, + + Sdi::PopCacheMarker => return, + Sdi::PushCacheMarker(_) => { str_node(&mut v, "type", "cache-marker"); } - PopStackingContext => return, - PopReferenceFrame => return, - SetGradientStops => panic!("dummy item yielded?"), - PushShadow(shadow) => { + Sdi::SetGradientStops => panic!("dummy item yielded?"), + Sdi::PushShadow(shadow) => { str_node(&mut v, "type", "shadow"); vector_node(&mut v, "offset", &shadow.offset); color_node(&mut v, "color", shadow.color); f32_node(&mut v, "blur-radius", shadow.blur_radius); } - PopAllShadows => { + Sdi::PopAllShadows => { str_node(&mut v, "type", "pop-all-shadows"); } } @@ -1247,43 +1246,62 @@ impl webrender::ApiRecordingReceiver for YamlFrameWriterReceiver { } /// This structure allows mapping both `Clip` and `ClipExternalId` -/// `ClipIds` onto one set of numeric ids. This prevents ids -/// from clashing in the yaml output. +/// `ClipIds` onto one set of numeric ids. It also handles `SpatialId` +/// in a separate map. This prevents ids from clashing in the yaml output. struct ClipIdMapper { - hash_map: HashMap<ClipId, usize>, + clip_map: HashMap<ClipId, usize>, + spatial_map: HashMap<SpatialId, usize>, current_clip_id: usize, + current_spatial_id: usize, } impl ClipIdMapper { - fn new() -> ClipIdMapper { + fn new() -> Self { ClipIdMapper { - hash_map: HashMap::new(), - current_clip_id: 2, + clip_map: HashMap::new(), + spatial_map: HashMap::new(), + current_clip_id: 1, // see FIRST_CLIP_NODE_INDEX + current_spatial_id: 2, // see FIRST_SPATIAL_NODE_INDEX } } - fn add_id(&mut self, id: ClipId) -> usize { - self.hash_map.insert(id, self.current_clip_id); + fn add_clip_id(&mut self, id: ClipId) -> usize { + self.clip_map.insert(id, self.current_clip_id); self.current_clip_id += 1; self.current_clip_id - 1 } - fn map_id(&self, id: &ClipId) -> Yaml { + fn add_spatial_id(&mut self, id: SpatialId) -> usize { + self.spatial_map.insert(id, self.current_spatial_id); + self.current_spatial_id += 1; + self.current_spatial_id - 1 + } + + fn map_spatial_id(&self, id: &SpatialId) -> Yaml { if id.is_root_reference_frame() { Yaml::String("root-reference-frame".to_owned()) } else if id.is_root_scroll_node() { Yaml::String("root-scroll-node".to_owned()) } else { - Yaml::Integer(*self.hash_map.get(id).unwrap() as i64) + Yaml::Integer(self.spatial_map[id] as i64) + } + } + + fn map_clip_id(&self, id: &ClipId) -> Yaml { + assert!(id.is_valid()); + if id.is_root() { + Yaml::String("root_clip".to_owned()) + } else { + Yaml::Integer(self.clip_map[id] as i64) } } - fn map_info(&self, info: &ClipAndScrollInfo) -> Yaml { - let scroll_node_yaml = self.map_id(&info.scroll_node_id); - match info.clip_node_id { + fn map_clip_and_scroll_ids(&self, clip_id: Option<ClipId>, spatial_id: SpatialId) -> Yaml { + let scroll_node_yaml = self.map_spatial_id(&spatial_id); + match clip_id { Some(ref clip_node_id) => Yaml::Array(vec![ scroll_node_yaml, - self.map_id(&clip_node_id) + self.map_clip_id(&clip_node_id) ]), None => scroll_node_yaml, }