VectorDrawable.h revision fc9999505a36c66892d7ccce85187936105f4f36
11ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/*
21ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
31ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
41ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
51ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * you may not use this file except in compliance with the License.
61ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * You may obtain a copy of the License at
71ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
81ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
91ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Unless required by applicable law or agreed to in writing, software
111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * See the License for the specific language governing permissions and
141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * limitations under the License.
151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */
161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#ifndef ANDROID_HWUI_VPATH_H
181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#define ANDROID_HWUI_VPATH_H
191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "hwui/Canvas.h"
21ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "hwui/Bitmap.h"
22ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "DisplayList.h"
23ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
24ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <SkBitmap.h>
25ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <SkColor.h>
26ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <SkColorFilter.h>
27ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <SkCanvas.h>
28ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <SkMatrix.h>
291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <SkPaint.h>
301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <SkPath.h>
311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <SkPathMeasure.h>
321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <SkRect.h>
331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <SkShader.h>
341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <cutils/compiler.h>
361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <stddef.h>
37ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <vector>
38cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include <string>
39ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
40cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinskinamespace android {
41ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskinamespace uirenderer {
42cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski// Debug
441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#if DEBUG_VECTOR_DRAWABLE
451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
46cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#else
471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    #define VECTOR_DRAWABLE_LOGD(...)
481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#endif
4964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
501e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinskinamespace VectorDrawable {
51ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
5364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
54cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    onPropertyChanged(); retVal;})
55cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
56c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski
57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski/* A VectorDrawable is composed of a tree of nodes.
58c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * Each node can be a group node, or a path.
59c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * A group node can have groups or paths as children, but a path node has
60c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * no children.
61c744ae8aca97edfb2422598ea620e8219449fa9bAdam Lesinski * One example can be:
62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski *                 Root Group
63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski *                /    |     \
64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski *           Group    Path    Group
65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski *          /     \             |
66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski *         Path   Path         Path
67cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski *
68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
69cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
70ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
71cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * Each cache has their own generation id to track whether they are up to date with the latest
72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * change in the tree.
731e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski *
741e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
751e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski * all the properties, and viewport change, etc.) are only modifying the staging properties. The
761e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski * staging properties will then be marked dirty and will be pushed over to render thread properties
771e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
78cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * staging properties with render thread properties to reflect the latest animation value.
79ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski *
80ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski */
81ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
82ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskiclass PropertyChangedListener {
83ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskipublic:
84ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    PropertyChangedListener(bool* dirty, bool* stagingDirty)
85ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            : mDirty(dirty), mStagingDirty(stagingDirty) {}
86cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    void onPropertyChanged() {
87ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski            *mDirty = true;
88ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    }
89ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    void onStagingPropertyChanged() {
90ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski            *mStagingDirty = true;
91ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    }
92ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskiprivate:
93ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    bool* mDirty;
94cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    bool* mStagingDirty;
95ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski};
96ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
97ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskiclass ANDROID_API Node {
98ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskipublic:
99ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    class Properties {
100cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    public:
101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        explicit Properties(Node* node) : mNode(node) {}
102ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski        inline void onPropertyChanged() {
1031e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski            mNode->onPropertyChanged(this);
104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        }
105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    private:
106cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        Node* mNode;
107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    };
108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    Node(const Node& node) {
109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        mName = node.mName;
110cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    Node() {}
11264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            float scaleX, float scaleY, bool useStagingData) = 0;
1141e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    virtual void dump() = 0;
1151e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    void setName(const char* name) {
1161e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        mName = name;
1171e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    }
1181e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
1191e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        mPropertyChangedListener = listener;
1201e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    }
1211e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    virtual void onPropertyChanged(Properties* properties) = 0;
1221e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    virtual ~Node(){}
1231e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    virtual void syncProperties() = 0;
1241e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinskiprotected:
1251e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    std::string mName;
1261e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    PropertyChangedListener* mPropertyChangedListener = nullptr;
1271e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski};
1281e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski
1291e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinskiclass ANDROID_API Path : public Node {
1301e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinskipublic:
1311e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    struct ANDROID_API Data {
1321e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        std::vector<char> verbs;
1331e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        std::vector<size_t> verbSizes;
1341e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        std::vector<float> points;
1351e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        bool operator==(const Data& data) const {
1361e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski            return verbs == data.verbs && verbSizes == data.verbSizes
1371e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski                    && points == data.points;
1381e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        }
1391e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    };
1401e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski
1411e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    class PathProperties : public Properties {
1421e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    public:
1431e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        explicit PathProperties(Node* node) : Properties(node) {}
1441e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        void syncProperties(const PathProperties& prop) {
1451e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski            mData = prop.mData;
1461e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski            onPropertyChanged();
1471e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        }
1481e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski        void setData(const Data& data) {
14964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            // Updates the path data. Note that we don't generate a new Skia path right away
150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // because there are cases where the animation is changing the path data, but the view
151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // that hosts the VD has gone off screen, in which case we won't even draw. So we
152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // postpone the Skia path generation to the draw time.
153ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            if (data == mData) {
154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                return;
155ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            }
156cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            mData = data;
1571e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski            onPropertyChanged();
158ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
159cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        }
160cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        const Data& getData() const {
161ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            return mData;
162cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        }
163ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    private:
1647656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski        Data mData;
165cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    };
166cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
16764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    Path(const Path& path);
1681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    Path(const char* path, size_t strLength);
1691e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    Path() {}
1701e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski
1711e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski    void dump() override;
17264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
173cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            float scaleX, float scaleY, bool useStagingData) override;
174ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    static float getMatrixScale(const SkMatrix& groupStackedMatrix);
1751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    virtual void syncProperties() override;
176ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    virtual void onPropertyChanged(Properties* prop) override {
177cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        if (prop == &mStagingProperties) {
17864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski            mStagingPropertiesDirty = true;
179ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            if (mPropertyChangedListener) {
180cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                mPropertyChangedListener->onStagingPropertyChanged();
181cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            }
1821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        } else if (prop == &mProperties){
183cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            mSkPathDirty = true;
184ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            if (mPropertyChangedListener) {
1851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                mPropertyChangedListener->onPropertyChanged();
186cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            }
18764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski        }
1881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
18964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    PathProperties* mutateStagingProperties() { return &mStagingProperties; }
190cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    const PathProperties* stagingProperties() { return &mStagingProperties; }
191cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
1921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    // This should only be called from animations on RT
193d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski    PathProperties* mutateProperties() { return &mProperties; }
194ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
19564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskiprotected:
196ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    virtual const SkPath& getUpdatedPath();
197cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    virtual void getStagingPath(SkPath* outPath);
198ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
199ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
200cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
20164587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski    // Internal data, render thread only.
202cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    bool mSkPathDirty = true;
203ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    SkPath mSkPath;
20464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski
205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinskiprivate:
2061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    PathProperties mProperties = PathProperties(this);
2071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    PathProperties mStagingProperties = PathProperties(this);
208cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    bool mStagingPropertiesDirty = true;
2091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski};
2101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
211class ANDROID_API FullPath: public Path {
212public:
213    class FullPathProperties : public Properties {
214    public:
215        struct PrimitiveFields {
216            float strokeWidth = 0;
217            SkColor strokeColor = SK_ColorTRANSPARENT;
218            float strokeAlpha = 1;
219            SkColor fillColor = SK_ColorTRANSPARENT;
220            float fillAlpha = 1;
221            float trimPathStart = 0;
222            float trimPathEnd = 1;
223            float trimPathOffset = 0;
224            int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
225            int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
226            float strokeMiterLimit = 4;
227            int fillType = 0; /* non-zero or kWinding_FillType in Skia */
228        };
229        explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
230        ~FullPathProperties() {
231            SkSafeUnref(fillGradient);
232            SkSafeUnref(strokeGradient);
233        }
234        void syncProperties(const FullPathProperties& prop) {
235            mPrimitiveFields = prop.mPrimitiveFields;
236            mTrimDirty = true;
237            UPDATE_SKPROP(fillGradient, prop.fillGradient);
238            UPDATE_SKPROP(strokeGradient, prop.strokeGradient);
239            onPropertyChanged();
240        }
241        void setFillGradient(SkShader* gradient) {
242            if(UPDATE_SKPROP(fillGradient, gradient)) {
243                onPropertyChanged();
244            }
245        }
246        void setStrokeGradient(SkShader* gradient) {
247            if(UPDATE_SKPROP(strokeGradient, gradient)) {
248                onPropertyChanged();
249            }
250        }
251        SkShader* getFillGradient() const {
252            return fillGradient;
253        }
254        SkShader* getStrokeGradient() const {
255            return strokeGradient;
256        }
257        float getStrokeWidth() const{
258            return mPrimitiveFields.strokeWidth;
259        }
260        void setStrokeWidth(float strokeWidth) {
261            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
262        }
263        SkColor getStrokeColor() const{
264            return mPrimitiveFields.strokeColor;
265        }
266        void setStrokeColor(SkColor strokeColor) {
267            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
268        }
269        float getStrokeAlpha() const{
270            return mPrimitiveFields.strokeAlpha;
271        }
272        void setStrokeAlpha(float strokeAlpha) {
273            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
274        }
275        SkColor getFillColor() const {
276            return mPrimitiveFields.fillColor;
277        }
278        void setFillColor(SkColor fillColor) {
279            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
280        }
281        float getFillAlpha() const{
282            return mPrimitiveFields.fillAlpha;
283        }
284        void setFillAlpha(float fillAlpha) {
285            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
286        }
287        float getTrimPathStart() const{
288            return mPrimitiveFields.trimPathStart;
289        }
290        void setTrimPathStart(float trimPathStart) {
291            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
292        }
293        float getTrimPathEnd() const{
294            return mPrimitiveFields.trimPathEnd;
295        }
296        void setTrimPathEnd(float trimPathEnd) {
297            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
298        }
299        float getTrimPathOffset() const{
300            return mPrimitiveFields.trimPathOffset;
301        }
302        void setTrimPathOffset(float trimPathOffset) {
303            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
304        }
305
306        float getStrokeMiterLimit() const {
307            return mPrimitiveFields.strokeMiterLimit;
308        }
309        float getStrokeLineCap() const {
310            return mPrimitiveFields.strokeLineCap;
311        }
312        float getStrokeLineJoin() const {
313            return mPrimitiveFields.strokeLineJoin;
314        }
315        float getFillType() const {
316            return mPrimitiveFields.fillType;
317        }
318        bool copyProperties(int8_t* outProperties, int length) const;
319        void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
320                SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
321                float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
322                int fillType) {
323            mPrimitiveFields.strokeWidth = strokeWidth;
324            mPrimitiveFields.strokeColor = strokeColor;
325            mPrimitiveFields.strokeAlpha = strokeAlpha;
326            mPrimitiveFields.fillColor = fillColor;
327            mPrimitiveFields.fillAlpha = fillAlpha;
328            mPrimitiveFields.trimPathStart = trimPathStart;
329            mPrimitiveFields.trimPathEnd = trimPathEnd;
330            mPrimitiveFields.trimPathOffset = trimPathOffset;
331            mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
332            mPrimitiveFields.strokeLineCap = strokeLineCap;
333            mPrimitiveFields.strokeLineJoin = strokeLineJoin;
334            mPrimitiveFields.fillType = fillType;
335            mTrimDirty = true;
336            onPropertyChanged();
337        }
338        // Set property values during animation
339        void setColorPropertyValue(int propertyId, int32_t value);
340        void setPropertyValue(int propertyId, float value);
341        bool mTrimDirty;
342    private:
343        enum class Property {
344            strokeWidth = 0,
345            strokeColor,
346            strokeAlpha,
347            fillColor,
348            fillAlpha,
349            trimPathStart,
350            trimPathEnd,
351            trimPathOffset,
352            strokeLineCap,
353            strokeLineJoin,
354            strokeMiterLimit,
355            fillType,
356            count,
357        };
358        PrimitiveFields mPrimitiveFields;
359        SkShader* fillGradient = nullptr;
360        SkShader* strokeGradient = nullptr;
361    };
362
363    // Called from UI thread
364    FullPath(const FullPath& path); // for cloning
365    FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
366    FullPath() : Path() {}
367    void dump() override;
368    FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
369    const FullPathProperties* stagingProperties() { return &mStagingProperties; }
370
371    // This should only be called from animations on RT
372    FullPathProperties* mutateProperties() { return &mProperties; }
373
374    virtual void syncProperties() override;
375    virtual void onPropertyChanged(Properties* properties) override {
376        Path::onPropertyChanged(properties);
377        if (properties == &mStagingProperties) {
378            mStagingPropertiesDirty = true;
379            if (mPropertyChangedListener) {
380                mPropertyChangedListener->onStagingPropertyChanged();
381            }
382        } else if (properties == &mProperties) {
383            if (mPropertyChangedListener) {
384                mPropertyChangedListener->onPropertyChanged();
385            }
386        }
387    }
388
389protected:
390    const SkPath& getUpdatedPath() override;
391    void getStagingPath(SkPath* outPath) override;
392    void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
393            float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
394private:
395
396    FullPathProperties mProperties = FullPathProperties(this);
397    FullPathProperties mStagingProperties = FullPathProperties(this);
398    bool mStagingPropertiesDirty = true;
399
400    // Intermediate data for drawing, render thread only
401    SkPath mTrimmedSkPath;
402
403};
404
405class ANDROID_API ClipPath: public Path {
406public:
407    ClipPath(const ClipPath& path) : Path(path) {}
408    ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
409    ClipPath() : Path() {}
410
411protected:
412    void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
413            float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
414};
415
416class ANDROID_API Group: public Node {
417public:
418    class GroupProperties : public Properties {
419    public:
420        explicit GroupProperties(Node* mNode) : Properties(mNode) {}
421        struct PrimitiveFields {
422            float rotate = 0;
423            float pivotX = 0;
424            float pivotY = 0;
425            float scaleX = 1;
426            float scaleY = 1;
427            float translateX = 0;
428            float translateY = 0;
429        } mPrimitiveFields;
430        void syncProperties(const GroupProperties& prop) {
431            mPrimitiveFields = prop.mPrimitiveFields;
432            onPropertyChanged();
433        }
434        float getRotation() const {
435            return mPrimitiveFields.rotate;
436        }
437        void setRotation(float rotation) {
438            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
439        }
440        float getPivotX() const {
441            return mPrimitiveFields.pivotX;
442        }
443        void setPivotX(float pivotX) {
444            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
445        }
446        float getPivotY() const {
447            return mPrimitiveFields.pivotY;
448        }
449        void setPivotY(float pivotY) {
450            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
451        }
452        float getScaleX() const {
453            return mPrimitiveFields.scaleX;
454        }
455        void setScaleX(float scaleX) {
456            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
457        }
458        float getScaleY() const {
459            return mPrimitiveFields.scaleY;
460        }
461        void setScaleY(float scaleY) {
462            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
463        }
464        float getTranslateX() const {
465            return mPrimitiveFields.translateX;
466        }
467        void setTranslateX(float translateX) {
468            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
469        }
470        float getTranslateY() const {
471            return mPrimitiveFields.translateY;
472        }
473        void setTranslateY(float translateY) {
474            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
475        }
476        void updateProperties(float rotate, float pivotX, float pivotY,
477                float scaleX, float scaleY, float translateX, float translateY) {
478            mPrimitiveFields.rotate = rotate;
479            mPrimitiveFields.pivotX = pivotX;
480            mPrimitiveFields.pivotY = pivotY;
481            mPrimitiveFields.scaleX = scaleX;
482            mPrimitiveFields.scaleY = scaleY;
483            mPrimitiveFields.translateX = translateX;
484            mPrimitiveFields.translateY = translateY;
485            onPropertyChanged();
486        }
487        void setPropertyValue(int propertyId, float value);
488        float getPropertyValue(int propertyId) const;
489        bool copyProperties(float* outProperties, int length) const;
490        static bool isValidProperty(int propertyId);
491    private:
492        enum class Property {
493            rotate = 0,
494            pivotX,
495            pivotY,
496            scaleX,
497            scaleY,
498            translateX,
499            translateY,
500            // Count of the properties, must be at the end.
501            count,
502        };
503    };
504
505    Group(const Group& group);
506    Group() {}
507    void addChild(Node* child);
508    virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
509        Node::setPropertyChangedListener(listener);
510        for (auto& child : mChildren) {
511             child->setPropertyChangedListener(listener);
512        }
513    }
514    virtual void syncProperties() override;
515    GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
516    const GroupProperties* stagingProperties() { return &mStagingProperties; }
517
518    // This should only be called from animations on RT
519    GroupProperties* mutateProperties() { return &mProperties; }
520
521    // Methods below could be called from either UI thread or Render Thread.
522    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
523            float scaleX, float scaleY, bool useStagingData) override;
524    void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
525    void dump() override;
526    static bool isValidProperty(int propertyId);
527
528    virtual void onPropertyChanged(Properties* properties) override {
529        if (properties == &mStagingProperties) {
530            mStagingPropertiesDirty = true;
531            if (mPropertyChangedListener) {
532                mPropertyChangedListener->onStagingPropertyChanged();
533            }
534        } else {
535            if (mPropertyChangedListener) {
536                mPropertyChangedListener->onPropertyChanged();
537            }
538        }
539    }
540
541private:
542    GroupProperties mProperties = GroupProperties(this);
543    GroupProperties mStagingProperties = GroupProperties(this);
544    bool mStagingPropertiesDirty = true;
545    std::vector< std::unique_ptr<Node> > mChildren;
546};
547
548class ANDROID_API Tree : public VirtualLightRefBase {
549public:
550    explicit Tree(Group* rootNode) : mRootNode(rootNode) {
551        mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
552    }
553
554    // Copy properties from the tree and use the give node as the root node
555    Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
556        mStagingProperties.syncAnimatableProperties(*copy->stagingProperties());
557        mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties());
558    }
559    // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
560    // canvas. Returns the number of pixels needed for the bitmap cache.
561    int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
562            const SkRect& bounds, bool needsMirroring, bool canReuseCache);
563    void drawStaging(Canvas* canvas);
564
565    Bitmap& getBitmapUpdateIfDirty();
566    void setAllowCaching(bool allowCaching) {
567        mAllowCaching = allowCaching;
568    }
569    SkPaint* getPaint();
570    void syncProperties() {
571        if (mStagingProperties.mNonAnimatablePropertiesDirty) {
572            mProperties.syncNonAnimatableProperties(mStagingProperties);
573            mStagingProperties.mNonAnimatablePropertiesDirty = false;
574        }
575
576        if (mStagingProperties.mAnimatablePropertiesDirty) {
577            mProperties.syncAnimatableProperties(mStagingProperties);
578        } else {
579            mStagingProperties.syncAnimatableProperties(mProperties);
580        }
581        mStagingProperties.mAnimatablePropertiesDirty = false;
582        mRootNode->syncProperties();
583    }
584
585    class TreeProperties {
586    public:
587        explicit TreeProperties(Tree* tree) : mTree(tree) {}
588        // Properties that can only be modified by UI thread, therefore sync should
589        // only go from UI to RT
590        struct NonAnimatableProperties {
591            float viewportWidth = 0;
592            float viewportHeight = 0;
593            SkRect bounds;
594            int scaledWidth = 0;
595            int scaledHeight = 0;
596            SkColorFilter* colorFilter = nullptr;
597            ~NonAnimatableProperties() {
598                SkSafeUnref(colorFilter);
599            }
600        } mNonAnimatableProperties;
601        bool mNonAnimatablePropertiesDirty = true;
602
603        float mRootAlpha = 1.0f;
604        bool mAnimatablePropertiesDirty = true;
605
606        void syncNonAnimatableProperties(const TreeProperties& prop) {
607            // Copy over the data that can only be changed in UI thread
608            if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
609                SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
610                        prop.mNonAnimatableProperties.colorFilter);
611            }
612            mNonAnimatableProperties = prop.mNonAnimatableProperties;
613        }
614
615        void setViewportSize(float width, float height) {
616            if (mNonAnimatableProperties.viewportWidth != width
617                    || mNonAnimatableProperties.viewportHeight != height) {
618                mNonAnimatablePropertiesDirty = true;
619                mNonAnimatableProperties.viewportWidth = width;
620                mNonAnimatableProperties.viewportHeight = height;
621                mTree->onPropertyChanged(this);
622            }
623        }
624        void setBounds(const SkRect& bounds) {
625            if (mNonAnimatableProperties.bounds != bounds) {
626                mNonAnimatableProperties.bounds = bounds;
627                mNonAnimatablePropertiesDirty = true;
628                mTree->onPropertyChanged(this);
629            }
630        }
631
632        void setScaledSize(int width, int height) {
633            if (mNonAnimatableProperties.scaledWidth != width
634                    || mNonAnimatableProperties.scaledHeight != height) {
635                mNonAnimatableProperties.scaledWidth = width;
636                mNonAnimatableProperties.scaledHeight = height;
637                mNonAnimatablePropertiesDirty = true;
638                mTree->onPropertyChanged(this);
639            }
640        }
641        void setColorFilter(SkColorFilter* filter) {
642            if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
643                mNonAnimatablePropertiesDirty = true;
644                mTree->onPropertyChanged(this);
645            }
646        }
647        SkColorFilter* getColorFilter() const{
648            return mNonAnimatableProperties.colorFilter;
649        }
650
651        float getViewportWidth() const {
652            return mNonAnimatableProperties.viewportWidth;
653        }
654        float getViewportHeight() const {
655            return mNonAnimatableProperties.viewportHeight;
656        }
657        float getScaledWidth() const {
658            return mNonAnimatableProperties.scaledWidth;
659        }
660        float getScaledHeight() const {
661            return mNonAnimatableProperties.scaledHeight;
662        }
663        void syncAnimatableProperties(const TreeProperties& prop) {
664            mRootAlpha = prop.mRootAlpha;
665        }
666        bool setRootAlpha(float rootAlpha) {
667            if (rootAlpha != mRootAlpha) {
668                mAnimatablePropertiesDirty = true;
669                mRootAlpha = rootAlpha;
670                mTree->onPropertyChanged(this);
671                return true;
672            }
673            return false;
674        }
675        float getRootAlpha() const { return mRootAlpha;}
676        const SkRect& getBounds() const {
677            return mNonAnimatableProperties.bounds;
678        }
679        Tree* mTree;
680    };
681    void onPropertyChanged(TreeProperties* prop);
682    TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
683    const TreeProperties* stagingProperties() const { return &mStagingProperties; }
684
685    // This should only be called from animations on RT
686    TreeProperties* mutateProperties() { return &mProperties; }
687
688    // This should always be called from RT.
689    void markDirty() { mCache.dirty = true; }
690    bool isDirty() const { return mCache.dirty; }
691    bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
692    void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
693
694private:
695    struct Cache {
696        sk_sp<Bitmap> bitmap;
697        bool dirty = true;
698    };
699
700    SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
701    bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
702    bool canReuseBitmap(Bitmap*, int width, int height);
703    void updateBitmapCache(Bitmap& outCache, bool useStagingData);
704    // Cap the bitmap size, such that it won't hurt the performance too much
705    // and it won't crash due to a very large scale.
706    // The drawable will look blurry above this size.
707    const static int MAX_CACHED_BITMAP_SIZE;
708
709    bool mAllowCaching = true;
710    std::unique_ptr<Group> mRootNode;
711
712    TreeProperties mProperties = TreeProperties(this);
713    TreeProperties mStagingProperties = TreeProperties(this);
714
715    SkPaint mPaint;
716
717    Cache mStagingCache;
718    Cache mCache;
719
720    PropertyChangedListener mPropertyChangedListener
721            = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
722
723    mutable bool mWillBeConsumed = false;
724};
725
726} // namespace VectorDrawable
727
728typedef VectorDrawable::Path::Data PathData;
729} // namespace uirenderer
730} // namespace android
731
732#endif // ANDROID_HWUI_VPATH_H
733