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