ClipAreaTests.cpp revision 261725fdb2962271c222a049fcdf57bbdc8363c7
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 <gtest/gtest.h> 18#include <SkPath.h> 19#include <SkRegion.h> 20 21#include "ClipArea.h" 22 23#include "Matrix.h" 24#include "Rect.h" 25#include "utils/LinearAllocator.h" 26 27namespace android { 28namespace uirenderer { 29 30static Rect kViewportBounds(0, 0, 2048, 2048); 31 32static ClipArea createClipArea() { 33 ClipArea area; 34 area.setViewportDimensions(kViewportBounds.getWidth(), kViewportBounds.getHeight()); 35 return area; 36} 37 38TEST(TransformedRectangle, basics) { 39 Rect r(0, 0, 100, 100); 40 Matrix4 minus90; 41 minus90.loadRotate(-90); 42 minus90.mapRect(r); 43 Rect r2(20, 40, 120, 60); 44 45 Matrix4 m90; 46 m90.loadRotate(90); 47 TransformedRectangle tr(r, m90); 48 EXPECT_TRUE(tr.canSimplyIntersectWith(tr)); 49 50 Matrix4 m0; 51 TransformedRectangle tr0(r2, m0); 52 EXPECT_FALSE(tr.canSimplyIntersectWith(tr0)); 53 54 Matrix4 m45; 55 m45.loadRotate(45); 56 TransformedRectangle tr2(r, m45); 57 EXPECT_FALSE(tr2.canSimplyIntersectWith(tr)); 58} 59 60TEST(RectangleList, basics) { 61 RectangleList list; 62 EXPECT_TRUE(list.isEmpty()); 63 64 Rect r(0, 0, 100, 100); 65 Matrix4 m45; 66 m45.loadRotate(45); 67 list.set(r, m45); 68 EXPECT_FALSE(list.isEmpty()); 69 70 Rect r2(20, 20, 200, 200); 71 list.intersectWith(r2, m45); 72 EXPECT_FALSE(list.isEmpty()); 73 EXPECT_EQ(1, list.getTransformedRectanglesCount()); 74 75 Rect r3(20, 20, 200, 200); 76 Matrix4 m30; 77 m30.loadRotate(30); 78 list.intersectWith(r2, m30); 79 EXPECT_FALSE(list.isEmpty()); 80 EXPECT_EQ(2, list.getTransformedRectanglesCount()); 81 82 SkRegion clip; 83 clip.setRect(0, 0, 2000, 2000); 84 SkRegion rgn(list.convertToRegion(clip)); 85 EXPECT_FALSE(rgn.isEmpty()); 86} 87 88TEST(ClipArea, basics) { 89 ClipArea area(createClipArea()); 90 EXPECT_FALSE(area.isEmpty()); 91} 92 93TEST(ClipArea, paths) { 94 ClipArea area(createClipArea()); 95 SkPath path; 96 SkScalar r = 100; 97 path.addCircle(r, r, r); 98 area.clipPathWithTransform(path, &Matrix4::identity(), SkRegion::kIntersect_Op); 99 EXPECT_FALSE(area.isEmpty()); 100 EXPECT_FALSE(area.isSimple()); 101 EXPECT_FALSE(area.isRectangleList()); 102 103 Rect clipRect(area.getClipRect()); 104 Rect expected(0, 0, r * 2, r * 2); 105 EXPECT_EQ(expected, clipRect); 106 SkRegion clipRegion(area.getClipRegion()); 107 auto skRect(clipRegion.getBounds()); 108 Rect regionBounds; 109 regionBounds.set(skRect); 110 EXPECT_EQ(expected, regionBounds); 111} 112 113TEST(ClipArea, replaceNegative) { 114 ClipArea area(createClipArea()); 115 area.setClip(0, 0, 100, 100); 116 117 Rect expected(-50, -50, 50, 50); 118 area.clipRectWithTransform(expected, &Matrix4::identity(), SkRegion::kReplace_Op); 119 EXPECT_EQ(expected, area.getClipRect()); 120} 121 122TEST(ClipArea, serializeClip) { 123 ClipArea area(createClipArea()); 124 LinearAllocator allocator; 125 126 // unset clip 127 EXPECT_EQ(nullptr, area.serializeClip(allocator)); 128 129 // rect clip 130 area.setClip(0, 0, 200, 200); 131 { 132 auto serializedClip = area.serializeClip(allocator); 133 ASSERT_NE(nullptr, serializedClip); 134 ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode); 135 auto clipRect = reinterpret_cast<const ClipRect*>(serializedClip); 136 EXPECT_EQ(Rect(200, 200), clipRect->rect); 137 EXPECT_EQ(serializedClip, area.serializeClip(allocator)) 138 << "Requery of clip on unmodified ClipArea must return same pointer."; 139 } 140 141 // rect list 142 Matrix4 rotate; 143 rotate.loadRotate(2.0f); 144 area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op); 145 { 146 auto serializedClip = area.serializeClip(allocator); 147 ASSERT_NE(nullptr, serializedClip); 148 ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode); 149 auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip); 150 EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount()); 151 EXPECT_FALSE(clipRectList->rect.isEmpty()); 152 EXPECT_FLOAT_EQ(199.87817f, clipRectList->rect.right) 153 << "Right side should be clipped by rotated rect"; 154 EXPECT_EQ(serializedClip, area.serializeClip(allocator)) 155 << "Requery of clip on unmodified ClipArea must return same pointer."; 156 } 157 158 // region 159 SkPath circlePath; 160 circlePath.addCircle(100, 100, 100); 161 area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op); 162 { 163 auto serializedClip = area.serializeClip(allocator); 164 ASSERT_NE(nullptr, serializedClip); 165 ASSERT_EQ(ClipMode::Region, serializedClip->mode); 166 auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip); 167 EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds()) 168 << "Clip region should be 200x200"; 169 EXPECT_EQ(Rect(200, 200), clipRegion->rect); 170 EXPECT_EQ(serializedClip, area.serializeClip(allocator)) 171 << "Requery of clip on unmodified ClipArea must return same pointer."; 172 } 173} 174 175TEST(ClipArea, serializeIntersectedClip) { 176 ClipArea area(createClipArea()); 177 LinearAllocator allocator; 178 179 // simple state; 180 EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity())); 181 area.setClip(0, 0, 200, 200); 182 { 183 auto origRectClip = area.serializeClip(allocator); 184 ASSERT_NE(nullptr, origRectClip); 185 EXPECT_EQ(origRectClip, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity())); 186 } 187 188 // rect 189 { 190 ClipRect recordedClip(Rect(100, 100)); 191 Matrix4 translateScale; 192 translateScale.loadTranslate(100, 100, 0); 193 translateScale.scale(2, 3, 1); 194 auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale); 195 ASSERT_NE(nullptr, resolvedClip); 196 ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode); 197 EXPECT_EQ(Rect(100, 100, 200, 200), 198 reinterpret_cast<const ClipRect*>(resolvedClip)->rect); 199 200 EXPECT_EQ(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip, translateScale)) 201 << "Must return previous serialization, since input is same"; 202 203 ClipRect recordedClip2(Rect(100, 100)); 204 EXPECT_NE(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip2, translateScale)) 205 << "Shouldn't return previous serialization, since matrix location is different"; 206 } 207 208 // rect list 209 Matrix4 rotate; 210 rotate.loadRotate(2.0f); 211 area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op); 212 { 213 ClipRect recordedClip(Rect(100, 100)); 214 auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity()); 215 ASSERT_NE(nullptr, resolvedClip); 216 ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode); 217 auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip); 218 EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount()); 219 } 220 221 // region 222 SkPath circlePath; 223 circlePath.addCircle(100, 100, 100); 224 area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op); 225 { 226 SkPath ovalPath; 227 ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200)); 228 229 ClipRegion recordedClip; 230 recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200))); 231 recordedClip.rect = Rect(200, 200); 232 233 Matrix4 translate10x20; 234 translate10x20.loadTranslate(10, 20, 0); 235 auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, 236 translate10x20); // Note: only translate for now, others not handled correctly 237 ASSERT_NE(nullptr, resolvedClip); 238 ASSERT_EQ(ClipMode::Region, resolvedClip->mode); 239 auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip); 240 EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds()); 241 } 242} 243 244} // namespace uirenderer 245} // namespace android 246