Commit 0156c949 authored by Denis Bessonov's avatar Denis Bessonov Committed by Commit Bot

Fix 0,0-0x0 turning into PaintOp::kUnsetRect.

When a paint chunk having 0,0-0x0 rect is processed inside an effect, an early
return prevents the effect_bounds_stack_.back() update in a
ConversionContext::UpdateEffectBounds call. This results in keeping default
PaintOp::kUnsetRect in SaveLayerOp::bounds instead of 0,0-0x0 rect.

This is probably a reason for a related bug 918240 (see bug thread Comment 4 for
details). Application of this patch fixes the lagging print preview.

R=fmalita@chromium.org, samans@chromium.org

Bug: 918240
Change-Id: I022ae01418e83184421cff7e22566228a2f7c6d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1396958
Commit-Queue: Denis Bessonov <dbessonov@yandex-team.ru>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#714293}
parent 68c978df
...@@ -90,6 +90,8 @@ class CC_PAINT_EXPORT DisplayItemList ...@@ -90,6 +90,8 @@ class CC_PAINT_EXPORT DisplayItemList
return offset; return offset;
} }
UsageHint GetUsageHint() const { return usage_hint_; }
// Called by blink::PaintChunksToCcLayer when an effect ends, to update the // Called by blink::PaintChunksToCcLayer when an effect ends, to update the
// bounds of a SaveLayer[Alpha]Op which was emitted when the effect started. // bounds of a SaveLayer[Alpha]Op which was emitted when the effect started.
// This is needed because blink doesn't know the bounds when an effect starts. // This is needed because blink doesn't know the bounds when an effect starts.
......
...@@ -172,7 +172,8 @@ class ConversionContext { ...@@ -172,7 +172,8 @@ class ConversionContext {
// Ends the effect on the top of the state stack if the stack is not empty, // Ends the effect on the top of the state stack if the stack is not empty,
// and update the bounds of the SaveLayer[Alpha]Op of the effect. // and update the bounds of the SaveLayer[Alpha]Op of the effect.
void EndEffect(); void EndEffect();
void UpdateEffectBounds(const FloatRect&, const TransformPaintPropertyNode&); void UpdateEffectBounds(const base::Optional<FloatRect>&,
const TransformPaintPropertyNode&);
// Starts a clip state by adjusting the transform state, applying // Starts a clip state by adjusting the transform state, applying
// |combined_clip_rect| which is combined from one or more consecutive clips, // |combined_clip_rect| which is combined from one or more consecutive clips,
...@@ -243,7 +244,7 @@ class ConversionContext { ...@@ -243,7 +244,7 @@ class ConversionContext {
// Records the bounds of the effect which initiated the entry. Note that // Records the bounds of the effect which initiated the entry. Note that
// the effect is not |this->effect| (which is the previous effect), but the // the effect is not |this->effect| (which is the previous effect), but the
// |current_effect_| when this entry is the top of the stack. // |current_effect_| when this entry is the top of the stack.
FloatRect bounds; base::Optional<FloatRect> bounds;
}; };
Vector<EffectBoundsInfo> effect_bounds_stack_; Vector<EffectBoundsInfo> effect_bounds_stack_;
...@@ -589,22 +590,25 @@ void ConversionContext::StartEffect(const EffectPaintPropertyNode& effect) { ...@@ -589,22 +590,25 @@ void ConversionContext::StartEffect(const EffectPaintPropertyNode& effect) {
const ClipPaintPropertyNode* input_clip = current_clip_; const ClipPaintPropertyNode* input_clip = current_clip_;
PushState(StateEntry::kEffect, saved_count); PushState(StateEntry::kEffect, saved_count);
effect_bounds_stack_.emplace_back( effect_bounds_stack_.emplace_back(
EffectBoundsInfo{save_layer_id, current_transform_}); EffectBoundsInfo{save_layer_id, current_transform_, base::nullopt});
current_clip_ = input_clip; current_clip_ = input_clip;
current_effect_ = &effect; current_effect_ = &effect;
} }
void ConversionContext::UpdateEffectBounds( void ConversionContext::UpdateEffectBounds(
const FloatRect& bounds, const base::Optional<FloatRect>& bounds,
const TransformPaintPropertyNode& transform) { const TransformPaintPropertyNode& transform) {
if (effect_bounds_stack_.IsEmpty() || bounds.IsEmpty()) if (effect_bounds_stack_.IsEmpty() || !bounds)
return; return;
auto& effect_bounds_info = effect_bounds_stack_.back(); auto& effect_bounds_info = effect_bounds_stack_.back();
FloatRect mapped_bounds = bounds; FloatRect mapped_bounds = *bounds;
GeometryMapper::SourceToDestinationRect( GeometryMapper::SourceToDestinationRect(
transform, *effect_bounds_info.transform, mapped_bounds); transform, *effect_bounds_info.transform, mapped_bounds);
effect_bounds_info.bounds.Unite(mapped_bounds); if (effect_bounds_info.bounds)
effect_bounds_info.bounds->Unite(mapped_bounds);
else
effect_bounds_info.bounds = mapped_bounds;
} }
void ConversionContext::EndEffect() { void ConversionContext::EndEffect() {
...@@ -618,20 +622,20 @@ void ConversionContext::EndEffect() { ...@@ -618,20 +622,20 @@ void ConversionContext::EndEffect() {
DCHECK(effect_bounds_stack_.size()); DCHECK(effect_bounds_stack_.size());
const auto& bounds_info = effect_bounds_stack_.back(); const auto& bounds_info = effect_bounds_stack_.back();
FloatRect bounds = bounds_info.bounds; base::Optional<FloatRect> bounds = bounds_info.bounds;
if (!bounds.IsEmpty()) { if (bounds) {
if (current_effect_->Filter().IsEmpty()) { if (current_effect_->Filter().IsEmpty()) {
cc_list_.UpdateSaveLayerBounds(bounds_info.save_layer_id, bounds); cc_list_.UpdateSaveLayerBounds(bounds_info.save_layer_id, *bounds);
} else { } else {
// The bounds for the SaveLayer[Alpha]Op should be the source bounds // The bounds for the SaveLayer[Alpha]Op should be the source bounds
// before the filter is applied, in the space of the TranslateOp which was // before the filter is applied, in the space of the TranslateOp which was
// emitted before the SaveLayer[Alpha]Op. // emitted before the SaveLayer[Alpha]Op.
auto save_layer_bounds = bounds; auto save_layer_bounds = *bounds;
save_layer_bounds.MoveBy(-current_effect_->FiltersOrigin()); save_layer_bounds.MoveBy(-current_effect_->FiltersOrigin());
cc_list_.UpdateSaveLayerBounds(bounds_info.save_layer_id, cc_list_.UpdateSaveLayerBounds(bounds_info.save_layer_id,
save_layer_bounds); save_layer_bounds);
// We need to propagate the filtered bounds to the parent. // We need to propagate the filtered bounds to the parent.
bounds = current_effect_->MapRect(bounds); bounds = current_effect_->MapRect(*bounds);
} }
} }
...@@ -750,7 +754,17 @@ void ConversionContext::Convert(const PaintChunkSubset& paint_chunks, ...@@ -750,7 +754,17 @@ void ConversionContext::Convert(const PaintChunkSubset& paint_chunks,
cc_list_.EndPaintOfUnpaired( cc_list_.EndPaintOfUnpaired(
chunk_to_layer_mapper_.MapVisualRect(item.VisualRect())); chunk_to_layer_mapper_.MapVisualRect(item.VisualRect()));
} }
UpdateEffectBounds(FloatRect(chunk.bounds), chunk_state.Transform());
// Chunk bounds are only important when we are actually drawing. There may
// also be cases when we only generate a paint record and do not draw,
// for example, to implement an SVG clip. In such cases, we can safely
// ignore effect bounds.
base::Optional<FloatRect> chunk_bounds;
if (cc_list_.GetUsageHint() ==
cc::DisplayItemList::kTopLevelDisplayItemList) {
chunk_bounds = FloatRect(chunk.bounds);
}
UpdateEffectBounds(chunk_bounds, chunk_state.Transform());
} }
} }
......
...@@ -101,7 +101,7 @@ class PaintRecordMatcher ...@@ -101,7 +101,7 @@ class PaintRecordMatcher
Vector<cc::PaintOpType> expected_ops_; Vector<cc::PaintOpType> expected_ops_;
}; };
#define EXPECT_EFFECT_BOUNDS(x, y, width, height, op_buffer, index) \ #define EXPECT_EFFECT_BOUNDS(rect, op_buffer, index) \
do { \ do { \
FloatRect bounds; \ FloatRect bounds; \
if (const auto* save_layer_alpha = \ if (const auto* save_layer_alpha = \
...@@ -113,7 +113,7 @@ class PaintRecordMatcher ...@@ -113,7 +113,7 @@ class PaintRecordMatcher
} else { \ } else { \
FAIL() << "No SaveLayer[Alpha]Op at " << index; \ FAIL() << "No SaveLayer[Alpha]Op at " << index; \
} \ } \
EXPECT_EQ(FloatRect(x, y, width, height), bounds); \ EXPECT_EQ(rect, bounds); \
} while (false) } while (false)
#define EXPECT_TRANSFORM_MATRIX(transform, op_buffer, index) \ #define EXPECT_TRANSFORM_MATRIX(transform, op_buffer, index) \
...@@ -183,6 +183,10 @@ struct TestChunks { ...@@ -183,6 +183,10 @@ struct TestChunks {
} }
}; };
const cc::DisplayItemList::UsageHint kUsageHints[] = {
cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer,
cc::DisplayItemList::kTopLevelDisplayItemList};
TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) { TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) {
// This test verifies effects are applied as a group. // This test verifies effects are applied as a group.
auto e1 = CreateOpacityEffect(e0(), 0.5f); auto e1 = CreateOpacityEffect(e0(), 0.5f);
...@@ -190,18 +194,23 @@ TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) { ...@@ -190,18 +194,23 @@ TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) {
chunks.AddChunk(t0(), c0(), *e1, IntRect(0, 0, 50, 50)); chunks.AddChunk(t0(), c0(), *e1, IntRect(0, 0, 50, 50));
chunks.AddChunk(t0(), c0(), *e1, IntRect(20, 20, 70, 70)); chunks.AddChunk(t0(), c0(), *e1, IntRect(20, 20, 70, 70));
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 90, 90)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
->ReleaseAsRecord(); sk_sp<PaintRecord> output =
EXPECT_THAT( PaintChunksToCcLayer::Convert(chunks.chunks, PropertyTreeState::Root(),
*output, gfx::Vector2dF(), chunks.items,
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1> kUsageHints[hint])
cc::PaintOpType::DrawRecord, // <p0/> ->ReleaseAsRecord();
cc::PaintOpType::DrawRecord, // <p1/> EXPECT_THAT(
cc::PaintOpType::Restore})); // </e1> *output,
EXPECT_EFFECT_BOUNDS(0, 0, 90, 90, *output, 0); PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1>
cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::DrawRecord, // <p1/>
cc::PaintOpType::Restore})); // </e1>
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 0);
}
} }
TEST_P(PaintChunksToCcLayerTest, EffectGroupingNested) { TEST_P(PaintChunksToCcLayerTest, EffectGroupingNested) {
...@@ -213,24 +222,33 @@ TEST_P(PaintChunksToCcLayerTest, EffectGroupingNested) { ...@@ -213,24 +222,33 @@ TEST_P(PaintChunksToCcLayerTest, EffectGroupingNested) {
chunks.AddChunk(t0(), c0(), *e2); chunks.AddChunk(t0(), c0(), *e2);
chunks.AddChunk(t0(), c0(), *e3, IntRect(111, 222, 333, 444)); chunks.AddChunk(t0(), c0(), *e3, IntRect(111, 222, 333, 444));
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds1[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 444, 666)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(), const FloatRect kExpectedBounds2[] = {FloatRect(cc::PaintOp::kUnsetRect),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) FloatRect(0, 0, 100, 100)};
->ReleaseAsRecord(); const FloatRect kExpectedBounds3[] = {FloatRect(cc::PaintOp::kUnsetRect),
EXPECT_THAT( FloatRect(111, 222, 333, 444)};
*output,
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1> for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
cc::PaintOpType::SaveLayerAlpha, // <e2> sk_sp<PaintRecord> output =
cc::PaintOpType::DrawRecord, // <p0/> PaintChunksToCcLayer::Convert(chunks.chunks, PropertyTreeState::Root(),
cc::PaintOpType::Restore, // </e2> gfx::Vector2dF(), chunks.items,
cc::PaintOpType::SaveLayerAlpha, // <e3> kUsageHints[hint])
cc::PaintOpType::DrawRecord, // <p1/> ->ReleaseAsRecord();
cc::PaintOpType::Restore, // </e3> EXPECT_THAT(
cc::PaintOpType::Restore})); // </e1> *output,
EXPECT_EFFECT_BOUNDS(0, 0, 444, 666, *output, 0); PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1>
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 1); cc::PaintOpType::SaveLayerAlpha, // <e2>
EXPECT_EFFECT_BOUNDS(111, 222, 333, 444, *output, 4); cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::Restore, // </e2>
cc::PaintOpType::SaveLayerAlpha, // <e3>
cc::PaintOpType::DrawRecord, // <p1/>
cc::PaintOpType::Restore, // </e3>
cc::PaintOpType::Restore})); // </e1>
EXPECT_EFFECT_BOUNDS(kExpectedBounds1[hint], *output, 0);
EXPECT_EFFECT_BOUNDS(kExpectedBounds2[hint], *output, 1);
EXPECT_EFFECT_BOUNDS(kExpectedBounds3[hint], *output, 4);
}
} }
TEST_P(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) { TEST_P(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) {
...@@ -246,40 +264,47 @@ TEST_P(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) { ...@@ -246,40 +264,47 @@ TEST_P(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) {
chunks.AddChunk(*t2, c0(), *e1, IntRect(0, 0, 50, 50)); chunks.AddChunk(*t2, c0(), *e1, IntRect(0, 0, 50, 50));
chunks.AddChunk(*t1, c0(), *e2, IntRect(20, 20, 70, 70)); chunks.AddChunk(*t1, c0(), *e2, IntRect(20, 20, 70, 70));
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds1[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 155, 155)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(), const FloatRect kExpectedBounds2[] = {FloatRect(cc::PaintOp::kUnsetRect),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) FloatRect(10, 10, 70, 70)};
->ReleaseAsRecord();
EXPECT_THAT( for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
*output, sk_sp<PaintRecord> output =
PaintRecordMatcher::Make( PaintChunksToCcLayer::Convert(chunks.chunks, PropertyTreeState::Root(),
{cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1*t2> gfx::Vector2dF(), chunks.items,
cc::PaintOpType::SaveLayerAlpha, // <e1> kUsageHints[hint])
cc::PaintOpType::DrawRecord, // <p1/> ->ReleaseAsRecord();
cc::PaintOpType::Save, cc::PaintOpType::Translate, // <e2_offset> EXPECT_THAT(
cc::PaintOpType::SaveLayer, // <e2> *output,
cc::PaintOpType::Translate, // <e2_offset^-1/> PaintRecordMatcher::Make(
cc::PaintOpType::Save, cc::PaintOpType::Translate, // <t2^-1> {cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1*t2>
cc::PaintOpType::DrawRecord, // <p2/> cc::PaintOpType::SaveLayerAlpha, // <e1>
cc::PaintOpType::Restore, // </t2^-1> cc::PaintOpType::DrawRecord, // <p1/>
cc::PaintOpType::Restore, // </e2> cc::PaintOpType::Save, cc::PaintOpType::Translate, // <e2_offset>
cc::PaintOpType::Restore, // </e2_offset> cc::PaintOpType::SaveLayer, // <e2>
cc::PaintOpType::Restore, // </e1> cc::PaintOpType::Translate, // <e2_offset^-1/>
cc::PaintOpType::Restore})); // </t1*t2> cc::PaintOpType::Save, cc::PaintOpType::Translate, // <t2^-1>
EXPECT_TRANSFORM_MATRIX(t1->Matrix() * t2->SlowMatrix(), *output, 1); cc::PaintOpType::DrawRecord, // <p2/>
// chunk1.bounds + e2(t2^-1(chunk2.bounds)) cc::PaintOpType::Restore, // </t2^-1>
EXPECT_EFFECT_BOUNDS(0, 0, 155, 155, *output, 2); cc::PaintOpType::Restore, // </e2>
// e2_offset cc::PaintOpType::Restore, // </e2_offset>
EXPECT_TRANSLATE(60, 60, *output, 5); cc::PaintOpType::Restore, // </e1>
// t2^-1(chunk2.bounds) - e2_offset cc::PaintOpType::Restore})); // </t1*t2>
EXPECT_EFFECT_BOUNDS(10, 10, 70, 70, *output, 6); EXPECT_TRANSFORM_MATRIX(t1->Matrix() * t2->SlowMatrix(), *output, 1);
// -e2_offset // chunk1.bounds + e2(t2^-1(chunk2.bounds))
EXPECT_TRANSLATE(-e2->FiltersOrigin().X(), -e2->FiltersOrigin().Y(), *output, EXPECT_EFFECT_BOUNDS(kExpectedBounds1[hint], *output, 2);
7); // e2_offset
// t2^1 EXPECT_TRANSLATE(60, 60, *output, 5);
EXPECT_TRANSLATE(-t2->Translation2D().Width(), -t2->Translation2D().Height(), // t2^-1(chunk2.bounds) - e2_offset
*output, 9); EXPECT_EFFECT_BOUNDS(kExpectedBounds2[hint], *output, 6);
// -e2_offset
EXPECT_TRANSLATE(-e2->FiltersOrigin().X(), -e2->FiltersOrigin().Y(),
*output, 7);
// t2^1
EXPECT_TRANSLATE(-t2->Translation2D().Width(),
-t2->Translation2D().Height(), *output, 9);
}
} }
TEST_P(PaintChunksToCcLayerTest, InterleavedClipEffect) { TEST_P(PaintChunksToCcLayerTest, InterleavedClipEffect) {
...@@ -301,38 +326,45 @@ TEST_P(PaintChunksToCcLayerTest, InterleavedClipEffect) { ...@@ -301,38 +326,45 @@ TEST_P(PaintChunksToCcLayerTest, InterleavedClipEffect) {
chunks.AddChunk(t0(), *c3, *e1, IntRect(20, 20, 70, 70)); chunks.AddChunk(t0(), *c3, *e1, IntRect(20, 20, 70, 70));
chunks.AddChunk(t0(), *c4, e0()); chunks.AddChunk(t0(), *c4, e0());
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds1[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 90, 90)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(), const FloatRect kExpectedBounds2[] = {FloatRect(cc::PaintOp::kUnsetRect),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) FloatRect(0, 0, 50, 50)};
->ReleaseAsRecord();
EXPECT_THAT(*output, PaintRecordMatcher::Make( for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
{cc::PaintOpType::Save, sk_sp<PaintRecord> output =
cc::PaintOpType::ClipRect, // <c1+c2> PaintChunksToCcLayer::Convert(chunks.chunks, PropertyTreeState::Root(),
cc::PaintOpType::DrawRecord, // <p0/> gfx::Vector2dF(), chunks.items,
cc::PaintOpType::Save, kUsageHints[hint])
cc::PaintOpType::ClipRect, // <c3> ->ReleaseAsRecord();
cc::PaintOpType::DrawRecord, // <p1/> EXPECT_THAT(*output, PaintRecordMatcher::Make(
cc::PaintOpType::Restore, // </c3> {cc::PaintOpType::Save,
cc::PaintOpType::SaveLayerAlpha, // <e1> cc::PaintOpType::ClipRect, // <c1+c2>
cc::PaintOpType::Save, cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::ClipRect, // <c3+c4> cc::PaintOpType::Save,
cc::PaintOpType::SaveLayerAlpha, // <e2> cc::PaintOpType::ClipRect, // <c3>
cc::PaintOpType::DrawRecord, // <p2/> cc::PaintOpType::DrawRecord, // <p1/>
cc::PaintOpType::Restore, // </e2> cc::PaintOpType::Restore, // </c3>
cc::PaintOpType::Restore, // </c3+c4> cc::PaintOpType::SaveLayerAlpha, // <e1>
cc::PaintOpType::Save, cc::PaintOpType::Save,
cc::PaintOpType::ClipRect, // <c3> cc::PaintOpType::ClipRect, // <c3+c4>
cc::PaintOpType::DrawRecord, // <p3/> cc::PaintOpType::SaveLayerAlpha, // <e2>
cc::PaintOpType::Restore, // </c3> cc::PaintOpType::DrawRecord, // <p2/>
cc::PaintOpType::Restore, // </e1> cc::PaintOpType::Restore, // </e2>
cc::PaintOpType::Save, cc::PaintOpType::Restore, // </c3+c4>
cc::PaintOpType::ClipRect, // <c3+c4> cc::PaintOpType::Save,
cc::PaintOpType::DrawRecord, // <p4/> cc::PaintOpType::ClipRect, // <c3>
cc::PaintOpType::Restore, // </c3+c4> cc::PaintOpType::DrawRecord, // <p3/>
cc::PaintOpType::Restore})); // </c1+c2> cc::PaintOpType::Restore, // </c3>
EXPECT_EFFECT_BOUNDS(0, 0, 90, 90, *output, 7); cc::PaintOpType::Restore, // </e1>
EXPECT_EFFECT_BOUNDS(0, 0, 50, 50, *output, 10); cc::PaintOpType::Save,
cc::PaintOpType::ClipRect, // <c3+c4>
cc::PaintOpType::DrawRecord, // <p4/>
cc::PaintOpType::Restore, // </c3+c4>
cc::PaintOpType::Restore})); // </c1+c2>
EXPECT_EFFECT_BOUNDS(kExpectedBounds1[hint], *output, 7);
EXPECT_EFFECT_BOUNDS(kExpectedBounds2[hint], *output, 10);
}
} }
TEST_P(PaintChunksToCcLayerTest, ClipSpaceInversion) { TEST_P(PaintChunksToCcLayerTest, ClipSpaceInversion) {
...@@ -375,24 +407,29 @@ TEST_P(PaintChunksToCcLayerTest, OpacityEffectSpaceInversion) { ...@@ -375,24 +407,29 @@ TEST_P(PaintChunksToCcLayerTest, OpacityEffectSpaceInversion) {
chunks.AddChunk(t0(), c0(), *e1); chunks.AddChunk(t0(), c0(), *e1);
chunks.AddChunk(*t1, c0(), *e1); chunks.AddChunk(*t1, c0(), *e1);
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 100, 100)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
->ReleaseAsRecord(); sk_sp<PaintRecord> output =
EXPECT_THAT(*output, PaintChunksToCcLayer::Convert(chunks.chunks, PropertyTreeState::Root(),
PaintRecordMatcher::Make( gfx::Vector2dF(), chunks.items,
{cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1> kUsageHints[hint])
cc::PaintOpType::SaveLayerAlpha, // <e1> ->ReleaseAsRecord();
cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1^-1> EXPECT_THAT(*output,
cc::PaintOpType::DrawRecord, // <p0/> PaintRecordMatcher::Make(
cc::PaintOpType::Restore, // </t1^-1> {cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1>
cc::PaintOpType::DrawRecord, // <p1/> cc::PaintOpType::SaveLayerAlpha, // <e1>
cc::PaintOpType::Restore, // </e1> cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1^-1>
cc::PaintOpType::Restore})); // </t1> cc::PaintOpType::DrawRecord, // <p0/>
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 2); cc::PaintOpType::Restore, // </t1^-1>
EXPECT_TRANSFORM_MATRIX(t1->Matrix(), *output, 1); cc::PaintOpType::DrawRecord, // <p1/>
EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 4); cc::PaintOpType::Restore, // </e1>
cc::PaintOpType::Restore})); // </t1>
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 2);
EXPECT_TRANSFORM_MATRIX(t1->Matrix(), *output, 1);
EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 4);
}
} }
TEST_P(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) { TEST_P(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) {
...@@ -410,29 +447,33 @@ TEST_P(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) { ...@@ -410,29 +447,33 @@ TEST_P(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) {
TestChunks chunks; TestChunks chunks;
chunks.AddChunk(t0(), c0(), *e1); chunks.AddChunk(t0(), c0(), *e1);
auto output = const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(-66, -88, 50, 50)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
->ReleaseAsRecord(); auto output = PaintChunksToCcLayer::Convert(
EXPECT_THAT( chunks.chunks, PropertyTreeState::Root(),
*output, gfx::Vector2dF(), chunks.items, kUsageHints[hint])
PaintRecordMatcher::Make( ->ReleaseAsRecord();
{cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1> EXPECT_THAT(
cc::PaintOpType::Save, cc::PaintOpType::Translate, // <e1_offset> *output,
cc::PaintOpType::SaveLayer, // <e1> PaintRecordMatcher::Make(
cc::PaintOpType::Translate, // <e1_offset^-1/> {cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1>
cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1^-1> cc::PaintOpType::Save, cc::PaintOpType::Translate, // <e1_offset>
cc::PaintOpType::DrawRecord, // <p0/> cc::PaintOpType::SaveLayer, // <e1>
cc::PaintOpType::Restore, // </t1^-1> cc::PaintOpType::Translate, // <e1_offset^-1/>
cc::PaintOpType::Restore, // </e1> cc::PaintOpType::Save, cc::PaintOpType::Concat, // <t1^-1>
cc::PaintOpType::Restore, // </e1_offset> cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::Restore})); // </t1> cc::PaintOpType::Restore, // </t1^-1>
EXPECT_TRANSFORM_MATRIX(t1->Matrix(), *output, 1); cc::PaintOpType::Restore, // </e1>
EXPECT_TRANSLATE(66, 88, *output, 3); cc::PaintOpType::Restore, // </e1_offset>
EXPECT_EFFECT_BOUNDS(-66, -88, 50, 50, *output, 4); cc::PaintOpType::Restore})); // </t1>
EXPECT_TRANSLATE(-66, -88, *output, 5); EXPECT_TRANSFORM_MATRIX(t1->Matrix(), *output, 1);
EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 7); EXPECT_TRANSLATE(66, 88, *output, 3);
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 4);
EXPECT_TRANSLATE(-66, -88, *output, 5);
EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 7);
}
} }
TEST_P(PaintChunksToCcLayerTest, NonRootLayerSimple) { TEST_P(PaintChunksToCcLayerTest, NonRootLayerSimple) {
...@@ -482,20 +523,25 @@ TEST_P(PaintChunksToCcLayerTest, EffectWithNoOutputClip) { ...@@ -482,20 +523,25 @@ TEST_P(PaintChunksToCcLayerTest, EffectWithNoOutputClip) {
TestChunks chunks; TestChunks chunks;
chunks.AddChunk(t0(), *c2, *e1); chunks.AddChunk(t0(), *c2, *e1);
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 100, 100)};
chunks.chunks, PropertyTreeState(t0(), *c1, e0()), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
->ReleaseAsRecord(); sk_sp<PaintRecord> output =
EXPECT_THAT( PaintChunksToCcLayer::Convert(
*output, chunks.chunks, PropertyTreeState(t0(), *c1, e0()), gfx::Vector2dF(),
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1> chunks.items, kUsageHints[hint])
cc::PaintOpType::Save, ->ReleaseAsRecord();
cc::PaintOpType::ClipRect, // <c2> EXPECT_THAT(
cc::PaintOpType::DrawRecord, // <p0/> *output,
cc::PaintOpType::Restore, // </c2> PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1>
cc::PaintOpType::Restore})); // </e1> cc::PaintOpType::Save,
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); cc::PaintOpType::ClipRect, // <c2>
cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::Restore, // </c2>
cc::PaintOpType::Restore})); // </e1>
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 0);
}
} }
TEST_P(PaintChunksToCcLayerTest, TEST_P(PaintChunksToCcLayerTest,
...@@ -507,23 +553,30 @@ TEST_P(PaintChunksToCcLayerTest, ...@@ -507,23 +553,30 @@ TEST_P(PaintChunksToCcLayerTest,
TestChunks chunks; TestChunks chunks;
chunks.AddChunk(t0(), *c1, *e2); chunks.AddChunk(t0(), *c1, *e2);
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds1[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 100, 100)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(), const FloatRect kExpectedBounds2[] = {FloatRect(cc::PaintOp::kUnsetRect),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) FloatRect(0, 0, 100, 100)};
->ReleaseAsRecord();
EXPECT_THAT( for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
*output, sk_sp<PaintRecord> output =
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1> PaintChunksToCcLayer::Convert(chunks.chunks, PropertyTreeState::Root(),
cc::PaintOpType::SaveLayerAlpha, // <e2> gfx::Vector2dF(), chunks.items,
cc::PaintOpType::Save, kUsageHints[hint])
cc::PaintOpType::ClipRect, // <c1> ->ReleaseAsRecord();
cc::PaintOpType::DrawRecord, // <p0/> EXPECT_THAT(
cc::PaintOpType::Restore, // </c1> *output,
cc::PaintOpType::Restore, // </e2> PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e1>
cc::PaintOpType::Restore})); // </e1> cc::PaintOpType::SaveLayerAlpha, // <e2>
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); cc::PaintOpType::Save,
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 1); cc::PaintOpType::ClipRect, // <c1>
cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::Restore, // </c1>
cc::PaintOpType::Restore, // </e2>
cc::PaintOpType::Restore})); // </e1>
EXPECT_EFFECT_BOUNDS(kExpectedBounds1[hint], *output, 0);
EXPECT_EFFECT_BOUNDS(kExpectedBounds2[hint], *output, 1);
}
} }
TEST_P(PaintChunksToCcLayerTest, TEST_P(PaintChunksToCcLayerTest,
...@@ -535,20 +588,25 @@ TEST_P(PaintChunksToCcLayerTest, ...@@ -535,20 +588,25 @@ TEST_P(PaintChunksToCcLayerTest,
TestChunks chunks; TestChunks chunks;
chunks.AddChunk(t0(), *c1, *e2); chunks.AddChunk(t0(), *c1, *e2);
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 100, 100)};
chunks.chunks, PropertyTreeState(t0(), c0(), *e1), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
->ReleaseAsRecord(); sk_sp<PaintRecord> output =
EXPECT_THAT( PaintChunksToCcLayer::Convert(
*output, chunks.chunks, PropertyTreeState(t0(), c0(), *e1), gfx::Vector2dF(),
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e2> chunks.items, kUsageHints[hint])
cc::PaintOpType::Save, ->ReleaseAsRecord();
cc::PaintOpType::ClipRect, // <c1> EXPECT_THAT(
cc::PaintOpType::DrawRecord, // <p0/> *output,
cc::PaintOpType::Restore, // </c1> PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e2>
cc::PaintOpType::Restore})); // </e2> cc::PaintOpType::Save,
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); cc::PaintOpType::ClipRect, // <c1>
cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::Restore, // </c1>
cc::PaintOpType::Restore})); // </e2>
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 0);
}
} }
TEST_P(PaintChunksToCcLayerTest, TEST_P(PaintChunksToCcLayerTest,
...@@ -560,17 +618,22 @@ TEST_P(PaintChunksToCcLayerTest, ...@@ -560,17 +618,22 @@ TEST_P(PaintChunksToCcLayerTest,
TestChunks chunks; TestChunks chunks;
chunks.AddChunk(t0(), *c1, *e2); chunks.AddChunk(t0(), *c1, *e2);
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 100, 100)};
chunks.chunks, PropertyTreeState(t0(), *c1, *e1), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
->ReleaseAsRecord(); sk_sp<PaintRecord> output =
EXPECT_THAT( PaintChunksToCcLayer::Convert(
*output, chunks.chunks, PropertyTreeState(t0(), *c1, *e1), gfx::Vector2dF(),
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e2> chunks.items, kUsageHints[hint])
cc::PaintOpType::DrawRecord, // <p0/> ->ReleaseAsRecord();
cc::PaintOpType::Restore})); // </e2> EXPECT_THAT(
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); *output,
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayerAlpha, // <e2>
cc::PaintOpType::DrawRecord, // <p0/>
cc::PaintOpType::Restore})); // </e2>
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 0);
}
} }
TEST_P(PaintChunksToCcLayerTest, VisualRect) { TEST_P(PaintChunksToCcLayerTest, VisualRect) {
...@@ -688,17 +751,22 @@ TEST_P(PaintChunksToCcLayerTest, EmptyEffectsAreStored) { ...@@ -688,17 +751,22 @@ TEST_P(PaintChunksToCcLayerTest, EmptyEffectsAreStored) {
chunks.AddChunk(nullptr, t0(), c0(), e0()); chunks.AddChunk(nullptr, t0(), c0(), e0());
chunks.AddChunk(nullptr, t0(), c0(), *e1); chunks.AddChunk(nullptr, t0(), c0(), *e1);
sk_sp<PaintRecord> output = const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
PaintChunksToCcLayer::Convert( FloatRect(0, 0, 100, 100)};
chunks.chunks, PropertyTreeState::Root(), gfx::Vector2dF(),
chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer) for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
->ReleaseAsRecord(); sk_sp<PaintRecord> output =
PaintChunksToCcLayer::Convert(chunks.chunks, PropertyTreeState::Root(),
EXPECT_THAT(*output, PaintRecordMatcher::Make({ gfx::Vector2dF(), chunks.items,
cc::PaintOpType::SaveLayerAlpha, // <e1> kUsageHints[hint])
cc::PaintOpType::Restore, // </e1> ->ReleaseAsRecord();
}));
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); EXPECT_THAT(*output, PaintRecordMatcher::Make({
cc::PaintOpType::SaveLayerAlpha, // <e1>
cc::PaintOpType::Restore, // </e1>
}));
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 0);
}
} }
TEST_P(PaintChunksToCcLayerTest, CombineClips) { TEST_P(PaintChunksToCcLayerTest, CombineClips) {
...@@ -1313,5 +1381,28 @@ TEST_P(PaintChunksToCcLayerTest, AllowChunkEscapeLayerNoopEffects) { ...@@ -1313,5 +1381,28 @@ TEST_P(PaintChunksToCcLayerTest, AllowChunkEscapeLayerNoopEffects) {
})); }));
} }
// https://crbug.com/918240
TEST_P(PaintChunksToCcLayerTest, EmptyChunkRectDoesntTurnToUnsetOne) {
CompositorFilterOperations filter;
filter.AppendBlurFilter(5);
auto e1 = CreateFilterEffect(e0(), t0(), &c0(), filter, FloatPoint(0, 0));
TestChunks chunks;
chunks.AddChunk(nullptr, t0(), c0(), *e1, {0, 0, 0, 0});
const FloatRect kExpectedBounds[] = {FloatRect(cc::PaintOp::kUnsetRect),
FloatRect(0, 0, 0, 0)};
for (size_t hint = 0; hint < base::size(kUsageHints); ++hint) {
auto output = PaintChunksToCcLayer::Convert(
chunks.chunks, PropertyTreeState::Root(),
gfx::Vector2dF(), chunks.items, kUsageHints[hint])
->ReleaseAsRecord();
EXPECT_THAT(*output,
PaintRecordMatcher::Make({cc::PaintOpType::SaveLayer, // <e1>
cc::PaintOpType::Restore})); // </e1>
EXPECT_EFFECT_BOUNDS(kExpectedBounds[hint], *output, 0);
}
}
} // namespace } // namespace
} // namespace blink } // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment