VectorDrawable.h revision a7f6bba1a3565c19715e878dfe7f0e01022944ff
1/*
2 * Copyright (C) 2015 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#ifndef ANDROID_HWUI_VPATH_H
18#define ANDROID_HWUI_VPATH_H
19
20#include "hwui/Canvas.h"
21
22#include <SkBitmap.h>
23#include <SkColor.h>
24#include <SkCanvas.h>
25#include <SkMatrix.h>
26#include <SkPaint.h>
27#include <SkPath.h>
28#include <SkPathMeasure.h>
29#include <SkRect.h>
30#include <SkShader.h>
31
32#include <cutils/compiler.h>
33#include <stddef.h>
34#include <vector>
35#include <string>
36
37namespace android {
38namespace uirenderer {
39
40namespace VectorDrawable {
41#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
42#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
43
44/* A VectorDrawable is composed of a tree of nodes.
45 * Each node can be a group node, or a path.
46 * A group node can have groups or paths as children, but a path node has
47 * no children.
48 * One example can be:
49 *                 Root Group
50 *                /    |     \
51 *           Group    Path    Group
52 *          /     \             |
53 *         Path   Path         Path
54 *
55 */
56class ANDROID_API Node {
57public:
58    Node(const Node& node) {
59        mName = node.mName;
60    }
61    Node() {}
62    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
63            float scaleX, float scaleY) = 0;
64    virtual void dump() = 0;
65    void setName(const char* name) {
66        mName = name;
67    }
68    virtual ~Node(){}
69protected:
70    std::string mName;
71};
72
73class ANDROID_API Path : public Node {
74public:
75    struct ANDROID_API Data {
76        std::vector<char> verbs;
77        std::vector<size_t> verbSizes;
78        std::vector<float> points;
79        bool operator==(const Data& data) const {
80            return verbs == data.verbs && verbSizes == data.verbSizes
81                    && points == data.points;
82        }
83    };
84    Path(const Data& nodes);
85    Path(const Path& path);
86    Path(const char* path, size_t strLength);
87    Path() {}
88    void dump() override;
89    bool canMorph(const Data& path);
90    bool canMorph(const Path& path);
91    void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
92            float scaleX, float scaleY) override;
93    void setPath(const char* path, size_t strLength);
94    void setPathData(const Data& data);
95    static float getMatrixScale(const SkMatrix& groupStackedMatrix);
96
97protected:
98    virtual const SkPath& getUpdatedPath();
99    virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
100            float strokeScale, const SkMatrix& matrix) = 0;
101    Data mData;
102    SkPath mSkPath;
103    bool mSkPathDirty = true;
104};
105
106class ANDROID_API FullPath: public Path {
107public:
108
109struct Properties {
110    float strokeWidth = 0;
111    SkColor strokeColor = SK_ColorTRANSPARENT;
112    float strokeAlpha = 1;
113    SkColor fillColor = SK_ColorTRANSPARENT;
114    float fillAlpha = 1;
115    float trimPathStart = 0;
116    float trimPathEnd = 1;
117    float trimPathOffset = 0;
118    int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
119    int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
120    float strokeMiterLimit = 4;
121    int fillType = 0; /* non-zero or kWinding_FillType in Skia */
122};
123
124    FullPath(const FullPath& path); // for cloning
125    FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
126    FullPath() : Path() {}
127    FullPath(const Data& nodes) : Path(nodes) {}
128
129    ~FullPath() {
130        SkSafeUnref(mFillGradient);
131        SkSafeUnref(mStrokeGradient);
132    }
133
134    void updateProperties(float strokeWidth, SkColor strokeColor,
135            float strokeAlpha, SkColor fillColor, float fillAlpha,
136            float trimPathStart, float trimPathEnd, float trimPathOffset,
137            float strokeMiterLimit, int strokeLineCap, int strokeLineJoin, int fillType);
138    // TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
139    float getStrokeWidth() {
140        return mProperties.strokeWidth;
141    }
142    void setStrokeWidth(float strokeWidth) {
143        mProperties.strokeWidth = strokeWidth;
144    }
145    SkColor getStrokeColor() {
146        return mProperties.strokeColor;
147    }
148    void setStrokeColor(SkColor strokeColor) {
149        mProperties.strokeColor = strokeColor;
150    }
151    float getStrokeAlpha() {
152        return mProperties.strokeAlpha;
153    }
154    void setStrokeAlpha(float strokeAlpha) {
155        mProperties.strokeAlpha = strokeAlpha;
156    }
157    SkColor getFillColor() {
158        return mProperties.fillColor;
159    }
160    void setFillColor(SkColor fillColor) {
161        mProperties.fillColor = fillColor;
162    }
163    float getFillAlpha() {
164        return mProperties.fillAlpha;
165    }
166    void setFillAlpha(float fillAlpha) {
167        mProperties.fillAlpha = fillAlpha;
168    }
169    float getTrimPathStart() {
170        return mProperties.trimPathStart;
171    }
172    void setTrimPathStart(float trimPathStart) {
173        VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty);
174    }
175    float getTrimPathEnd() {
176        return mProperties.trimPathEnd;
177    }
178    void setTrimPathEnd(float trimPathEnd) {
179        VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty);
180    }
181    float getTrimPathOffset() {
182        return mProperties.trimPathOffset;
183    }
184    void setTrimPathOffset(float trimPathOffset) {
185        VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty);
186    }
187    bool getProperties(int8_t* outProperties, int length);
188    void setColorPropertyValue(int propertyId, int32_t value);
189    void setPropertyValue(int propertyId, float value);
190
191    void setFillGradient(SkShader* fillGradient) {
192        SkRefCnt_SafeAssign(mFillGradient, fillGradient);
193    };
194    void setStrokeGradient(SkShader* strokeGradient) {
195        SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
196    };
197
198
199protected:
200    const SkPath& getUpdatedPath() override;
201    void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
202            float strokeScale, const SkMatrix& matrix) override;
203
204private:
205    enum class Property {
206        StrokeWidth = 0,
207        StrokeColor,
208        StrokeAlpha,
209        FillColor,
210        FillAlpha,
211        TrimPathStart,
212        TrimPathEnd,
213        TrimPathOffset,
214        StrokeLineCap,
215        StrokeLineJoin,
216        StrokeMiterLimit,
217        FillType,
218        Count,
219    };
220    // Applies trimming to the specified path.
221    void applyTrim();
222    Properties mProperties;
223    bool mTrimDirty = true;
224    SkPath mTrimmedSkPath;
225    SkPaint mPaint;
226    SkShader* mStrokeGradient = nullptr;
227    SkShader* mFillGradient = nullptr;
228};
229
230class ANDROID_API ClipPath: public Path {
231public:
232    ClipPath(const ClipPath& path) : Path(path) {}
233    ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
234    ClipPath() : Path() {}
235    ClipPath(const Data& nodes) : Path(nodes) {}
236
237protected:
238    void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
239            float strokeScale, const SkMatrix& matrix) override;
240};
241
242class ANDROID_API Group: public Node {
243public:
244    struct Properties {
245        float rotate = 0;
246        float pivotX = 0;
247        float pivotY = 0;
248        float scaleX = 1;
249        float scaleY = 1;
250        float translateX = 0;
251        float translateY = 0;
252    };
253    Group(const Group& group);
254    Group() {}
255    float getRotation() {
256        return mProperties.rotate;
257    }
258    void setRotation(float rotation) {
259        mProperties.rotate = rotation;
260    }
261    float getPivotX() {
262        return mProperties.pivotX;
263    }
264    void setPivotX(float pivotX) {
265        mProperties.pivotX = pivotX;
266    }
267    float getPivotY() {
268        return mProperties.pivotY;
269    }
270    void setPivotY(float pivotY) {
271        mProperties.pivotY = pivotY;
272    }
273    float getScaleX() {
274        return mProperties.scaleX;
275    }
276    void setScaleX(float scaleX) {
277        mProperties.scaleX = scaleX;
278    }
279    float getScaleY() {
280        return mProperties.scaleY;
281    }
282    void setScaleY(float scaleY) {
283        mProperties.scaleY = scaleY;
284    }
285    float getTranslateX() {
286        return mProperties.translateX;
287    }
288    void setTranslateX(float translateX) {
289        mProperties.translateX = translateX;
290    }
291    float getTranslateY() {
292        return mProperties.translateY;
293    }
294    void setTranslateY(float translateY) {
295        mProperties.translateY = translateY;
296    }
297    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
298            float scaleX, float scaleY) override;
299    void updateLocalMatrix(float rotate, float pivotX, float pivotY,
300            float scaleX, float scaleY, float translateX, float translateY);
301    void getLocalMatrix(SkMatrix* outMatrix);
302    void addChild(Node* child);
303    void dump() override;
304    bool getProperties(float* outProperties, int length);
305    float getPropertyValue(int propertyId) const;
306    void setPropertyValue(int propertyId, float value);
307    static bool isValidProperty(int propertyId);
308
309private:
310    enum class Property {
311        Rotate = 0,
312        PivotX,
313        PivotY,
314        ScaleX,
315        ScaleY,
316        TranslateX,
317        TranslateY,
318        // Count of the properties, must be at the end.
319        Count,
320    };
321    std::vector< std::unique_ptr<Node> > mChildren;
322    Properties mProperties;
323};
324
325class ANDROID_API Tree : public VirtualLightRefBase {
326public:
327    Tree(Group* rootNode) : mRootNode(rootNode) {}
328    void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
329            const SkRect& bounds, bool needsMirroring, bool canReuseCache);
330
331    const SkBitmap& getBitmapUpdateIfDirty();
332    void createCachedBitmapIfNeeded(int width, int height);
333    bool canReuseBitmap(int width, int height);
334    void setAllowCaching(bool allowCaching) {
335        mAllowCaching = allowCaching;
336    }
337    bool setRootAlpha(float rootAlpha) {
338        return VD_SET_PROP(mRootAlpha, rootAlpha);
339    }
340
341    float getRootAlpha() {
342        return mRootAlpha;
343    }
344    void setViewportSize(float viewportWidth, float viewportHeight) {
345        mViewportWidth = viewportWidth;
346        mViewportHeight = viewportHeight;
347    }
348    SkPaint* getPaint();
349    const SkRect& getBounds() const {
350        return mBounds;
351    }
352
353private:
354    // Cap the bitmap size, such that it won't hurt the performance too much
355    // and it won't crash due to a very large scale.
356    // The drawable will look blurry above this size.
357    const static int MAX_CACHED_BITMAP_SIZE;
358
359    bool mCacheDirty = true;
360    bool mAllowCaching = true;
361    float mViewportWidth = 0;
362    float mViewportHeight = 0;
363    float mRootAlpha = 1.0f;
364
365    std::unique_ptr<Group> mRootNode;
366    SkRect mBounds;
367    SkMatrix mCanvasMatrix;
368    SkPaint mPaint;
369    SkPathMeasure mPathMeasure;
370    SkBitmap mCachedBitmap;
371
372};
373
374} // namespace VectorDrawable
375
376typedef VectorDrawable::Path::Data PathData;
377} // namespace uirenderer
378} // namespace android
379
380#endif // ANDROID_HWUI_VPATH_H
381