152771272f4f018f4fc6846224bf047497e784af1Stan Iliev/*
252771272f4f018f4fc6846224bf047497e784af1Stan Iliev * Copyright (C) 2016 The Android Open Source Project
352771272f4f018f4fc6846224bf047497e784af1Stan Iliev *
452771272f4f018f4fc6846224bf047497e784af1Stan Iliev * Licensed under the Apache License, Version 2.0 (the "License");
552771272f4f018f4fc6846224bf047497e784af1Stan Iliev * you may not use this file except in compliance with the License.
652771272f4f018f4fc6846224bf047497e784af1Stan Iliev * You may obtain a copy of the License at
752771272f4f018f4fc6846224bf047497e784af1Stan Iliev *
852771272f4f018f4fc6846224bf047497e784af1Stan Iliev *      http://www.apache.org/licenses/LICENSE-2.0
952771272f4f018f4fc6846224bf047497e784af1Stan Iliev *
1052771272f4f018f4fc6846224bf047497e784af1Stan Iliev * Unless required by applicable law or agreed to in writing, software
1152771272f4f018f4fc6846224bf047497e784af1Stan Iliev * distributed under the License is distributed on an "AS IS" BASIS,
1252771272f4f018f4fc6846224bf047497e784af1Stan Iliev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352771272f4f018f4fc6846224bf047497e784af1Stan Iliev * See the License for the specific language governing permissions and
1452771272f4f018f4fc6846224bf047497e784af1Stan Iliev * limitations under the License.
1552771272f4f018f4fc6846224bf047497e784af1Stan Iliev */
1652771272f4f018f4fc6846224bf047497e784af1Stan Iliev
1752771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include <gtest/gtest.h>
1852771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include <VectorDrawable.h>
1952771272f4f018f4fc6846224bf047497e784af1Stan Iliev
2052771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "AnimationContext.h"
2152771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "DamageAccumulator.h"
2252771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "IContextFactory.h"
2352771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "pipeline/skia/SkiaDisplayList.h"
2452771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "pipeline/skia/SkiaPipeline.h"
2552771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "pipeline/skia/SkiaRecordingCanvas.h"
2652771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "renderthread/CanvasContext.h"
2752771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "tests/common/TestUtils.h"
2852771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "SkiaCanvas.h"
2952771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include <SkSurface_Base.h>
3052771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include <SkLiteRecorder.h>
3152771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include <SkClipStack.h>
3252771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "FatalTestCanvas.h"
3352771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include <string.h>
3452771272f4f018f4fc6846224bf047497e784af1Stan Iliev
3552771272f4f018f4fc6846224bf047497e784af1Stan Ilievusing namespace android;
3652771272f4f018f4fc6846224bf047497e784af1Stan Ilievusing namespace android::uirenderer;
3752771272f4f018f4fc6846224bf047497e784af1Stan Ilievusing namespace android::uirenderer::renderthread;
3852771272f4f018f4fc6846224bf047497e784af1Stan Ilievusing namespace android::uirenderer::skiapipeline;
3952771272f4f018f4fc6846224bf047497e784af1Stan Iliev
4052771272f4f018f4fc6846224bf047497e784af1Stan Ilievnamespace {
4152771272f4f018f4fc6846224bf047497e784af1Stan Iliev
4252771272f4f018f4fc6846224bf047497e784af1Stan Ilievstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
4352771272f4f018f4fc6846224bf047497e784af1Stan Iliev        std::function<void(const SkCanvas&)> opValidateCallback) {
4452771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_WIDTH = 100;
4552771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_HEIGHT = 100;
4652771272f4f018f4fc6846224bf047497e784af1Stan Iliev    class PropertyTestCanvas : public TestCanvasBase {
4752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    public:
4852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
4952771272f4f018f4fc6846224bf047497e784af1Stan Iliev                : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {}
5052771272f4f018f4fc6846224bf047497e784af1Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
5152771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(mDrawCounter++, 0);
5252771272f4f018f4fc6846224bf047497e784af1Stan Iliev            mCallback(*this);
5352771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
54d43eaa909018068bc1ac197839f5e2ed79d9139dMike Reed        void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) {
5552771272f4f018f4fc6846224bf047497e784af1Stan Iliev            SkCanvas::onClipRRect(rrect, op, style);
5652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
5752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        std::function<void(const SkCanvas&)> mCallback;
5852771272f4f018f4fc6846224bf047497e784af1Stan Iliev    };
5952771272f4f018f4fc6846224bf047497e784af1Stan Iliev
6052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
6152771272f4f018f4fc6846224bf047497e784af1Stan Iliev            [propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) {
6252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        propSetupCallback(props);
6352771272f4f018f4fc6846224bf047497e784af1Stan Iliev        SkPaint paint;
6452771272f4f018f4fc6846224bf047497e784af1Stan Iliev        paint.setColor(SK_ColorWHITE);
6552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
6652771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
6752771272f4f018f4fc6846224bf047497e784af1Stan Iliev
68d43eaa909018068bc1ac197839f5e2ed79d9139dMike Reed    PropertyTestCanvas canvas(opValidateCallback);
69d43eaa909018068bc1ac197839f5e2ed79d9139dMike Reed    RenderNodeDrawable drawable(node.get(), &canvas, true);
70d43eaa909018068bc1ac197839f5e2ed79d9139dMike Reed    canvas.drawDrawable(&drawable);
71d43eaa909018068bc1ac197839f5e2ed79d9139dMike Reed    EXPECT_EQ(1, canvas.mDrawCounter);
7252771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
7352771272f4f018f4fc6846224bf047497e784af1Stan Iliev
7452771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
7552771272f4f018f4fc6846224bf047497e784af1Stan Iliev
7698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielTEST(RenderNodeDrawable, renderPropClipping) {
7752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    testProperty([](RenderProperties& properties) {
7852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setClipToBounds(true);
7952771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400));
8052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    }, [](const SkCanvas& canvas) {
8152771272f4f018f4fc6846224bf047497e784af1Stan Iliev        EXPECT_EQ(SkRect::MakeLTRB(10, 20, 100, 100), TestUtils::getClipBounds(&canvas))
8252771272f4f018f4fc6846224bf047497e784af1Stan Iliev                << "Clip rect should be intersection of node bounds and clip bounds";
8352771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
8452771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
8552771272f4f018f4fc6846224bf047497e784af1Stan Iliev
8698c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielTEST(RenderNodeDrawable, renderPropRevealClip) {
8752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    testProperty([](RenderProperties& properties) {
8852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.mutableRevealClip().set(true, 50, 50, 25);
8952771272f4f018f4fc6846224bf047497e784af1Stan Iliev    }, [](const SkCanvas& canvas) {
90c1db0e0ff701c81aa909789e3c6c4d3d5b3aca84Stan Iliev        EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas));
9152771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
9252771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
9352771272f4f018f4fc6846224bf047497e784af1Stan Iliev
9498c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielTEST(RenderNodeDrawable, renderPropOutlineClip) {
9552771272f4f018f4fc6846224bf047497e784af1Stan Iliev    testProperty([](RenderProperties& properties) {
9652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.mutableOutline().setShouldClip(true);
9752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
9852771272f4f018f4fc6846224bf047497e784af1Stan Iliev    }, [](const SkCanvas& canvas) {
99c1db0e0ff701c81aa909789e3c6c4d3d5b3aca84Stan Iliev        EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas));
10052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
10152771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
10252771272f4f018f4fc6846224bf047497e784af1Stan Iliev
10398c78dad1969e2321cfee2085faa55d95bba7e29Greg DanielTEST(RenderNodeDrawable, renderPropTransform) {
10452771272f4f018f4fc6846224bf047497e784af1Stan Iliev    testProperty([](RenderProperties& properties) {
10552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setLeftTopRightBottom(10, 10, 110, 110);
10652771272f4f018f4fc6846224bf047497e784af1Stan Iliev
10752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
10852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setStaticMatrix(&staticMatrix);
10952771272f4f018f4fc6846224bf047497e784af1Stan Iliev
11052771272f4f018f4fc6846224bf047497e784af1Stan Iliev        // ignored, since static overrides animation
11152771272f4f018f4fc6846224bf047497e784af1Stan Iliev        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
11252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setAnimationMatrix(&animationMatrix);
11352771272f4f018f4fc6846224bf047497e784af1Stan Iliev
11452771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setTranslationX(10);
11552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setTranslationY(20);
11652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setScaleX(0.5f);
11752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        properties.setScaleY(0.7f);
11852771272f4f018f4fc6846224bf047497e784af1Stan Iliev    }, [](const SkCanvas& canvas) {
11952771272f4f018f4fc6846224bf047497e784af1Stan Iliev        Matrix4 matrix;
12052771272f4f018f4fc6846224bf047497e784af1Stan Iliev        matrix.loadTranslate(10, 10, 0); // left, top
12152771272f4f018f4fc6846224bf047497e784af1Stan Iliev        matrix.scale(1.2f, 1.2f, 1); // static matrix
12252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        // ignore animation matrix, since static overrides it
12352771272f4f018f4fc6846224bf047497e784af1Stan Iliev
12452771272f4f018f4fc6846224bf047497e784af1Stan Iliev        // translation xy
12552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        matrix.translate(10, 20);
12652771272f4f018f4fc6846224bf047497e784af1Stan Iliev
12752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        // scale xy (from default pivot - center)
12852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        matrix.translate(50, 50);
12952771272f4f018f4fc6846224bf047497e784af1Stan Iliev        matrix.scale(0.5f, 0.7f, 1);
13052771272f4f018f4fc6846224bf047497e784af1Stan Iliev        matrix.translate(-50, -50);
13152771272f4f018f4fc6846224bf047497e784af1Stan Iliev        Matrix4 actual(canvas.getTotalMatrix());
13252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        EXPECT_MATRIX_APPROX_EQ(matrix, actual)
13352771272f4f018f4fc6846224bf047497e784af1Stan Iliev                << "Op draw matrix must match expected combination of transformation properties";
13452771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
13552771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
136