| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2020 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 |  | 
| John Reck | dc95f10 | 2020-11-16 12:35:02 -0500 | [diff] [blame] | 19 | #include <canvas/CanvasFrontend.h> | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 20 | #include <canvas/CanvasOpBuffer.h> | 
 | 21 | #include <canvas/CanvasOps.h> | 
 | 22 | #include <canvas/CanvasOpRasterizer.h> | 
 | 23 |  | 
 | 24 | #include <tests/common/CallCountingCanvas.h> | 
 | 25 |  | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 26 | #include "SkPictureRecorder.h" | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 27 | #include "SkColor.h" | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 28 | #include "SkLatticeIter.h" | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 29 | #include "pipeline/skia/AnimatedDrawables.h" | 
| John Reck | dc95f10 | 2020-11-16 12:35:02 -0500 | [diff] [blame] | 30 | #include <SkNoDrawCanvas.h> | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 31 |  | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 32 | using namespace android; | 
 | 33 | using namespace android::uirenderer; | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 34 | using namespace android::uirenderer::skiapipeline; | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 35 | using namespace android::uirenderer::test; | 
 | 36 |  | 
 | 37 | // We lazy | 
 | 38 | using Op = CanvasOpType; | 
 | 39 |  | 
| John Reck | dc95f10 | 2020-11-16 12:35:02 -0500 | [diff] [blame] | 40 | class CanvasOpCountingReceiver { | 
 | 41 | public: | 
 | 42 |     template <CanvasOpType T> | 
 | 43 |     void push_container(CanvasOpContainer<T>&& op) { | 
 | 44 |         mOpCounts[static_cast<size_t>(T)] += 1; | 
 | 45 |     } | 
 | 46 |  | 
 | 47 |     int operator[](CanvasOpType op) const { | 
 | 48 |         return mOpCounts[static_cast<size_t>(op)]; | 
 | 49 |     } | 
 | 50 |  | 
 | 51 | private: | 
 | 52 |     std::array<int, static_cast<size_t>(CanvasOpType::COUNT)> mOpCounts; | 
 | 53 | }; | 
 | 54 |  | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 55 | template<typename T> | 
 | 56 | static int countItems(const T& t) { | 
 | 57 |     int count = 0; | 
 | 58 |     t.for_each([&](auto i) { | 
 | 59 |         count++; | 
 | 60 |     }); | 
 | 61 |     return count; | 
 | 62 | } | 
 | 63 |  | 
