VectorDrawable.h revision ef062ebd20032efe697741d6c3dfd1faec54f590
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 "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, const 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};
122
123    FullPath(const FullPath& path); // for cloning
124    FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
125    FullPath() : Path() {}
126    FullPath(const Data& nodes) : Path(nodes) {}
127
128    ~FullPath() {
129        SkSafeUnref(mFillGradient);
130        SkSafeUnref(mStrokeGradient);
131    }
132
133    void updateProperties(float strokeWidth, SkColor strokeColor,
134            float strokeAlpha, SkColor fillColor, float fillAlpha,
135            float trimPathStart, float trimPathEnd, float trimPathOffset,
136            float strokeMiterLimit, int strokeLineCap, int strokeLineJoin);
137    // TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
138    float getStrokeWidth() {
139        return mProperties.strokeWidth;
140    }
141    void setStrokeWidth(float strokeWidth) {
142        mProperties.strokeWidth = strokeWidth;
143    }
144    SkColor getStrokeColor() {
145        return mProperties.strokeColor;
146    }
147    void setStrokeColor(SkColor strokeColor) {
148        mProperties.strokeColor = strokeColor;
149    }
150    float getStrokeAlpha() {
151        return mProperties.strokeAlpha;
152    }
153    void setStrokeAlpha(float strokeAlpha) {
154        mProperties.strokeAlpha = strokeAlpha;
155    }
156    SkColor getFillColor() {
157        return mProperties.fillColor;
158    }
159    void setFillColor(SkColor fillColor) {
160        mProperties.fillColor = fillColor;
161    }
162    float getFillAlpha() {
163        return mProperties.fillAlpha;
164    }
165    void setFillAlpha(float fillAlpha) {
166        mProperties.fillAlpha = fillAlpha;
167    }
168    float getTrimPathStart() {
169        return mProperties.trimPathStart;
170    }
171    void setTrimPathStart(float trimPathStart) {
172        VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty);
173    }
174    float getTrimPathEnd() {
175        return mProperties.trimPathEnd;
176    }
177    void setTrimPathEnd(float trimPathEnd) {
178        VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty);
179    }
180    float getTrimPathOffset() {
181        return mProperties.trimPathOffset;
182    }
183    void setTrimPathOffset(float trimPathOffset) {
184        VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty);
185    }
186    bool getProperties(int8_t* outProperties, int length);
187    void setColorPropertyValue(int propertyId, int32_t value);
188    void setPropertyValue(int propertyId, float value);
189
190    void setFillGradient(SkShader* fillGradient) {
191        SkRefCnt_SafeAssign(mFillGradient, fillGradient);
192    };
193    void setStrokeGradient(SkShader* strokeGradient) {
194        SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
195    };
196
197
198protected:
199    const SkPath& getUpdatedPath() override;
200    void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
201            float strokeScale, const SkMatrix& matrix) override;
202
203private:
204    enum class Property {
205        StrokeWidth = 0,
206        StrokeColor,
207        StrokeAlpha,
208        FillColor,
209        FillAlpha,
210        TrimPathStart,
211        TrimPathEnd,
212        TrimPathOffset,
213        StrokeLineCap,
214        StrokeLineJoin,
215        StrokeMiterLimit,
216        Count,
217    };
218    // Applies trimming to the specified path.
219    void applyTrim();
220    Properties mProperties;
221    bool mTrimDirty = true;
222    SkPath mTrimmedSkPath;
223    SkPaint mPaint;
224    SkShader* mStrokeGradient = nullptr;
225    SkShader* mFillGradient = nullptr;
226};
227
228class ANDROID_API ClipPath: public Path {
229public:
230    ClipPath(const ClipPath& path) : Path(path) {}
231    ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
232    ClipPath() : Path() {}
233    ClipPath(const Data& nodes) : Path(nodes) {}
234
235protected:
236    void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
237            float strokeScale, const SkMatrix& matrix) override;
238};
239
240class ANDROID_API Group: public Node {
241public:
242    struct Properties {
243        float rotate = 0;
244        float pivotX = 0;
245        float pivotY = 0;
246        float scaleX = 1;
247        float scaleY = 1;
248        float translateX = 0;
249        float translateY = 0;
250    };
251    Group(const Group& group);
252    Group() {}
253    float getRotation() {
254        return mProperties.rotate;
255    }
256    void setRotation(float rotation) {
257        mProperties.rotate = rotation;
258    }
259    float getPivotX() {
260        return mProperties.pivotX;
261    }
262    void setPivotX(float pivotX) {
263        mProperties.pivotX = pivotX;
264    }
265    float getPivotY() {
266        return mProperties.pivotY;
267    }
268    void setPivotY(float pivotY) {
269        mProperties.pivotY = pivotY;
270    }
271    float getScaleX() {
272        return mProperties.scaleX;
273    }
274    void setScaleX(float scaleX) {
275        mProperties.scaleX = scaleX;
276    }
277    float getScaleY() {
278        return mProperties.scaleY;
279    }
280    void setScaleY(float scaleY) {
281        mProperties.scaleY = scaleY;
282    }
283    float getTranslateX() {
284        return mProperties.translateX;
285    }
286    void setTranslateX(float translateX) {
287        mProperties.translateX = translateX;
288    }
289    float getTranslateY() {
290        return mProperties.translateY;
291    }
292    void setTranslateY(float translateY) {
293        mProperties.translateY = translateY;
294    }
295    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
296            float scaleX, float scaleY) override;
297    void updateLocalMatrix(float rotate, float pivotX, float pivotY,
298            float scaleX, float scaleY, float translateX, float translateY);
299    void getLocalMatrix(SkMatrix* outMatrix);
300    void addChild(Node* child);
301    void dump() override;
302    bool getProperties(float* outProperties, int length);
303    float getPropertyValue(int propertyId) const;
304    void setPropertyValue(int propertyId, float value);
305    static bool isValidProperty(int propertyId);
306
307private:
308    enum class Property {
309        Rotate = 0,
310        PivotX,
311        PivotY,
312        ScaleX,
313        ScaleY,
314        TranslateX,
315        TranslateY,
316        // Count of the properties, must be at the end.
317        Count,
318    };
319    std::vector< std::unique_ptr<Node> > mChildren;
320    Properties mProperties;
321};
322
323class ANDROID_API Tree : public VirtualLightRefBase {
324public:
325    Tree(Group* rootNode) : mRootNode(rootNode) {}
326    void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
327            const SkRect& bounds, bool needsMirroring, bool canReuseCache);
328
329    const SkBitmap& getBitmapUpdateIfDirty();
330    void createCachedBitmapIfNeeded(int width, int height);
331    bool canReuseBitmap(int width, int height);
332    void setAllowCaching(bool allowCaching) {
333        mAllowCaching = allowCaching;
334    }
335    bool setRootAlpha(float rootAlpha) {
336        return VD_SET_PROP(mRootAlpha, rootAlpha);
337    }
338
339    float getRootAlpha() {
340        return mRootAlpha;
341    }
342    void setViewportSize(float viewportWidth, float viewportHeight) {
343        mViewportWidth = viewportWidth;
344        mViewportHeight = viewportHeight;
345    }
346    SkPaint* getPaint();
347    const SkRect& getBounds() const {
348        return mBounds;
349    }
350
351private:
352    // Cap the bitmap size, such that it won't hurt the performance too much
353    // and it won't crash due to a very large scale.
354    // The drawable will look blurry above this size.
355    const static int MAX_CACHED_BITMAP_SIZE;
356
357    bool mCacheDirty = true;
358    bool mAllowCaching = true;
359    float mViewportWidth = 0;
360    float mViewportHeight = 0;
361    float mRootAlpha = 1.0f;
362
363    std::unique_ptr<Group> mRootNode;
364    SkRect mBounds;
365    SkMatrix mCanvasMatrix;
366    SkPaint mPaint;
367    SkPathMeasure mPathMeasure;
368    SkBitmap mCachedBitmap;
369
370};
371
372} // namespace VectorDrawable
373
374typedef VectorDrawable::Path::Data PathData;
375} // namespace uirenderer
376} // namespace android
377
378#endif // ANDROID_HWUI_VPATH_H
379