1 /* 2 * Copyright (C) 2016 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 <VectorDrawable.h> 18 #include <gtest/gtest.h> 19 20 #include <SkClipStack.h> 21 #include <SkSurface_Base.h> 22 #include <string.h> 23 #include "AnimationContext.h" 24 #include "DamageAccumulator.h" 25 #include "FatalTestCanvas.h" 26 #include "IContextFactory.h" 27 #include "SkiaCanvas.h" 28 #include "pipeline/skia/SkiaDisplayList.h" 29 #include "pipeline/skia/SkiaPipeline.h" 30 #include "pipeline/skia/SkiaRecordingCanvas.h" 31 #include "renderthread/CanvasContext.h" 32 #include "tests/common/TestUtils.h" 33 34 using namespace android; 35 using namespace android::uirenderer; 36 using namespace android::uirenderer::renderthread; 37 using namespace android::uirenderer::skiapipeline; 38 39 namespace { 40 41 static void testProperty(std::function<void(RenderProperties&)> propSetupCallback, 42 std::function<void(const SkCanvas&)> opValidateCallback) { 43 static const int CANVAS_WIDTH = 100; 44 static const int CANVAS_HEIGHT = 100; 45 class PropertyTestCanvas : public TestCanvasBase { 46 public: 47 explicit PropertyTestCanvas(std::function<void(const SkCanvas&)> callback) 48 : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {} 49 void onDrawRect(const SkRect& rect, const SkPaint& paint) override { 50 EXPECT_EQ(mDrawCounter++, 0); 51 mCallback(*this); 52 } 53 void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) { 54 SkCanvas::onClipRRect(rrect, op, style); 55 } 56 std::function<void(const SkCanvas&)> mCallback; 57 }; 58 59 auto node = TestUtils::createSkiaNode( 60 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 61 [propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) { 62 propSetupCallback(props); 63 SkPaint paint; 64 paint.setColor(SK_ColorWHITE); 65 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint); 66 }); 67 68 PropertyTestCanvas canvas(opValidateCallback); 69 RenderNodeDrawable drawable(node.get(), &canvas, true); 70 canvas.drawDrawable(&drawable); 71 EXPECT_EQ(1, canvas.mDrawCounter); 72 } 73 } 74 75 TEST(RenderNodeDrawable, renderPropClipping) { 76 testProperty( 77 [](RenderProperties& properties) { 78 properties.setClipToBounds(true); 79 properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400)); 80 }, 81 [](const SkCanvas& canvas) { 82 EXPECT_EQ(SkRect::MakeLTRB(10, 20, 100, 100), TestUtils::getClipBounds(&canvas)) 83 << "Clip rect should be intersection of node bounds and clip bounds"; 84 }); 85 } 86 87 TEST(RenderNodeDrawable, renderPropRevealClip) { 88 testProperty( 89 [](RenderProperties& properties) { 90 properties.mutableRevealClip().set(true, 50, 50, 25); 91 }, 92 [](const SkCanvas& canvas) { 93 EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas)); 94 }); 95 } 96 97 TEST(RenderNodeDrawable, renderPropOutlineClip) { 98 testProperty( 99 [](RenderProperties& properties) { 100 properties.mutableOutline().setShouldClip(true); 101 properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f); 102 }, 103 [](const SkCanvas& canvas) { 104 EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas)); 105 }); 106 } 107 108 TEST(RenderNodeDrawable, renderPropTransform) { 109 testProperty( 110 [](RenderProperties& properties) { 111 properties.setLeftTopRightBottom(10, 10, 110, 110); 112 113 SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f); 114 properties.setStaticMatrix(&staticMatrix); 115 116 // ignored, since static overrides animation 117 SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15); 118 properties.setAnimationMatrix(&animationMatrix); 119 120 properties.setTranslationX(10); 121 properties.setTranslationY(20); 122 properties.setScaleX(0.5f); 123 properties.setScaleY(0.7f); 124 }, 125 [](const SkCanvas& canvas) { 126 Matrix4 matrix; 127 matrix.loadTranslate(10, 10, 0); // left, top 128 matrix.scale(1.2f, 1.2f, 1); // static matrix 129 // ignore animation matrix, since static overrides it 130 131 // translation xy 132 matrix.translate(10, 20); 133 134 // scale xy (from default pivot - center) 135 matrix.translate(50, 50); 136 matrix.scale(0.5f, 0.7f, 1); 137 matrix.translate(-50, -50); 138 Matrix4 actual(canvas.getTotalMatrix()); 139 EXPECT_MATRIX_APPROX_EQ(matrix, actual) << "Op draw matrix must match expected " 140 "combination of transformation " 141 "properties"; 142 }); 143 } 144