| John Reck | 90b0a1c | 2020-11-12 12:37:30 -0500 | [diff] [blame] | 64 | TEST(CanvasOp, verifyConst) { | 
 | 65 |     CanvasOpBuffer buffer; | 
 | 66 |     buffer.push<Op::DrawColor>({ | 
 | 67 |         .color = SkColors::kBlack, | 
 | 68 |         .mode = SkBlendMode::kSrcOver, | 
 | 69 |     }); | 
 | 70 |     buffer.for_each([](auto op) { | 
 | 71 |         static_assert(std::is_const_v<std::remove_reference_t<decltype(*op)>>, | 
 | 72 |                 "Expected container to be const"); | 
 | 73 |         static_assert(std::is_const_v<std::remove_reference_t<decltype(op->op())>>, | 
 | 74 |                 "Expected op to be const"); | 
 | 75 |     }); | 
 | 76 | } | 
 | 77 |  | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 78 | TEST(CanvasOp, simplePush) { | 
 | 79 |     CanvasOpBuffer buffer; | 
 | 80 |     EXPECT_EQ(buffer.size(), 0); | 
 | 81 |     buffer.push<Op::Save>({}); | 
 | 82 |     buffer.push<Op::Save>({}); | 
 | 83 |     buffer.push<Op::Restore>({}); | 
 | 84 |     EXPECT_GT(buffer.size(), 0); | 
 | 85 |  | 
 | 86 |     int saveCount = 0; | 
 | 87 |     int restoreCount = 0; | 
 | 88 |     int otherCount = 0; | 
 | 89 |  | 
 | 90 |     buffer.for_each([&](auto op) { | 
 | 91 |         switch (op->type()) { | 
 | 92 |             case Op::Save: | 
 | 93 |                 saveCount++; | 
 | 94 |                 break; | 
 | 95 |             case Op::Restore: | 
 | 96 |                 restoreCount++; | 
 | 97 |                 break; | 
 | 98 |             default: | 
 | 99 |                 otherCount++; | 
 | 100 |                 break; | 
 | 101 |         } | 
 | 102 |     }); | 
 | 103 |  | 
 | 104 |     EXPECT_EQ(saveCount, 2); | 
 | 105 |     EXPECT_EQ(restoreCount, 1); | 
 | 106 |     EXPECT_EQ(otherCount, 0); | 
 | 107 |  | 
 | 108 |     buffer.clear(); | 
 | 109 |     int itemCount = 0; | 
 | 110 |     buffer.for_each([&](auto op) { | 
 | 111 |         itemCount++; | 
 | 112 |     }); | 
 | 113 |     EXPECT_EQ(itemCount, 0); | 
 | 114 |     buffer.resize(0); | 
 | 115 |     EXPECT_EQ(buffer.size(), 0); | 
 | 116 | } | 
 | 117 |  | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 118 | TEST(CanvasOp, simpleDrawPaint) { | 
 | 119 |     CanvasOpBuffer buffer; | 
 | 120 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 121 |     buffer.push<Op::DrawColor> ({ | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 122 |         .color = SkColor4f{1, 1, 1, 1}, | 
 | 123 |         .mode = SkBlendMode::kSrcIn | 
 | 124 |     }); | 
 | 125 |  | 
 | 126 |     CallCountingCanvas canvas; | 
 | 127 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 128 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 129 |     EXPECT_EQ(1, canvas.drawPaintCount); | 
 | 130 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 131 | } | 
 | 132 |  | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 133 | TEST(CanvasOp, simpleDrawPoint) { | 
 | 134 |     CanvasOpBuffer buffer; | 
 | 135 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 136 |     buffer.push<Op::DrawPoint> ({ | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 137 |         .x = 12, | 
 | 138 |         .y = 42, | 
 | 139 |         .paint = SkPaint{} | 
 | 140 |     }); | 
 | 141 |  | 
 | 142 |     CallCountingCanvas canvas; | 
 | 143 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 144 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 145 |     EXPECT_EQ(1, canvas.drawPoints); | 
 | 146 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 147 | } | 
 | 148 |  | 
| Nader Jawad | 4285c8a | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 149 | TEST(CanvasOp, simpleDrawPoints) { | 
 | 150 |     CanvasOpBuffer buffer; | 
 | 151 |     EXPECT_EQ(buffer.size(), 0); | 
 | 152 |     size_t numPts = 3; | 
| John Reck | 064650b | 2021-01-19 21:29:24 -0500 | [diff] [blame] | 153 |     auto pts = sk_sp<Points>( | 
| Nader Jawad | 4285c8a | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 154 |           new Points({ | 
 | 155 |               {32, 16}, | 
 | 156 |               {48, 48}, | 
 | 157 |               {16, 32} | 
 | 158 |           }) | 
 | 159 |     ); | 
 | 160 |  | 
 | 161 |     buffer.push(CanvasOp<Op::DrawPoints> { | 
 | 162 |         .count = numPts, | 
 | 163 |         .paint = SkPaint{}, | 
 | 164 |         .points = pts | 
 | 165 |     }); | 
 | 166 |  | 
 | 167 |     CallCountingCanvas canvas; | 
 | 168 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 169 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 170 |     EXPECT_EQ(1, canvas.drawPoints); | 
 | 171 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 172 | } | 
 | 173 |  | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 174 | TEST(CanvasOp, simpleDrawLine) { | 
 | 175 |     CanvasOpBuffer buffer; | 
 | 176 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 177 |     buffer.push<Op::DrawLine> ({ | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 178 |         .startX = 16, | 
 | 179 |         .startY = 28, | 
 | 180 |         .endX = 12, | 
 | 181 |         .endY = 30, | 
 | 182 |         .paint = SkPaint{} | 
 | 183 |     }); | 
 | 184 |  | 
 | 185 |     CallCountingCanvas canvas; | 
 | 186 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 187 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 188 |     EXPECT_EQ(1, canvas.drawPoints); | 
 | 189 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 190 | } | 
 | 191 |  | 
