[skotty,sksg] Initial gradient support
TBR= Change-Id: I61e4d46ac14660f4c9ea757be2278e4098131a6b Reviewed-on: https://skia-review.googlesource.com/94121 Reviewed-by: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
4f34fca3eb
commit
6aaee59c04
1
BUILD.gn
1
BUILD.gn
@ -1392,6 +1392,7 @@ if (skia_enable_tools) {
|
||||
"experimental/sksg/geometry/SkSGRect.cpp",
|
||||
"experimental/sksg/geometry/SkSGTrimEffect.cpp",
|
||||
"experimental/sksg/paint/SkSGColor.cpp",
|
||||
"experimental/sksg/paint/SkSGGradient.cpp",
|
||||
]
|
||||
deps = [
|
||||
":skia",
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "SkPoint.h"
|
||||
#include "SkSGColor.h"
|
||||
#include "SkSGDraw.h"
|
||||
#include "SkSGGradient.h"
|
||||
#include "SkSGGroup.h"
|
||||
#include "SkSGImage.h"
|
||||
#include "SkSGInvalidationController.h"
|
||||
@ -293,13 +294,11 @@ sk_sp<sksg::GeometryNode> AttachPolystarGeometry(const Json::Value& jstar, Attac
|
||||
return path_node;
|
||||
}
|
||||
|
||||
sk_sp<sksg::Color> AttachColorPaint(const Json::Value& obj, AttachContext* ctx) {
|
||||
sk_sp<sksg::Color> AttachColor(const Json::Value& obj, AttachContext* ctx) {
|
||||
SkASSERT(obj.isObject());
|
||||
|
||||
auto color_node = sksg::Color::Make(SK_ColorBLACK);
|
||||
color_node->setAntiAlias(true);
|
||||
|
||||
auto composite = sk_make_sp<CompositeColor>(color_node);
|
||||
auto composite = sk_make_sp<CompositeColor>(color_node);
|
||||
auto color_attached = BindProperty<VectorValue>(obj["c"], ctx, composite,
|
||||
[](CompositeColor* node, const VectorValue& c) {
|
||||
node->setColor(ValueTraits<VectorValue>::As<SkColor>(c));
|
||||
@ -312,29 +311,70 @@ sk_sp<sksg::Color> AttachColorPaint(const Json::Value& obj, AttachContext* ctx)
|
||||
return (color_attached || opacity_attached) ? color_node : nullptr;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachFillPaint(const Json::Value& jfill, AttachContext* ctx) {
|
||||
SkASSERT(jfill.isObject());
|
||||
sk_sp<sksg::Gradient> AttachGradient(const Json::Value& obj, AttachContext* ctx) {
|
||||
SkASSERT(obj.isObject());
|
||||
|
||||
auto color = AttachColorPaint(jfill, ctx);
|
||||
if (color) {
|
||||
LOG("** Attached color fill: 0x%x\n", color->getColor());
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachStrokePaint(const Json::Value& jstroke, AttachContext* ctx) {
|
||||
SkASSERT(jstroke.isObject());
|
||||
|
||||
auto stroke_node = AttachColorPaint(jstroke, ctx);
|
||||
if (!stroke_node)
|
||||
const auto& stops = obj["g"];
|
||||
if (!stops.isObject())
|
||||
return nullptr;
|
||||
|
||||
LOG("** Attached color stroke: 0x%x\n", stroke_node->getColor());
|
||||
const auto stopCount = ParseInt(stops["p"], -1);
|
||||
if (stopCount < 0)
|
||||
return nullptr;
|
||||
|
||||
sk_sp<sksg::Gradient> gradient_node;
|
||||
sk_sp<CompositeGradient> composite;
|
||||
|
||||
if (ParseInt(obj["t"], 1) == 1) {
|
||||
auto linear_node = sksg::LinearGradient::Make();
|
||||
composite = sk_make_sp<CompositeLinearGradient>(linear_node, stopCount);
|
||||
gradient_node = std::move(linear_node);
|
||||
} else {
|
||||
auto radial_node = sksg::RadialGradient::Make();
|
||||
composite = sk_make_sp<CompositeRadialGradient>(radial_node, stopCount);
|
||||
|
||||
// TODO: highlight, angle
|
||||
gradient_node = std::move(radial_node);
|
||||
}
|
||||
|
||||
BindProperty<VectorValue>(stops["k"], ctx, composite,
|
||||
[](CompositeGradient* node, const VectorValue& stops) {
|
||||
node->setColorStops(stops);
|
||||
});
|
||||
BindProperty<VectorValue>(obj["s"], ctx, composite,
|
||||
[](CompositeGradient* node, const VectorValue& s) {
|
||||
node->setStartPoint(ValueTraits<VectorValue>::As<SkPoint>(s));
|
||||
});
|
||||
BindProperty<VectorValue>(obj["e"], ctx, composite,
|
||||
[](CompositeGradient* node, const VectorValue& e) {
|
||||
node->setEndPoint(ValueTraits<VectorValue>::As<SkPoint>(e));
|
||||
});
|
||||
|
||||
return gradient_node;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachPaint(const Json::Value& jfill, AttachContext* ctx,
|
||||
sk_sp<sksg::PaintNode> paint_node) {
|
||||
if (paint_node) {
|
||||
paint_node->setAntiAlias(true);
|
||||
|
||||
// TODO: refactor opacity
|
||||
}
|
||||
|
||||
return paint_node;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachStroke(const Json::Value& jstroke, AttachContext* ctx,
|
||||
sk_sp<sksg::PaintNode> stroke_node) {
|
||||
SkASSERT(jstroke.isObject());
|
||||
|
||||
if (!stroke_node)
|
||||
return nullptr;
|
||||
|
||||
stroke_node->setStyle(SkPaint::kStroke_Style);
|
||||
|
||||
auto width_attached = BindProperty<ScalarValue>(jstroke["w"], ctx, stroke_node,
|
||||
[](sksg::Color* node, const ScalarValue& w) {
|
||||
[](sksg::PaintNode* node, const ScalarValue& w) {
|
||||
node->setStrokeWidth(w);
|
||||
});
|
||||
if (!width_attached)
|
||||
@ -361,6 +401,30 @@ sk_sp<sksg::PaintNode> AttachStrokePaint(const Json::Value& jstroke, AttachConte
|
||||
return stroke_node;
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachColorFill(const Json::Value& jfill, AttachContext* ctx) {
|
||||
SkASSERT(jfill.isObject());
|
||||
|
||||
return AttachPaint(jfill, ctx, AttachColor(jfill, ctx));
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachGradientFill(const Json::Value& jfill, AttachContext* ctx) {
|
||||
SkASSERT(jfill.isObject());
|
||||
|
||||
return AttachPaint(jfill, ctx, AttachGradient(jfill, ctx));
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachColorStroke(const Json::Value& jstroke, AttachContext* ctx) {
|
||||
SkASSERT(jstroke.isObject());
|
||||
|
||||
return AttachStroke(jstroke, ctx, AttachPaint(jstroke, ctx, AttachColor(jstroke, ctx)));
|
||||
}
|
||||
|
||||
sk_sp<sksg::PaintNode> AttachGradientStroke(const Json::Value& jstroke, AttachContext* ctx) {
|
||||
SkASSERT(jstroke.isObject());
|
||||
|
||||
return AttachStroke(jstroke, ctx, AttachPaint(jstroke, ctx, AttachGradient(jstroke, ctx)));
|
||||
}
|
||||
|
||||
std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
|
||||
const Json::Value& jmerge, AttachContext* ctx, std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
|
||||
std::vector<sk_sp<sksg::GeometryNode>> merged;
|
||||
@ -433,8 +497,10 @@ static constexpr GeometryAttacherT gGeometryAttachers[] = {
|
||||
|
||||
using PaintAttacherT = sk_sp<sksg::PaintNode> (*)(const Json::Value&, AttachContext*);
|
||||
static constexpr PaintAttacherT gPaintAttachers[] = {
|
||||
AttachFillPaint,
|
||||
AttachStrokePaint,
|
||||
AttachColorFill,
|
||||
AttachColorStroke,
|
||||
AttachGradientFill,
|
||||
AttachGradientStroke,
|
||||
};
|
||||
|
||||
using GroupAttacherT = sk_sp<sksg::RenderNode> (*)(const Json::Value&, AttachContext*);
|
||||
@ -468,13 +534,15 @@ struct ShapeInfo {
|
||||
const ShapeInfo* FindShapeInfo(const Json::Value& shape) {
|
||||
static constexpr ShapeInfo gShapeInfo[] = {
|
||||
{ "el", ShapeType::kGeometry , 2 }, // ellipse -> AttachEllipseGeometry
|
||||
{ "fl", ShapeType::kPaint , 0 }, // fill -> AttachFillPaint
|
||||
{ "fl", ShapeType::kPaint , 0 }, // fill -> AttachColorFill
|
||||
{ "gf", ShapeType::kPaint , 2 }, // gfill -> AttachGradientFill
|
||||
{ "gr", ShapeType::kGroup , 0 }, // group -> AttachShapeGroup
|
||||
{ "gs", ShapeType::kPaint , 3 }, // gstroke -> AttachGradientStroke
|
||||
{ "mm", ShapeType::kGeometryEffect, 0 }, // merge -> AttachMergeGeometryEffect
|
||||
{ "rc", ShapeType::kGeometry , 1 }, // rrect -> AttachRRectGeometry
|
||||
{ "sh", ShapeType::kGeometry , 0 }, // shape -> AttachPathGeometry
|
||||
{ "sr", ShapeType::kGeometry , 3 }, // polystar -> AttachPolyStarGeometry
|
||||
{ "st", ShapeType::kPaint , 1 }, // stroke -> AttachStrokePaint
|
||||
{ "st", ShapeType::kPaint , 1 }, // stroke -> AttachColorStroke
|
||||
{ "tm", ShapeType::kGeometryEffect, 1 }, // trim -> AttachTrimGeometryEffect
|
||||
{ "tr", ShapeType::kTransform , 0 }, // transform -> In-place handler
|
||||
};
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "SkottyPriv.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkSGColor.h"
|
||||
#include "SkSGGradient.h"
|
||||
#include "SkSGPath.h"
|
||||
#include "SkSGRect.h"
|
||||
#include "SkSGTransform.h"
|
||||
@ -41,6 +42,19 @@ bool ParsePoints(const Json::Value& v, PointArray* pts) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SkColor VecToColor(const float* v, size_t size) {
|
||||
// best effort to turn this into a color
|
||||
const auto r = size > 0 ? v[0] : 0,
|
||||
g = size > 1 ? v[1] : 0,
|
||||
b = size > 2 ? v[2] : 0,
|
||||
a = size > 3 ? v[3] : 1;
|
||||
|
||||
return SkColorSetARGB(SkTPin<SkScalar>(a, 0, 1) * 255,
|
||||
SkTPin<SkScalar>(r, 0, 1) * 255,
|
||||
SkTPin<SkScalar>(g, 0, 1) * 255,
|
||||
SkTPin<SkScalar>(b, 0, 1) * 255);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
@ -94,16 +108,7 @@ size_t ValueTraits<VectorValue>::Cardinality(const VectorValue& vec) {
|
||||
template <>
|
||||
template <>
|
||||
SkColor ValueTraits<VectorValue>::As<SkColor>(const VectorValue& vec) {
|
||||
// best effort to turn this into a color
|
||||
const auto r = vec.size() > 0 ? vec[0] : 0,
|
||||
g = vec.size() > 1 ? vec[1] : 0,
|
||||
b = vec.size() > 2 ? vec[2] : 0,
|
||||
a = vec.size() > 3 ? vec[3] : 1;
|
||||
|
||||
return SkColorSetARGB(SkTPin<SkScalar>(a, 0, 1) * 255,
|
||||
SkTPin<SkScalar>(r, 0, 1) * 255,
|
||||
SkTPin<SkScalar>(g, 0, 1) * 255,
|
||||
SkTPin<SkScalar>(b, 0, 1) * 255);
|
||||
return VecToColor(vec.data(), vec.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -251,4 +256,49 @@ void CompositePolyStar::apply() {
|
||||
fPathNode->setPath(poly);
|
||||
}
|
||||
|
||||
CompositeGradient::CompositeGradient(sk_sp<sksg::Gradient> grad, size_t stopCount)
|
||||
: fGradient(std::move(grad))
|
||||
, fStopCount(stopCount) {}
|
||||
|
||||
void CompositeGradient::apply() {
|
||||
this->onApply();
|
||||
|
||||
// |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
|
||||
|
||||
if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
|
||||
LOG("!! Invalid gradient stop array size: %zu", fColorStops.size());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<sksg::Gradient::ColorStop> stops;
|
||||
|
||||
// TODO: merge/lerp opacity stops
|
||||
const auto csEnd = fColorStops.cbegin() + fStopCount * 4;
|
||||
for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) {
|
||||
stops.push_back({ *cs, VecToColor(&*(cs + 1), 3) });
|
||||
}
|
||||
|
||||
fGradient->setColorStops(std::move(stops));
|
||||
}
|
||||
|
||||
CompositeLinearGradient::CompositeLinearGradient(sk_sp<sksg::LinearGradient> grad, size_t stopCount)
|
||||
: INHERITED(std::move(grad), stopCount) {}
|
||||
|
||||
void CompositeLinearGradient::onApply() {
|
||||
auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get());
|
||||
grad->setStartPoint(this->startPoint());
|
||||
grad->setEndPoint(this->endPoint());
|
||||
}
|
||||
|
||||
CompositeRadialGradient::CompositeRadialGradient(sk_sp<sksg::RadialGradient> grad, size_t stopCount)
|
||||
: INHERITED(std::move(grad), stopCount) {}
|
||||
|
||||
void CompositeRadialGradient::onApply() {
|
||||
auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get());
|
||||
grad->setStartCenter(this->startPoint());
|
||||
grad->setEndCenter(this->startPoint());
|
||||
grad->setStartRadius(0);
|
||||
grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint()));
|
||||
}
|
||||
|
||||
} // namespace skotty
|
||||
|
@ -22,8 +22,11 @@
|
||||
|
||||
namespace sksg {
|
||||
class Color;
|
||||
class Gradient;
|
||||
class LinearGradient;
|
||||
class Matrix;
|
||||
class Path;
|
||||
class RadialGradient;
|
||||
class RRect;
|
||||
class RenderNode;;
|
||||
}
|
||||
@ -130,6 +133,49 @@ private:
|
||||
using INHERITED = SkRefCnt;
|
||||
};
|
||||
|
||||
class CompositeGradient : public SkRefCnt {
|
||||
public:
|
||||
COMPOSITE_PROPERTY(StartPoint, SkPoint , SkPoint::Make(0, 0) )
|
||||
COMPOSITE_PROPERTY(EndPoint , SkPoint , SkPoint::Make(0, 0) )
|
||||
COMPOSITE_PROPERTY(ColorStops, std::vector<SkScalar>, std::vector<SkScalar>())
|
||||
|
||||
protected:
|
||||
CompositeGradient(sk_sp<sksg::Gradient>, size_t stopCount);
|
||||
|
||||
const SkPoint& startPoint() const { return fStartPoint; }
|
||||
const SkPoint& endPoint() const { return fEndPoint; }
|
||||
|
||||
sk_sp<sksg::Gradient> fGradient;
|
||||
size_t fStopCount;
|
||||
|
||||
virtual void onApply() = 0;
|
||||
|
||||
private:
|
||||
void apply();
|
||||
|
||||
using INHERITED = SkRefCnt;
|
||||
};
|
||||
|
||||
class CompositeLinearGradient final : public CompositeGradient {
|
||||
public:
|
||||
CompositeLinearGradient(sk_sp<sksg::LinearGradient>, size_t stopCount);
|
||||
|
||||
private:
|
||||
void onApply() override;
|
||||
|
||||
using INHERITED = CompositeGradient;
|
||||
};
|
||||
|
||||
class CompositeRadialGradient final : public CompositeGradient {
|
||||
public:
|
||||
CompositeRadialGradient(sk_sp<sksg::RadialGradient>, size_t stopCount);
|
||||
|
||||
private:
|
||||
void onApply() override;
|
||||
|
||||
using INHERITED = CompositeGradient;
|
||||
};
|
||||
|
||||
#undef COMPOSITE_PROPERTY
|
||||
|
||||
} // namespace skotty
|
||||
|
60
experimental/sksg/paint/SkSGGradient.cpp
Normal file
60
experimental/sksg/paint/SkSGGradient.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkSGGradient.h"
|
||||
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkPaint.h"
|
||||
|
||||
namespace sksg {
|
||||
|
||||
void Gradient::onApplyToPaint(SkPaint* paint) const {
|
||||
if (fColorStops.empty()) {
|
||||
paint->setShader(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<SkColor> colors;
|
||||
std::vector<SkScalar> positions;
|
||||
colors.reserve(fColorStops.size());
|
||||
positions.reserve(fColorStops.size());
|
||||
|
||||
SkScalar position = 0;
|
||||
for (const auto& stop : fColorStops) {
|
||||
colors.push_back(stop.fColor);
|
||||
position = SkTPin(stop.fPosition, position, 1.0f);
|
||||
positions.push_back(position);
|
||||
}
|
||||
|
||||
// TODO: detect even stop distributions, pass null for positions.
|
||||
paint->setShader(this->onMakeShader(colors, positions));
|
||||
}
|
||||
|
||||
sk_sp<SkShader> LinearGradient::onMakeShader(const std::vector<SkColor>& colors,
|
||||
const std::vector<SkScalar>& positions) const {
|
||||
SkASSERT(colors.size() == positions.size());
|
||||
|
||||
const SkPoint pts[] = { fStartPoint, fEndPoint };
|
||||
return SkGradientShader::MakeLinear(pts, colors.data(), positions.data(), colors.size(),
|
||||
this->getTileMode());
|
||||
}
|
||||
|
||||
sk_sp<SkShader> RadialGradient::onMakeShader(const std::vector<SkColor>& colors,
|
||||
const std::vector<SkScalar>& positions) const {
|
||||
SkASSERT(colors.size() == positions.size());
|
||||
|
||||
return (fStartRadius <= 0 && fStartCenter == fEndCenter)
|
||||
? SkGradientShader::MakeRadial(fEndCenter, fEndRadius,
|
||||
colors.data(), positions.data(), colors.size(),
|
||||
this->getTileMode())
|
||||
: SkGradientShader::MakeTwoPointConical(fStartCenter, fStartRadius,
|
||||
fEndCenter, fEndRadius,
|
||||
colors.data(), positions.data(), colors.size(),
|
||||
this->getTileMode());
|
||||
}
|
||||
|
||||
} //namespace sksg
|
105
experimental/sksg/paint/SkSGGradient.h
Normal file
105
experimental/sksg/paint/SkSGGradient.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkSGGradient_DEFINED
|
||||
#define SkSGGradient_DEFINED
|
||||
|
||||
#include "SkSGPaintNode.h"
|
||||
|
||||
#include "SkColor.h"
|
||||
#include "SkPoint.h"
|
||||
#include "SkScalar.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace sksg {
|
||||
|
||||
/**
|
||||
* Gradient base class.
|
||||
*/
|
||||
class Gradient : public PaintNode {
|
||||
public:
|
||||
struct ColorStop {
|
||||
SkScalar fPosition;
|
||||
SkColor fColor;
|
||||
|
||||
bool operator==(const ColorStop& other) const {
|
||||
return fPosition == other.fPosition && fColor == other.fColor;
|
||||
}
|
||||
};
|
||||
|
||||
SG_ATTRIBUTE(ColorStops, std::vector<ColorStop>, fColorStops)
|
||||
SG_ATTRIBUTE(TileMode , SkShader::TileMode , fTileMode )
|
||||
|
||||
protected:
|
||||
void onApplyToPaint(SkPaint*) const final;
|
||||
|
||||
virtual sk_sp<SkShader> onMakeShader(const std::vector<SkColor>& colors,
|
||||
const std::vector<SkScalar>& positions) const = 0;
|
||||
|
||||
protected:
|
||||
Gradient() = default;
|
||||
|
||||
private:
|
||||
std::vector<ColorStop> fColorStops;
|
||||
SkShader::TileMode fTileMode = SkShader::kClamp_TileMode;
|
||||
|
||||
using INHERITED = PaintNode;
|
||||
};
|
||||
|
||||
class LinearGradient final : public Gradient {
|
||||
public:
|
||||
static sk_sp<LinearGradient> Make() {
|
||||
return sk_sp<LinearGradient>(new LinearGradient());
|
||||
}
|
||||
|
||||
SG_ATTRIBUTE(StartPoint, SkPoint, fStartPoint)
|
||||
SG_ATTRIBUTE(EndPoint , SkPoint, fEndPoint )
|
||||
|
||||
protected:
|
||||
sk_sp<SkShader> onMakeShader(const std::vector<SkColor>& colors,
|
||||
const std::vector<SkScalar>& positions) const override;
|
||||
|
||||
private:
|
||||
LinearGradient() = default;
|
||||
|
||||
SkPoint fStartPoint = SkPoint::Make(0, 0),
|
||||
fEndPoint = SkPoint::Make(0, 0);
|
||||
|
||||
using INHERITED = Gradient;
|
||||
};
|
||||
|
||||
class RadialGradient final : public Gradient {
|
||||
public:
|
||||
static sk_sp<RadialGradient> Make() {
|
||||
return sk_sp<RadialGradient>(new RadialGradient());
|
||||
}
|
||||
|
||||
SG_ATTRIBUTE(StartCenter, SkPoint , fStartCenter)
|
||||
SG_ATTRIBUTE(EndCenter , SkPoint , fEndCenter )
|
||||
SG_ATTRIBUTE(StartRadius, SkScalar, fStartRadius)
|
||||
SG_ATTRIBUTE(EndRadius , SkScalar, fEndRadius )
|
||||
|
||||
protected:
|
||||
sk_sp<SkShader> onMakeShader(const std::vector<SkColor>& colors,
|
||||
const std::vector<SkScalar>& positions) const override;
|
||||
|
||||
private:
|
||||
RadialGradient() = default;
|
||||
|
||||
SkPoint fStartCenter = SkPoint::Make(0, 0),
|
||||
fEndCenter = SkPoint::Make(0, 0);
|
||||
SkScalar fStartRadius = 0,
|
||||
fEndRadius = 0;
|
||||
|
||||
using INHERITED = Gradient;
|
||||
};
|
||||
|
||||
} // namespace sksg
|
||||
|
||||
#endif // SkSGGradient_DEFINED
|
Loading…
Reference in New Issue
Block a user