/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "SkPictureRecorder.h" #include "SkColor.h" #include "SkLatticeIter.h" #include "pipeline/skia/AnimatedDrawables.h" #include using namespace android; using namespace android::uirenderer; using namespace android::uirenderer::test; class CanvasOpCountingReceiver { public: template void push_container(CanvasOpContainer&& op) { mOpCounts[static_cast(T)] += 1; } int operator[](CanvasOpType op) const { return mOpCounts[static_cast(op)]; } private: std::array(CanvasOpType::COUNT)> mOpCounts; }; TEST(CanvasFrontend, saveCount) { SkNoDrawCanvas skiaCanvas(100, 100); CanvasFrontend opCanvas(100, 100); const auto& receiver = opCanvas.receiver(); EXPECT_EQ(1, skiaCanvas.getSaveCount()); EXPECT_EQ(1, opCanvas.saveCount()); skiaCanvas.save(); opCanvas.save(SaveFlags::MatrixClip); EXPECT_EQ(2, skiaCanvas.getSaveCount()); EXPECT_EQ(2, opCanvas.saveCount()); skiaCanvas.restore(); opCanvas.restore(); EXPECT_EQ(1, skiaCanvas.getSaveCount()); EXPECT_EQ(1, opCanvas.saveCount()); skiaCanvas.restore(); opCanvas.restore(); EXPECT_EQ(1, skiaCanvas.getSaveCount()); EXPECT_EQ(1, opCanvas.saveCount()); EXPECT_EQ(1, receiver[CanvasOpType::Save]); EXPECT_EQ(1, receiver[CanvasOpType::Restore]); } TEST(CanvasFrontend, transform) { SkNoDrawCanvas skiaCanvas(100, 100); CanvasFrontend opCanvas(100, 100); skiaCanvas.translate(10, 10); opCanvas.translate(10, 10); EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform()); { skiaCanvas.save(); opCanvas.save(SaveFlags::Matrix); skiaCanvas.scale(2.0f, 1.125f); opCanvas.scale(2.0f, 1.125f); EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform()); skiaCanvas.restore(); opCanvas.restore(); } EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform()); { skiaCanvas.save(); opCanvas.save(SaveFlags::Matrix); skiaCanvas.rotate(90.f); opCanvas.rotate(90.f); EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform()); { skiaCanvas.save(); opCanvas.save(SaveFlags::Matrix); skiaCanvas.skew(5.0f, 2.25f); opCanvas.skew(5.0f, 2.25f); EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform()); skiaCanvas.restore(); opCanvas.restore(); } skiaCanvas.restore(); opCanvas.restore(); } EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform()); } TEST(CanvasFrontend, drawOpTransform) { CanvasFrontend opCanvas(100, 100); const auto &receiver = opCanvas.receiver(); auto makeDrawRect = [] { return CanvasOp{ .rect = SkRect::MakeWH(50, 50), .paint = SkPaint(SkColors::kBlack), }; }; opCanvas.draw(makeDrawRect()); opCanvas.translate(10, 10); opCanvas.draw(makeDrawRect()); opCanvas.save(); opCanvas.scale(2.0f, 4.0f); opCanvas.draw(makeDrawRect()); opCanvas.restore(); opCanvas.save(); opCanvas.translate(20, 15); opCanvas.draw(makeDrawRect()); opCanvas.save(); opCanvas.rotate(90.f); opCanvas.draw(makeDrawRect()); opCanvas.restore(); opCanvas.restore(); // Validate the results std::vector transforms; transforms.reserve(5); receiver.for_each([&](auto op) { // Filter for the DrawRect calls; ignore the save & restores // (TODO: Add a filtered for_each variant to OpBuffer?) if (op->type() == CanvasOpType::DrawRect) { transforms.push_back(op->transform()); } }); EXPECT_EQ(transforms.size(), 5); { // First result should be identity const auto &result = transforms[0]; EXPECT_EQ(SkMatrix::kIdentity_Mask, result.getType()); EXPECT_EQ(SkMatrix::I(), result); } { // Should be translate 10, 10 const auto &result = transforms[1]; EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType()); SkMatrix m; m.setTranslate(10, 10); EXPECT_EQ(m, result); } { // Should be translate 10, 10 + scale 2, 4 const auto &result = transforms[2]; EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask, result.getType()); SkMatrix m; m.setTranslate(10, 10); m.preScale(2.0f, 4.0f); EXPECT_EQ(m, result); } { // Should be translate 10, 10 + translate 20, 15 const auto &result = transforms[3]; EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType()); SkMatrix m; m.setTranslate(30, 25); EXPECT_EQ(m, result); } { // Should be translate 10, 10 + translate 20, 15 + rotate 90 const auto &result = transforms[4]; EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask, result.getType()); SkMatrix m; m.setTranslate(30, 25); m.preRotate(90.f); EXPECT_EQ(m, result); } }