| Nader Jawad | 4285c8a | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 192 | TEST(CanvasOp, simpleDrawLines) { | 
 | 193 |     CanvasOpBuffer buffer; | 
 | 194 |     EXPECT_EQ(buffer.size(), 0); | 
 | 195 |     size_t numPts = 3; | 
| John Reck | 064650b | 2021-01-19 21:29:24 -0500 | [diff] [blame] | 196 |     auto pts = sk_sp<Points>( | 
| Nader Jawad | 4285c8a | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 197 |         new Points({ | 
 | 198 |                {32, 16}, | 
 | 199 |                {48, 48}, | 
 | 200 |                {16, 32} | 
 | 201 |           }) | 
 | 202 |         ); | 
 | 203 |     buffer.push(CanvasOp<Op::DrawLines> { | 
 | 204 |         .count = numPts, | 
 | 205 |         .paint = SkPaint{}, | 
 | 206 |         .points = pts | 
 | 207 |     }); | 
 | 208 |  | 
 | 209 |     CallCountingCanvas canvas; | 
 | 210 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 211 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 212 |     EXPECT_EQ(1, canvas.drawPoints); | 
 | 213 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 214 | } | 
 | 215 |  | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 216 | TEST(CanvasOp, simpleDrawRect) { | 
 | 217 |     CanvasOpBuffer buffer; | 
 | 218 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 219 |     buffer.push<Op::DrawRect> ({ | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 220 |         .paint = SkPaint{}, | 
 | 221 |         .rect = SkRect::MakeEmpty() | 
 | 222 |     }); | 
 | 223 |  | 
 | 224 |     CallCountingCanvas canvas; | 
 | 225 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 226 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 227 |     EXPECT_EQ(1, canvas.drawRectCount); | 
 | 228 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 229 | } | 
 | 230 |  | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 231 | TEST(CanvasOp, simpleDrawRegionRect) { | 
 | 232 |     CanvasOpBuffer buffer; | 
 | 233 |     EXPECT_EQ(buffer.size(), 0); | 
 | 234 |     SkRegion region; | 
 | 235 |     region.setRect(SkIRect::MakeWH(12, 50)); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 236 |     buffer.push<Op::DrawRegion> ({ | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 237 |         .paint = SkPaint{}, | 
 | 238 |         .region = region | 
 | 239 |     }); | 
 | 240 |  | 
 | 241 |     CallCountingCanvas canvas; | 
 | 242 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 243 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 244 |     // If the region is a rectangle, drawRegion calls into drawRect as a fast path | 
 | 245 |     EXPECT_EQ(1, canvas.drawRectCount); | 
 | 246 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 247 | } | 
 | 248 |  | 
 | 249 | TEST(CanvasOp, simpleDrawRegionPath) { | 
 | 250 |     CanvasOpBuffer buffer; | 
 | 251 |     EXPECT_EQ(buffer.size(), 0); | 
 | 252 |     SkPath path; | 
 | 253 |     path.addCircle(50, 50, 50); | 
 | 254 |     SkRegion clip; | 
 | 255 |     clip.setRect(SkIRect::MakeWH(100, 100)); | 
 | 256 |     SkRegion region; | 
 | 257 |     region.setPath(path, clip); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 258 |     buffer.push<Op::DrawRegion> ({ | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 259 |         .paint = SkPaint{}, | 
 | 260 |         .region = region | 
 | 261 |     }); | 
 | 262 |  | 
 | 263 |     CallCountingCanvas canvas; | 
 | 264 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 265 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 266 |     EXPECT_EQ(1, canvas.drawRegionCount); | 
 | 267 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 268 | } | 
 | 269 |  | 
