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 { 32 void onViewportInitialized() override {} 33 void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} 34 GLuint getTargetFbo() const override { return 0; } 35 }; 36 37 static NullClient sNullClient; 38 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 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 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 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 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 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