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