| Nader Jawad | d5c2b6d | 2020-11-05 19:12:29 -0800 | [diff] [blame] | 270 | TEST(CanvasOp, simpleDrawRoundRect) { | 
 | 271 |     CanvasOpBuffer buffer; | 
 | 272 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 273 |     buffer.push<Op::DrawRoundRect> ({ | 
| Nader Jawad | d5c2b6d | 2020-11-05 19:12:29 -0800 | [diff] [blame] | 274 |         .paint = SkPaint{}, | 
 | 275 |         .rect = SkRect::MakeEmpty(), | 
 | 276 |         .rx = 10, | 
 | 277 |         .ry = 10 | 
 | 278 |     }); | 
 | 279 |  | 
 | 280 |     CallCountingCanvas canvas; | 
 | 281 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 282 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 283 |     EXPECT_EQ(1, canvas.drawRRectCount); | 
 | 284 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 285 | } | 
 | 286 |  | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 287 | TEST(CanvasOp, simpleDrawDoubleRoundRect) { | 
 | 288 |     CanvasOpBuffer buffer; | 
 | 289 |     EXPECT_EQ(buffer.size(), 0); | 
 | 290 |     SkRect outer = SkRect::MakeLTRB(0, 0, 100, 100); | 
 | 291 |     SkRect inner = SkRect::MakeLTRB(20, 20, 80, 80); | 
 | 292 |  | 
 | 293 |     const int numPts = 4; | 
 | 294 |     SkRRect outerRRect; | 
 | 295 |  | 
 | 296 |     auto outerPts = std::make_unique<SkVector[]>(numPts); | 
 | 297 |     outerPts[0].set(32, 16); | 
 | 298 |     outerPts[1].set(48, 48); | 
 | 299 |     outerPts[2].set(16, 32); | 
 | 300 |     outerPts[3].set(20, 20); | 
 | 301 |     outerRRect.setRectRadii(outer, outerPts.get()); | 
 | 302 |     outerRRect.setRect(outer); | 
 | 303 |  | 
 | 304 |     SkRRect innerRRect; | 
 | 305 |     auto innerPts = std::make_unique<SkVector[]>(numPts); | 
 | 306 |     innerPts[0].set(16, 8); | 
 | 307 |     innerPts[1].set(24, 24); | 
 | 308 |     innerPts[2].set(8, 16); | 
 | 309 |     innerPts[3].set(10, 10); | 
 | 310 |     innerRRect.setRectRadii(inner, innerPts.get()); | 
 | 311 |  | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 312 |     buffer.push<Op::DrawDoubleRoundRect> ({ | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 313 |         .outer = outerRRect, | 
 | 314 |         .inner = innerRRect, | 
 | 315 |         .paint = SkPaint{} | 
 | 316 |     }); | 
 | 317 |  | 
 | 318 |     CallCountingCanvas canvas; | 
 | 319 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 320 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 321 |     EXPECT_EQ(1, canvas.drawDRRectCount); | 
 | 322 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 323 | } | 
 | 324 |  | 
