blob: f49dd3f6bc818c327658c85e94160337c1215c57 [file] [log] [blame]
Chris Craikb565df12015-10-05 13:00:52 -07001/*
Chris Craik5ea17242016-01-11 14:07:59 -08002 * Copyright (C) 2016 The Android Open Source Project
Chris Craikb565df12015-10-05 13:00:52 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <BakedOpState.h>
Chris Craikd2dfd8f2015-12-16 14:27:20 -080020#include <DeferredLayerUpdater.h>
Chris Craikf158b492016-01-12 14:45:08 -080021#include <FrameBuilder.h>
Chris Craik8ecf41c2015-11-16 10:27:59 -080022#include <LayerUpdateQueue.h>
Chris Craikb565df12015-10-05 13:00:52 -070023#include <RecordedOp.h>
24#include <RecordingCanvas.h>
Chris Craik8160f202015-12-02 14:50:25 -080025#include <tests/common/TestUtils.h>
Chris Craikb565df12015-10-05 13:00:52 -070026
27#include <unordered_map>
28
29namespace android {
30namespace uirenderer {
31
Chris Craik8ecf41c2015-11-16 10:27:59 -080032const LayerUpdateQueue sEmptyLayerUpdateQueue;
Chris Craik6e068c012016-01-15 16:15:30 -080033const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
34
Chris Craik98787e62015-11-13 10:55:30 -080035
Chris Craik6fe991e52015-10-20 09:39:42 -070036/**
Chris Craik5854b342015-10-26 15:49:56 -070037 * Virtual class implemented by each test to redirect static operation / state transitions to
38 * virtual methods.
Chris Craik6fe991e52015-10-20 09:39:42 -070039 *
Chris Craik5854b342015-10-26 15:49:56 -070040 * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
41 * and allows Renderer vs Dispatching behavior to be merged.
Chris Craik6fe991e52015-10-20 09:39:42 -070042 *
43 * onXXXOp methods fail by default - tests should override ops they expect
Chris Craikd3daa312015-11-06 10:59:56 -080044 * startRepaintLayer fails by default - tests should override if expected
Chris Craik6fe991e52015-10-20 09:39:42 -070045 * startFrame/endFrame do nothing by default - tests should override to intercept
46 */
Chris Craik5854b342015-10-26 15:49:56 -070047class TestRendererBase {
Chris Craik6fe991e52015-10-20 09:39:42 -070048public:
Chris Craik5854b342015-10-26 15:49:56 -070049 virtual ~TestRendererBase() {}
Chris Craikd3daa312015-11-06 10:59:56 -080050 virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
Chris Craika6ac95e2015-11-02 18:06:59 -080051 ADD_FAILURE() << "Layer creation not expected in this test";
52 return nullptr;
53 }
Chris Craik98787e62015-11-13 10:55:30 -080054 virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
Chris Craika6ac95e2015-11-02 18:06:59 -080055 ADD_FAILURE() << "Layer repaint not expected in this test";
56 }
57 virtual void endLayer() {
58 ADD_FAILURE() << "Layer updates not expected in this test";
59 }
Chris Craik98787e62015-11-13 10:55:30 -080060 virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
Chris Craike4db79d2015-12-22 16:32:23 -080061 virtual void endFrame(const Rect& repaintRect) {}
Chris Craik6fe991e52015-10-20 09:39:42 -070062
Chris Craik15c3f192015-12-03 12:16:56 -080063 // define virtual defaults for single draw methods
64#define X(Type) \
Chris Craika6ac95e2015-11-02 18:06:59 -080065 virtual void on##Type(const Type&, const BakedOpState&) { \
66 ADD_FAILURE() << #Type " not expected in this test"; \
67 }
Chris Craik7cbf63d2016-01-06 13:46:52 -080068 MAP_RENDERABLE_OPS(X)
Chris Craik15c3f192015-12-03 12:16:56 -080069#undef X
70
71 // define virtual defaults for merged draw methods
72#define X(Type) \
73 virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
74 ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
75 }
Chris Craik7cbf63d2016-01-06 13:46:52 -080076 MAP_MERGEABLE_OPS(X)
Chris Craik15c3f192015-12-03 12:16:56 -080077#undef X
78
Chris Craik5854b342015-10-26 15:49:56 -070079 int getIndex() { return mIndex; }
Chris Craik6fe991e52015-10-20 09:39:42 -070080
Chris Craik5854b342015-10-26 15:49:56 -070081protected:
82 int mIndex = 0;
83};
84
85/**
86 * Dispatches all static methods to similar formed methods on renderer, which fail by default but
Chris Craik8ecf41c2015-11-16 10:27:59 -080087 * are overridden by subclasses per test.
Chris Craik5854b342015-10-26 15:49:56 -070088 */
89class TestDispatcher {
90public:
Chris Craik15c3f192015-12-03 12:16:56 -080091 // define single op methods, which redirect to TestRendererBase
92#define X(Type) \
Chris Craik5854b342015-10-26 15:49:56 -070093 static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
94 renderer.on##Type(op, state); \
Chris Craik6fe991e52015-10-20 09:39:42 -070095 }
Chris Craik7cbf63d2016-01-06 13:46:52 -080096 MAP_RENDERABLE_OPS(X);
Chris Craik15c3f192015-12-03 12:16:56 -080097#undef X
98
99 // define merged op methods, which redirect to TestRendererBase
100#define X(Type) \
101 static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
102 renderer.onMerged##Type##s(opList); \
103 }
Chris Craik7cbf63d2016-01-06 13:46:52 -0800104 MAP_MERGEABLE_OPS(X);
Chris Craik15c3f192015-12-03 12:16:56 -0800105#undef X
Chris Craik6fe991e52015-10-20 09:39:42 -0700106};
Chris Craikb565df12015-10-05 13:00:52 -0700107
Chris Craik5854b342015-10-26 15:49:56 -0700108class FailRenderer : public TestRendererBase {};
Chris Craik6fe991e52015-10-20 09:39:42 -0700109
Chris Craikf158b492016-01-12 14:45:08 -0800110TEST(FrameBuilder, simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800111 class SimpleTestRenderer : public TestRendererBase {
112 public:
Chris Craik98787e62015-11-13 10:55:30 -0800113 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800114 EXPECT_EQ(0, mIndex++);
115 EXPECT_EQ(100u, width);
116 EXPECT_EQ(200u, height);
117 }
118 void onRectOp(const RectOp& op, const BakedOpState& state) override {
119 EXPECT_EQ(1, mIndex++);
120 }
121 void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
122 EXPECT_EQ(2, mIndex++);
123 }
Chris Craike4db79d2015-12-22 16:32:23 -0800124 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800125 EXPECT_EQ(3, mIndex++);
126 }
127 };
128
Chris Craik8d1f2122015-11-24 16:40:09 -0800129 auto node = TestUtils::createNode(0, 0, 100, 200,
130 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700131 SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
Chris Craikb565df12015-10-05 13:00:52 -0700132 canvas.drawRect(0, 0, 100, 200, SkPaint());
133 canvas.drawBitmap(bitmap, 10, 10, nullptr);
134 });
Chris Craikf158b492016-01-12 14:45:08 -0800135 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800136 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik5854b342015-10-26 15:49:56 -0700137 SimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800138 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700139 EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
Chris Craik6fe991e52015-10-20 09:39:42 -0700140}
141
Chris Craikf158b492016-01-12 14:45:08 -0800142TEST(FrameBuilder, simpleStroke) {
Chris Craik386aa032015-12-07 17:08:25 -0800143 class SimpleStrokeTestRenderer : public TestRendererBase {
144 public:
145 void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
146 EXPECT_EQ(0, mIndex++);
147 // even though initial bounds are empty...
148 EXPECT_TRUE(op.unmappedBounds.isEmpty())
149 << "initial bounds should be empty, since they're unstroked";
150 EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
151 << "final bounds should account for stroke";
152 }
153 };
154
155 auto node = TestUtils::createNode(0, 0, 100, 200,
156 [](RenderProperties& props, RecordingCanvas& canvas) {
157 SkPaint strokedPaint;
158 strokedPaint.setStrokeWidth(10);
159 canvas.drawPoint(50, 50, strokedPaint);
160 });
Chris Craikf158b492016-01-12 14:45:08 -0800161 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800162 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik386aa032015-12-07 17:08:25 -0800163 SimpleStrokeTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800164 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik386aa032015-12-07 17:08:25 -0800165 EXPECT_EQ(1, renderer.getIndex());
166}
167
Chris Craikf158b492016-01-12 14:45:08 -0800168TEST(FrameBuilder, simpleRejection) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800169 auto node = TestUtils::createNode(0, 0, 200, 200,
170 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500171 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700172 canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
173 canvas.drawRect(0, 0, 400, 400, SkPaint());
174 canvas.restore();
175 });
Chris Craikf158b492016-01-12 14:45:08 -0800176 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800177 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik6fe991e52015-10-20 09:39:42 -0700178
Chris Craik5854b342015-10-26 15:49:56 -0700179 FailRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800180 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb565df12015-10-05 13:00:52 -0700181}
182
Chris Craikf158b492016-01-12 14:45:08 -0800183TEST(FrameBuilder, simpleBatching) {
Chris Craika1717272015-11-19 13:02:43 -0800184 const int LOOPS = 5;
Chris Craikd3daa312015-11-06 10:59:56 -0800185 class SimpleBatchingTestRenderer : public TestRendererBase {
186 public:
187 void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
Chris Craika1717272015-11-19 13:02:43 -0800188 EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
Chris Craikd3daa312015-11-06 10:59:56 -0800189 }
190 void onRectOp(const RectOp& op, const BakedOpState& state) override {
Chris Craika1717272015-11-19 13:02:43 -0800191 EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
Chris Craikd3daa312015-11-06 10:59:56 -0800192 }
193 };
194
Chris Craik8d1f2122015-11-24 16:40:09 -0800195 auto node = TestUtils::createNode(0, 0, 200, 200,
196 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik15c3f192015-12-03 12:16:56 -0800197 SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
198 kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
Chris Craikb565df12015-10-05 13:00:52 -0700199
200 // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
201 // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
Florin Malitaeecff562015-12-21 10:43:01 -0500202 canvas.save(SaveFlags::MatrixClip);
Chris Craika1717272015-11-19 13:02:43 -0800203 for (int i = 0; i < LOOPS; i++) {
Chris Craikb565df12015-10-05 13:00:52 -0700204 canvas.translate(0, 10);
205 canvas.drawRect(0, 0, 10, 10, SkPaint());
206 canvas.drawBitmap(bitmap, 5, 0, nullptr);
207 }
208 canvas.restore();
209 });
210
Chris Craikf158b492016-01-12 14:45:08 -0800211 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800212 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik5854b342015-10-26 15:49:56 -0700213 SimpleBatchingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800214 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craika1717272015-11-19 13:02:43 -0800215 EXPECT_EQ(2 * LOOPS, renderer.getIndex())
Chris Craik15c3f192015-12-03 12:16:56 -0800216 << "Expect number of ops = 2 * loop count";
Chris Craika1717272015-11-19 13:02:43 -0800217}
218
John Reck65182cc2016-01-26 10:50:10 -0800219// TODO: Disabled due to b/26793764
220TEST(FrameBuilder, DISABLED_clippedMerging) {
Chris Craik93e53e02015-12-17 18:42:44 -0800221 class ClippedMergingTestRenderer : public TestRendererBase {
222 public:
223 void onMergedBitmapOps(const MergedBakedOpList& opList) override {
224 EXPECT_EQ(0, mIndex);
225 mIndex += opList.count;
226 EXPECT_EQ(4u, opList.count);
227 EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
228 EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
229 opList.clipSideFlags);
230 }
231 };
232 auto node = TestUtils::createNode(0, 0, 100, 100,
233 [](RenderProperties& props, TestCanvas& canvas) {
234 SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
235
236 // left side clipped (to inset left half)
237 canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
238 canvas.drawBitmap(bitmap, 0, 40, nullptr);
239
240 // top side clipped (to inset top half)
241 canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
242 canvas.drawBitmap(bitmap, 40, 0, nullptr);
243
244 // right side clipped (to inset right half)
245 canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
246 canvas.drawBitmap(bitmap, 80, 40, nullptr);
247
248 // bottom not clipped, just abutting (inset bottom half)
249 canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
250 canvas.drawBitmap(bitmap, 40, 70, nullptr);
251 });
252
Chris Craikf158b492016-01-12 14:45:08 -0800253 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
Chris Craik6e068c012016-01-15 16:15:30 -0800254 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik93e53e02015-12-17 18:42:44 -0800255 ClippedMergingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800256 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik93e53e02015-12-17 18:42:44 -0800257 EXPECT_EQ(4, renderer.getIndex());
258}
259
Chris Craikf158b492016-01-12 14:45:08 -0800260TEST(FrameBuilder, textMerging) {
Chris Craikd7448e62015-12-15 10:34:36 -0800261 class TextMergingTestRenderer : public TestRendererBase {
262 public:
263 void onMergedTextOps(const MergedBakedOpList& opList) override {
264 EXPECT_EQ(0, mIndex);
265 mIndex += opList.count;
266 EXPECT_EQ(2u, opList.count);
267 EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
268 EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
269 EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
270 }
271 };
272 auto node = TestUtils::createNode(0, 0, 400, 400,
273 [](RenderProperties& props, TestCanvas& canvas) {
274 SkPaint paint;
275 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
276 paint.setAntiAlias(true);
277 paint.setTextSize(50);
278 TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
279 TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
280 });
Chris Craikf158b492016-01-12 14:45:08 -0800281 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
Chris Craik6e068c012016-01-15 16:15:30 -0800282 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craikd7448e62015-12-15 10:34:36 -0800283 TextMergingTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800284 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd7448e62015-12-15 10:34:36 -0800285 EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
286}
287
Chris Craikf158b492016-01-12 14:45:08 -0800288TEST(FrameBuilder, textStrikethrough) {
Chris Craika1717272015-11-19 13:02:43 -0800289 const int LOOPS = 5;
290 class TextStrikethroughTestRenderer : public TestRendererBase {
291 public:
292 void onRectOp(const RectOp& op, const BakedOpState& state) override {
293 EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
294 }
Chris Craik15c3f192015-12-03 12:16:56 -0800295 void onMergedTextOps(const MergedBakedOpList& opList) override {
296 EXPECT_EQ(0, mIndex);
297 mIndex += opList.count;
298 EXPECT_EQ(5u, opList.count);
Chris Craika1717272015-11-19 13:02:43 -0800299 }
300 };
Chris Craik8d1f2122015-11-24 16:40:09 -0800301 auto node = TestUtils::createNode(0, 0, 200, 2000,
302 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craika1717272015-11-19 13:02:43 -0800303 SkPaint textPaint;
304 textPaint.setAntiAlias(true);
305 textPaint.setTextSize(20);
306 textPaint.setStrikeThruText(true);
Chris Craik42a54072015-11-24 11:41:54 -0800307 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800308 for (int i = 0; i < LOOPS; i++) {
309 TestUtils::drawTextToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
310 }
311 });
Chris Craikf158b492016-01-12 14:45:08 -0800312 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
Chris Craik6e068c012016-01-15 16:15:30 -0800313 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craika1717272015-11-19 13:02:43 -0800314 TextStrikethroughTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800315 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craika1717272015-11-19 13:02:43 -0800316 EXPECT_EQ(2 * LOOPS, renderer.getIndex())
Chris Craikd7448e62015-12-15 10:34:36 -0800317 << "Expect number of ops = 2 * loop count";
Chris Craikb565df12015-10-05 13:00:52 -0700318}
319
Chris Craikf158b492016-01-12 14:45:08 -0800320RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800321 class TextureLayerTestRenderer : public TestRendererBase {
322 public:
323 void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
324 EXPECT_EQ(0, mIndex++);
Chris Craike4db79d2015-12-22 16:32:23 -0800325 EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800326 EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
327
328 Matrix4 expected;
329 expected.loadTranslate(5, 5, 0);
330 EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
331 }
332 };
333
334 auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
335 [](Matrix4* transform) {
336 transform->loadTranslate(5, 5, 0);
337 });
338
339 auto node = TestUtils::createNode(0, 0, 200, 200,
340 [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500341 canvas.save(SaveFlags::MatrixClip);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800342 canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
343 canvas.drawLayer(layerUpdater.get());
344 canvas.restore();
345 });
Chris Craikf158b492016-01-12 14:45:08 -0800346 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800347 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800348 TextureLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800349 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800350 EXPECT_EQ(1, renderer.getIndex());
351}
352
Chris Craikf158b492016-01-12 14:45:08 -0800353TEST(FrameBuilder, renderNode) {
Chris Craikd3daa312015-11-06 10:59:56 -0800354 class RenderNodeTestRenderer : public TestRendererBase {
355 public:
356 void onRectOp(const RectOp& op, const BakedOpState& state) override {
357 switch(mIndex++) {
358 case 0:
Chris Craik5430ab22015-12-10 16:28:16 -0800359 EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
Chris Craikd3daa312015-11-06 10:59:56 -0800360 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
361 break;
362 case 1:
363 EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
364 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
365 break;
366 default:
367 ADD_FAILURE();
368 }
369 }
370 };
371
Chris Craik8d1f2122015-11-24 16:40:09 -0800372 auto child = TestUtils::createNode(10, 10, 110, 110,
373 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikb565df12015-10-05 13:00:52 -0700374 SkPaint paint;
375 paint.setColor(SK_ColorWHITE);
376 canvas.drawRect(0, 0, 100, 100, paint);
377 });
378
Chris Craik8d1f2122015-11-24 16:40:09 -0800379 auto parent = TestUtils::createNode(0, 0, 200, 200,
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800380 [&child](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700381 SkPaint paint;
382 paint.setColor(SK_ColorDKGRAY);
383 canvas.drawRect(0, 0, 200, 200, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700384
Florin Malitaeecff562015-12-21 10:43:01 -0500385 canvas.save(SaveFlags::MatrixClip);
Chris Craikddf22152015-10-14 17:42:47 -0700386 canvas.translate(40, 40);
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800387 canvas.drawRenderNode(child.get());
Chris Craikddf22152015-10-14 17:42:47 -0700388 canvas.restore();
Chris Craikb565df12015-10-05 13:00:52 -0700389 });
390
Chris Craikf158b492016-01-12 14:45:08 -0800391 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800392 TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
Chris Craik5854b342015-10-26 15:49:56 -0700393 RenderNodeTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800394 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb565df12015-10-05 13:00:52 -0700395}
396
Chris Craikf158b492016-01-12 14:45:08 -0800397TEST(FrameBuilder, clipped) {
Chris Craikd3daa312015-11-06 10:59:56 -0800398 class ClippedTestRenderer : public TestRendererBase {
399 public:
400 void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
401 EXPECT_EQ(0, mIndex++);
402 EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800403 EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800404 EXPECT_TRUE(state.computedState.transform.isIdentity());
405 }
406 };
407
Chris Craik8d1f2122015-11-24 16:40:09 -0800408 auto node = TestUtils::createNode(0, 0, 200, 200,
409 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikddf22152015-10-14 17:42:47 -0700410 SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
411 canvas.drawBitmap(bitmap, 0, 0, nullptr);
412 });
Chris Craikddf22152015-10-14 17:42:47 -0700413
Chris Craikf158b492016-01-12 14:45:08 -0800414 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
Chris Craik0b7e8242015-10-28 16:50:44 -0700415 SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
Chris Craik6e068c012016-01-15 16:15:30 -0800416 200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik5854b342015-10-26 15:49:56 -0700417 ClippedTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800418 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikddf22152015-10-14 17:42:47 -0700419}
420
Chris Craikf158b492016-01-12 14:45:08 -0800421TEST(FrameBuilder, saveLayer_simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800422 class SaveLayerSimpleTestRenderer : public TestRendererBase {
423 public:
424 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
425 EXPECT_EQ(0, mIndex++);
426 EXPECT_EQ(180u, width);
427 EXPECT_EQ(180u, height);
428 return nullptr;
429 }
430 void endLayer() override {
431 EXPECT_EQ(2, mIndex++);
432 }
433 void onRectOp(const RectOp& op, const BakedOpState& state) override {
434 EXPECT_EQ(1, mIndex++);
435 EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
Chris Craik5430ab22015-12-10 16:28:16 -0800436 EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800437 EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800438
439 Matrix4 expectedTransform;
440 expectedTransform.loadTranslate(-10, -10, 0);
441 EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
442 }
443 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
444 EXPECT_EQ(3, mIndex++);
445 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800446 EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
Chris Craikd3daa312015-11-06 10:59:56 -0800447 EXPECT_TRUE(state.computedState.transform.isIdentity());
448 }
449 };
450
Chris Craik8d1f2122015-11-24 16:40:09 -0800451 auto node = TestUtils::createNode(0, 0, 200, 200,
452 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500453 canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700454 canvas.drawRect(10, 10, 190, 190, SkPaint());
455 canvas.restore();
456 });
Chris Craikf158b492016-01-12 14:45:08 -0800457 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800458 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik5854b342015-10-26 15:49:56 -0700459 SaveLayerSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800460 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700461 EXPECT_EQ(4, renderer.getIndex());
Chris Craikb565df12015-10-05 13:00:52 -0700462}
Chris Craik6fe991e52015-10-20 09:39:42 -0700463
Chris Craikf158b492016-01-12 14:45:08 -0800464TEST(FrameBuilder, saveLayer_nested) {
Chris Craikd3daa312015-11-06 10:59:56 -0800465 /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
466 * - startTemporaryLayer2, rect2 endLayer2
467 * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
468 * - startFrame, layerOp1, endFrame
469 */
470 class SaveLayerNestedTestRenderer : public TestRendererBase {
471 public:
472 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
473 const int index = mIndex++;
474 if (index == 0) {
475 EXPECT_EQ(400u, width);
476 EXPECT_EQ(400u, height);
477 return (OffscreenBuffer*) 0x400;
478 } else if (index == 3) {
479 EXPECT_EQ(800u, width);
480 EXPECT_EQ(800u, height);
481 return (OffscreenBuffer*) 0x800;
482 } else { ADD_FAILURE(); }
483 return (OffscreenBuffer*) nullptr;
484 }
485 void endLayer() override {
486 int index = mIndex++;
487 EXPECT_TRUE(index == 2 || index == 6);
488 }
Chris Craik98787e62015-11-13 10:55:30 -0800489 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800490 EXPECT_EQ(7, mIndex++);
491 }
Chris Craike4db79d2015-12-22 16:32:23 -0800492 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800493 EXPECT_EQ(9, mIndex++);
494 }
495 void onRectOp(const RectOp& op, const BakedOpState& state) override {
496 const int index = mIndex++;
497 if (index == 1) {
Chris Craik5430ab22015-12-10 16:28:16 -0800498 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
Chris Craikd3daa312015-11-06 10:59:56 -0800499 } else if (index == 4) {
Chris Craik5430ab22015-12-10 16:28:16 -0800500 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
Chris Craikd3daa312015-11-06 10:59:56 -0800501 } else { ADD_FAILURE(); }
502 }
503 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
504 const int index = mIndex++;
505 if (index == 5) {
506 EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
Chris Craik5430ab22015-12-10 16:28:16 -0800507 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
Chris Craikd3daa312015-11-06 10:59:56 -0800508 } else if (index == 8) {
509 EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
Chris Craik5430ab22015-12-10 16:28:16 -0800510 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
Chris Craikd3daa312015-11-06 10:59:56 -0800511 } else { ADD_FAILURE(); }
512 }
513 };
514
Chris Craik8d1f2122015-11-24 16:40:09 -0800515 auto node = TestUtils::createNode(0, 0, 800, 800,
516 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500517 canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700518 {
519 canvas.drawRect(0, 0, 800, 800, SkPaint());
Florin Malitaeecff562015-12-21 10:43:01 -0500520 canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700521 {
522 canvas.drawRect(0, 0, 400, 400, SkPaint());
523 }
524 canvas.restore();
525 }
526 canvas.restore();
527 });
528
Chris Craikf158b492016-01-12 14:45:08 -0800529 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
Chris Craik6e068c012016-01-15 16:15:30 -0800530 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik5854b342015-10-26 15:49:56 -0700531 SaveLayerNestedTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800532 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik5854b342015-10-26 15:49:56 -0700533 EXPECT_EQ(10, renderer.getIndex());
Chris Craikb565df12015-10-05 13:00:52 -0700534}
Chris Craik6fe991e52015-10-20 09:39:42 -0700535
Chris Craikf158b492016-01-12 14:45:08 -0800536TEST(FrameBuilder, saveLayer_contentRejection) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800537 auto node = TestUtils::createNode(0, 0, 200, 200,
538 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500539 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700540 canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
Florin Malitaeecff562015-12-21 10:43:01 -0500541 canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700542
543 // draw within save layer may still be recorded, but shouldn't be drawn
544 canvas.drawRect(200, 200, 400, 400, SkPaint());
545
546 canvas.restore();
547 canvas.restore();
548 });
Chris Craikf158b492016-01-12 14:45:08 -0800549 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800550 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik6fe991e52015-10-20 09:39:42 -0700551
Chris Craik5854b342015-10-26 15:49:56 -0700552 FailRenderer renderer;
Chris Craik6fe991e52015-10-20 09:39:42 -0700553 // should see no ops, even within the layer, since the layer should be rejected
Chris Craikf158b492016-01-12 14:45:08 -0800554 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700555}
556
Chris Craikf158b492016-01-12 14:45:08 -0800557TEST(FrameBuilder, saveLayerUnclipped_simple) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800558 class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
559 public:
560 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
561 EXPECT_EQ(0, mIndex++);
562 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craik7435eb12016-01-07 17:41:40 -0800563 EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
Chris Craikb87eadd2016-01-06 09:16:05 -0800564 EXPECT_TRUE(state.computedState.transform.isIdentity());
565 }
566 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
567 EXPECT_EQ(1, mIndex++);
568 ASSERT_NE(nullptr, op.paint);
569 ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
570 }
571 void onRectOp(const RectOp& op, const BakedOpState& state) override {
572 EXPECT_EQ(2, mIndex++);
573 EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
574 EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
575 EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
576 EXPECT_TRUE(state.computedState.transform.isIdentity());
577 }
578 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
579 EXPECT_EQ(3, mIndex++);
580 EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
Chris Craik7435eb12016-01-07 17:41:40 -0800581 EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
Chris Craikb87eadd2016-01-06 09:16:05 -0800582 EXPECT_TRUE(state.computedState.transform.isIdentity());
583 }
584 };
585
586 auto node = TestUtils::createNode(0, 0, 200, 200,
587 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500588 canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
Chris Craikb87eadd2016-01-06 09:16:05 -0800589 canvas.drawRect(0, 0, 200, 200, SkPaint());
590 canvas.restore();
591 });
Chris Craikf158b492016-01-12 14:45:08 -0800592 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800593 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craikb87eadd2016-01-06 09:16:05 -0800594 SaveLayerUnclippedSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800595 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800596 EXPECT_EQ(4, renderer.getIndex());
597}
598
Chris Craikf158b492016-01-12 14:45:08 -0800599TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800600 class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
601 public:
602 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
603 int index = mIndex++;
604 EXPECT_GT(4, index);
605 EXPECT_EQ(5, op.unmappedBounds.getWidth());
606 EXPECT_EQ(5, op.unmappedBounds.getHeight());
607 if (index == 0) {
608 EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
609 } else if (index == 1) {
610 EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
611 } else if (index == 2) {
612 EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
613 } else if (index == 3) {
614 EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
615 }
616 }
617 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
618 EXPECT_EQ(4, mIndex++);
619 ASSERT_EQ(op.vertexCount, 16u);
620 for (size_t i = 0; i < op.vertexCount; i++) {
621 auto v = op.vertices[i];
622 EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
623 EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
624 }
625 }
626 void onRectOp(const RectOp& op, const BakedOpState& state) override {
627 EXPECT_EQ(5, mIndex++);
628 }
629 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
630 EXPECT_LT(5, mIndex++);
631 }
632 };
633
634 auto node = TestUtils::createNode(0, 0, 200, 200,
635 [](RenderProperties& props, RecordingCanvas& canvas) {
636
Florin Malitaeecff562015-12-21 10:43:01 -0500637 int restoreTo = canvas.save(SaveFlags::MatrixClip);
Chris Craikb87eadd2016-01-06 09:16:05 -0800638 canvas.scale(2, 2);
Florin Malitaeecff562015-12-21 10:43:01 -0500639 canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
640 canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
641 canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
642 canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
Chris Craikb87eadd2016-01-06 09:16:05 -0800643 canvas.drawRect(0, 0, 100, 100, SkPaint());
644 canvas.restoreToCount(restoreTo);
645 });
Chris Craikf158b492016-01-12 14:45:08 -0800646 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800647 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craikb87eadd2016-01-06 09:16:05 -0800648 SaveLayerUnclippedMergedClearsTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800649 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800650 EXPECT_EQ(10, renderer.getIndex())
651 << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
652}
653
654/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
655 * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
656 * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
657 */
Chris Craikf158b492016-01-12 14:45:08 -0800658TEST(FrameBuilder, saveLayerUnclipped_complex) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800659 class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
660 public:
661 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
662 EXPECT_EQ(0, mIndex++); // savelayer first
663 return (OffscreenBuffer*)0xabcd;
664 }
665 void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
666 int index = mIndex++;
667 EXPECT_TRUE(index == 1 || index == 7);
668 }
669 void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
670 int index = mIndex++;
671 EXPECT_TRUE(index == 2 || index == 8);
672 }
673 void onRectOp(const RectOp& op, const BakedOpState& state) override {
674 EXPECT_EQ(3, mIndex++);
675 Matrix4 expected;
676 expected.loadTranslate(-100, -100, 0);
677 EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
678 EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
679 }
680 void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
681 int index = mIndex++;
682 EXPECT_TRUE(index == 4 || index == 10);
683 }
684 void endLayer() override {
685 EXPECT_EQ(5, mIndex++);
686 }
687 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
688 EXPECT_EQ(6, mIndex++);
689 }
690 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
691 EXPECT_EQ(9, mIndex++);
692 }
693 void endFrame(const Rect& repaintRect) override {
694 EXPECT_EQ(11, mIndex++);
695 }
696 };
697
698 auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
699 [](RenderProperties& props, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500700 canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
701 canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
702 canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
Chris Craikb87eadd2016-01-06 09:16:05 -0800703 canvas.drawRect(200, 200, 300, 300, SkPaint());
704 canvas.restore();
705 canvas.restore();
706 canvas.restore();
707 });
Chris Craikf158b492016-01-12 14:45:08 -0800708 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
Chris Craik6e068c012016-01-15 16:15:30 -0800709 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craikb87eadd2016-01-06 09:16:05 -0800710 SaveLayerUnclippedComplexTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800711 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800712 EXPECT_EQ(12, renderer.getIndex());
713}
714
Chris Craikf158b492016-01-12 14:45:08 -0800715RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
Chris Craikd3daa312015-11-06 10:59:56 -0800716 class HwLayerSimpleTestRenderer : public TestRendererBase {
717 public:
Chris Craik98787e62015-11-13 10:55:30 -0800718 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800719 EXPECT_EQ(0, mIndex++);
Chris Craik98787e62015-11-13 10:55:30 -0800720 EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
721 EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
722 EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
Chris Craikd3daa312015-11-06 10:59:56 -0800723 }
724 void onRectOp(const RectOp& op, const BakedOpState& state) override {
725 EXPECT_EQ(1, mIndex++);
726
727 EXPECT_TRUE(state.computedState.transform.isIdentity())
728 << "Transform should be reset within layer";
729
Chris Craike4db79d2015-12-22 16:32:23 -0800730 EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
Chris Craikd3daa312015-11-06 10:59:56 -0800731 << "Damage rect should be used to clip layer content";
732 }
733 void endLayer() override {
734 EXPECT_EQ(2, mIndex++);
735 }
Chris Craik98787e62015-11-13 10:55:30 -0800736 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800737 EXPECT_EQ(3, mIndex++);
738 }
739 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
740 EXPECT_EQ(4, mIndex++);
741 }
Chris Craike4db79d2015-12-22 16:32:23 -0800742 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800743 EXPECT_EQ(5, mIndex++);
744 }
745 };
746
Chris Craik8d1f2122015-11-24 16:40:09 -0800747 auto node = TestUtils::createNode(10, 10, 110, 110,
John Reck16c9d6a2015-11-17 15:51:08 -0800748 [](RenderProperties& props, RecordingCanvas& canvas) {
749 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700750 SkPaint paint;
751 paint.setColor(SK_ColorWHITE);
752 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -0800753 });
Chris Craik98787e62015-11-13 10:55:30 -0800754 OffscreenBuffer** layerHandle = node->getLayerHandle();
Chris Craik0b7e8242015-10-28 16:50:44 -0700755
Chris Craik98787e62015-11-13 10:55:30 -0800756 // create RenderNode's layer here in same way prepareTree would
757 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
758 *layerHandle = &layer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700759
John Reck7db5ffb2016-01-15 13:17:09 -0800760 auto syncedNodeList = TestUtils::createSyncedNodeList(node);
Chris Craik0b7e8242015-10-28 16:50:44 -0700761
762 // only enqueue partial damage
Chris Craik98787e62015-11-13 10:55:30 -0800763 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
Chris Craik0b7e8242015-10-28 16:50:44 -0700764 layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
765
Chris Craikf158b492016-01-12 14:45:08 -0800766 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800767 syncedNodeList, sLightGeometry, nullptr);
Chris Craik0b7e8242015-10-28 16:50:44 -0700768 HwLayerSimpleTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800769 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700770 EXPECT_EQ(6, renderer.getIndex());
771
772 // clean up layer pointer, so we can safely destruct RenderNode
Chris Craik98787e62015-11-13 10:55:30 -0800773 *layerHandle = nullptr;
Chris Craik0b7e8242015-10-28 16:50:44 -0700774}
775
Chris Craikf158b492016-01-12 14:45:08 -0800776RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
Chris Craikd3daa312015-11-06 10:59:56 -0800777 /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
778 * - startRepaintLayer(child), rect(grey), endLayer
779 * - startTemporaryLayer, drawLayer(child), endLayer
780 * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
781 * - startFrame, drawLayer(parent), endLayerb
782 */
783 class HwLayerComplexTestRenderer : public TestRendererBase {
784 public:
785 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
786 EXPECT_EQ(3, mIndex++); // savelayer first
787 return (OffscreenBuffer*)0xabcd;
788 }
Chris Craik98787e62015-11-13 10:55:30 -0800789 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800790 int index = mIndex++;
791 if (index == 0) {
792 // starting inner layer
Chris Craik98787e62015-11-13 10:55:30 -0800793 EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
794 EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800795 } else if (index == 6) {
796 // starting outer layer
Chris Craik98787e62015-11-13 10:55:30 -0800797 EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
798 EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800799 } else { ADD_FAILURE(); }
800 }
801 void onRectOp(const RectOp& op, const BakedOpState& state) override {
802 int index = mIndex++;
803 if (index == 1) {
804 // inner layer's rect (white)
805 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
806 } else if (index == 7) {
807 // outer layer's rect (grey)
808 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
809 } else { ADD_FAILURE(); }
810 }
811 void endLayer() override {
812 int index = mIndex++;
813 EXPECT_TRUE(index == 2 || index == 5 || index == 9);
814 }
Chris Craik98787e62015-11-13 10:55:30 -0800815 void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800816 EXPECT_EQ(10, mIndex++);
817 }
818 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
Chris Craik98787e62015-11-13 10:55:30 -0800819 OffscreenBuffer* layer = *op.layerHandle;
Chris Craikd3daa312015-11-06 10:59:56 -0800820 int index = mIndex++;
821 if (index == 4) {
Chris Craik98787e62015-11-13 10:55:30 -0800822 EXPECT_EQ(100u, layer->viewportWidth);
823 EXPECT_EQ(100u, layer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800824 } else if (index == 8) {
825 EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
826 } else if (index == 11) {
Chris Craik98787e62015-11-13 10:55:30 -0800827 EXPECT_EQ(200u, layer->viewportWidth);
828 EXPECT_EQ(200u, layer->viewportHeight);
Chris Craikd3daa312015-11-06 10:59:56 -0800829 } else { ADD_FAILURE(); }
830 }
Chris Craike4db79d2015-12-22 16:32:23 -0800831 void endFrame(const Rect& repaintRect) override {
Chris Craikd3daa312015-11-06 10:59:56 -0800832 EXPECT_EQ(12, mIndex++);
833 }
834 };
835
John Reck16c9d6a2015-11-17 15:51:08 -0800836 auto child = TestUtils::createNode(50, 50, 150, 150,
837 [](RenderProperties& props, RecordingCanvas& canvas) {
838 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700839 SkPaint paint;
840 paint.setColor(SK_ColorWHITE);
841 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -0800842 });
Chris Craik98787e62015-11-13 10:55:30 -0800843 OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
844 *(child->getLayerHandle()) = &childLayer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700845
846 RenderNode* childPtr = child.get();
John Reck16c9d6a2015-11-17 15:51:08 -0800847 auto parent = TestUtils::createNode(0, 0, 200, 200,
848 [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
849 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700850 SkPaint paint;
851 paint.setColor(SK_ColorDKGRAY);
852 canvas.drawRect(0, 0, 200, 200, paint);
853
Florin Malitaeecff562015-12-21 10:43:01 -0500854 canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700855 canvas.drawRenderNode(childPtr);
856 canvas.restore();
John Reck16c9d6a2015-11-17 15:51:08 -0800857 });
Chris Craik98787e62015-11-13 10:55:30 -0800858 OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
859 *(parent->getLayerHandle()) = &parentLayer;
Chris Craik0b7e8242015-10-28 16:50:44 -0700860
John Reck7db5ffb2016-01-15 13:17:09 -0800861 auto syncedList = TestUtils::createSyncedNodeList(parent);
Chris Craik0b7e8242015-10-28 16:50:44 -0700862
Chris Craik98787e62015-11-13 10:55:30 -0800863 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
Chris Craik0b7e8242015-10-28 16:50:44 -0700864 layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
865 layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
866
Chris Craikf158b492016-01-12 14:45:08 -0800867 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -0800868 syncedList, sLightGeometry, nullptr);
Chris Craik0b7e8242015-10-28 16:50:44 -0700869 HwLayerComplexTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800870 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700871 EXPECT_EQ(13, renderer.getIndex());
872
873 // clean up layer pointers, so we can safely destruct RenderNodes
874 *(child->getLayerHandle()) = nullptr;
875 *(parent->getLayerHandle()) = nullptr;
876}
877
Chris Craik161f54b2015-11-05 11:08:52 -0800878static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
879 SkPaint paint;
880 paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
881 canvas->drawRect(0, 0, 100, 100, paint);
882}
883static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
John Reck16c9d6a2015-11-17 15:51:08 -0800884 auto node = TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -0800885 [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik161f54b2015-11-05 11:08:52 -0800886 drawOrderedRect(&canvas, expectedDrawOrder);
887 });
888 node->mutateStagingProperties().setTranslationZ(z);
889 node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
890 canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
891}
Chris Craikf158b492016-01-12 14:45:08 -0800892TEST(FrameBuilder, zReorder) {
Chris Craikd3daa312015-11-06 10:59:56 -0800893 class ZReorderTestRenderer : public TestRendererBase {
894 public:
895 void onRectOp(const RectOp& op, const BakedOpState& state) override {
896 int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
897 EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
898 }
899 };
900
John Reck16c9d6a2015-11-17 15:51:08 -0800901 auto parent = TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -0800902 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik161f54b2015-11-05 11:08:52 -0800903 drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
904 drawOrderedRect(&canvas, 1);
905 canvas.insertReorderBarrier(true);
906 drawOrderedNode(&canvas, 6, 2.0f);
907 drawOrderedRect(&canvas, 3);
908 drawOrderedNode(&canvas, 4, 0.0f);
909 drawOrderedRect(&canvas, 5);
910 drawOrderedNode(&canvas, 2, -2.0f);
911 drawOrderedNode(&canvas, 7, 2.0f);
912 canvas.insertReorderBarrier(false);
913 drawOrderedRect(&canvas, 8);
914 drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
915 });
Chris Craikf158b492016-01-12 14:45:08 -0800916 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
Chris Craik6e068c012016-01-15 16:15:30 -0800917 TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
Chris Craik161f54b2015-11-05 11:08:52 -0800918 ZReorderTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -0800919 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik161f54b2015-11-05 11:08:52 -0800920 EXPECT_EQ(10, renderer.getIndex());
921};
922
Chris Craikf158b492016-01-12 14:45:08 -0800923TEST(FrameBuilder, projectionReorder) {
Chris Craik8d1f2122015-11-24 16:40:09 -0800924 static const int scrollX = 5;
925 static const int scrollY = 10;
926 class ProjectionReorderTestRenderer : public TestRendererBase {
927 public:
928 void onRectOp(const RectOp& op, const BakedOpState& state) override {
929 const int index = mIndex++;
930
931 Matrix4 expectedMatrix;
932 switch (index) {
933 case 0:
934 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
935 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
936 expectedMatrix.loadIdentity();
937 break;
938 case 1:
939 EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
940 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
941 expectedMatrix.loadTranslate(50, 50, 0); // TODO: should scroll be respected here?
942 break;
943 case 2:
944 EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
945 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
946 expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
947 break;
948 default:
949 ADD_FAILURE();
950 }
951 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
952 }
953 };
954
955 /**
956 * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
957 * with a projecting child (P) of its own. P would normally draw between B and C's "background"
958 * draw, but because it is projected backwards, it's drawn in between B and C.
959 *
960 * The parent is scrolled by scrollX/scrollY, but this does not affect the background
961 * (which isn't affected by scroll).
962 */
963 auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
964 [](RenderProperties& properties, RecordingCanvas& canvas) {
965 properties.setProjectionReceiver(true);
966 // scroll doesn't apply to background, so undone via translationX/Y
967 // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
968 properties.setTranslationX(scrollX);
969 properties.setTranslationY(scrollY);
970
971 SkPaint paint;
972 paint.setColor(SK_ColorWHITE);
973 canvas.drawRect(0, 0, 100, 100, paint);
974 });
975 auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
976 [](RenderProperties& properties, RecordingCanvas& canvas) {
977 properties.setProjectBackwards(true);
978 properties.setClipToBounds(false);
979 SkPaint paint;
980 paint.setColor(SK_ColorDKGRAY);
981 canvas.drawRect(-10, -10, 60, 60, paint);
982 });
983 auto child = TestUtils::createNode(0, 50, 100, 100,
984 [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
985 SkPaint paint;
986 paint.setColor(SK_ColorBLUE);
987 canvas.drawRect(0, 0, 100, 50, paint);
988 canvas.drawRenderNode(projectingRipple.get());
989 });
990 auto parent = TestUtils::createNode(0, 0, 100, 100,
991 [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500992 canvas.save(SaveFlags::MatrixClip);
Chris Craik8d1f2122015-11-24 16:40:09 -0800993 canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
994 canvas.drawRenderNode(receiverBackground.get());
995 canvas.drawRenderNode(child.get());
996 canvas.restore();
997 });
998
Chris Craikf158b492016-01-12 14:45:08 -0800999 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
Chris Craik6e068c012016-01-15 16:15:30 -08001000 TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
Chris Craik8d1f2122015-11-24 16:40:09 -08001001 ProjectionReorderTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001002 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik8d1f2122015-11-24 16:40:09 -08001003 EXPECT_EQ(3, renderer.getIndex());
1004}
1005
Chris Craik98787e62015-11-13 10:55:30 -08001006// creates a 100x100 shadow casting node with provided translationZ
1007static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
John Reck16c9d6a2015-11-17 15:51:08 -08001008 return TestUtils::createNode(0, 0, 100, 100,
Chris Craik8d1f2122015-11-24 16:40:09 -08001009 [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
John Reck16c9d6a2015-11-17 15:51:08 -08001010 properties.setTranslationZ(translationZ);
1011 properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
Chris Craik98787e62015-11-13 10:55:30 -08001012 SkPaint paint;
1013 paint.setColor(SK_ColorWHITE);
1014 canvas.drawRect(0, 0, 100, 100, paint);
Chris Craik98787e62015-11-13 10:55:30 -08001015 });
1016}
1017
Chris Craik6e068c012016-01-15 16:15:30 -08001018RENDERTHREAD_TEST(FrameBuilder, shadow) {
Chris Craikd3daa312015-11-06 10:59:56 -08001019 class ShadowTestRenderer : public TestRendererBase {
1020 public:
1021 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1022 EXPECT_EQ(0, mIndex++);
Chris Craik98787e62015-11-13 10:55:30 -08001023 EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
Chris Craik6e068c012016-01-15 16:15:30 -08001024 EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
1025 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
Chris Craik98787e62015-11-13 10:55:30 -08001026
1027 Matrix4 expectedZ;
1028 expectedZ.loadTranslate(0, 0, 5);
Chris Craik6e068c012016-01-15 16:15:30 -08001029 EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
Chris Craikd3daa312015-11-06 10:59:56 -08001030 }
1031 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1032 EXPECT_EQ(1, mIndex++);
1033 }
1034 };
Chris Craik161f54b2015-11-05 11:08:52 -08001035
Chris Craik8d1f2122015-11-24 16:40:09 -08001036 auto parent = TestUtils::createNode(0, 0, 200, 200,
1037 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craikd3daa312015-11-06 10:59:56 -08001038 canvas.insertReorderBarrier(true);
Chris Craik98787e62015-11-13 10:55:30 -08001039 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
Chris Craikd3daa312015-11-06 10:59:56 -08001040 });
1041
Chris Craikf158b492016-01-12 14:45:08 -08001042 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -08001043 TestUtils::createSyncedNodeList(parent), sLightGeometry, &Caches::getInstance());
Chris Craikd3daa312015-11-06 10:59:56 -08001044 ShadowTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001045 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craikd3daa312015-11-06 10:59:56 -08001046 EXPECT_EQ(2, renderer.getIndex());
1047}
Chris Craik76caecf2015-11-02 19:17:45 -08001048
Chris Craik6e068c012016-01-15 16:15:30 -08001049RENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
Chris Craik98787e62015-11-13 10:55:30 -08001050 class ShadowSaveLayerTestRenderer : public TestRendererBase {
1051 public:
1052 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
1053 EXPECT_EQ(0, mIndex++);
1054 return nullptr;
1055 }
1056 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1057 EXPECT_EQ(1, mIndex++);
Chris Craik6e068c012016-01-15 16:15:30 -08001058 EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
1059 EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
Chris Craik98787e62015-11-13 10:55:30 -08001060 }
1061 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1062 EXPECT_EQ(2, mIndex++);
1063 }
1064 void endLayer() override {
1065 EXPECT_EQ(3, mIndex++);
1066 }
1067 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1068 EXPECT_EQ(4, mIndex++);
1069 }
1070 };
1071
Chris Craik8d1f2122015-11-24 16:40:09 -08001072 auto parent = TestUtils::createNode(0, 0, 200, 200,
1073 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik98787e62015-11-13 10:55:30 -08001074 // save/restore outside of reorderBarrier, so they don't get moved out of place
1075 canvas.translate(20, 10);
Florin Malitaeecff562015-12-21 10:43:01 -05001076 int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
Chris Craik98787e62015-11-13 10:55:30 -08001077 canvas.insertReorderBarrier(true);
1078 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1079 canvas.insertReorderBarrier(false);
1080 canvas.restoreToCount(count);
1081 });
1082
Chris Craikf158b492016-01-12 14:45:08 -08001083 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -08001084 TestUtils::createSyncedNodeList(parent),
1085 (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
1086 &Caches::getInstance());
Chris Craik98787e62015-11-13 10:55:30 -08001087 ShadowSaveLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001088 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001089 EXPECT_EQ(5, renderer.getIndex());
1090}
1091
Chris Craikf158b492016-01-12 14:45:08 -08001092RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
Chris Craik98787e62015-11-13 10:55:30 -08001093 class ShadowHwLayerTestRenderer : public TestRendererBase {
1094 public:
1095 void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1096 EXPECT_EQ(0, mIndex++);
1097 }
1098 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1099 EXPECT_EQ(1, mIndex++);
Chris Craik6e068c012016-01-15 16:15:30 -08001100 EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
1101 EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
1102 EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
Chris Craik98787e62015-11-13 10:55:30 -08001103 }
1104 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1105 EXPECT_EQ(2, mIndex++);
1106 }
1107 void endLayer() override {
1108 EXPECT_EQ(3, mIndex++);
1109 }
1110 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1111 EXPECT_EQ(4, mIndex++);
1112 }
1113 };
1114
Chris Craik8d1f2122015-11-24 16:40:09 -08001115 auto parent = TestUtils::createNode(50, 60, 150, 160,
John Reck16c9d6a2015-11-17 15:51:08 -08001116 [](RenderProperties& props, RecordingCanvas& canvas) {
1117 props.mutateLayerProperties().setType(LayerType::RenderLayer);
Chris Craik98787e62015-11-13 10:55:30 -08001118 canvas.insertReorderBarrier(true);
Florin Malitaeecff562015-12-21 10:43:01 -05001119 canvas.save(SaveFlags::MatrixClip);
Chris Craik98787e62015-11-13 10:55:30 -08001120 canvas.translate(20, 10);
1121 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1122 canvas.restore();
John Reck16c9d6a2015-11-17 15:51:08 -08001123 });
Chris Craik98787e62015-11-13 10:55:30 -08001124 OffscreenBuffer** layerHandle = parent->getLayerHandle();
1125
1126 // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1127 OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
1128 Matrix4 windowTransform;
1129 windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
1130 layer.setWindowTransform(windowTransform);
1131 *layerHandle = &layer;
1132
John Reck7db5ffb2016-01-15 13:17:09 -08001133 auto syncedList = TestUtils::createSyncedNodeList(parent);
Chris Craik98787e62015-11-13 10:55:30 -08001134 LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1135 layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
Chris Craikf158b492016-01-12 14:45:08 -08001136 FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -08001137 syncedList,
1138 (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30},
1139 &Caches::getInstance());
Chris Craik98787e62015-11-13 10:55:30 -08001140 ShadowHwLayerTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001141 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001142 EXPECT_EQ(5, renderer.getIndex());
1143
1144 // clean up layer pointer, so we can safely destruct RenderNode
1145 *layerHandle = nullptr;
1146}
1147
Chris Craikf158b492016-01-12 14:45:08 -08001148TEST(FrameBuilder, shadowLayering) {
Chris Craik98787e62015-11-13 10:55:30 -08001149 class ShadowLayeringTestRenderer : public TestRendererBase {
1150 public:
1151 void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1152 int index = mIndex++;
1153 EXPECT_TRUE(index == 0 || index == 1);
1154 }
1155 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1156 int index = mIndex++;
1157 EXPECT_TRUE(index == 2 || index == 3);
1158 }
1159 };
Chris Craik8d1f2122015-11-24 16:40:09 -08001160 auto parent = TestUtils::createNode(0, 0, 200, 200,
1161 [](RenderProperties& props, RecordingCanvas& canvas) {
Chris Craik98787e62015-11-13 10:55:30 -08001162 canvas.insertReorderBarrier(true);
1163 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1164 canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
1165 });
1166
Chris Craikf158b492016-01-12 14:45:08 -08001167 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -08001168 TestUtils::createSyncedNodeList(parent),
1169 (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
1170 &Caches::getInstance());
Chris Craik98787e62015-11-13 10:55:30 -08001171 ShadowLayeringTestRenderer renderer;
Chris Craikf158b492016-01-12 14:45:08 -08001172 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik98787e62015-11-13 10:55:30 -08001173 EXPECT_EQ(4, renderer.getIndex());
1174}
1175
John Reck16c9d6a2015-11-17 15:51:08 -08001176static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
Chris Craik76caecf2015-11-02 19:17:45 -08001177 std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
Chris Craikd3daa312015-11-06 10:59:56 -08001178 class PropertyTestRenderer : public TestRendererBase {
1179 public:
1180 PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1181 : mCallback(callback) {}
1182 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1183 EXPECT_EQ(mIndex++, 0);
1184 mCallback(op, state);
1185 }
1186 std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1187 };
1188
John Reck16c9d6a2015-11-17 15:51:08 -08001189 auto node = TestUtils::createNode(0, 0, 100, 100,
1190 [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
1191 propSetupCallback(props);
Chris Craik76caecf2015-11-02 19:17:45 -08001192 SkPaint paint;
1193 paint.setColor(SK_ColorWHITE);
1194 canvas.drawRect(0, 0, 100, 100, paint);
John Reck16c9d6a2015-11-17 15:51:08 -08001195 });
Chris Craik76caecf2015-11-02 19:17:45 -08001196
Chris Craikf158b492016-01-12 14:45:08 -08001197 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
Chris Craik6e068c012016-01-15 16:15:30 -08001198 TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
Chris Craik76caecf2015-11-02 19:17:45 -08001199 PropertyTestRenderer renderer(opValidateCallback);
Chris Craikf158b492016-01-12 14:45:08 -08001200 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik76caecf2015-11-02 19:17:45 -08001201 EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
1202}
1203
Chris Craikf158b492016-01-12 14:45:08 -08001204TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
Chris Craik76caecf2015-11-02 19:17:45 -08001205 testProperty([](RenderProperties& properties) {
1206 properties.setAlpha(0.5f);
1207 properties.setHasOverlappingRendering(false);
Chris Craik76caecf2015-11-02 19:17:45 -08001208 }, [](const RectOp& op, const BakedOpState& state) {
1209 EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
1210 });
1211}
1212
Chris Craikf158b492016-01-12 14:45:08 -08001213TEST(FrameBuilder, renderPropClipping) {
Chris Craik76caecf2015-11-02 19:17:45 -08001214 testProperty([](RenderProperties& properties) {
1215 properties.setClipToBounds(true);
1216 properties.setClipBounds(Rect(10, 20, 300, 400));
Chris Craik76caecf2015-11-02 19:17:45 -08001217 }, [](const RectOp& op, const BakedOpState& state) {
1218 EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
1219 << "Clip rect should be intersection of node bounds and clip bounds";
1220 });
1221}
1222
Chris Craikf158b492016-01-12 14:45:08 -08001223TEST(FrameBuilder, renderPropRevealClip) {
Chris Craik76caecf2015-11-02 19:17:45 -08001224 testProperty([](RenderProperties& properties) {
1225 properties.mutableRevealClip().set(true, 50, 50, 25);
Chris Craik76caecf2015-11-02 19:17:45 -08001226 }, [](const RectOp& op, const BakedOpState& state) {
1227 ASSERT_NE(nullptr, state.roundRectClipState);
1228 EXPECT_TRUE(state.roundRectClipState->highPriority);
1229 EXPECT_EQ(25, state.roundRectClipState->radius);
1230 EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
1231 });
1232}
1233
Chris Craikf158b492016-01-12 14:45:08 -08001234TEST(FrameBuilder, renderPropOutlineClip) {
Chris Craik76caecf2015-11-02 19:17:45 -08001235 testProperty([](RenderProperties& properties) {
1236 properties.mutableOutline().setShouldClip(true);
1237 properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
Chris Craik76caecf2015-11-02 19:17:45 -08001238 }, [](const RectOp& op, const BakedOpState& state) {
1239 ASSERT_NE(nullptr, state.roundRectClipState);
1240 EXPECT_FALSE(state.roundRectClipState->highPriority);
1241 EXPECT_EQ(5, state.roundRectClipState->radius);
1242 EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
1243 });
1244}
1245
Chris Craikf158b492016-01-12 14:45:08 -08001246TEST(FrameBuilder, renderPropTransform) {
Chris Craik76caecf2015-11-02 19:17:45 -08001247 testProperty([](RenderProperties& properties) {
1248 properties.setLeftTopRightBottom(10, 10, 110, 110);
1249
1250 SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
1251 properties.setStaticMatrix(&staticMatrix);
1252
1253 // ignored, since static overrides animation
1254 SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
1255 properties.setAnimationMatrix(&animationMatrix);
1256
1257 properties.setTranslationX(10);
1258 properties.setTranslationY(20);
1259 properties.setScaleX(0.5f);
1260 properties.setScaleY(0.7f);
Chris Craik76caecf2015-11-02 19:17:45 -08001261 }, [](const RectOp& op, const BakedOpState& state) {
1262 Matrix4 matrix;
1263 matrix.loadTranslate(10, 10, 0); // left, top
1264 matrix.scale(1.2f, 1.2f, 1); // static matrix
1265 // ignore animation matrix, since static overrides it
1266
1267 // translation xy
1268 matrix.translate(10, 20);
1269
1270 // scale xy (from default pivot - center)
1271 matrix.translate(50, 50);
1272 matrix.scale(0.5f, 0.7f, 1);
1273 matrix.translate(-50, -50);
1274 EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
1275 << "Op draw matrix must match expected combination of transformation properties";
1276 });
1277}
Chris Craik161f54b2015-11-05 11:08:52 -08001278
Chris Craik8ecf41c2015-11-16 10:27:59 -08001279struct SaveLayerAlphaData {
1280 uint32_t layerWidth = 0;
1281 uint32_t layerHeight = 0;
1282 Rect rectClippedBounds;
1283 Matrix4 rectMatrix;
1284};
1285/**
1286 * Constructs a view to hit the temporary layer alpha property implementation:
1287 * a) 0 < alpha < 1
1288 * b) too big for layer (larger than maxTextureSize)
1289 * c) overlapping rendering content
1290 * returning observed data about layer size and content clip/transform.
1291 *
1292 * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
1293 * (for efficiency, and to fit in layer size constraints) based on parent clip.
1294 */
1295void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
John Reck16c9d6a2015-11-17 15:51:08 -08001296 std::function<void(RenderProperties&)> propSetupCallback) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001297 class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
1298 public:
1299 SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
1300 : mOutData(outData) {}
1301
1302 OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
1303 EXPECT_EQ(0, mIndex++);
1304 mOutData->layerWidth = width;
1305 mOutData->layerHeight = height;
1306 return nullptr;
1307 }
1308 void onRectOp(const RectOp& op, const BakedOpState& state) override {
1309 EXPECT_EQ(1, mIndex++);
1310
1311 mOutData->rectClippedBounds = state.computedState.clippedBounds;
1312 mOutData->rectMatrix = state.computedState.transform;
1313 }
1314 void endLayer() override {
1315 EXPECT_EQ(2, mIndex++);
1316 }
1317 void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1318 EXPECT_EQ(3, mIndex++);
1319 }
1320 private:
1321 SaveLayerAlphaData* mOutData;
1322 };
1323
1324 ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
1325 << "Node must be bigger than max texture size to exercise saveLayer codepath";
John Reck16c9d6a2015-11-17 15:51:08 -08001326 auto node = TestUtils::createNode(0, 0, 10000, 10000,
1327 [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
1328 properties.setHasOverlappingRendering(true);
1329 properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
1330 // apply other properties
1331 propSetupCallback(properties);
1332
Chris Craik8ecf41c2015-11-16 10:27:59 -08001333 SkPaint paint;
1334 paint.setColor(SK_ColorWHITE);
1335 canvas.drawRect(0, 0, 10000, 10000, paint);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001336 });
John Reck7db5ffb2016-01-15 13:17:09 -08001337 auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
Chris Craik8ecf41c2015-11-16 10:27:59 -08001338
Chris Craik6e068c012016-01-15 16:15:30 -08001339 FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
1340 nodes, sLightGeometry, nullptr);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001341 SaveLayerAlphaClipTestRenderer renderer(outObservedData);
Chris Craikf158b492016-01-12 14:45:08 -08001342 frameBuilder.replayBakedOps<TestDispatcher>(renderer);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001343
1344 // assert, since output won't be valid if we haven't seen a save layer triggered
1345 ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
1346}
1347
Chris Craikf158b492016-01-12 14:45:08 -08001348TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001349 SaveLayerAlphaData observedData;
1350 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1351 properties.setTranslationX(10); // offset rendering content
1352 properties.setTranslationY(-2000); // offset rendering content
Chris Craik8ecf41c2015-11-16 10:27:59 -08001353 });
1354 EXPECT_EQ(190u, observedData.layerWidth);
1355 EXPECT_EQ(200u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001356 EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
Chris Craik8ecf41c2015-11-16 10:27:59 -08001357 << "expect content to be clipped to screen area";
1358 Matrix4 expected;
1359 expected.loadTranslate(0, -2000, 0);
1360 EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
1361 << "expect content to be translated as part of being clipped";
1362}
1363
Chris Craikf158b492016-01-12 14:45:08 -08001364TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001365 SaveLayerAlphaData observedData;
1366 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1367 // Translate and rotate the view so that the only visible part is the top left corner of
Chris Craik8d1f2122015-11-24 16:40:09 -08001368 // the view. It will form an isosceles right triangle with a long side length of 200 at the
Chris Craik8ecf41c2015-11-16 10:27:59 -08001369 // bottom of the viewport.
1370 properties.setTranslationX(100);
1371 properties.setTranslationY(100);
1372 properties.setPivotX(0);
1373 properties.setPivotY(0);
1374 properties.setRotation(45);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001375 });
1376 // ceil(sqrt(2) / 2 * 200) = 142
1377 EXPECT_EQ(142u, observedData.layerWidth);
1378 EXPECT_EQ(142u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001379 EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001380 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
1381}
1382
Chris Craikf158b492016-01-12 14:45:08 -08001383TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
Chris Craik8ecf41c2015-11-16 10:27:59 -08001384 SaveLayerAlphaData observedData;
1385 testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
1386 properties.setPivotX(0);
1387 properties.setPivotY(0);
1388 properties.setScaleX(2);
1389 properties.setScaleY(0.5f);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001390 });
1391 EXPECT_EQ(100u, observedData.layerWidth);
1392 EXPECT_EQ(400u, observedData.layerHeight);
Chris Craik5430ab22015-12-10 16:28:16 -08001393 EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
Chris Craik8ecf41c2015-11-16 10:27:59 -08001394 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
1395}
1396
Chris Craik6fe991e52015-10-20 09:39:42 -07001397} // namespace uirenderer
1398} // namespace android