Bug 1574493 - Part 1. Split out repeating and non-repeating images in the display list. r=jrmuizel

Repeating/background images may have extra parameters such the stretch
size and tile spacing, that non-repeating images do not require. By
splitting these apart, we can make it easier to infer what we should do
if snapping changes the size of an image primitive, in addition to
reducing the display list size for non-repeating images.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrew Osmond 2019-09-12 12:42:37 +00:00
Родитель 7c06e89288
Коммит 7cda552aeb
17 изменённых файлов: 216 добавлений и 120 удалений

Просмотреть файл

@ -1091,14 +1091,15 @@ void DisplayListBuilder::PushImage(
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
bool aIsBackfaceVisible, wr::ImageRendering aFilter, wr::ImageKey aImage,
bool aPremultipliedAlpha, const wr::ColorF& aColor) {
wr::LayoutSize size;
size.width = aBounds.size.width;
size.height = aBounds.size.height;
PushImage(aBounds, aClip, aIsBackfaceVisible, size, size, aFilter, aImage,
wr::LayoutRect clip = MergeClipLeaf(aClip);
WRDL_LOG("PushImage b=%s cl=%s\n", mWrState, Stringify(aBounds).c_str(),
Stringify(clip).c_str());
wr_dp_push_image(mWrState, aBounds, clip, aIsBackfaceVisible,
&mCurrentSpaceAndClipChain, aFilter, aImage,
aPremultipliedAlpha, aColor);
}
void DisplayListBuilder::PushImage(
void DisplayListBuilder::PushRepeatingImage(
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize,
const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter,
@ -1107,9 +1108,9 @@ void DisplayListBuilder::PushImage(
WRDL_LOG("PushImage b=%s cl=%s s=%s t=%s\n", mWrState,
Stringify(aBounds).c_str(), Stringify(clip).c_str(),
Stringify(aStretchSize).c_str(), Stringify(aTileSpacing).c_str());
wr_dp_push_image(mWrState, aBounds, clip, aIsBackfaceVisible,
&mCurrentSpaceAndClipChain, aStretchSize, aTileSpacing,
aFilter, aImage, aPremultipliedAlpha, aColor);
wr_dp_push_repeating_image(
mWrState, aBounds, clip, aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
aStretchSize, aTileSpacing, aFilter, aImage, aPremultipliedAlpha, aColor);
}
void DisplayListBuilder::PushYCbCrPlanarImage(

Просмотреть файл

@ -479,7 +479,8 @@ class DisplayListBuilder final {
wr::ImageKey aImage, bool aPremultipliedAlpha = true,
const wr::ColorF& aColor = wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f});
void PushImage(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
void PushRepeatingImage(
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
bool aIsBackfaceVisible, const wr::LayoutSize& aStretchSize,
const wr::LayoutSize& aTileSpacing, wr::ImageRendering aFilter,
wr::ImageKey aImage, bool aPremultipliedAlpha = true,

Просмотреть файл

@ -2566,6 +2566,44 @@ pub extern "C" fn wr_dp_push_clear_rect_with_parent_clip(
#[no_mangle]
pub extern "C" fn wr_dp_push_image(state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_rendering: ImageRendering,
key: WrImageKey,
premultiplied_alpha: bool,
color: ColorF) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
let space_and_clip = parent.to_webrender(state.pipeline_id);
let prim_info = CommonItemProperties {
clip_rect: clip,
clip_id: space_and_clip.clip_id,
spatial_id: space_and_clip.spatial_id,
is_backface_visible,
hit_info: state.current_tag,
};
let alpha_type = if premultiplied_alpha {
AlphaType::PremultipliedAlpha
} else {
AlphaType::Alpha
};
state.frame_builder
.dl_builder
.push_image(&prim_info,
bounds,
image_rendering,
alpha_type,
key,
color);
}
#[no_mangle]
pub extern "C" fn wr_dp_push_repeating_image(state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
@ -2596,7 +2634,7 @@ pub extern "C" fn wr_dp_push_image(state: &mut WrState,
state.frame_builder
.dl_builder
.push_image(&prim_info,
.push_repeating_image(&prim_info,
bounds,
stretch_size,
tile_spacing,

Просмотреть файл

@ -236,8 +236,6 @@ impl Example for App {
builder.push_image(
&CommonItemProperties::new(bounds, space_and_clip),
bounds,
LayoutSize::new(500.0, 500.0),
LayoutSize::new(0.0, 0.0),
api::ImageRendering::Auto,
api::AlphaType::PremultipliedAlpha,
blob_img1.as_image(),
@ -248,8 +246,6 @@ impl Example for App {
builder.push_image(
&CommonItemProperties::new(bounds, space_and_clip),
bounds,
LayoutSize::new(200.0, 200.0),
LayoutSize::new(0.0, 0.0),
api::ImageRendering::Auto,
api::AlphaType::PremultipliedAlpha,
blob_img2.as_image(),

Просмотреть файл

@ -170,8 +170,6 @@ impl Example for App {
builder.push_image(
&CommonItemProperties::new(bounds, space_and_clip),
bounds,
bounds.size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
self.external_image_key.unwrap(),

Просмотреть файл

@ -55,8 +55,6 @@ impl Example for App {
space_and_clip,
),
bounds,
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
self.image_key,
@ -69,8 +67,6 @@ impl Example for App {
space_and_clip,
),
bounds,
image_size,
LayoutSize::zero(),
ImageRendering::Pixelated,
AlphaType::PremultipliedAlpha,
self.image_key,

Просмотреть файл

@ -147,8 +147,6 @@ impl Example for App {
builder.push_image(
&info,
bounds,
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
*key,
@ -165,8 +163,6 @@ impl Example for App {
builder.push_image(
&info,
bounds,
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
image_key,
@ -183,8 +179,6 @@ impl Example for App {
builder.push_image(
&info,
bounds,
image_size,
LayoutSize::zero(),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
swap_key,

Просмотреть файл

@ -1098,6 +1098,25 @@ impl<'a> DisplayListFlattener<'a> {
apply_pipeline_clip,
);
self.add_image(
clip_and_scroll,
&layout,
layout.rect.size,
LayoutSize::zero(),
None,
info.image_key,
info.image_rendering,
info.alpha_type,
info.color,
);
}
DisplayItem::RepeatingImage(ref info) => {
let (layout, clip_and_scroll) = self.process_common_properties_with_bounds(
&info.common,
&info.bounds,
apply_pipeline_clip,
);
self.add_image(
clip_and_scroll,
&layout,

Просмотреть файл

@ -104,6 +104,7 @@ pub enum DisplayItem {
Gradient(GradientDisplayItem),
RadialGradient(RadialGradientDisplayItem),
Image(ImageDisplayItem),
RepeatingImage(RepeatingImageDisplayItem),
YuvImage(YuvImageDisplayItem),
BackdropFilter(BackdropFilterDisplayItem),
@ -148,6 +149,7 @@ pub enum DebugDisplayItem {
Gradient(GradientDisplayItem),
RadialGradient(RadialGradientDisplayItem),
Image(ImageDisplayItem),
RepeatingImage(RepeatingImageDisplayItem),
YuvImage(YuvImageDisplayItem),
BackdropFilter(BackdropFilterDisplayItem),
@ -1071,10 +1073,28 @@ pub struct IframeDisplayItem {
pub ignore_missing_pipeline: bool,
}
/// This describes an image or, more generally, a background-image and its tiling.
/// (A background-image repeats in a grid to fill the specified area).
/// This describes an image that fills the specified area. It stretches or shrinks
/// the image as necessary. While RepeatingImageDisplayItem could otherwise provide
/// a superset of the functionality, it has been problematic inferring the desired
/// repetition properties when snapping changes the size of the primitive.
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct ImageDisplayItem {
pub common: CommonItemProperties,
/// The area to tile the image over (first tile starts at origin of this rect)
// FIXME: this should ideally just be `tile_origin` here, with the clip_rect
// defining the bounds of the item. Needs non-trivial backend changes.
pub bounds: LayoutRect,
pub image_key: ImageKey,
pub image_rendering: ImageRendering,
pub alpha_type: AlphaType,
/// A hack used by gecko to color a simple bitmap font used for tofu glyphs
pub color: ColorF,
}
/// This describes a background-image and its tiling. It repeats in a grid to fill
/// the specified area.
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct RepeatingImageDisplayItem {
pub common: CommonItemProperties,
/// The area to tile the image over (first tile starts at origin of this rect)
// FIXME: this should ideally just be `tile_origin` here, with the clip_rect
@ -1406,6 +1426,7 @@ impl DisplayItem {
DisplayItem::Gradient(..) => "gradient",
DisplayItem::Iframe(..) => "iframe",
DisplayItem::Image(..) => "image",
DisplayItem::RepeatingImage(..) => "repeating_image",
DisplayItem::Line(..) => "line",
DisplayItem::PopAllShadows => "pop_all_shadows",
DisplayItem::PopReferenceFrame => "pop_reference_frame",

Просмотреть файл

@ -623,6 +623,7 @@ impl Serialize for BuiltDisplayList {
Real::HitTest(v) => Debug::HitTest(v),
Real::Line(v) => Debug::Line(v),
Real::Image(v) => Debug::Image(v),
Real::RepeatingImage(v) => Debug::RepeatingImage(v),
Real::YuvImage(v) => Debug::YuvImage(v),
Real::Border(v) => Debug::Border(v),
Real::BoxShadow(v) => Debug::BoxShadow(v),
@ -727,6 +728,7 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
Debug::HitTest(v) => Real::HitTest(v),
Debug::Line(v) => Real::Line(v),
Debug::Image(v) => Real::Image(v),
Debug::RepeatingImage(v) => Real::RepeatingImage(v),
Debug::YuvImage(v) => Real::YuvImage(v),
Debug::Border(v) => Real::Border(v),
Debug::BoxShadow(v) => Real::BoxShadow(v),
@ -1001,6 +1003,27 @@ impl DisplayListBuilder {
}
pub fn push_image(
&mut self,
common: &di::CommonItemProperties,
bounds: LayoutRect,
image_rendering: di::ImageRendering,
alpha_type: di::AlphaType,
key: ImageKey,
color: ColorF,
) {
let item = di::DisplayItem::Image(di::ImageDisplayItem {
common: *common,
bounds,
image_key: key,
image_rendering,
alpha_type,
color,
});
self.push_item(&item);
}
pub fn push_repeating_image(
&mut self,
common: &di::CommonItemProperties,
bounds: LayoutRect,
@ -1011,7 +1034,7 @@ impl DisplayListBuilder {
key: ImageKey,
color: ColorF,
) {
let item = di::DisplayItem::Image(di::ImageDisplayItem {
let item = di::DisplayItem::RepeatingImage(di::RepeatingImageDisplayItem {
common: *common,
bounds,
image_key: key,

Просмотреть файл

@ -21,3 +21,4 @@ pipelines:
bounds: [1075, -1, 12, 199]
"clip-rect": [1075, -1, 12, 199]
image: checkerboard(4, 8, 8)
stretch-size: 72 72

Просмотреть файл

@ -15,3 +15,4 @@ root:
-
bounds: [350, 200, 260, 300]
image: checkerboard(2, 16, 16)
stretch-size: 260 260

Просмотреть файл

@ -163,8 +163,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(64.0, 64.0),
size2(64.0, 64.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
img,
@ -192,8 +190,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(1024.0, 1024.0),
size2(1024.0, 1024.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
img,
@ -218,8 +214,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(1024.0, 1024.0),
size2(1024.0, 1024.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
img,
@ -255,7 +249,7 @@ impl<'a> RawtestHarness<'a> {
let info = self.make_common_properties(rect(448.899994, 74.0, 151.000031, 56.));
// setup some malicious image size parameters
builder.push_image(
builder.push_repeating_image(
&info,
info.clip_rect,
size2(151., 56.0),
@ -335,7 +329,7 @@ impl<'a> RawtestHarness<'a> {
};
// setup some malicious image size parameters
builder.push_image(
builder.push_repeating_image(
&info,
info.clip_rect,
image_size * 2.,
@ -440,7 +434,7 @@ impl<'a> RawtestHarness<'a> {
Some(100),
);
builder.push_image(
builder.push_repeating_image(
&info,
info.clip_rect,
image_size,
@ -477,7 +471,7 @@ impl<'a> RawtestHarness<'a> {
Some(100),
);
builder.push_image(
builder.push_repeating_image(
&info,
info.clip_rect,
image_size,
@ -532,7 +526,7 @@ impl<'a> RawtestHarness<'a> {
let image_size = size2(1510., 1510.);
// setup some malicious image size parameters
builder.push_image(
builder.push_repeating_image(
&info,
info.clip_rect,
image_size,
@ -558,7 +552,7 @@ impl<'a> RawtestHarness<'a> {
let image_size = size2(1510., 1510.);
// setup some malicious image size parameters
builder.push_image(
builder.push_repeating_image(
&info,
info.clip_rect,
image_size,
@ -590,7 +584,7 @@ impl<'a> RawtestHarness<'a> {
let image_size = size2(1510., 1510.);
// setup some malicious image size parameters
builder.push_image(
builder.push_repeating_image(
&info,
info.clip_rect,
image_size,
@ -656,8 +650,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(200.0, 200.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img.as_image(),
@ -680,8 +672,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(200.0, 200.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img.as_image(),
@ -767,8 +757,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(200.0, 200.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img.as_image(),
@ -777,8 +765,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info2,
info2.clip_rect,
size2(200.0, 200.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img2.as_image(),
@ -870,8 +856,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(200.0, 200.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img.as_image(),
@ -899,8 +883,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(200.0, 200.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img.as_image(),
@ -926,8 +908,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(200.0, 200.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img.as_image(),
@ -1126,8 +1106,6 @@ impl<'a> RawtestHarness<'a> {
builder.push_image(
&info,
info.clip_rect,
size2(150.0, 50.0),
size2(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
image,

Просмотреть файл

@ -1374,10 +1374,6 @@ impl YamlFrameReader {
item["bounds"]
);
};
let stretch_size = item["stretch-size"].as_size().unwrap_or(image_dims);
let tile_spacing = item["tile-spacing"]
.as_size()
.unwrap_or(LayoutSize::new(0.0, 0.0));
let rendering = match item["rendering"].as_str() {
Some("auto") | None => ImageRendering::Auto,
Some("crisp-edges") => ImageRendering::CrispEdges,
@ -1395,16 +1391,29 @@ impl YamlFrameReader {
item
),
};
let stretch_size = item["stretch-size"].as_size();
let tile_spacing = item["tile-spacing"].as_size();
if stretch_size.is_none() && tile_spacing.is_none() {
dl.push_image(
&info,
bounds,
stretch_size,
tile_spacing,
rendering,
alpha_type,
image_key,
ColorF::WHITE,
);
} else {
dl.push_repeating_image(
&info,
bounds,
stretch_size.unwrap_or(image_dims),
tile_spacing.unwrap_or(LayoutSize::zero()),
rendering,
alpha_type,
image_key,
ColorF::WHITE,
);
}
}
fn handle_text(

Просмотреть файл

@ -1053,6 +1053,29 @@ impl YamlFrameWriter {
}
}
DisplayItem::Image(item) => {
common_node(&mut v, clip_id_mapper, &item.common);
rect_node(&mut v, "bounds", &item.bounds);
if let Some(path) = self.path_for_image(item.image_key) {
path_node(&mut v, "image", &path);
}
if let Some(&CachedImage {
tiling: Some(tile_size),
..
}) = self.images.get(&item.image_key)
{
u32_node(&mut v, "tile-size", tile_size as u32);
}
match item.image_rendering {
ImageRendering::Auto => (),
ImageRendering::CrispEdges => str_node(&mut v, "rendering", "crisp-edges"),
ImageRendering::Pixelated => str_node(&mut v, "rendering", "pixelated"),
};
match item.alpha_type {
AlphaType::PremultipliedAlpha => str_node(&mut v, "alpha-type", "premultiplied-alpha"),
AlphaType::Alpha => str_node(&mut v, "alpha-type", "alpha"),
};
}
DisplayItem::RepeatingImage(item) => {
common_node(&mut v, clip_id_mapper, &item.common);
rect_node(&mut v, "bounds", &item.bounds);
if let Some(path) = self.path_for_image(item.image_key) {

Просмотреть файл

@ -630,25 +630,26 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
break;
}
wr::LayoutRect roundedDest = wr::ToLayoutRect(destRect);
wr::LayoutRect clip = wr::ToRoundedLayoutRect(
LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel));
if (mExtendMode == ExtendMode::CLAMP) {
// The image is not repeating. Just push as a regular image.
aBuilder.PushImage(roundedDest, clip, !aItem->BackfaceIsHidden(),
rendering, key.value());
} else {
nsPoint firstTilePos = nsLayoutUtils::GetBackgroundFirstTilePos(
aDest.TopLeft(), aFill.TopLeft(), aRepeatSize);
LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(
nsRect(firstTilePos.x, firstTilePos.y, aFill.XMost() - firstTilePos.x,
nsRect(firstTilePos.x, firstTilePos.y,
aFill.XMost() - firstTilePos.x,
aFill.YMost() - firstTilePos.y),
appUnitsPerDevPixel);
wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
wr::LayoutRect roundedDest = wr::ToLayoutRect(destRect);
// WebRender special cases situations where stretchSize == fillSize to
// infer that it shouldn't use repeat sampling. This makes sure
// we hit those special cases when not repeating.
switch (mExtendMode) {
case ExtendMode::CLAMP:
fill = roundedDest;
stretchSize = roundedDest.size;
break;
case ExtendMode::REPEAT_Y:
fill.origin.x = roundedDest.origin.x;
fill.size.width = roundedDest.size.width;
@ -663,14 +664,13 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
break;
}
wr::LayoutRect clip = wr::ToRoundedLayoutRect(
LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel));
LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits(
aRepeatSize - aDest.Size(), appUnitsPerDevPixel);
aBuilder.PushImage(fill, clip, !aItem->BackfaceIsHidden(), stretchSize,
wr::ToLayoutSize(gapSize), rendering, key.value());
aBuilder.PushRepeatingImage(fill, clip, !aItem->BackfaceIsHidden(),
stretchSize, wr::ToLayoutSize(gapSize),
rendering, key.value());
}
break;
}
default:

Просмотреть файл

@ -442,12 +442,9 @@ ImgDrawResult nsImageBoxFrame::CreateWebRenderCommands(
if (key.isNothing()) {
return result;
}
wr::LayoutRect fill = wr::ToLayoutRect(fillRect);
LayoutDeviceSize gapSize(0, 0);
aBuilder.PushImage(fill, fill, !BackfaceIsHidden(),
wr::ToLayoutSize(fillRect.Size()),
wr::ToLayoutSize(gapSize), rendering, key.value());
wr::LayoutRect fill = wr::ToLayoutRect(fillRect);
aBuilder.PushImage(fill, fill, !BackfaceIsHidden(), rendering, key.value());
return result;
}