| Nader Jawad | d5c2b6d | 2020-11-05 19:12:29 -0800 | [diff] [blame] | 325 | TEST(CanvasOp, simpleDrawCircle) { | 
 | 326 |     CanvasOpBuffer buffer; | 
 | 327 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 328 |     buffer.push<Op::DrawCircle>({ | 
| Nader Jawad | d5c2b6d | 2020-11-05 19:12:29 -0800 | [diff] [blame] | 329 |         .cx = 5, | 
 | 330 |         .cy = 7, | 
 | 331 |         .radius = 10, | 
 | 332 |         .paint = SkPaint{} | 
 | 333 |     }); | 
 | 334 |  | 
 | 335 |     CallCountingCanvas canvas; | 
 | 336 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 337 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 338 |     EXPECT_EQ(1, canvas.drawOvalCount); | 
 | 339 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 340 | } | 
 | 341 |  | 
 | 342 | TEST(CanvasOp, simpleDrawOval) { | 
 | 343 |     CanvasOpBuffer buffer; | 
 | 344 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 345 |     buffer.push<Op::DrawOval> ({ | 
| Nader Jawad | d5c2b6d | 2020-11-05 19:12:29 -0800 | [diff] [blame] | 346 |         .oval = SkRect::MakeEmpty(), | 
 | 347 |         .paint = SkPaint{} | 
 | 348 |     }); | 
 | 349 |  | 
 | 350 |     CallCountingCanvas canvas; | 
 | 351 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 352 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 353 |     EXPECT_EQ(1, canvas.drawOvalCount); | 
 | 354 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 355 | } | 
 | 356 |  | 
 | 357 | TEST(CanvasOp, simpleDrawArc) { | 
 | 358 |     CanvasOpBuffer buffer; | 
 | 359 |     EXPECT_EQ(buffer.size(), 0); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 360 |     buffer.push<Op::DrawArc>({ | 
| Nader Jawad | d5c2b6d | 2020-11-05 19:12:29 -0800 | [diff] [blame] | 361 |         .oval = SkRect::MakeWH(100, 100), | 
 | 362 |         .startAngle = 120, | 
 | 363 |         .sweepAngle = 70, | 
 | 364 |         .useCenter = true, | 
 | 365 |         .paint = SkPaint{} | 
 | 366 |     }); | 
 | 367 |  | 
 | 368 |     CallCountingCanvas canvas; | 
 | 369 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 370 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 371 |     EXPECT_EQ(1, canvas.drawArcCount); | 
 | 372 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 373 | } | 
 | 374 |  | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 375 | TEST(CanvasOp, simpleDrawPath) { | 
 | 376 |     CanvasOpBuffer buffer; | 
 | 377 |     EXPECT_EQ(buffer.size(), 0); | 
 | 378 |     SkPath path; | 
 | 379 |     path.addCircle(50, 50, 30); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 380 |     buffer.push<Op::DrawPath> ({ | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 381 |         .path = path, | 
 | 382 |         .paint = SkPaint{} | 
 | 383 |     }); | 
 | 384 |  | 
 | 385 |     CallCountingCanvas canvas; | 
 | 386 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 387 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 388 |     EXPECT_EQ(1, canvas.drawPathCount); | 
 | 389 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 390 | } | 
 | 391 |  | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 392 | TEST(CanvasOp, simpleDrawRoundRectProperty) { | 
 | 393 |     CanvasOpBuffer buffer; | 
 | 394 |     EXPECT_EQ(buffer.size(), 0); | 
 | 395 |  | 
 | 396 |     auto left = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1)); | 
 | 397 |     auto top = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2)); | 
 | 398 |     auto right = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(3)); | 
 | 399 |     auto bottom = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(4)); | 
 | 400 |     auto radiusX = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5)); | 
 | 401 |     auto radiusY = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(6)); | 
 | 402 |     auto propertyPaint = | 
 | 403 |             sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{})); | 
 | 404 |  | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 405 |     buffer.push<Op::DrawRoundRectProperty> ({ | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 406 |         .left = left, | 
 | 407 |         .top = top, | 
 | 408 |         .right = right, | 
 | 409 |         .bottom = bottom, | 
 | 410 |         .rx = radiusX, | 
 | 411 |         .ry = radiusY, | 
 | 412 |         .paint = propertyPaint | 
 | 413 |     }); | 
 | 414 |  | 
 | 415 |     CallCountingCanvas canvas; | 
 | 416 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 417 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 418 |     EXPECT_EQ(1, canvas.drawRRectCount); | 
 | 419 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 420 | } | 
 | 421 |  | 
 | 422 | TEST(CanvasOp, simpleDrawCircleProperty) { | 
 | 423 |     CanvasOpBuffer buffer; | 
 | 424 |     EXPECT_EQ(buffer.size(), 0); | 
 | 425 |  | 
 | 426 |     auto x = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1)); | 
 | 427 |     auto y = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2)); | 
 | 428 |     auto radius = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5)); | 
 | 429 |     auto propertyPaint = | 
 | 430 |             sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{})); | 
 | 431 |  | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 432 |     buffer.push<Op::DrawCircleProperty> ({ | 
| Nader Jawad | de3ce84 | 2020-11-06 16:54:48 -0800 | [diff] [blame] | 433 |         .x = x, | 
 | 434 |         .y = y, | 
 | 435 |         .radius = radius, | 
 | 436 |         .paint = propertyPaint | 
 | 437 |     }); | 
 | 438 |  | 
 | 439 |     CallCountingCanvas canvas; | 
 | 440 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 441 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 442 |     EXPECT_EQ(1, canvas.drawOvalCount); | 
 | 443 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 444 | } | 
 | 445 |  | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 446 | TEST(CanvasOp, simpleDrawVertices) { | 
 | 447 |     CanvasOpBuffer buffer; | 
 | 448 |     EXPECT_EQ(buffer.size(), 0); | 
 | 449 |  | 
 | 450 |     SkPoint pts[3] = {{64, 32}, {0, 224}, {128, 224}}; | 
 | 451 |     SkColor colors[3] = {SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN}; | 
 | 452 |     sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, pts, | 
 | 453 |             nullptr, colors); | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 454 |     buffer.push<Op::DrawVertices> ({ | 
| Nader Jawad | fb1e7f1 | 2020-11-06 22:49:42 -0800 | [diff] [blame] | 455 |         .vertices = vertices, | 
 | 456 |         .mode = SkBlendMode::kSrcOver, | 
 | 457 |         .paint = SkPaint{} | 
 | 458 |     }); | 
 | 459 |  | 
 | 460 |     CallCountingCanvas canvas; | 
 | 461 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 462 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 463 |     EXPECT_EQ(1, canvas.drawVerticesCount); | 
 | 464 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 465 | } | 
 | 466 |  | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 467 | TEST(CanvasOp, simpleDrawImage) { | 
 | 468 |     CanvasOpBuffer buffer; | 
 | 469 |     EXPECT_EQ(buffer.size(), 0); | 
 | 470 |  | 
 | 471 |     SkImageInfo info =SkImageInfo::Make(5, 1, | 
 | 472 |         kGray_8_SkColorType, kOpaque_SkAlphaType); | 
 | 473 |     sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info); | 
 | 474 |     buffer.push<Op::DrawImage> ({ | 
 | 475 |             bitmap, | 
 | 476 |             7, | 
 | 477 |             19, | 
| Mike Reed | 7994a31 | 2021-01-28 18:06:26 -0500 | [diff] [blame] | 478 |             SkFilterMode::kNearest, | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 479 |             SkPaint{} | 
 | 480 |         } | 
 | 481 |     ); | 
 | 482 |  | 
 | 483 |     CallCountingCanvas canvas; | 
 | 484 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 485 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 486 |     EXPECT_EQ(1, canvas.drawImageCount); | 
 | 487 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 488 | } | 
 | 489 |  | 
 | 490 | TEST(CanvasOp, simpleDrawImageRect) { | 
 | 491 |     CanvasOpBuffer buffer; | 
 | 492 |     EXPECT_EQ(buffer.size(), 0); | 
 | 493 |  | 
 | 494 |     SkImageInfo info = SkImageInfo::Make(5, 1, | 
 | 495 |         kGray_8_SkColorType, kOpaque_SkAlphaType); | 
 | 496 |  | 
 | 497 |     sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info); | 
 | 498 |     buffer.push<Op::DrawImageRect> ({ | 
 | 499 |           bitmap, SkRect::MakeWH(100, 100), | 
 | 500 |           SkRect::MakeLTRB(120, 110, 220, 210), | 
| Mike Reed | 7994a31 | 2021-01-28 18:06:26 -0500 | [diff] [blame] | 501 |           SkFilterMode::kNearest, SkPaint{} | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 502 |         } | 
 | 503 |     ); | 
 | 504 |  | 
 | 505 |     CallCountingCanvas canvas; | 
 | 506 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 507 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 508 |     EXPECT_EQ(1, canvas.drawImageRectCount); | 
 | 509 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 510 | } | 
 | 511 |  | 
 | 512 | TEST(CanvasOp, simpleDrawImageLattice) { | 
 | 513 |     CanvasOpBuffer buffer; | 
 | 514 |     EXPECT_EQ(buffer.size(), 0); | 
 | 515 |  | 
 | 516 |     SkBitmap skBitmap; | 
 | 517 |     skBitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60)); | 
 | 518 |  | 
 | 519 |     const int xDivs[] = { 20, 50 }; | 
 | 520 |     const int yDivs[] = { 10, 40 }; | 
 | 521 |     SkCanvas::Lattice::RectType fillTypes[3][3]; | 
 | 522 |     memset(fillTypes, 0, sizeof(fillTypes)); | 
 | 523 |     fillTypes[1][1] = SkCanvas::Lattice::kTransparent; | 
 | 524 |     SkColor colors[9]; | 
 | 525 |     SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], 2, | 
 | 526 |          2, nullptr, colors }; | 
 | 527 |     sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(&skBitmap); | 
 | 528 |     buffer.push<Op::DrawImageLattice>( | 
 | 529 |         { | 
 | 530 |             bitmap, | 
 | 531 |             SkRect::MakeWH(5, 1), | 
 | 532 |             lattice, | 
| Mike Reed | 1b3dcfc | 2021-01-26 20:31:20 -0500 | [diff] [blame] | 533 |             SkFilterMode::kNearest, | 
| Nader Jawad | da9248c | 2020-11-09 17:27:36 -0800 | [diff] [blame] | 534 |             SkPaint{} | 
 | 535 |         } | 
 | 536 |     ); | 
 | 537 |  | 
 | 538 |     CallCountingCanvas canvas; | 
 | 539 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 540 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 541 |     EXPECT_EQ(1, canvas.drawImageLatticeCount); | 
 | 542 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 543 | } | 
 | 544 |  | 
 | 545 | TEST(CanvasOp, simpleDrawPicture) { | 
 | 546 |     CanvasOpBuffer buffer; | 
 | 547 |     EXPECT_EQ(buffer.size(), 0); | 
 | 548 |  | 
 | 549 |     SkPictureRecorder recorder; | 
 | 550 |     SkCanvas* pictureCanvas = recorder.beginRecording({64, 64, 192, 192}); | 
 | 551 |     SkPaint paint; | 
 | 552 |     pictureCanvas->drawRect(SkRect::MakeWH(200, 200), paint); | 
 | 553 |     paint.setColor(SK_ColorWHITE); | 
 | 554 |     pictureCanvas->drawRect(SkRect::MakeLTRB(20, 20, 180, 180), paint); | 
 | 555 |     sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); | 
 | 556 |     buffer.push<Op::DrawPicture> ({ | 
 | 557 |         .picture = picture | 
 | 558 |     }); | 
 | 559 |  | 
 | 560 |     CallCountingCanvas canvas; | 
 | 561 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 562 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 563 |     // Note because we are explicitly issuing 2 drawRect calls | 
 | 564 |     // in the picture recorder above, when it is played back into | 
 | 565 |     // CallCountingCanvas we will see 2 calls to drawRect instead of 1 | 
 | 566 |     // call to drawPicture. | 
 | 567 |     // This is because SkiaCanvas::drawPicture uses picture.playback(canvas) | 
 | 568 |     // instead of canvas->drawPicture. | 
 | 569 |     EXPECT_EQ(2, canvas.drawRectCount); | 
 | 570 |     EXPECT_EQ(2, canvas.sumTotalDrawCalls()); | 
 | 571 | } | 
 | 572 |  | 
