Also added API check so that for pre-N we ignore invalid VD animation, in order to avoid breaking old apps. Bug: 26975469 Bug: 26949340 Change-Id: I498539ad6a05de3d886e7dcdc8a167e78333ab11
379 lines
11 KiB
C++
379 lines
11 KiB
C++
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ANDROID_HWUI_VPATH_H
|
|
#define ANDROID_HWUI_VPATH_H
|
|
|
|
#include "Canvas.h"
|
|
|
|
#include <SkBitmap.h>
|
|
#include <SkColor.h>
|
|
#include <SkCanvas.h>
|
|
#include <SkMatrix.h>
|
|
#include <SkPaint.h>
|
|
#include <SkPath.h>
|
|
#include <SkPathMeasure.h>
|
|
#include <SkRect.h>
|
|
#include <SkShader.h>
|
|
|
|
#include <cutils/compiler.h>
|
|
#include <stddef.h>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
namespace android {
|
|
namespace uirenderer {
|
|
|
|
namespace VectorDrawable {
|
|
#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
|
|
#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
|
|
|
|
/* A VectorDrawable is composed of a tree of nodes.
|
|
* Each node can be a group node, or a path.
|
|
* A group node can have groups or paths as children, but a path node has
|
|
* no children.
|
|
* One example can be:
|
|
* Root Group
|
|
* / | \
|
|
* Group Path Group
|
|
* / \ |
|
|
* Path Path Path
|
|
*
|
|
*/
|
|
class ANDROID_API Node {
|
|
public:
|
|
Node(const Node& node) {
|
|
mName = node.mName;
|
|
}
|
|
Node() {}
|
|
virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
|
|
float scaleX, float scaleY) = 0;
|
|
virtual void dump() = 0;
|
|
void setName(const char* name) {
|
|
mName = name;
|
|
}
|
|
virtual ~Node(){}
|
|
protected:
|
|
std::string mName;
|
|
};
|
|
|
|
class ANDROID_API Path : public Node {
|
|
public:
|
|
struct ANDROID_API Data {
|
|
std::vector<char> verbs;
|
|
std::vector<size_t> verbSizes;
|
|
std::vector<float> points;
|
|
bool operator==(const Data& data) const {
|
|
return verbs == data.verbs && verbSizes == data.verbSizes
|
|
&& points == data.points;
|
|
}
|
|
};
|
|
Path(const Data& nodes);
|
|
Path(const Path& path);
|
|
Path(const char* path, size_t strLength);
|
|
Path() {}
|
|
void dump() override;
|
|
bool canMorph(const Data& path);
|
|
bool canMorph(const Path& path);
|
|
void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
|
|
float scaleX, float scaleY) override;
|
|
void setPath(const char* path, size_t strLength);
|
|
void setPathData(const Data& data);
|
|
static float getMatrixScale(const SkMatrix& groupStackedMatrix);
|
|
|
|
protected:
|
|
virtual const SkPath& getUpdatedPath();
|
|
virtual void drawPath(SkCanvas *outCanvas, const SkPath& renderPath,
|
|
float strokeScale, const SkMatrix& matrix) = 0;
|
|
Data mData;
|
|
SkPath mSkPath;
|
|
bool mSkPathDirty = true;
|
|
};
|
|
|
|
class ANDROID_API FullPath: public Path {
|
|
public:
|
|
|
|
struct Properties {
|
|
float strokeWidth = 0;
|
|
SkColor strokeColor = SK_ColorTRANSPARENT;
|
|
float strokeAlpha = 1;
|
|
SkColor fillColor = SK_ColorTRANSPARENT;
|
|
float fillAlpha = 1;
|
|
float trimPathStart = 0;
|
|
float trimPathEnd = 1;
|
|
float trimPathOffset = 0;
|
|
int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
|
|
int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
|
|
float strokeMiterLimit = 4;
|
|
};
|
|
|
|
FullPath(const FullPath& path); // for cloning
|
|
FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
|
|
FullPath() : Path() {}
|
|
FullPath(const Data& nodes) : Path(nodes) {}
|
|
|
|
~FullPath() {
|
|
SkSafeUnref(mFillGradient);
|
|
SkSafeUnref(mStrokeGradient);
|
|
}
|
|
|
|
void updateProperties(float strokeWidth, SkColor strokeColor,
|
|
float strokeAlpha, SkColor fillColor, float fillAlpha,
|
|
float trimPathStart, float trimPathEnd, float trimPathOffset,
|
|
float strokeMiterLimit, int strokeLineCap, int strokeLineJoin);
|
|
// TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
|
|
float getStrokeWidth() {
|
|
return mProperties.strokeWidth;
|
|
}
|
|
void setStrokeWidth(float strokeWidth) {
|
|
mProperties.strokeWidth = strokeWidth;
|
|
}
|
|
SkColor getStrokeColor() {
|
|
return mProperties.strokeColor;
|
|
}
|
|
void setStrokeColor(SkColor strokeColor) {
|
|
mProperties.strokeColor = strokeColor;
|
|
}
|
|
float getStrokeAlpha() {
|
|
return mProperties.strokeAlpha;
|
|
}
|
|
void setStrokeAlpha(float strokeAlpha) {
|
|
mProperties.strokeAlpha = strokeAlpha;
|
|
}
|
|
SkColor getFillColor() {
|
|
return mProperties.fillColor;
|
|
}
|
|
void setFillColor(SkColor fillColor) {
|
|
mProperties.fillColor = fillColor;
|
|
}
|
|
float getFillAlpha() {
|
|
return mProperties.fillAlpha;
|
|
}
|
|
void setFillAlpha(float fillAlpha) {
|
|
mProperties.fillAlpha = fillAlpha;
|
|
}
|
|
float getTrimPathStart() {
|
|
return mProperties.trimPathStart;
|
|
}
|
|
void setTrimPathStart(float trimPathStart) {
|
|
VD_SET_PROP_WITH_FLAG(mProperties.trimPathStart, trimPathStart, mTrimDirty);
|
|
}
|
|
float getTrimPathEnd() {
|
|
return mProperties.trimPathEnd;
|
|
}
|
|
void setTrimPathEnd(float trimPathEnd) {
|
|
VD_SET_PROP_WITH_FLAG(mProperties.trimPathEnd, trimPathEnd, mTrimDirty);
|
|
}
|
|
float getTrimPathOffset() {
|
|
return mProperties.trimPathOffset;
|
|
}
|
|
void setTrimPathOffset(float trimPathOffset) {
|
|
VD_SET_PROP_WITH_FLAG(mProperties.trimPathOffset, trimPathOffset, mTrimDirty);
|
|
}
|
|
bool getProperties(int8_t* outProperties, int length);
|
|
void setColorPropertyValue(int propertyId, int32_t value);
|
|
void setPropertyValue(int propertyId, float value);
|
|
|
|
void setFillGradient(SkShader* fillGradient) {
|
|
SkRefCnt_SafeAssign(mFillGradient, fillGradient);
|
|
};
|
|
void setStrokeGradient(SkShader* strokeGradient) {
|
|
SkRefCnt_SafeAssign(mStrokeGradient, strokeGradient);
|
|
};
|
|
|
|
|
|
protected:
|
|
const SkPath& getUpdatedPath() override;
|
|
void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
|
|
float strokeScale, const SkMatrix& matrix) override;
|
|
|
|
private:
|
|
enum class Property {
|
|
StrokeWidth = 0,
|
|
StrokeColor,
|
|
StrokeAlpha,
|
|
FillColor,
|
|
FillAlpha,
|
|
TrimPathStart,
|
|
TrimPathEnd,
|
|
TrimPathOffset,
|
|
StrokeLineCap,
|
|
StrokeLineJoin,
|
|
StrokeMiterLimit,
|
|
Count,
|
|
};
|
|
// Applies trimming to the specified path.
|
|
void applyTrim();
|
|
Properties mProperties;
|
|
bool mTrimDirty = true;
|
|
SkPath mTrimmedSkPath;
|
|
SkPaint mPaint;
|
|
SkShader* mStrokeGradient = nullptr;
|
|
SkShader* mFillGradient = nullptr;
|
|
};
|
|
|
|
class ANDROID_API ClipPath: public Path {
|
|
public:
|
|
ClipPath(const ClipPath& path) : Path(path) {}
|
|
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
|
|
ClipPath() : Path() {}
|
|
ClipPath(const Data& nodes) : Path(nodes) {}
|
|
|
|
protected:
|
|
void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
|
|
float strokeScale, const SkMatrix& matrix) override;
|
|
};
|
|
|
|
class ANDROID_API Group: public Node {
|
|
public:
|
|
struct Properties {
|
|
float rotate = 0;
|
|
float pivotX = 0;
|
|
float pivotY = 0;
|
|
float scaleX = 1;
|
|
float scaleY = 1;
|
|
float translateX = 0;
|
|
float translateY = 0;
|
|
};
|
|
Group(const Group& group);
|
|
Group() {}
|
|
float getRotation() {
|
|
return mProperties.rotate;
|
|
}
|
|
void setRotation(float rotation) {
|
|
mProperties.rotate = rotation;
|
|
}
|
|
float getPivotX() {
|
|
return mProperties.pivotX;
|
|
}
|
|
void setPivotX(float pivotX) {
|
|
mProperties.pivotX = pivotX;
|
|
}
|
|
float getPivotY() {
|
|
return mProperties.pivotY;
|
|
}
|
|
void setPivotY(float pivotY) {
|
|
mProperties.pivotY = pivotY;
|
|
}
|
|
float getScaleX() {
|
|
return mProperties.scaleX;
|
|
}
|
|
void setScaleX(float scaleX) {
|
|
mProperties.scaleX = scaleX;
|
|
}
|
|
float getScaleY() {
|
|
return mProperties.scaleY;
|
|
}
|
|
void setScaleY(float scaleY) {
|
|
mProperties.scaleY = scaleY;
|
|
}
|
|
float getTranslateX() {
|
|
return mProperties.translateX;
|
|
}
|
|
void setTranslateX(float translateX) {
|
|
mProperties.translateX = translateX;
|
|
}
|
|
float getTranslateY() {
|
|
return mProperties.translateY;
|
|
}
|
|
void setTranslateY(float translateY) {
|
|
mProperties.translateY = translateY;
|
|
}
|
|
virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
|
|
float scaleX, float scaleY) override;
|
|
void updateLocalMatrix(float rotate, float pivotX, float pivotY,
|
|
float scaleX, float scaleY, float translateX, float translateY);
|
|
void getLocalMatrix(SkMatrix* outMatrix);
|
|
void addChild(Node* child);
|
|
void dump() override;
|
|
bool getProperties(float* outProperties, int length);
|
|
float getPropertyValue(int propertyId) const;
|
|
void setPropertyValue(int propertyId, float value);
|
|
static bool isValidProperty(int propertyId);
|
|
|
|
private:
|
|
enum class Property {
|
|
Rotate = 0,
|
|
PivotX,
|
|
PivotY,
|
|
ScaleX,
|
|
ScaleY,
|
|
TranslateX,
|
|
TranslateY,
|
|
// Count of the properties, must be at the end.
|
|
Count,
|
|
};
|
|
std::vector< std::unique_ptr<Node> > mChildren;
|
|
Properties mProperties;
|
|
};
|
|
|
|
class ANDROID_API Tree : public VirtualLightRefBase {
|
|
public:
|
|
Tree(Group* rootNode) : mRootNode(rootNode) {}
|
|
void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
|
|
const SkRect& bounds, bool needsMirroring, bool canReuseCache);
|
|
|
|
const SkBitmap& getBitmapUpdateIfDirty();
|
|
void createCachedBitmapIfNeeded(int width, int height);
|
|
bool canReuseBitmap(int width, int height);
|
|
void setAllowCaching(bool allowCaching) {
|
|
mAllowCaching = allowCaching;
|
|
}
|
|
bool setRootAlpha(float rootAlpha) {
|
|
return VD_SET_PROP(mRootAlpha, rootAlpha);
|
|
}
|
|
|
|
float getRootAlpha() {
|
|
return mRootAlpha;
|
|
}
|
|
void setViewportSize(float viewportWidth, float viewportHeight) {
|
|
mViewportWidth = viewportWidth;
|
|
mViewportHeight = viewportHeight;
|
|
}
|
|
SkPaint* getPaint();
|
|
const SkRect& getBounds() const {
|
|
return mBounds;
|
|
}
|
|
|
|
private:
|
|
// Cap the bitmap size, such that it won't hurt the performance too much
|
|
// and it won't crash due to a very large scale.
|
|
// The drawable will look blurry above this size.
|
|
const static int MAX_CACHED_BITMAP_SIZE;
|
|
|
|
bool mCacheDirty = true;
|
|
bool mAllowCaching = true;
|
|
float mViewportWidth = 0;
|
|
float mViewportHeight = 0;
|
|
float mRootAlpha = 1.0f;
|
|
|
|
std::unique_ptr<Group> mRootNode;
|
|
SkRect mBounds;
|
|
SkMatrix mCanvasMatrix;
|
|
SkPaint mPaint;
|
|
SkPathMeasure mPathMeasure;
|
|
SkBitmap mCachedBitmap;
|
|
|
|
};
|
|
|
|
} // namespace VectorDrawable
|
|
|
|
typedef VectorDrawable::Path::Data PathData;
|
|
} // namespace uirenderer
|
|
} // namespace android
|
|
|
|
#endif // ANDROID_HWUI_VPATH_H
|