1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
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 "CanvasState.h"
18
19 #include "Matrix.h"
20 #include "Rect.h"
21 #include "hwui/Canvas.h"
22 #include "utils/LinearAllocator.h"
23
24 #include <SkClipOp.h>
25 #include <SkPath.h>
26 #include <gtest/gtest.h>
27
28 namespace android {
29 namespace uirenderer {
30
31 class NullClient : public CanvasStateClient {
onViewportInitialized()32 void onViewportInitialized() override {}
onSnapshotRestored(const Snapshot & removed,const Snapshot & restored)33 void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
getTargetFbo() const34 GLuint getTargetFbo() const override { return 0; }
35 };
36
37 static NullClient sNullClient;
38
approxEqual(const Matrix4 & a,const Matrix4 & b)39 static bool approxEqual(const Matrix4& a, const Matrix4& b) {
40 for (int i = 0; i < 16; i++) {
41 if (!MathUtils::areEqual(a[i], b[i])) {
42 return false;
43 }
44 }
45 return true;
46 }
47
TEST(CanvasState,gettersAndSetters)48 TEST(CanvasState, gettersAndSetters) {
49 CanvasState state(sNullClient);
50 state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
51
52 ASSERT_EQ(state.getWidth(), 200);
53 ASSERT_EQ(state.getHeight(), 200);
54
55 Matrix4 simpleTranslate;
56 simpleTranslate.loadTranslate(10, 20, 0);
57 state.setMatrix(simpleTranslate);
58
59 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200));
60 ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
61 EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
62 EXPECT_TRUE(state.clipIsSimple());
63 }
64
TEST(CanvasState,simpleClipping)65 TEST(CanvasState, simpleClipping) {
66 CanvasState state(sNullClient);
67 state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
68
69 state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
70 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
71
72 state.clipRect(10, 10, 200, 200, SkClipOp::kIntersect);
73 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
74
75 state.clipRect(50, 50, 150, 150, SkClipOp::kReplace_deprecated);
76 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150));
77 }
78
TEST(CanvasState,complexClipping)79 TEST(CanvasState, complexClipping) {
80 CanvasState state(sNullClient);
81 state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
82
83 state.save(SaveFlags::MatrixClip);
84 {
85 // rotated clip causes complex clip
86 state.rotate(10);
87 EXPECT_TRUE(state.clipIsSimple());
88 state.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
89 EXPECT_FALSE(state.clipIsSimple());
90 }
91 state.restore();
92
93 state.save(SaveFlags::MatrixClip);
94 {
95 // subtracted clip causes complex clip
96 EXPECT_TRUE(state.clipIsSimple());
97 state.clipRect(50, 50, 150, 150, SkClipOp::kDifference);
98 EXPECT_FALSE(state.clipIsSimple());
99 }
100 state.restore();
101
102 state.save(SaveFlags::MatrixClip);
103 {
104 // complex path causes complex clip
105 SkPath path;
106 path.addOval(SkRect::MakeWH(200, 200));
107 EXPECT_TRUE(state.clipIsSimple());
108 state.clipPath(&path, SkClipOp::kDifference);
109 EXPECT_FALSE(state.clipIsSimple());
110 }
111 state.restore();
112 }
113
TEST(CanvasState,saveAndRestore)114 TEST(CanvasState, saveAndRestore) {
115 CanvasState state(sNullClient);
116 state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
117
118 state.save(SaveFlags::Clip);
119 {
120 state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
121 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
122 }
123 state.restore();
124 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
125
126 Matrix4 simpleTranslate;
127 simpleTranslate.loadTranslate(10, 10, 0);
128 state.save(SaveFlags::Matrix);
129 {
130 state.translate(10, 10, 0);
131 EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
132 }
133 state.restore();
134 EXPECT_FALSE(approxEqual(*state.currentTransform(), simpleTranslate));
135 }
136
TEST(CanvasState,saveAndRestoreButNotTooMuch)137 TEST(CanvasState, saveAndRestoreButNotTooMuch) {
138 CanvasState state(sNullClient);
139 state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
140
141 state.save(SaveFlags::Matrix); // NOTE: clip not saved
142 {
143 state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
144 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
145 }
146 state.restore();
147 ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
148
149 Matrix4 simpleTranslate;
150 simpleTranslate.loadTranslate(10, 10, 0);
151 state.save(SaveFlags::Clip); // NOTE: matrix not saved
152 {
153 state.translate(10, 10, 0);
154 EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
155 }
156 state.restore();
157 EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
158 }
159 }
160 }
161