| Lucas Dupin | 00af527 | 2021-04-29 20:30:01 -0700 | [diff] [blame] | 573 | TEST(CanvasOp, simpleDrawRipple) { | 
 | 574 |     CanvasOpBuffer buffer; | 
 | 575 |     EXPECT_EQ(buffer.size(), 0); | 
 | 576 |  | 
 | 577 |     const char* sksl = | 
 | 578 |             "half4 main(float2 coord) {" | 
 | 579 |             "  return half4(1.);" | 
 | 580 |             "}"; | 
 | 581 |     auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(sksl)); | 
 | 582 |     auto params = RippleDrawableParams{ | 
 | 583 |             .x = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(100)), | 
 | 584 |             .y = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(200)), | 
 | 585 |             .radius = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(50)), | 
 | 586 |             .progress = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(0.5)), | 
 | 587 |             .turbulencePhase = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(1)), | 
 | 588 |             .color = 0xff00ff, | 
 | 589 |             .paint = sp<CanvasPropertyPaint>(new CanvasPropertyPaint(SkPaint{})), | 
 | 590 |             .effectBuilder = SkRuntimeShaderBuilder(effect)}; | 
 | 591 |     buffer.push<Op::DrawRippleDrawable>({.params = params}); | 
 | 592 |  | 
 | 593 |     CallCountingCanvas canvas; | 
 | 594 |     EXPECT_EQ(0, canvas.sumTotalDrawCalls()); | 
 | 595 |     rasterizeCanvasBuffer(buffer, &canvas); | 
 | 596 |     EXPECT_EQ(1, canvas.drawOvalCount); | 
 | 597 |     EXPECT_EQ(1, canvas.sumTotalDrawCalls()); | 
 | 598 | } | 
 | 599 |  | 
