Bug 1518605 - Update webrender to commit e16ab884672151fbdebc149479f9bfdecd1da216 (WR PR #3251). r=kats

https://github.com/servo/webrender/pull/3251

Differential Revision: https://phabricator.services.mozilla.com/D16005

--HG--
extra : moz-landing-system : lando
This commit is contained in:
WR Updater Bot 2019-01-09 03:27:04 +00:00
parent 271033048d
commit 44eff8f1b7
29 changed files with 900 additions and 775 deletions

View File

@ -1 +1 @@
9019124fdccab50096ef5af76d1acbd251c1ad07
e16ab884672151fbdebc149479f9bfdecd1da216

View File

@ -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);
let clip_id = builder.define_clip(
&api::SpaceAndClipInfo::root_scroll(pipeline_id),
rect,
vec![region],
None,
);
builder.push_rect(&api::PrimitiveInfo::new(rect), self.color);
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(

View File

@ -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();

View File

@ -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 {

View File

@ -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,

View File

@ -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,

View File

@ -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();

View File

@ -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,

View File

@ -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();
}
}

View File

@ -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,

View File

@ -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),

View File

@ -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.push_rect(&info, &space_and_clip2, ColorF::new(0.0, 1.0, 1.0, 1.0));
builder.pop_clip_id(); // nested_clip_id
builder.pop_clip_id(); // clip_id
builder.pop_stacking_context();
}

View File

@ -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,

View File

@ -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,

View File

@ -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.

View File

@ -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,

View File

@ -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);

View File

@ -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() {

View File

@ -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"),

View File

@ -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>
@ -647,7 +644,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,
}
@ -857,48 +853,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

View File

@ -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,

View File

@ -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]

View File

@ -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:

View File

@ -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]

View File

@ -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: []

View File

@ -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:])

View File

@ -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();

View File

@ -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.u64_to_clip_id(value as u64, pipeline_id)),
Yaml::String(ref id_string) if id_string == "root-reference-frame" =>
Some(ClipId::root_reference_frame(pipeline_id)),
Yaml::String(ref id_string) if id_string == "root-scroll-node" =>
Some(ClipId::root_scroll_node(pipeline_id)),
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_spatial_id(&self, item: &Yaml, pipeline_id: PipelineId) -> SpatialId {
match *item {
Yaml::Integer(value) => self.user_spatial_id_map[&(value as u64)],
Yaml::String(ref id_string) if id_string == "root-reference-frame" =>
SpatialId::root_reference_frame(pipeline_id),
Yaml::String(ref id_string) if id_string == "root-scroll-node" =>
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();
}
}

View File

@ -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,6 +1041,18 @@ impl YamlFrameWriter {
&item.stacking_context,
&scene.properties,
filters,
);
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);
}
Sdi::PushReferenceFrame(item) => {
str_node(&mut v, "type", "reference-frame");
write_reference_frame(
&mut v,
&item.reference_frame,
&scene.properties,
clip_id_mapper,
);
@ -1049,22 +1060,9 @@ impl YamlFrameWriter {
self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper);
continue_traversal = Some(sub_iter);
}
PushReferenceFrame(item) => {
str_node(&mut v, "type", "reference-frame");
write_reference_frame(
&mut v,
&item.reference_frame,
&scene.properties,
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_info(&self, info: &ClipAndScrollInfo) -> Yaml {
let scroll_node_yaml = self.map_id(&info.scroll_node_id);
match info.clip_node_id {
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_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,
}