Commit 6f895b07 authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Chromium LUCI CQ

Add CullRect::ApplyPaintProperties()

It will be called to map a cull rect from parent space to local space
in cull rect update during PrePaint. The purpose is to mark PaintLayers
needing repaint on cull rect changes before paint, instead of checking
interest rect / cull rect changes during paint, to avoid setting
PaintLayer needing repaint unnecessarily, especially for CAP during
composited scrolling.

Besides the original features of CullRect::ApplyTransforms() which is
used in cull rect mapping for CompositeAfterPaint, it also implements
the following features to be on par with CompositedLayerMapping::
ReComputeInterestRect():

- Considering clips in additional to scroll clips,
- Clipping expanded cull rect by scrolling contents rect for composited
  scroll translations,
- Clamping extreme geometry values,
- Adaptive expansion distance for composited transforms.

The next steps are:
1. Add CullRectUpdater which updates cull rects during PrePaint when
   runtime feature CullRectUpdate is enabled.
2. Use the updated cull rect to replace interest rect in pre-CAP and
   cull rect in CAP and pre-CAP, still behind the runtime feature.
3. Enable CullRectUpdate for CAP
4. Enable CullRectUpdate for pre-CAP.
5. Remove old interest rect / cull rect code.

Bug: 1046544
Change-Id: I6e7e9f85bc0b4640e67de1732744e647b6f7e230
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2620090Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843304}
parent 184d43b2
...@@ -421,19 +421,14 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) { ...@@ -421,19 +421,14 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
EXPECT_THAT(ContentDisplayItems(), EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM, ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType))); IsSameId(content1, kBackgroundType)));
EXPECT_EQ(IntRect(0, 0, 800, 4600), target_layer->PreviousCullRect().Rect());
auto chunks = ContentPaintChunks(); auto chunks = ContentPaintChunks();
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// CAP doesn't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
target_layer->PreviousCullRect());
// |target| still created subsequence (cached). // |target| still created subsequence (cached).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 2); EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 2);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON, EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
IsPaintChunk(1, 1), IsPaintChunk(1, 2))); IsPaintChunk(1, 1), IsPaintChunk(1, 2)));
} else { } else {
EXPECT_EQ(CullRect(IntRect(0, 0, 800, 4600)),
target_layer->PreviousCullRect());
EXPECT_THAT(ContentDisplayItems(), EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM, ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType))); IsSameId(content1, kBackgroundType)));
...@@ -459,12 +454,9 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) { ...@@ -459,12 +454,9 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
EXPECT_THAT(ContentDisplayItems(), EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM, ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType))); IsSameId(content1, kBackgroundType)));
EXPECT_EQ(IntRect(0, 0, 800, 4600), target_layer->PreviousCullRect().Rect());
chunks = ContentPaintChunks(); chunks = ContentPaintChunks();
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// CAP doesn't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
target_layer->PreviousCullRect());
EXPECT_THAT(ContentDisplayItems(), EXPECT_THAT(ContentDisplayItems(),
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM, ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType))); IsSameId(content1, kBackgroundType)));
...@@ -473,8 +465,6 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) { ...@@ -473,8 +465,6 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON, EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
IsPaintChunk(1, 1), IsPaintChunk(1, 2))); IsPaintChunk(1, 1), IsPaintChunk(1, 2)));
} else { } else {
EXPECT_EQ(CullRect(IntRect(0, 0, 800, 4600)),
target_layer->PreviousCullRect());
// |target| still created subsequence (cached). // |target| still created subsequence (cached).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 1); EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 1);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON, EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
...@@ -501,19 +491,14 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) { ...@@ -501,19 +491,14 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM, ElementsAre(VIEW_SCROLLING_BACKGROUND_DISPLAY_ITEM,
IsSameId(content1, kBackgroundType), IsSameId(content1, kBackgroundType),
IsSameId(content2, kBackgroundType))); IsSameId(content2, kBackgroundType)));
EXPECT_EQ(IntRect(0, 0, 800, 7600), target_layer->PreviousCullRect().Rect());
chunks = ContentPaintChunks(); chunks = ContentPaintChunks();
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
// CAP doesn't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -1000, 8800, 8600)),
target_layer->PreviousCullRect());
// |target| still created subsequence (repainted). // |target| still created subsequence (repainted).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 2); EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 2);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON, EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
IsPaintChunk(1, 1), IsPaintChunk(1, 3))); IsPaintChunk(1, 1), IsPaintChunk(1, 3)));
} else { } else {
EXPECT_EQ(CullRect(IntRect(0, 0, 800, 7600)),
target_layer->PreviousCullRect());
// |target| still created subsequence (repainted). // |target| still created subsequence (repainted).
EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 1); EXPECT_SUBSEQUENCE_FROM_CHUNK(*target_layer, chunks.begin() + 1, 1);
EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON, EXPECT_THAT(chunks, ElementsAre(VIEW_SCROLLING_BACKGROUND_CHUNK_COMMON,
...@@ -1057,8 +1042,9 @@ TEST_P(PaintLayerPainterTestCAP, TallLayerCullRect) { ...@@ -1057,8 +1042,9 @@ TEST_P(PaintLayerPainterTestCAP, TallLayerCullRect) {
</div> </div>
)HTML"); )HTML");
// Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling. // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped
EXPECT_EQ(IntRect(-4000, -4000, 8800, 8600), // by the contents rect.
EXPECT_EQ(IntRect(0, 0, 800, 4600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1070,7 +1056,7 @@ TEST_P(PaintLayerPainterTestCAP, WideLayerCullRect) { ...@@ -1070,7 +1056,7 @@ TEST_P(PaintLayerPainterTestCAP, WideLayerCullRect) {
)HTML"); )HTML");
// Same as TallLayerCullRect. // Same as TallLayerCullRect.
EXPECT_EQ(IntRect(-4000, -4000, 8800, 8600), EXPECT_EQ(IntRect(0, 0, 4800, 600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1080,28 +1066,29 @@ TEST_P(PaintLayerPainterTestCAP, TallScrolledLayerCullRect) { ...@@ -1080,28 +1066,29 @@ TEST_P(PaintLayerPainterTestCAP, TallScrolledLayerCullRect) {
</div> </div>
)HTML"); )HTML");
// Viewport rect (0, 0, 800, 600) expanded by 4000. // Viewport rect (0, 0, 800, 600) expanded by 4000 for scrolling then clipped
EXPECT_EQ(IntRect(-4000, -4000, 8800, 8600), // by the contents rect.
EXPECT_EQ(IntRect(0, 0, 800, 4600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
GetDocument().View()->LayoutViewport()->SetScrollOffset( GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 6000), mojom::blink::ScrollType::kProgrammatic); ScrollOffset(0, 4000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest(); UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(IntRect(-4000, 2000, 8800, 8600), EXPECT_EQ(IntRect(0, 0, 800, 8600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
GetDocument().View()->LayoutViewport()->SetScrollOffset( GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 6500), mojom::blink::ScrollType::kProgrammatic); ScrollOffset(0, 4500), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest(); UpdateAllLifecyclePhasesForTest();
// Used the previous cull rect because the scroll amount is small. // Used the previous cull rect because the scroll amount is small.
EXPECT_EQ(IntRect(-4000, 2000, 8800, 8600), EXPECT_EQ(IntRect(0, 0, 800, 8600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
GetDocument().View()->LayoutViewport()->SetScrollOffset( GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 6600), mojom::blink::ScrollType::kProgrammatic); ScrollOffset(0, 4600), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest(); UpdateAllLifecyclePhasesForTest();
// Used new cull rect. // Used new cull rect.
EXPECT_EQ(IntRect(-4000, 2600, 8800, 8600), EXPECT_EQ(IntRect(0, 600, 800, 8600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1136,7 +1123,7 @@ TEST_P(PaintLayerPainterTestCAP, WholeDocumentCullRect) { ...@@ -1136,7 +1123,7 @@ TEST_P(PaintLayerPainterTestCAP, WholeDocumentCullRect) {
// Cull rect is normal for contents below scroll other than the viewport. // Cull rect is normal for contents below scroll other than the viewport.
EXPECT_EQ( EXPECT_EQ(
IntRect(-4000, -4000, 8200, 8200), IntRect(0, 0, 200, 4200),
GetPaintLayerByElementId("below-scroll")->PreviousCullRect().Rect()); GetPaintLayerByElementId("below-scroll")->PreviousCullRect().Rect());
EXPECT_THAT(ContentDisplayItems(), EXPECT_THAT(ContentDisplayItems(),
...@@ -1174,22 +1161,30 @@ TEST_P(PaintLayerPainterTestCAP, VerticalRightLeftWritingModeDocument) { ...@@ -1174,22 +1161,30 @@ TEST_P(PaintLayerPainterTestCAP, VerticalRightLeftWritingModeDocument) {
// A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px = // A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px =
// 4200px in non-RTL mode. Expanding the resulting rect by 4000px in each // 4200px in non-RTL mode. Expanding the resulting rect by 4000px in each
// direction yields this result. // direction and clipping by the contents rect yields this result.
EXPECT_EQ(IntRect(200, -4000, 8800, 8600), EXPECT_EQ(IntRect(200, 0, 8800, 600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
// TODO(wangxianzhu): These tests should correspond to the tests in
// CompositedLayerMapping testing interest rects. However, for now because in
// CompositeAfterPaint we expand cull rect for composited scrollers only, so
// the tests are modified to use composited scrolling. Will change these back to
// their original version when we support expansion for all composited layers.
// Will be done in CullRectUpdate.
TEST_P(PaintLayerPainterTestCAP, ScaledCullRect) { TEST_P(PaintLayerPainterTestCAP, ScaledCullRect) {
GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true); GetDocument().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll; <div style='width: 200px; height: 300px; overflow: scroll;
transform: scaleX(2) scaleY(0.5)'> transform: scaleX(2) scaleY(0.5)'>
<div id='target' style='height: 400px; position: relative'></div> <div id='target' style='height: 400px; position: relative'></div>
<div style='width: 10000px; height: 10000px'></div>
</div> </div>
)HTML"); )HTML");
// The scale doesn't affect the cull rect. // The scale doesn't affect the cull rect.
EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300), // TODO(wangxianzhu): actually it should.
EXPECT_EQ(IntRect(0, 0, 4200, 4300),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1198,12 +1193,15 @@ TEST_P(PaintLayerPainterTestCAP, ScaledAndRotatedCullRect) { ...@@ -1198,12 +1193,15 @@ TEST_P(PaintLayerPainterTestCAP, ScaledAndRotatedCullRect) {
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<div style='width: 200px; height: 300px; overflow: scroll; <div style='width: 200px; height: 300px; overflow: scroll;
transform: scaleX(2) scaleY(0.5) rotateZ(45deg)'> transform: scaleX(2) scaleY(0.5) rotateZ(45deg)'>
<div id='target' style='height: 400px; position: relative'></div> <div id='target' style='height: 400px; position: relative;
will-change: transform'></div>
<div style='width: 10000px; height: 10000px'></div>
</div> </div>
)HTML"); )HTML");
// The scale and the rotation don't affect the cull rect. // The scale and the rotation don't affect the cull rect.
EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300), // TODO(wangxianzhu): actually they should.
EXPECT_EQ(IntRect(0, 0, 4200, 4300),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1213,12 +1211,13 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotated90DegreesCullRect) { ...@@ -1213,12 +1211,13 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotated90DegreesCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll; <div style='width: 200px; height: 300px; overflow: scroll;
transform: rotateY(90deg)'> transform: rotateY(90deg)'>
<div id='target' style='height: 400px; position: relative'></div> <div id='target' style='height: 400px; position: relative'></div>
<div style='width: 10000px; height: 10000px'></div>
</div> </div>
)HTML"); )HTML");
// It's rotated 90 degrees about the X axis, which means its visual content // It's rotated 90 degrees about the X axis, which means its visual content
// rect is empty, we fall back to the 4000px cull rect padding amount. // rect is empty, we fall back to the 4000px cull rect padding amount.
EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300), EXPECT_EQ(IntRect(0, 0, 4200, 4300),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1228,6 +1227,7 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) { ...@@ -1228,6 +1227,7 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll; <div style='width: 200px; height: 300px; overflow: scroll;
transform: rotateY(89.9999deg)'> transform: rotateY(89.9999deg)'>
<div id='target' style='height: 400px; position: relative'></div> <div id='target' style='height: 400px; position: relative'></div>
<div style='width: 10000px; height: 10000px'></div>
</div> </div>
)HTML"); )HTML");
...@@ -1235,7 +1235,7 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) { ...@@ -1235,7 +1235,7 @@ TEST_P(PaintLayerPainterTestCAP, 3DRotatedNear90DegreesCullRect) {
// leads to a reverse-projected rect that is much much larger than the // leads to a reverse-projected rect that is much much larger than the
// original layer size in certain dimensions. In such cases, we often fall // original layer size in certain dimensions. In such cases, we often fall
// back to the 4000px cull rect padding amount. // back to the 4000px cull rect padding amount.
EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300), EXPECT_EQ(IntRect(0, 0, 4200, 4300),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1280,10 +1280,11 @@ TEST_P(PaintLayerPainterTestCAP, LayerOffscreenNearCullRect) { ...@@ -1280,10 +1280,11 @@ TEST_P(PaintLayerPainterTestCAP, LayerOffscreenNearCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll; <div style='width: 200px; height: 300px; overflow: scroll;
position: absolute; top: 3000px; left: 0px;'> position: absolute; top: 3000px; left: 0px;'>
<div id='target' style='height: 500px; position: relative'></div> <div id='target' style='height: 500px; position: relative'></div>
<div style='width: 10000px; height: 10000px'></div>
</div> </div>
)HTML"); )HTML");
EXPECT_EQ(IntRect(-4000, -4000, 8200, 8300), EXPECT_EQ(IntRect(0, 0, 4200, 4300),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
...@@ -1293,6 +1294,7 @@ TEST_P(PaintLayerPainterTestCAP, LayerOffscreenFarCullRect) { ...@@ -1293,6 +1294,7 @@ TEST_P(PaintLayerPainterTestCAP, LayerOffscreenFarCullRect) {
<div style='width: 200px; height: 300px; overflow: scroll; <div style='width: 200px; height: 300px; overflow: scroll;
position: absolute; top: 9000px'> position: absolute; top: 9000px'>
<div id='target' style='height: 500px; position: relative'></div> <div id='target' style='height: 500px; position: relative'></div>
<div style='width: 10000px; height: 10000px'></div>
</div> </div>
)HTML"); )HTML");
...@@ -1318,8 +1320,9 @@ TEST_P(PaintLayerPainterTestCAP, ScrollingLayerCullRect) { ...@@ -1318,8 +1320,9 @@ TEST_P(PaintLayerPainterTestCAP, ScrollingLayerCullRect) {
// of 'target', scrollbar and root margin). // of 'target', scrollbar and root margin).
// Applying the viewport clip of the root has no effect because // Applying the viewport clip of the root has no effect because
// the clip is already small. Mapping it down into the graphics layer // the clip is already small. Mapping it down into the graphics layer
// space yields (0, 0, 195, 193). This is then expanded by 4000px. // space yields (0, 0, 195, 193). This is then expanded by 4000px and clipped
EXPECT_EQ(IntRect(-4000, -4000, 8195, 8193), // by the contents rect.
EXPECT_EQ(IntRect(0, 0, 195, 4193),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect()); GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h" #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
#include "base/containers/adapters.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h" #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
...@@ -14,6 +15,30 @@ ...@@ -14,6 +15,30 @@
namespace blink { namespace blink {
static constexpr int kReasonablePixelLimit =
std::numeric_limits<int>::max() / 2;
// Returns the number of pixels to expand the cull rect for composited scroll
// and transform.
static int LocalPixelDistanceToExpand(
const TransformPaintPropertyNode& root_transform,
const TransformPaintPropertyNode& local_transform) {
// Number of pixels to expand in root coordinates for cull rect under
// composited scroll translation or other composited transform.
static constexpr int kPixelDistanceToExpand = 4000;
FloatRect rect(0, 0, 1, 1);
GeometryMapper::SourceToDestinationRect(root_transform, local_transform,
rect);
// Now rect.Size() is the size of a screen pixel in local coordinates.
float scale = std::max(rect.Width(), rect.Height());
// A very big scale may be caused by non-invertable near non-invertable
// transforms. Fallback to scale 1. The limit is heuristic.
if (scale > kReasonablePixelLimit / kPixelDistanceToExpand)
return kPixelDistanceToExpand;
return scale * kPixelDistanceToExpand;
}
bool CullRect::Intersects(const IntRect& rect) const { bool CullRect::Intersects(const IntRect& rect) const {
return IsInfinite() || rect.Intersects(rect_); return IsInfinite() || rect.Intersects(rect_);
} }
...@@ -50,29 +75,40 @@ void CullRect::Move(const FloatSize& offset) { ...@@ -50,29 +75,40 @@ void CullRect::Move(const FloatSize& offset) {
rect_ = EnclosingIntRect(float_rect); rect_ = EnclosingIntRect(float_rect);
} }
static void MapRect(const TransformPaintPropertyNode& transform, void CullRect::ApplyTransform(const TransformPaintPropertyNode& transform) {
IntRect& rect) { if (transform.ScrollNode()) {
if (transform.IsIdentityOr2DTranslation()) { DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
FloatRect float_rect(rect); // TODO(wangxianzhu): Remove this code path for CullRectUpdate.
float_rect.Move(-transform.Translation2D()); ApplyScrollTranslation(transform, transform);
rect = EnclosingIntRect(float_rect);
} else { } else {
rect = transform.MatrixWithOriginApplied().Inverse().MapRect(rect); ApplyTransformWithoutExpansion(transform);
} }
} }
CullRect::ApplyTransformResult CullRect::ApplyTransformInternal( void CullRect::ApplyTransformWithoutExpansion(
const TransformPaintPropertyNode& transform) { const TransformPaintPropertyNode& transform) {
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (IsInfinite())
if (const auto* scroll = transform.ScrollNode()) { return;
DCHECK(transform.Parent());
GeometryMapper::SourceToDestinationRect(*transform.Parent(), transform,
rect_);
}
CullRect::ApplyTransformResult CullRect::ApplyScrollTranslation(
const TransformPaintPropertyNode& root_transform,
const TransformPaintPropertyNode& scroll_translation) {
const auto* scroll = scroll_translation.ScrollNode();
DCHECK(scroll);
rect_.Intersect(scroll->ContainerRect()); rect_.Intersect(scroll->ContainerRect());
if (rect_.IsEmpty()) if (rect_.IsEmpty())
return kNotExpanded; return kNotExpanded;
MapRect(transform, rect_); ApplyTransformWithoutExpansion(scroll_translation);
// Don't expand for non-composited scrolling. // Don't expand for non-composited scrolling.
if (!transform.HasDirectCompositingReasons()) if (!scroll_translation.HasDirectCompositingReasons())
return kNotExpanded; return kNotExpanded;
// We create scroll node for the root scroller even it's not scrollable. // We create scroll node for the root scroller even it's not scrollable.
...@@ -82,19 +118,11 @@ CullRect::ApplyTransformResult CullRect::ApplyTransformInternal( ...@@ -82,19 +118,11 @@ CullRect::ApplyTransformResult CullRect::ApplyTransformInternal(
return kNotExpanded; return kNotExpanded;
// Expand the cull rect for scrolling contents for composited scrolling. // Expand the cull rect for scrolling contents for composited scrolling.
static const int kPixelDistanceToExpand = 4000; rect_.Inflate(LocalPixelDistanceToExpand(root_transform, scroll_translation));
rect_.Inflate(kPixelDistanceToExpand); IntRect contents_rect(IntPoint(), scroll->ContentsSize());
// Don't clip the cull rect by contents size to let ChangedEnough() work rect_.Intersect(contents_rect);
// even if the new cull rect exceeds the bounds of contents rect. return rect_ == contents_rect ? kExpandedForWholeScrollingContents
return rect_.Contains(IntRect(IntPoint(), scroll->ContentsSize()))
? kExpandedForWholeScrollingContents
: kExpandedForPartialScrollingContents; : kExpandedForPartialScrollingContents;
}
}
if (!IsInfinite())
MapRect(transform, rect_);
return kNotExpanded;
} }
void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source, void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source,
...@@ -125,7 +153,7 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source, ...@@ -125,7 +153,7 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source,
*last_transform, *scroll_translation->Parent(), rect_); *last_transform, *scroll_translation->Parent(), rect_);
} }
last_scroll_translation_result = last_scroll_translation_result =
ApplyTransformInternal(*scroll_translation); ApplyScrollTranslation(source, *scroll_translation);
last_transform = scroll_translation; last_transform = scroll_translation;
} }
...@@ -135,25 +163,202 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source, ...@@ -135,25 +163,202 @@ void CullRect::ApplyTransforms(const TransformPaintPropertyNode& source,
} }
if (last_scroll_translation_result == kExpandedForPartialScrollingContents && if (last_scroll_translation_result == kExpandedForPartialScrollingContents &&
old_cull_rect && !ChangedEnough(*old_cull_rect)) old_cull_rect &&
!ChangedEnough(*old_cull_rect,
&last_transform->ScrollNode()->ContentsSize())) {
rect_ = old_cull_rect->Rect(); rect_ = old_cull_rect->Rect();
}
} }
bool CullRect::ChangedEnough(const CullRect& old_cull_rect) const { void CullRect::ApplyPaintPropertiesWithoutExpansion(
DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()); const PropertyTreeState& source,
const PropertyTreeState& destination) {
FloatClipRect clip_rect =
GeometryMapper::LocalToAncestorClipRect(destination, source);
if (!clip_rect.IsInfinite())
rect_.Intersect(EnclosingIntRect(clip_rect.Rect()));
if (!IsInfinite()) {
GeometryMapper::SourceToDestinationRect(source.Transform(),
destination.Transform(), rect_);
}
}
void CullRect::ApplyPaintProperties(
const PropertyTreeState& root,
const PropertyTreeState& source,
const PropertyTreeState& destination,
const base::Optional<CullRect>& old_cull_rect) {
DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::CullRectUpdateEnabled());
Vector<const TransformPaintPropertyNode*, 4> scroll_translations;
Vector<const ClipPaintPropertyNode*, 4> clips;
bool abnormal_hierarchy = false;
for (const auto* t = &destination.Transform(); t != &source.Transform();
t = t->UnaliasedParent()) {
DCHECK(t);
if (t == &root.Transform()) {
abnormal_hierarchy = true;
break;
}
if (t->ScrollNode())
scroll_translations.push_back(t);
}
if (!abnormal_hierarchy) {
for (const auto* c = &destination.Clip(); c != &source.Clip();
c = c->UnaliasedParent()) {
DCHECK(c);
if (c == &root.Clip()) {
abnormal_hierarchy = true;
break;
}
clips.push_back(c);
}
}
if (abnormal_hierarchy) {
// Either the transform or the clip of |source| is not an ancestor of
// |destination|. Map infinite rect from the root.
*this = Infinite();
ApplyPaintProperties(root, root, destination, old_cull_rect);
return;
}
// These are either the source transform/clip or the last scroll
// translation's transform/clip.
const auto* last_transform = &source.Transform();
const auto* last_clip = &source.Clip();
auto last_scroll_translation_result = kNotExpanded;
// For now effects (especially pixel-moving filters) are not considered in
// this class. The client has to use infinite cull rect in the case.
// TODO(wangxianzhu): support clip rect expansion for pixel-moving filters.
const auto& effect_root = EffectPaintPropertyNode::Root();
auto scroll_translation_it = scroll_translations.rbegin();
for (const auto* clip : base::Reversed(clips)) {
if (scroll_translation_it == scroll_translations.rend())
break;
const auto* scroll_translation = *scroll_translation_it++;
if (&clip->LocalTransformSpace() != scroll_translation->Parent())
continue;
ApplyPaintPropertiesWithoutExpansion(
PropertyTreeState(*last_transform, *last_clip, effect_root),
PropertyTreeState(*scroll_translation->UnaliasedParent(), *clip,
effect_root));
last_scroll_translation_result =
ApplyScrollTranslation(root.Transform(), *scroll_translation);
last_transform = scroll_translation;
last_clip = clip;
}
ApplyPaintPropertiesWithoutExpansion(
PropertyTreeState(*last_transform, *last_clip, effect_root), destination);
// Since the cull rect mapping above can produce extremely large numbers in
// cases of perspective, try our best to "normalize" the result by ensuring
// that none of the rect dimensions exceed some large, but reasonable, limit.
// Note that by clamping X and Y, we are effectively moving the rect right /
// down. However, this will at most make us paint more content, which is
// better than erroneously deciding that the rect produced here is far
// offscreen.
if (rect_.X() < -kReasonablePixelLimit)
rect_.SetX(-kReasonablePixelLimit);
if (rect_.Y() < -kReasonablePixelLimit)
rect_.SetY(-kReasonablePixelLimit);
if (rect_.MaxX() > kReasonablePixelLimit)
rect_.ShiftMaxXEdgeTo(kReasonablePixelLimit);
if (rect_.MaxY() > kReasonablePixelLimit)
rect_.ShiftMaxYEdgeTo(kReasonablePixelLimit);
const IntSize* expansion_bounds = nullptr;
bool expanded = false;
if (last_scroll_translation_result == kExpandedForPartialScrollingContents &&
last_clip == &destination.Clip()) {
DCHECK(last_transform->ScrollNode());
expansion_bounds = &last_transform->ScrollNode()->ContentsSize();
expanded = true;
} else if (!IsInfinite() && last_transform != &destination.Transform() &&
destination.Transform().HasDirectCompositingReasons()) {
// Direct compositing reasons such as will-change transform can cause the
// content to move arbitrarily, so there is no exact cull rect. Instead of
// using an infinite rect, we use a heuristic of expanding by
// |pixel_distance_to_expand|. To avoid extreme expansion in the presence
// of nested composited transforms, the heuristic is skipped for rects that
// are already very large.
int pixel_distance_to_expand =
LocalPixelDistanceToExpand(root.Transform(), destination.Transform());
if (rect_.Width() < pixel_distance_to_expand) {
rect_.InflateX(pixel_distance_to_expand);
expanded = true;
}
if (rect_.Height() < pixel_distance_to_expand) {
rect_.InflateY(pixel_distance_to_expand);
expanded = true;
}
}
if (expanded && old_cull_rect &&
!ChangedEnough(*old_cull_rect, expansion_bounds))
rect_ = old_cull_rect->Rect();
}
bool CullRect::ChangedEnough(const CullRect& old_cull_rect,
const IntSize* expansion_bounds) const {
DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
RuntimeEnabledFeatures::CullRectUpdateEnabled());
const auto& new_rect = Rect(); const auto& new_rect = Rect();
const auto& old_rect = old_cull_rect.Rect(); const auto& old_rect = old_cull_rect.Rect();
if (old_rect == new_rect || (old_rect.IsEmpty() && new_rect.IsEmpty())) if (old_rect.Contains(new_rect))
return false;
if (old_rect.IsEmpty() && new_rect.IsEmpty())
return false; return false;
if (old_rect.IsEmpty()) if (old_rect.IsEmpty())
return true; return true;
static constexpr int kChangedEnoughMinimumDistance = 512;
auto expanded_old_rect = old_rect; auto expanded_old_rect = old_rect;
static const int kChangedEnoughMinimumDistance = 512;
expanded_old_rect.Inflate(kChangedEnoughMinimumDistance); expanded_old_rect.Inflate(kChangedEnoughMinimumDistance);
return !expanded_old_rect.Contains(new_rect); if (!expanded_old_rect.Contains(new_rect))
return true;
// The following edge checking logic applies only when the bounds (which were
// used to clip the cull rect) are known.
if (!expansion_bounds)
return false;
// The cull rect must have been clipped by *expansion_bounds.
DCHECK(IntRect(IntPoint(), *expansion_bounds).Contains(rect_));
// Even if the new cull rect doesn't include enough new area to satisfy
// the condition above, update anyway if it touches the edge of the scrolling
// contents that is not touched by the existing cull rect. Because it's
// impossible to expose more area in the direction, update cannot be deferred
// until the exposed new area satisfies the condition above.
// For example,
// scroller contents dimensions: 100x1000
// old cull rect: 0,100 100x8000
// A new rect of 0,0 100x8000 will not be |kChangedEnoughMinimumDistance|
// pixels away from the current rect. Without additional logic for this case,
// we will continue using the old cull rect.
if (rect_.X() == 0 && old_cull_rect.Rect().X() != 0)
return true;
if (rect_.Y() == 0 && old_cull_rect.Rect().Y() != 0)
return true;
if (rect_.MaxX() == expansion_bounds->Width() &&
old_cull_rect.Rect().MaxX() != expansion_bounds->Width())
return true;
if (rect_.MaxY() == expansion_bounds->Height() &&
old_cull_rect.Rect().MaxY() != expansion_bounds->Height())
return true;
return false;
} }
} // namespace blink } // namespace blink
...@@ -18,6 +18,7 @@ class AffineTransform; ...@@ -18,6 +18,7 @@ class AffineTransform;
class FloatRect; class FloatRect;
class LayoutRect; class LayoutRect;
class LayoutUnit; class LayoutUnit;
class PropertyTreeState;
class TransformPaintPropertyNode; class TransformPaintPropertyNode;
class PLATFORM_EXPORT CullRect { class PLATFORM_EXPORT CullRect {
...@@ -47,9 +48,9 @@ class PLATFORM_EXPORT CullRect { ...@@ -47,9 +48,9 @@ class PLATFORM_EXPORT CullRect {
// 1. it's clipped by the container rect, // 1. it's clipped by the container rect,
// 2. transformed by inverse of the scroll translation, // 2. transformed by inverse of the scroll translation,
// 3. expanded by thousands of pixels for composited scrolling. // 3. expanded by thousands of pixels for composited scrolling.
void ApplyTransform(const TransformPaintPropertyNode& transform) { // 4. clipped by the contents rect.
ApplyTransformInternal(transform); // TODO(wangxianzhu): Remove this function for CullRectUpdate.
} void ApplyTransform(const TransformPaintPropertyNode&);
// For CompositeAfterPaint only. Applies transforms from |source| (not // For CompositeAfterPaint only. Applies transforms from |source| (not
// included) to |destination| (included). For each scroll translation, the // included) to |destination| (included). For each scroll translation, the
...@@ -58,10 +59,21 @@ class PLATFORM_EXPORT CullRect { ...@@ -58,10 +59,21 @@ class PLATFORM_EXPORT CullRect {
// doesn't cover the whole scrolling contents, and the new cull rect doesn't // doesn't cover the whole scrolling contents, and the new cull rect doesn't
// change enough (by hundreds of pixels) from |old_cull_rect|, the cull rect // change enough (by hundreds of pixels) from |old_cull_rect|, the cull rect
// will be set to |old_cull_rect| to avoid repaint on each composited scroll. // will be set to |old_cull_rect| to avoid repaint on each composited scroll.
// TODO(wangxianzhu): Remove this function for CullRectUpdate.
void ApplyTransforms(const TransformPaintPropertyNode& source, void ApplyTransforms(const TransformPaintPropertyNode& source,
const TransformPaintPropertyNode& destination, const TransformPaintPropertyNode& destination,
const base::Optional<CullRect>& old_cull_rect); const base::Optional<CullRect>& old_cull_rect);
// For CullRectUpdate only. Similar to the above but also applies clips and
// expands for all directly composited transforms (including scrolling and
// non-scrolling ones). |root| is used to calculate the expansion distance in
// the local space, to make the expansion distance approximately the same in
// the root space.
void ApplyPaintProperties(const PropertyTreeState& root,
const PropertyTreeState& source,
const PropertyTreeState& destination,
const base::Optional<CullRect>& old_cull_rect);
const IntRect& Rect() const { return rect_; } const IntRect& Rect() const { return rect_; }
String ToString() const { return rect_.ToString(); } String ToString() const { return rect_.ToString(); }
...@@ -82,10 +94,17 @@ class PLATFORM_EXPORT CullRect { ...@@ -82,10 +94,17 @@ class PLATFORM_EXPORT CullRect {
// doesn't cover the whole scrolling contents. // doesn't cover the whole scrolling contents.
kExpandedForPartialScrollingContents, kExpandedForPartialScrollingContents,
}; };
ApplyTransformResult ApplyTransformInternal( ApplyTransformResult ApplyScrollTranslation(
const TransformPaintPropertyNode&); const TransformPaintPropertyNode& root_transform,
const TransformPaintPropertyNode& scroll_translation);
void ApplyTransformWithoutExpansion(const TransformPaintPropertyNode&);
void ApplyPaintPropertiesWithoutExpansion(
const PropertyTreeState& source,
const PropertyTreeState& destination);
bool ChangedEnough(const CullRect& old_cull_rect) const; bool ChangedEnough(const CullRect& old_cull_rect,
const IntSize* bounds) const;
IntRect rect_; IntRect rect_;
}; };
......
...@@ -21,14 +21,27 @@ class CullRectTest : public testing::Test { ...@@ -21,14 +21,27 @@ class CullRectTest : public testing::Test {
const CullRect::ApplyTransformResult kExpandedForWholeScrollingContents = const CullRect::ApplyTransformResult kExpandedForWholeScrollingContents =
CullRect::kExpandedForWholeScrollingContents; CullRect::kExpandedForWholeScrollingContents;
CullRect::ApplyTransformResult ApplyTransform( // Tests only transforms without clips.
void ApplyTransforms(CullRect& cull_rect,
const TransformPaintPropertyNode& source,
const TransformPaintPropertyNode& destination,
const base::Optional<CullRect>& old_cull_rect) {
PropertyTreeState source_state(source, c0(), e0());
PropertyTreeState destination_state(destination, c0(), e0());
cull_rect.ApplyPaintProperties(PropertyTreeState::Root(), source_state,
destination_state, old_cull_rect);
}
CullRect::ApplyTransformResult ApplyScrollTranslation(
CullRect& cull_rect, CullRect& cull_rect,
const TransformPaintPropertyNode& t) { const TransformPaintPropertyNode& t) {
return cull_rect.ApplyTransformInternal(t); return cull_rect.ApplyScrollTranslation(t, t);
} }
bool ChangedEnough(const IntRect& old_rect, const IntRect& new_rect) { bool ChangedEnough(const IntRect& old_rect,
return CullRect(new_rect).ChangedEnough(CullRect(old_rect)); const IntRect& new_rect,
const IntSize* bounds = nullptr) {
return CullRect(new_rect).ChangedEnough(CullRect(old_rect), bounds);
} }
}; };
...@@ -91,7 +104,7 @@ TEST_F(CullRectTest, ApplyTransform) { ...@@ -91,7 +104,7 @@ TEST_F(CullRectTest, ApplyTransform) {
CullRect cull_rect(IntRect(1, 1, 50, 50)); CullRect cull_rect(IntRect(1, 1, 50, 50));
auto transform = auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 1)); CreateTransform(t0(), TransformationMatrix().Translate(1, 1));
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *transform)); cull_rect.ApplyTransform(*transform);
EXPECT_EQ(IntRect(0, 0, 50, 50), cull_rect.Rect()); EXPECT_EQ(IntRect(0, 0, 50, 50), cull_rect.Rect());
} }
...@@ -100,13 +113,12 @@ TEST_F(CullRectTest, ApplyTransformInfinite) { ...@@ -100,13 +113,12 @@ TEST_F(CullRectTest, ApplyTransformInfinite) {
CullRect cull_rect = CullRect::Infinite(); CullRect cull_rect = CullRect::Infinite();
auto transform = auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 1)); CreateTransform(t0(), TransformationMatrix().Translate(1, 1));
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *transform)); cull_rect.ApplyTransform(*transform);
EXPECT_TRUE(cull_rect.IsInfinite()); EXPECT_TRUE(cull_rect.IsInfinite());
} }
TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) { TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state; ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50); scroll_state.container_rect = IntRect(20, 10, 40, 50);
...@@ -118,24 +130,25 @@ TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) { ...@@ -118,24 +130,25 @@ TEST_F(CullRectTest, ApplyScrollTranslationPartialScrollingContents) {
CullRect cull_rect(IntRect(0, 0, 50, 100)); CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kExpandedForPartialScrollingContents, EXPECT_EQ(kExpandedForPartialScrollingContents,
ApplyTransform(cull_rect, *scroll_translation)); ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50) // Clipped: (20, 10, 30, 50)
// Inverse transformed: (3020, 5010, 30, 50) // Inverse transformed: (3020, 5010, 30, 50)
// Expanded: (-980, 1010, 8030, 8050) // Expanded: (-980, 1010, 8030, 8050)
EXPECT_EQ(IntRect(-980, 1010, 8030, 8050), cull_rect.Rect()); // Then clipped by the contents rect.
EXPECT_EQ(IntRect(0, 1010, 7050, 6990), cull_rect.Rect());
cull_rect = CullRect::Infinite(); cull_rect = CullRect::Infinite();
EXPECT_EQ(kExpandedForPartialScrollingContents, EXPECT_EQ(kExpandedForPartialScrollingContents,
ApplyTransform(cull_rect, *scroll_translation)); ApplyScrollTranslation(cull_rect, *scroll_translation));
// This result differs from the above result in height (8040 vs 8030) // This result differs from the above result in height (7050 vs 7060)
// because it's not clipped by the infinite input cull rect. // because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(-980, 1010, 8040, 8050), cull_rect.Rect()); EXPECT_EQ(IntRect(0, 1010, 7060, 6990), cull_rect.Rect());
} }
TEST_F(CullRectTest, TEST_F(CullRectTest,
ApplyNonCompositedScrollTranslationPartialScrollingContents) { ApplyNonCompositedScrollTranslationPartialScrollingContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state; ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50); scroll_state.container_rect = IntRect(20, 10, 40, 50);
...@@ -146,21 +159,23 @@ TEST_F(CullRectTest, ...@@ -146,21 +159,23 @@ TEST_F(CullRectTest,
CreateScrollTranslation(t0(), -3000, -5000, *scroll); CreateScrollTranslation(t0(), -3000, -5000, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100)); CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation)); EXPECT_EQ(kNotExpanded,
ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50) // Clipped: (20, 10, 30, 50)
// Inverse transformed: (3020, 5010, 30, 50) // Inverse transformed: (3020, 5010, 30, 50)
EXPECT_EQ(IntRect(3020, 5010, 30, 50), cull_rect.Rect()); EXPECT_EQ(IntRect(3020, 5010, 30, 50), cull_rect.Rect());
cull_rect = CullRect::Infinite(); cull_rect = CullRect::Infinite();
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation)); EXPECT_EQ(kNotExpanded,
ApplyScrollTranslation(cull_rect, *scroll_translation));
// This result differs from the above result in height (40 vs 30) // This result differs from the above result in height (40 vs 30)
// because it's not clipped by the infinite input cull rect. // because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(3020, 5010, 40, 50), cull_rect.Rect()); EXPECT_EQ(IntRect(3020, 5010, 40, 50), cull_rect.Rect());
} }
TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) { TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state; ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(200, 100, 40, 50); scroll_state.container_rect = IntRect(200, 100, 40, 50);
...@@ -171,13 +186,14 @@ TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) { ...@@ -171,13 +186,14 @@ TEST_F(CullRectTest, ApplyScrollTranslationNoIntersectionWithContainerRect) {
CreateCompositedScrollTranslation(t0(), -10, -15, *scroll); CreateCompositedScrollTranslation(t0(), -10, -15, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100)); CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation)); EXPECT_EQ(kNotExpanded,
ApplyScrollTranslation(cull_rect, *scroll_translation));
EXPECT_TRUE(cull_rect.Rect().IsEmpty()); EXPECT_TRUE(cull_rect.Rect().IsEmpty());
} }
TEST_F(CullRectTest, TEST_F(CullRectTest,
ApplyNonCompositedScrollTranslationNoIntersectionWithContainerRect) { ApplyNonCompositedScrollTranslationNoIntersectionWithContainerRect) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state; ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(200, 100, 40, 50); scroll_state.container_rect = IntRect(200, 100, 40, 50);
...@@ -187,12 +203,13 @@ TEST_F(CullRectTest, ...@@ -187,12 +203,13 @@ TEST_F(CullRectTest,
auto scroll_translation = CreateScrollTranslation(t0(), -10, -15, *scroll); auto scroll_translation = CreateScrollTranslation(t0(), -10, -15, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100)); CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation)); EXPECT_EQ(kNotExpanded,
ApplyScrollTranslation(cull_rect, *scroll_translation));
EXPECT_TRUE(cull_rect.Rect().IsEmpty()); EXPECT_TRUE(cull_rect.Rect().IsEmpty());
} }
TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) { TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state; ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50); scroll_state.container_rect = IntRect(20, 10, 40, 50);
...@@ -204,24 +221,23 @@ TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) { ...@@ -204,24 +221,23 @@ TEST_F(CullRectTest, ApplyScrollTranslationWholeScrollingContents) {
CullRect cull_rect(IntRect(0, 0, 50, 100)); CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kExpandedForWholeScrollingContents, EXPECT_EQ(kExpandedForWholeScrollingContents,
ApplyTransform(cull_rect, *scroll_translation)); ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50) // Clipped: (20, 10, 30, 50)
// Inverse transformed: (30, 25, 30, 50) // Inverse transformed: (30, 25, 30, 50)
// Expanded: (-3970, -3975, 8030, 8050) // Expanded: (-3970, -3975, 8030, 8050)
EXPECT_EQ(IntRect(-3970, -3975, 8030, 8050), cull_rect.Rect()); // Then clipped by the contents rect.
EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect.Rect());
cull_rect = CullRect::Infinite(); cull_rect = CullRect::Infinite();
EXPECT_EQ(kExpandedForWholeScrollingContents, EXPECT_EQ(kExpandedForWholeScrollingContents,
ApplyTransform(cull_rect, *scroll_translation)); ApplyScrollTranslation(cull_rect, *scroll_translation));
// This result differs from the above result in height (8040 vs 8030) EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect.Rect());
// because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(-3970, -3975, 8040, 8050), cull_rect.Rect());
} }
TEST_F(CullRectTest, TEST_F(CullRectTest,
ApplyNonCompositedScrollTranslationWholeScrollingContents) { ApplyNonCompositedScrollTranslationWholeScrollingContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
ScrollPaintPropertyNode::State scroll_state; ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = IntRect(20, 10, 40, 50); scroll_state.container_rect = IntRect(20, 10, 40, 50);
...@@ -231,21 +247,23 @@ TEST_F(CullRectTest, ...@@ -231,21 +247,23 @@ TEST_F(CullRectTest,
auto scroll_translation = CreateScrollTranslation(t0(), -10, -15, *scroll); auto scroll_translation = CreateScrollTranslation(t0(), -10, -15, *scroll);
CullRect cull_rect(IntRect(0, 0, 50, 100)); CullRect cull_rect(IntRect(0, 0, 50, 100));
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation)); EXPECT_EQ(kNotExpanded,
ApplyScrollTranslation(cull_rect, *scroll_translation));
// Clipped: (20, 10, 30, 50) // Clipped: (20, 10, 30, 50)
// Inverse transformed: (30, 25, 30, 50) // Inverse transformed: (30, 25, 30, 50)
EXPECT_EQ(IntRect(30, 25, 30, 50), cull_rect.Rect()); EXPECT_EQ(IntRect(30, 25, 30, 50), cull_rect.Rect());
cull_rect = CullRect::Infinite(); cull_rect = CullRect::Infinite();
EXPECT_EQ(kNotExpanded, ApplyTransform(cull_rect, *scroll_translation)); EXPECT_EQ(kNotExpanded,
ApplyScrollTranslation(cull_rect, *scroll_translation));
// This result differs from the above result in height (40 vs 30) // This result differs from the above result in height (40 vs 30)
// because it's not clipped by the infinite input cull rect. // because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(30, 25, 40, 50), cull_rect.Rect()); EXPECT_EQ(IntRect(30, 25, 40, 50), cull_rect.Rect());
} }
TEST_F(CullRectTest, ChangedEnoughEmpty) { TEST_F(CullRectTest, ChangedEnoughEmpty) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
EXPECT_FALSE(ChangedEnough(IntRect(), IntRect())); EXPECT_FALSE(ChangedEnough(IntRect(), IntRect()));
EXPECT_FALSE(ChangedEnough(IntRect(1, 1, 0, 0), IntRect(2, 2, 0, 0))); EXPECT_FALSE(ChangedEnough(IntRect(1, 1, 0, 0), IntRect(2, 2, 0, 0)));
EXPECT_TRUE(ChangedEnough(IntRect(), IntRect(0, 0, 1, 1))); EXPECT_TRUE(ChangedEnough(IntRect(), IntRect(0, 0, 1, 1)));
...@@ -253,7 +271,7 @@ TEST_F(CullRectTest, ChangedEnoughEmpty) { ...@@ -253,7 +271,7 @@ TEST_F(CullRectTest, ChangedEnoughEmpty) {
} }
TEST_F(CullRectTest, ChangedNotEnough) { TEST_F(CullRectTest, ChangedNotEnough) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
IntRect old_rect(100, 100, 100, 100); IntRect old_rect(100, 100, 100, 100);
EXPECT_FALSE(ChangedEnough(old_rect, old_rect)); EXPECT_FALSE(ChangedEnough(old_rect, old_rect));
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 90, 90))); EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 90, 90)));
...@@ -261,8 +279,8 @@ TEST_F(CullRectTest, ChangedNotEnough) { ...@@ -261,8 +279,8 @@ TEST_F(CullRectTest, ChangedNotEnough) {
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(1, 1, 200, 200))); EXPECT_FALSE(ChangedEnough(old_rect, IntRect(1, 1, 200, 200)));
} }
TEST_F(CullRectTest, ChangedEnoughScrollScenarios) { TEST_F(CullRectTest, ChangedEnoughOnMovement) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
IntRect old_rect(100, 100, 100, 100); IntRect old_rect(100, 100, 100, 100);
IntRect new_rect(old_rect); IntRect new_rect(old_rect);
new_rect.Move(500, 0); new_rect.Move(500, 0);
...@@ -275,241 +293,351 @@ TEST_F(CullRectTest, ChangedEnoughScrollScenarios) { ...@@ -275,241 +293,351 @@ TEST_F(CullRectTest, ChangedEnoughScrollScenarios) {
EXPECT_TRUE(ChangedEnough(old_rect, new_rect)); EXPECT_TRUE(ChangedEnough(old_rect, new_rect));
} }
TEST_F(CullRectTest, ApplyTransformsSameTransform) { TEST_F(CullRectTest, ChangedEnoughNewRectTouchingEdge) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
IntSize bounds(500, 500);
IntRect old_rect(100, 100, 100, 100);
// Top edge.
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 50, 100, 200), &bounds));
EXPECT_TRUE(ChangedEnough(old_rect, IntRect(100, 0, 100, 200), &bounds));
// Left edge.
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(50, 100, 200, 100), &bounds));
EXPECT_TRUE(ChangedEnough(old_rect, IntRect(0, 100, 200, 100), &bounds));
// Bottom edge.
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 100, 350), &bounds));
EXPECT_TRUE(ChangedEnough(old_rect, IntRect(100, 100, 100, 400), &bounds));
// Right edge.
EXPECT_FALSE(ChangedEnough(old_rect, IntRect(100, 100, 350, 100), &bounds));
EXPECT_TRUE(ChangedEnough(old_rect, IntRect(100, 100, 400, 100), &bounds));
}
TEST_F(CullRectTest, ChangedEnoughOldRectTouchingEdge) {
ScopedCullRectUpdateForTest cull_rect_update(true);
IntSize bounds(500, 500);
IntRect new_rect(100, 100, 300, 300);
// Top edge.
EXPECT_FALSE(ChangedEnough(IntRect(100, 0, 100, 100), new_rect, &bounds));
// Left edge.
EXPECT_FALSE(ChangedEnough(IntRect(0, 100, 100, 100), new_rect, &bounds));
// Bottom edge.
EXPECT_FALSE(ChangedEnough(IntRect(300, 400, 100, 100), new_rect, &bounds));
// Right edge.
EXPECT_FALSE(ChangedEnough(IntRect(400, 300, 100, 100), new_rect, &bounds));
}
TEST_F(CullRectTest, ApplyPaintPropertiesSameState) {
ScopedCullRectUpdateForTest cull_rect_update(true);
auto transform = auto transform =
CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
auto clip = CreateClip(c0(), t0(), FloatRoundedRect(1, 2, 3, 4));
PropertyTreeState root = PropertyTreeState::Root();
PropertyTreeState state(*transform, *clip, e0());
CullRect cull_rect1(IntRect(1, 1, 50, 50)); CullRect cull_rect1(IntRect(1, 1, 50, 50));
cull_rect1.ApplyTransforms(*transform, *transform, base::nullopt); cull_rect1.ApplyPaintProperties(state, state, state, base::nullopt);
EXPECT_EQ(IntRect(1, 1, 50, 50), cull_rect1.Rect());
cull_rect1.ApplyPaintProperties(root, state, state, base::nullopt);
EXPECT_EQ(IntRect(1, 1, 50, 50), cull_rect1.Rect()); EXPECT_EQ(IntRect(1, 1, 50, 50), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1; CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1)); old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(1, 1, 50, 50)); CullRect cull_rect2(IntRect(1, 1, 50, 50));
// Should ignore old_cull_rect. // Should ignore old_cull_rect.
cull_rect2.ApplyTransforms(*transform, *transform, old_cull_rect); cull_rect2.ApplyPaintProperties(state, state, state, old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
cull_rect2.ApplyPaintProperties(root, state, state, old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2); EXPECT_EQ(cull_rect1, cull_rect2);
CullRect infinite = CullRect::Infinite(); CullRect infinite = CullRect::Infinite();
infinite.ApplyTransforms(*transform, *transform, base::nullopt); infinite.ApplyPaintProperties(state, state, state, base::nullopt);
EXPECT_TRUE(infinite.IsInfinite());
infinite.ApplyPaintProperties(root, state, state, base::nullopt);
EXPECT_TRUE(infinite.IsInfinite()); EXPECT_TRUE(infinite.IsInfinite());
} }
TEST_F(CullRectTest, ApplyTransformsWithoutScroll) { TEST_F(CullRectTest, ApplyPaintPropertiesWithoutClipScroll) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
auto t2 = CreateTransform(*t1, TransformationMatrix().Translate(10, 20)); auto t2 = CreateTransform(*t1, TransformationMatrix().Translate(10, 20));
PropertyTreeState root = PropertyTreeState::Root();
PropertyTreeState state1(*t1, c0(), e0());
PropertyTreeState state2(*t2, c0(), e0());
CullRect cull_rect1(IntRect(1, 1, 50, 50)); CullRect cull_rect1(IntRect(1, 1, 50, 50));
cull_rect1.ApplyTransforms(*t1, *t2, base::nullopt); cull_rect1.ApplyPaintProperties(root, state1, state2, base::nullopt);
EXPECT_EQ(IntRect(-9, -19, 50, 50), cull_rect1.Rect()); EXPECT_EQ(IntRect(-9, -19, 50, 50), cull_rect1.Rect());
CullRect cull_rect2(IntRect(1, 1, 50, 50)); CullRect cull_rect2(IntRect(1, 1, 50, 50));
cull_rect2.ApplyTransforms(t0(), *t2, base::nullopt); cull_rect2.ApplyPaintProperties(root, root, state2, base::nullopt);
EXPECT_EQ(IntRect(-10, -21, 50, 50), cull_rect2.Rect()); EXPECT_EQ(IntRect(-10, -21, 50, 50), cull_rect2.Rect());
CullRect old_cull_rect = cull_rect2; CullRect old_cull_rect = cull_rect2;
old_cull_rect.Move(IntSize(1, 1)); old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect3(IntRect(1, 1, 50, 50)); CullRect cull_rect3(IntRect(1, 1, 50, 50));
// Should ignore old_cull_rect. // Should ignore old_cull_rect.
cull_rect3.ApplyTransforms(t0(), *t2, old_cull_rect); cull_rect3.ApplyPaintProperties(root, root, state2, old_cull_rect);
EXPECT_EQ(cull_rect2, cull_rect3); EXPECT_EQ(cull_rect2, cull_rect3);
CullRect infinite = CullRect::Infinite(); CullRect infinite = CullRect::Infinite();
infinite.ApplyTransforms(t0(), *t2, base::nullopt); infinite.ApplyPaintProperties(root, root, state2, base::nullopt);
EXPECT_TRUE(infinite.IsInfinite()); EXPECT_TRUE(infinite.IsInfinite());
} }
TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) { TEST_F(CullRectTest, ApplyTransformsSingleScrollWholeScrollingContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
ScrollPaintPropertyNode::State scroll_state; auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
scroll_state.container_rect = IntRect(20, 10, 40, 50); PropertyTreeState state1(*t1, c0(), e0());
scroll_state.contents_size = IntSize(2000, 2000); auto ref_scroll_translation_state = CreateCompositedScrollTranslationState(
auto scroll = ScrollPaintPropertyNode::Create(ScrollPaintPropertyNode::Root(), state1, -10, -15, IntRect(20, 10, 40, 50), IntSize(2000, 2000));
std::move(scroll_state)); auto scroll_translation_state =
auto scroll_translation = ref_scroll_translation_state.GetPropertyTreeState().Unalias();
CreateCompositedScrollTranslation(*t1, -10, -15, *scroll);
// Same as ApplyScrollTranslationWholeScrollingContents. // Same as ApplyScrollTranslationWholeScrollingContents.
CullRect cull_rect1(IntRect(0, 0, 50, 100)); CullRect cull_rect1(IntRect(0, 0, 50, 100));
cull_rect1.ApplyTransforms(*t1, *scroll_translation, base::nullopt); cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state,
EXPECT_EQ(IntRect(-3970, -3975, 8030, 8050), cull_rect1.Rect()); base::nullopt);
EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1; CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1)); old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 50, 100)); CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Should ignore old_cull_rect. // Should ignore old_cull_rect.
cull_rect2.ApplyTransforms(*t1, *scroll_translation, old_cull_rect); cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state,
old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2); EXPECT_EQ(cull_rect1, cull_rect2);
CullRect cull_rect3 = CullRect::Infinite(); CullRect cull_rect3 = CullRect::Infinite();
cull_rect3.ApplyTransforms(*t1, *scroll_translation, base::nullopt); cull_rect3.ApplyPaintProperties(state1, state1, scroll_translation_state,
// This result differs from the first result in height (8040 vs 8030) base::nullopt);
// because it's not clipped by the infinite input cull rect. EXPECT_EQ(IntRect(0, 0, 2000, 2000), cull_rect3.Rect());
EXPECT_EQ(IntRect(-3970, -3975, 8040, 8050), cull_rect3.Rect());
} }
TEST_F(CullRectTest, ApplyTransformsWithOrigin) { TEST_F(CullRectTest, ApplyTransformsWithOrigin) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
auto t2 = CreateTransform(*t1, TransformationMatrix().Scale(0.5), auto t2 = CreateTransform(*t1, TransformationMatrix().Scale(0.5),
FloatPoint3D(50, 100, 0)); FloatPoint3D(50, 100, 0));
PropertyTreeState root = PropertyTreeState::Root();
PropertyTreeState state1(*t1, c0(), e0());
PropertyTreeState state2(*t2, c0(), e0());
CullRect cull_rect1(IntRect(0, 0, 50, 200)); CullRect cull_rect1(IntRect(0, 0, 50, 200));
cull_rect1.ApplyTransforms(*t1, *t2, base::nullopt); cull_rect1.ApplyPaintProperties(root, state1, state2, base::nullopt);
EXPECT_EQ(IntRect(-50, -100, 100, 400), cull_rect1.Rect()); EXPECT_EQ(IntRect(-50, -100, 100, 400), cull_rect1.Rect());
} }
TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) { TEST_F(CullRectTest, ApplyTransformsSingleScrollPartialScrollingContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
PropertyTreeState state1(*t1, c0(), e0());
ScrollPaintPropertyNode::State scroll_state; auto ref_scroll_translation_state = CreateCompositedScrollTranslationState(
scroll_state.container_rect = IntRect(20, 10, 40, 50); state1, -3000, -5000, IntRect(20, 10, 40, 50), IntSize(8000, 8000));
scroll_state.contents_size = IntSize(8000, 8000); auto scroll_translation_state =
auto scroll = ScrollPaintPropertyNode::Create(ScrollPaintPropertyNode::Root(), ref_scroll_translation_state.GetPropertyTreeState().Unalias();
std::move(scroll_state));
auto scroll_translation =
CreateCompositedScrollTranslation(*t1, -3000, -5000, *scroll);
// Same as ApplyScrollTranslationPartialScrollingContents. // Same as ApplyScrollTranslationPartialScrollingContents.
CullRect cull_rect1(IntRect(0, 0, 50, 100)); CullRect cull_rect1(IntRect(0, 0, 50, 100));
cull_rect1.ApplyTransforms(*t1, *scroll_translation, base::nullopt); cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state,
EXPECT_EQ(IntRect(-980, 1010, 8030, 8050), cull_rect1.Rect()); base::nullopt);
EXPECT_EQ(IntRect(0, 1010, 7050, 6990), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1; CullRect old_cull_rect(IntRect(0, 1100, 7050, 6900));
old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 50, 100)); CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Use old_cull_rect if the new cull rect didn't change enough. // Use old_cull_rect if the new cull rect didn't change enough.
cull_rect2.ApplyTransforms(*t1, *scroll_translation, old_cull_rect); cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state,
old_cull_rect);
EXPECT_EQ(old_cull_rect, cull_rect2); EXPECT_EQ(old_cull_rect, cull_rect2);
old_cull_rect.Move(IntSize(1000, 1000)); old_cull_rect.Move(IntSize(1000, 1000));
CullRect cull_rect3(IntRect(0, 0, 50, 100)); CullRect cull_rect3(IntRect(0, 0, 50, 100));
// Use the new cull rect if it changed enough. // Use the new cull rect if it changed enough.
cull_rect3.ApplyTransforms(*t1, *scroll_translation, old_cull_rect); cull_rect3.ApplyPaintProperties(state1, state1, scroll_translation_state,
old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect3); EXPECT_EQ(cull_rect1, cull_rect3);
CullRect cull_rect4 = CullRect::Infinite(); CullRect cull_rect4 = CullRect::Infinite();
cull_rect4.ApplyTransforms(*t1, *scroll_translation, base::nullopt); cull_rect4.ApplyPaintProperties(state1, state1, scroll_translation_state,
// This result differs from the first result in height (8040 vs 8030) base::nullopt);
// This result differs from the first result in height (7050 vs 7060)
// because it's not clipped by the infinite input cull rect. // because it's not clipped by the infinite input cull rect.
EXPECT_EQ(IntRect(-980, 1010, 8040, 8050), cull_rect4.Rect()); EXPECT_EQ(IntRect(0, 1010, 7060, 6990), cull_rect4.Rect());
} }
TEST_F(CullRectTest, ApplyTransformsEscapingScroll) { TEST_F(CullRectTest, ApplyTransformsEscapingScroll) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
PropertyTreeState root = PropertyTreeState::Root();
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(111, 222, 333, 444));
PropertyTreeState state1(*t1, *c1, e0());
ScrollPaintPropertyNode::State scroll_state; auto ref_scroll_translation_state = CreateCompositedScrollTranslationState(
scroll_state.container_rect = IntRect(20, 10, 40, 50); state1, -3000, -5000, IntRect(20, 10, 40, 50), IntSize(8000, 8000));
scroll_state.contents_size = IntSize(8000, 8000); auto scroll_translation_state =
auto scroll = ScrollPaintPropertyNode::Create(ScrollPaintPropertyNode::Root(), ref_scroll_translation_state.GetPropertyTreeState().Unalias();
std::move(scroll_state));
auto scroll_translation = auto t2 = CreateTransform(scroll_translation_state.Transform(),
CreateCompositedScrollTranslation(*t1, -3000, -5000, *scroll);
auto t2 = CreateTransform(*scroll_translation,
TransformationMatrix().Translate(100, 200)); TransformationMatrix().Translate(100, 200));
PropertyTreeState state2(*t2, scroll_translation_state.Clip(), e0());
CullRect cull_rect1(IntRect(0, 0, 50, 100)); CullRect cull_rect1(IntRect(0, 0, 50, 100));
// Just apply tranforms without clipping and expansion for scroll translation. // Ignore the current cull rect, and apply paint properties from root to
cull_rect1.ApplyTransforms(*t2, *t1, base::nullopt); // state1 on infinite cull rect instead.
EXPECT_EQ(IntRect(-2900, -4800, 50, 100), cull_rect1.Rect()); cull_rect1.ApplyPaintProperties(root, state2, state1, base::nullopt);
EXPECT_EQ(IntRect(110, 220, 333, 444), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1; CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1)); old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 50, 100)); CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Should ignore old_cull_rect. // Should ignore old_cull_rect.
cull_rect2.ApplyTransforms(*t2, *t1, old_cull_rect); cull_rect2.ApplyPaintProperties(root, state2, state1, old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2); EXPECT_EQ(cull_rect1, cull_rect2);
CullRect infinite = CullRect::Infinite(); CullRect cull_rect3 = CullRect::Infinite();
infinite.ApplyTransforms(*t2, *t1, base::nullopt); cull_rect3.ApplyPaintProperties(root, state2, state1, base::nullopt);
EXPECT_TRUE(infinite.IsInfinite()); EXPECT_EQ(cull_rect1, cull_rect3);
} }
TEST_F(CullRectTest, ApplyTransformsSmallScrollContentsAfterBigScrollContents) { TEST_F(CullRectTest, ApplyTransformsSmallScrollContentsAfterBigScrollContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
PropertyTreeState state1(*t1, c0(), e0());
ScrollPaintPropertyNode::State scroll_state1; auto ref_scroll_translation_state1 = CreateCompositedScrollTranslationState(
scroll_state1.container_rect = IntRect(20, 10, 40, 50); state1, -10, -15, IntRect(20, 10, 40, 50), IntSize(8000, 8000));
scroll_state1.contents_size = IntSize(8000, 8000); auto scroll_translation_state1 =
auto scroll1 = ScrollPaintPropertyNode::Create( ref_scroll_translation_state1.GetPropertyTreeState().Unalias();
ScrollPaintPropertyNode::Root(), std::move(scroll_state1));
auto scroll_translation1 =
CreateCompositedScrollTranslation(*t1, -10, -15, *scroll1);
auto t2 = CreateTransform(*scroll_translation1, auto t2 = CreateTransform(scroll_translation_state1.Transform(),
TransformationMatrix().Translate(2000, 3000)); TransformationMatrix().Translate(2000, 3000));
PropertyTreeState state2(*t2, scroll_translation_state1.Clip(), e0());
ScrollPaintPropertyNode::State scroll_state2; auto ref_scroll_translation_state2 = CreateCompositedScrollTranslationState(
scroll_state2.container_rect = IntRect(30, 20, 100, 200); state2, -10, -15, IntRect(30, 20, 100, 200), IntSize(200, 400));
scroll_state2.contents_size = IntSize(200, 400); auto scroll_translation_state2 =
auto scroll2 = ScrollPaintPropertyNode::Create( ref_scroll_translation_state2.GetPropertyTreeState().Unalias();
ScrollPaintPropertyNode::Root(), std::move(scroll_state2));
auto scroll_translation2 =
CreateCompositedScrollTranslation(*t2, -10, -15, *scroll2);
CullRect cull_rect1(IntRect(0, 0, 50, 100)); CullRect cull_rect1(IntRect(0, 0, 50, 100));
cull_rect1.ApplyTransforms(*t1, *scroll_translation2, base::nullopt); cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state2,
EXPECT_EQ(IntRect(-3960, -3965, 8100, 8200), cull_rect1.Rect()); base::nullopt);
EXPECT_EQ(IntRect(0, 0, 200, 400), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1; CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(1, 1)); old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 50, 100)); CullRect cull_rect2(IntRect(0, 0, 50, 100));
// Should ignore old_cull_rect. // Should ignore old_cull_rect.
cull_rect2.ApplyTransforms(*t1, *scroll_translation2, old_cull_rect); cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state2,
old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2); EXPECT_EQ(cull_rect1, cull_rect2);
} }
TEST_F(CullRectTest, ApplyTransformsBigScrollContentsAfterSmallScrollContents) { TEST_F(CullRectTest, ApplyTransformsBigScrollContentsAfterSmallScrollContents) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCullRectUpdateForTest cull_rect_update(true);
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(1, 2));
PropertyTreeState state1(*t1, c0(), e0());
ScrollPaintPropertyNode::State scroll_state1; auto ref_scroll_translation_state1 = CreateCompositedScrollTranslationState(
scroll_state1.container_rect = IntRect(30, 20, 100, 200); state1, -10, -15, IntRect(30, 20, 100, 200), IntSize(200, 400));
scroll_state1.contents_size = IntSize(200, 400); auto scroll_translation_state1 =
auto scroll1 = ScrollPaintPropertyNode::Create( ref_scroll_translation_state1.GetPropertyTreeState().Unalias();
ScrollPaintPropertyNode::Root(), std::move(scroll_state1));
auto scroll_translation1 =
CreateCompositedScrollTranslation(*t1, -10, -15, *scroll1);
auto t2 = CreateTransform(*scroll_translation1, auto t2 = CreateTransform(scroll_translation_state1.Transform(),
TransformationMatrix().Translate(10, 20)); TransformationMatrix().Translate(10, 20));
PropertyTreeState state2(*t2, scroll_translation_state1.Clip(), e0());
ScrollPaintPropertyNode::State scroll_state2; auto ref_scroll_translation_state2 = CreateCompositedScrollTranslationState(
scroll_state2.container_rect = IntRect(20, 10, 50, 100); state2, -3000, -5000, IntRect(20, 10, 50, 100), IntSize(10000, 20000));
scroll_state2.contents_size = IntSize(10000, 20000); auto scroll_translation_state2 =
auto scroll2 = ScrollPaintPropertyNode::Create( ref_scroll_translation_state2.GetPropertyTreeState().Unalias();
ScrollPaintPropertyNode::Root(), std::move(scroll_state2));
auto scroll_translation2 =
CreateCompositedScrollTranslation(*t2, -3000, -5000, *scroll2);
CullRect cull_rect1(IntRect(0, 0, 100, 200)); CullRect cull_rect1(IntRect(0, 0, 100, 200));
cull_rect1.ApplyTransforms(*t1, *scroll_translation2, base::nullopt); cull_rect1.ApplyPaintProperties(state1, state1, scroll_translation_state2,
base::nullopt);
// After the first scroll: (-3960, -3965, 8070, 8180) // After the first scroll: (-3960, -3965, 8070, 8180)
// After t2: (-3980, -3975, 8070, 8180) // After t2: (-3980, -3975, 8070, 8180)
// Clipped by the container rect of the second scroll: (20, 10, 50, 100) // Clipped by the container rect of the second scroll: (20, 10, 50, 100)
// After the second scroll offset: (3020, 5010, 50, 100) // After the second scroll offset: (3020, 5010, 50, 100)
// Expanded: (-980, 1010, 8050, 8100) // Expanded: (-980, 1010, 8050, 8100)
EXPECT_EQ(IntRect(-980, 1010, 8050, 8100), cull_rect1.Rect()); // Then clipped by the contents rect.
EXPECT_EQ(IntRect(0, 1010, 7070, 8100), cull_rect1.Rect());
CullRect old_cull_rect = cull_rect1; CullRect old_cull_rect(IntRect(0, 1100, 7070, 8100));
old_cull_rect.Move(IntSize(1, 1));
CullRect cull_rect2(IntRect(0, 0, 100, 200)); CullRect cull_rect2(IntRect(0, 0, 100, 200));
// Use old_cull_rect if the new cull rect didn't change enough. // Use old_cull_rect if the new cull rect didn't change enough.
cull_rect2.ApplyTransforms(*t1, *scroll_translation2, old_cull_rect); cull_rect2.ApplyPaintProperties(state1, state1, scroll_translation_state2,
old_cull_rect);
EXPECT_EQ(old_cull_rect, cull_rect2); EXPECT_EQ(old_cull_rect, cull_rect2);
old_cull_rect.Move(IntSize(1000, 1000)); old_cull_rect.Move(IntSize(1000, 1000));
CullRect cull_rect3(IntRect(0, 0, 100, 200)); CullRect cull_rect3(IntRect(0, 0, 100, 200));
// Use the new cull rect if it changed enough. // Use the new cull rect if it changed enough.
cull_rect3.ApplyTransforms(*t1, *scroll_translation2, old_cull_rect); cull_rect3.ApplyPaintProperties(state1, state1, scroll_translation_state2,
old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect3); EXPECT_EQ(cull_rect1, cull_rect3);
} }
TEST_F(CullRectTest, NonCompositedTransformUnderClip) {
ScopedCullRectUpdateForTest cull_rect_update(true);
PropertyTreeState root = PropertyTreeState::Root();
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(100, 200, 300, 400));
auto t1 = CreateTransform(t0(), TransformationMatrix().Translate(10, 20));
PropertyTreeState state1(*t1, *c1, e0());
CullRect cull_rect1(IntRect(0, 0, 300, 500));
cull_rect1.ApplyPaintProperties(root, root, state1, base::nullopt);
// Clip by c1, then transformed by t1.
EXPECT_EQ(IntRect(90, 180, 200, 300), cull_rect1.Rect());
CullRect cull_rect2(IntRect(0, 0, 300, 500));
CullRect old_cull_rect(IntRect(133, 244, 333, 444));
// Should ignore old_cull_rect.
cull_rect2.ApplyPaintProperties(root, root, state1, old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect2);
CullRect cull_rect3 = CullRect::Infinite();
cull_rect3.ApplyPaintProperties(root, root, state1, base::nullopt);
EXPECT_EQ(IntRect(90, 180, 300, 400), cull_rect3.Rect());
}
TEST_F(CullRectTest, CompositedTranslationUnderClip) {
ScopedCullRectUpdateForTest cull_rect_update(true);
PropertyTreeState root = PropertyTreeState::Root();
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(100, 200, 300, 400));
auto t1 = CreateTransform(
t0(), TransformationMatrix().Translate(10, 20).Scale3d(2, 3, 1),
FloatPoint3D(), CompositingReason::kWillChangeTransform);
PropertyTreeState state1(*t1, *c1, e0());
CullRect cull_rect1(IntRect(0, 0, 300, 500));
cull_rect1.ApplyPaintProperties(root, root, state1, base::nullopt);
// The result in NonCompositedTransformUnderClip expanded by 2000 (scaled by
// maximum of 1/2 and 1/3).
EXPECT_EQ(IntRect(-1955, -1940, 4100, 4100), cull_rect1.Rect());
CullRect cull_rect2(IntRect(0, 0, 300, 500));
CullRect old_cull_rect = cull_rect1;
old_cull_rect.Move(IntSize(200, 200));
// Use old_cull_rect if the new cull rect didn't change enough.
cull_rect2.ApplyPaintProperties(root, root, state1, old_cull_rect);
EXPECT_EQ(old_cull_rect, cull_rect2);
CullRect cull_rect3(IntRect(0, 0, 300, 500));
old_cull_rect.Move(IntSize(1000, 1000));
// Use the new cull rect if it changed enough.
cull_rect3.ApplyPaintProperties(root, root, state1, old_cull_rect);
EXPECT_EQ(cull_rect1, cull_rect3);
CullRect cull_rect4 = CullRect::Infinite();
cull_rect4.ApplyPaintProperties(root, root, state1, base::nullopt);
EXPECT_EQ(IntRect(-1955, -1940, 4150, 4134), cull_rect4.Rect());
}
TEST_F(CullRectTest, IntersectsVerticalRange) { TEST_F(CullRectTest, IntersectsVerticalRange) {
CullRect cull_rect(IntRect(0, 0, 50, 100)); CullRect cull_rect(IntRect(0, 0, 50, 100));
......
...@@ -653,6 +653,9 @@ ...@@ -653,6 +653,9 @@
name: "CSSVariables2TransformValues", name: "CSSVariables2TransformValues",
status: "test", status: "test",
}, },
{
name: "CullRectUpdate",
},
{ {
name: "CustomElementDefaultStyle", name: "CustomElementDefaultStyle",
status: "experimental", status: "experimental",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h" #include "third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h" #include "third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h"
#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h" #include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
#include "third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h"
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h" #include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
#include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h" #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
...@@ -23,6 +24,9 @@ inline const ClipPaintPropertyNode& c0() { ...@@ -23,6 +24,9 @@ inline const ClipPaintPropertyNode& c0() {
inline const EffectPaintPropertyNode& e0() { inline const EffectPaintPropertyNode& e0() {
return EffectPaintPropertyNode::Root(); return EffectPaintPropertyNode::Root();
} }
inline const ScrollPaintPropertyNode& s0() {
return ScrollPaintPropertyNode::Root();
}
constexpr int c0_id = 1; constexpr int c0_id = 1;
constexpr int e0_id = 1; constexpr int e0_id = 1;
...@@ -217,6 +221,28 @@ inline scoped_refptr<TransformPaintPropertyNode> CreateScrollTranslation( ...@@ -217,6 +221,28 @@ inline scoped_refptr<TransformPaintPropertyNode> CreateScrollTranslation(
return TransformPaintPropertyNode::Create(parent, std::move(state)); return TransformPaintPropertyNode::Create(parent, std::move(state));
} }
inline scoped_refptr<TransformPaintPropertyNode> CreateScrollTranslation(
const TransformPaintPropertyNodeOrAlias& parent,
float offset_x,
float offset_y,
const IntRect& container_rect,
const IntSize& contents_size,
CompositingReasons compositing_reasons = CompositingReason::kNone) {
const auto* parent_scroll_translation = &parent.Unalias();
while (!parent_scroll_translation->ScrollNode())
parent_scroll_translation = parent_scroll_translation->UnaliasedParent();
ScrollPaintPropertyNode::State scroll_state;
scroll_state.container_rect = container_rect;
scroll_state.contents_size = contents_size;
TransformPaintPropertyNode::State translation_state{
FloatSize(offset_x, offset_y)};
translation_state.direct_compositing_reasons = compositing_reasons;
translation_state.scroll = ScrollPaintPropertyNode::Create(
*parent_scroll_translation->ScrollNode(), std::move(scroll_state));
return TransformPaintPropertyNode::Create(parent,
std::move(translation_state));
}
inline scoped_refptr<TransformPaintPropertyNode> inline scoped_refptr<TransformPaintPropertyNode>
CreateCompositedScrollTranslation( CreateCompositedScrollTranslation(
const TransformPaintPropertyNodeOrAlias& parent, const TransformPaintPropertyNodeOrAlias& parent,
...@@ -227,6 +253,46 @@ CreateCompositedScrollTranslation( ...@@ -227,6 +253,46 @@ CreateCompositedScrollTranslation(
CompositingReason::kOverflowScrolling); CompositingReason::kOverflowScrolling);
} }
inline scoped_refptr<TransformPaintPropertyNode>
CreateCompositedScrollTranslation(
const TransformPaintPropertyNodeOrAlias& parent,
float offset_x,
float offset_y,
const IntRect& container_rect,
const IntSize& contents_size) {
return CreateScrollTranslation(parent, offset_x, offset_y, container_rect,
contents_size,
CompositingReason::kOverflowScrolling);
}
inline RefCountedPropertyTreeState CreateScrollTranslationState(
const PropertyTreeState& parent_state,
float offset_x,
float offset_y,
const IntRect& container_rect,
const IntSize& contents_size,
CompositingReasons compositing_reasons = CompositingReason::kNone) {
return RefCountedPropertyTreeState(PropertyTreeState(
*CreateScrollTranslation(parent_state.Transform(), offset_x, offset_y,
container_rect, contents_size,
compositing_reasons),
*CreateClip(parent_state.Clip(), parent_state.Transform(),
FloatRoundedRect(container_rect)),
e0()));
}
inline RefCountedPropertyTreeState CreateCompositedScrollTranslationState(
const PropertyTreeState& parent_state,
float offset_x,
float offset_y,
const IntRect& container_rect,
const IntSize& contents_size,
CompositingReasons compositing_reasons = CompositingReason::kNone) {
return CreateScrollTranslationState(parent_state, offset_x, offset_y,
container_rect, contents_size,
CompositingReason::kOverflowScrolling);
}
inline PropertyTreeState DefaultPaintChunkProperties() { inline PropertyTreeState DefaultPaintChunkProperties() {
return PropertyTreeState::Root(); return PropertyTreeState::Root();
} }
......
...@@ -7,29 +7,11 @@ Layer tree when the fixed elements are out-of-view (should have just a root laye ...@@ -7,29 +7,11 @@ Layer tree when the fixed elements are out-of-view (should have just a root laye
"contentsOpaque": true, "contentsOpaque": true,
"backgroundColor": "#FFFFFF" "backgroundColor": "#FFFFFF"
}, },
{
"name": "LayoutNGBlockFlow (positioned) DIV id='fixed1'",
"bounds": [10, 10],
"contentsOpaque": true,
"backgroundColor": "#C0C0C0",
"transform": 1
},
{ {
"name": "VerticalScrollbar", "name": "VerticalScrollbar",
"position": [785, 0], "position": [785, 0],
"bounds": [15, 600] "bounds": [15, 600]
} }
],
"transforms": [
{
"id": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[100, -100, 0, 1]
]
}
] ]
} }
......
...@@ -13,20 +13,6 @@ ...@@ -13,20 +13,6 @@
"backgroundColor": "#C0C0C0", "backgroundColor": "#C0C0C0",
"transform": 1 "transform": 1
}, },
{
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10],
"contentsOpaque": true,
"backgroundColor": "#C0C0C0",
"transform": 2
},
{
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10],
"contentsOpaque": true,
"backgroundColor": "#C0C0C0",
"transform": 3
},
{ {
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'", "name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10], "bounds": [10, 10],
...@@ -48,24 +34,6 @@ ...@@ -48,24 +34,6 @@
[0, 0, 1, 0], [0, 0, 1, 0],
[8, 1013, 0, 1] [8, 1013, 0, 1]
] ]
},
{
"id": 2,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[8, -100, 0, 1]
]
},
{
"id": 3,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[1000, 0, 0, 1]
]
} }
] ]
} }
......
...@@ -29,13 +29,6 @@ Not scaled: ...@@ -29,13 +29,6 @@ Not scaled:
"backgroundColor": "#C0C0C0", "backgroundColor": "#C0C0C0",
"transform": 4 "transform": 4
}, },
{
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10],
"contentsOpaque": true,
"backgroundColor": "#C0C0C0",
"transform": 5
},
{ {
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'", "name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10], "bounds": [10, 10],
...@@ -59,16 +52,6 @@ Not scaled: ...@@ -59,16 +52,6 @@ Not scaled:
{ {
"id": 2, "id": 2,
"parent": 1, "parent": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[8, -100, 0, 1]
]
},
{
"id": 3,
"parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
[0, 1, 0, 0], [0, 1, 0, 0],
...@@ -77,7 +60,7 @@ Not scaled: ...@@ -77,7 +60,7 @@ Not scaled:
] ]
}, },
{ {
"id": 4, "id": 3,
"parent": 1, "parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
...@@ -87,7 +70,7 @@ Not scaled: ...@@ -87,7 +70,7 @@ Not scaled:
] ]
}, },
{ {
"id": 5, "id": 4,
"parent": 1, "parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
...@@ -130,13 +113,6 @@ Scale=0.5: ...@@ -130,13 +113,6 @@ Scale=0.5:
"backgroundColor": "#C0C0C0", "backgroundColor": "#C0C0C0",
"transform": 4 "transform": 4
}, },
{
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10],
"contentsOpaque": true,
"backgroundColor": "#C0C0C0",
"transform": 5
},
{ {
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'", "name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10], "bounds": [10, 10],
...@@ -160,16 +136,6 @@ Scale=0.5: ...@@ -160,16 +136,6 @@ Scale=0.5:
{ {
"id": 2, "id": 2,
"parent": 1, "parent": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[8, -100, 0, 1]
]
},
{
"id": 3,
"parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
[0, 1, 0, 0], [0, 1, 0, 0],
...@@ -178,7 +144,7 @@ Scale=0.5: ...@@ -178,7 +144,7 @@ Scale=0.5:
] ]
}, },
{ {
"id": 4, "id": 3,
"parent": 1, "parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
...@@ -188,7 +154,7 @@ Scale=0.5: ...@@ -188,7 +154,7 @@ Scale=0.5:
] ]
}, },
{ {
"id": 5, "id": 4,
"parent": 1, "parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
...@@ -231,13 +197,6 @@ Scale=1.5: ...@@ -231,13 +197,6 @@ Scale=1.5:
"backgroundColor": "#C0C0C0", "backgroundColor": "#C0C0C0",
"transform": 4 "transform": 4
}, },
{
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10],
"contentsOpaque": true,
"backgroundColor": "#C0C0C0",
"transform": 5
},
{ {
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'", "name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10], "bounds": [10, 10],
...@@ -261,16 +220,6 @@ Scale=1.5: ...@@ -261,16 +220,6 @@ Scale=1.5:
{ {
"id": 2, "id": 2,
"parent": 1, "parent": 1,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[8, -100, 0, 1]
]
},
{
"id": 3,
"parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
[0, 1, 0, 0], [0, 1, 0, 0],
...@@ -279,7 +228,7 @@ Scale=1.5: ...@@ -279,7 +228,7 @@ Scale=1.5:
] ]
}, },
{ {
"id": 4, "id": 3,
"parent": 1, "parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
...@@ -289,7 +238,7 @@ Scale=1.5: ...@@ -289,7 +238,7 @@ Scale=1.5:
] ]
}, },
{ {
"id": 5, "id": 4,
"parent": 1, "parent": 1,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
......
...@@ -11,16 +11,6 @@ ...@@ -11,16 +11,6 @@
"bounds": [10, 10], "bounds": [10, 10],
"transform": 1 "transform": 1
}, },
{
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10],
"transform": 2
},
{
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10],
"transform": 3
},
{ {
"name": "LayoutNGBlockFlow (positioned) DIV class='fixed'", "name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
"bounds": [10, 10] "bounds": [10, 10]
...@@ -40,24 +30,6 @@ ...@@ -40,24 +30,6 @@
[0, 0, 1, 0], [0, 0, 1, 0],
[8, 1013, 0, 1] [8, 1013, 0, 1]
] ]
},
{
"id": 2,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[8, -100, 0, 1]
]
},
{
"id": 3,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[1000, 0, 0, 1]
]
} }
] ]
} }
......
...@@ -7,19 +7,12 @@ ...@@ -7,19 +7,12 @@
"backgroundColor": "#FFFFFF", "backgroundColor": "#FFFFFF",
"transform": 1 "transform": 1
}, },
{
"name": "LayoutNGBlockFlow (positioned) DIV",
"bounds": [88, 88],
"contentsOpaque": true,
"backgroundColor": "#C0C0C0",
"transform": 2
},
{ {
"name": "LayoutNGBlockFlow (positioned) DIV", "name": "LayoutNGBlockFlow (positioned) DIV",
"bounds": [99, 99], "bounds": [99, 99],
"contentsOpaque": true, "contentsOpaque": true,
"backgroundColor": "#C0C0C0", "backgroundColor": "#C0C0C0",
"transform": 3 "transform": 2
}, },
{ {
"name": "VerticalScrollbar", "name": "VerticalScrollbar",
...@@ -39,15 +32,6 @@ ...@@ -39,15 +32,6 @@
}, },
{ {
"id": 2, "id": 2,
"transform": [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[100, -300, 0, 1]
]
},
{
"id": 3,
"transform": [ "transform": [
[1, 0, 0, 0], [1, 0, 0, 0],
[0, 1, 0, 0], [0, 1, 0, 0],
......
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
"contentsOpaque": true, "contentsOpaque": true,
"backgroundColor": "#FFFFFF", "backgroundColor": "#FFFFFF",
"invalidations": [ "invalidations": [
[0, 0, 668, 236], [450, 0, 218, 236],
[704, 0, 214, 232], [704, 0, 214, 232],
[0, 0, 214, 232],
[700, 217, 4, 19] [700, 217, 4, 19]
] ]
}, },
......
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