| John Reck | 013127b | 2020-10-29 20:53:51 -0400 | [diff] [blame] | 600 | TEST(CanvasOp, immediateRendering) { | 
 | 601 |     auto canvas = std::make_shared<CallCountingCanvas>(); | 
 | 602 |  | 
 | 603 |     EXPECT_EQ(0, canvas->sumTotalDrawCalls()); | 
 | 604 |     ImmediateModeRasterizer rasterizer{canvas}; | 
 | 605 |     auto op = CanvasOp<Op::DrawRect> { | 
 | 606 |         .paint = SkPaint{}, | 
 | 607 |         .rect = SkRect::MakeEmpty() | 
 | 608 |     }; | 
 | 609 |     EXPECT_TRUE(CanvasOpTraits::can_draw<decltype(op)>); | 
 | 610 |     rasterizer.draw(op); | 
 | 611 |     EXPECT_EQ(1, canvas->drawRectCount); | 
 | 612 |     EXPECT_EQ(1, canvas->sumTotalDrawCalls()); | 
| John Reck | dc95f10 | 2020-11-16 12:35:02 -0500 | [diff] [blame] | 613 | } | 
 | 614 |  | 
 | 615 | TEST(CanvasOp, frontendSaveCount) { | 
 | 616 |     SkNoDrawCanvas skiaCanvas(100, 100); | 
 | 617 |     CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100); | 
 | 618 |     const auto& receiver = opCanvas.receiver(); | 
 | 619 |  | 
 | 620 |     EXPECT_EQ(1, skiaCanvas.getSaveCount()); | 
 | 621 |     EXPECT_EQ(1, opCanvas.saveCount()); | 
 | 622 |  | 
 | 623 |     skiaCanvas.save(); | 
 | 624 |     opCanvas.save(SaveFlags::MatrixClip); | 
 | 625 |     EXPECT_EQ(2, skiaCanvas.getSaveCount()); | 
 | 626 |     EXPECT_EQ(2, opCanvas.saveCount()); | 
 | 627 |  | 
 | 628 |     skiaCanvas.restore(); | 
 | 629 |     opCanvas.restore(); | 
 | 630 |     EXPECT_EQ(1, skiaCanvas.getSaveCount()); | 
 | 631 |     EXPECT_EQ(1, opCanvas.saveCount()); | 
 | 632 |  | 
 | 633 |     skiaCanvas.restore(); | 
 | 634 |     opCanvas.restore(); | 
 | 635 |     EXPECT_EQ(1, skiaCanvas.getSaveCount()); | 
 | 636 |     EXPECT_EQ(1, opCanvas.saveCount()); | 
 | 637 |  | 
 | 638 |     EXPECT_EQ(1, receiver[Op::Save]); | 
 | 639 |     EXPECT_EQ(1, receiver[Op::Restore]); | 
 | 640 | } |