mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
sw_engine: adding a gradient as a stroke feature
* sw_engine: adding a gradient as a stroke feature Similarly as a shape may have a gradient fill so can the stroke. * Capi: adding APIs for a gradient stroke Co-authored-by: Hermet Park <hermetpark@gmail.com>
This commit is contained in:
parent
20324dc48e
commit
d86032df36
11 changed files with 155 additions and 30 deletions
|
@ -230,6 +230,7 @@ public:
|
||||||
//Stroke
|
//Stroke
|
||||||
Result stroke(float width) noexcept;
|
Result stroke(float width) noexcept;
|
||||||
Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept;
|
Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept;
|
||||||
|
Result stroke(std::unique_ptr<Fill> f) noexcept;
|
||||||
Result stroke(const float* dashPattern, uint32_t cnt) noexcept;
|
Result stroke(const float* dashPattern, uint32_t cnt) noexcept;
|
||||||
Result stroke(StrokeCap cap) noexcept;
|
Result stroke(StrokeCap cap) noexcept;
|
||||||
Result stroke(StrokeJoin join) noexcept;
|
Result stroke(StrokeJoin join) noexcept;
|
||||||
|
@ -248,6 +249,7 @@ public:
|
||||||
|
|
||||||
float strokeWidth() const noexcept;
|
float strokeWidth() const noexcept;
|
||||||
Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept;
|
Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept;
|
||||||
|
const Fill* strokeFill() const noexcept;
|
||||||
uint32_t strokeDash(const float** dashPattern) const noexcept;
|
uint32_t strokeDash(const float** dashPattern) const noexcept;
|
||||||
StrokeCap strokeCap() const noexcept;
|
StrokeCap strokeCap() const noexcept;
|
||||||
StrokeJoin strokeJoin() const noexcept;
|
StrokeJoin strokeJoin() const noexcept;
|
||||||
|
|
|
@ -829,6 +829,10 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_color(Tvg_Paint* paint, uint8_t r, ui
|
||||||
*/
|
*/
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_get_stroke_color(const Tvg_Paint* paint, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a);
|
TVG_EXPORT Tvg_Result tvg_shape_get_stroke_color(const Tvg_Paint* paint, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a);
|
||||||
|
|
||||||
|
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_linear_gradient(Tvg_Paint* paint, Tvg_Gradient* grad);
|
||||||
|
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_radial_gradient(Tvg_Paint* paint, Tvg_Gradient* grad);
|
||||||
|
TVG_EXPORT Tvg_Result tvg_shape_get_stroke_gradient(const Tvg_Paint* paint, Tvg_Gradient** grad);
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \fn TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* dashPattern, uint32_t cnt)
|
* \fn TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* dashPattern, uint32_t cnt)
|
||||||
|
|
|
@ -313,6 +313,28 @@ TVG_EXPORT Tvg_Result tvg_shape_get_stroke_color(const Tvg_Paint* paint, uint8_t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_linear_gradient(Tvg_Paint* paint, Tvg_Gradient* gradient)
|
||||||
|
{
|
||||||
|
if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
|
return (Tvg_Result) reinterpret_cast<Shape*>(paint)->stroke(unique_ptr<LinearGradient>((LinearGradient*)(gradient)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_radial_gradient(Tvg_Paint* paint, Tvg_Gradient* gradient)
|
||||||
|
{
|
||||||
|
if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
|
return (Tvg_Result) reinterpret_cast<Shape*>(paint)->stroke(unique_ptr<RadialGradient>((RadialGradient*)(gradient)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TVG_EXPORT Tvg_Result tvg_shape_stroke_get_gradient(const Tvg_Paint* paint, Tvg_Gradient** gradient)
|
||||||
|
{
|
||||||
|
if (!paint || !gradient) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
|
*gradient = (Tvg_Gradient*)(reinterpret_cast<Shape*>(CCP(paint))->strokeFill());
|
||||||
|
return TVG_RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* dashPattern, uint32_t cnt)
|
TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* dashPattern, uint32_t cnt)
|
||||||
{
|
{
|
||||||
if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
|
if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
|
||||||
|
|
|
@ -127,6 +127,32 @@ struct SwBBox
|
||||||
SwPoint min, max;
|
SwPoint min, max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SwFill
|
||||||
|
{
|
||||||
|
struct SwLinear {
|
||||||
|
float dx, dy;
|
||||||
|
float len;
|
||||||
|
float offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SwRadial {
|
||||||
|
float cx, cy;
|
||||||
|
float a;
|
||||||
|
float inv2a;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
SwLinear linear;
|
||||||
|
SwRadial radial;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t* ctable;
|
||||||
|
FillSpread spread;
|
||||||
|
float sx, sy;
|
||||||
|
|
||||||
|
bool translucent;
|
||||||
|
};
|
||||||
|
|
||||||
struct SwStrokeBorder
|
struct SwStrokeBorder
|
||||||
{
|
{
|
||||||
uint32_t ptsCnt;
|
uint32_t ptsCnt;
|
||||||
|
@ -152,6 +178,7 @@ struct SwStroke
|
||||||
StrokeCap cap;
|
StrokeCap cap;
|
||||||
StrokeJoin join;
|
StrokeJoin join;
|
||||||
StrokeJoin joinSaved;
|
StrokeJoin joinSaved;
|
||||||
|
SwFill* fill = nullptr;
|
||||||
|
|
||||||
SwStrokeBorder borders[2];
|
SwStrokeBorder borders[2];
|
||||||
|
|
||||||
|
@ -174,32 +201,6 @@ struct SwDashStroke
|
||||||
bool curOpGap;
|
bool curOpGap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwFill
|
|
||||||
{
|
|
||||||
struct SwLinear {
|
|
||||||
float dx, dy;
|
|
||||||
float len;
|
|
||||||
float offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SwRadial {
|
|
||||||
float cx, cy;
|
|
||||||
float a;
|
|
||||||
float inv2a;
|
|
||||||
};
|
|
||||||
|
|
||||||
union {
|
|
||||||
SwLinear linear;
|
|
||||||
SwRadial radial;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t* ctable;
|
|
||||||
FillSpread spread;
|
|
||||||
float sx, sy;
|
|
||||||
|
|
||||||
bool translucent;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SwShape
|
struct SwShape
|
||||||
{
|
{
|
||||||
SwOutline* outline = nullptr;
|
SwOutline* outline = nullptr;
|
||||||
|
@ -297,8 +298,11 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M
|
||||||
void shapeFree(SwShape* shape);
|
void shapeFree(SwShape* shape);
|
||||||
void shapeDelStroke(SwShape* shape);
|
void shapeDelStroke(SwShape* shape);
|
||||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
|
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
|
||||||
|
bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
|
||||||
void shapeResetFill(SwShape* shape);
|
void shapeResetFill(SwShape* shape);
|
||||||
|
void shapeResetStrokeFill(SwShape* shape);
|
||||||
void shapeDelFill(SwShape* shape);
|
void shapeDelFill(SwShape* shape);
|
||||||
|
void shapeDelStrokeFill(SwShape* shape);
|
||||||
|
|
||||||
void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform);
|
void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform);
|
||||||
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
|
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
|
||||||
|
@ -339,6 +343,7 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
|
||||||
bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||||
bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity);
|
bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity);
|
||||||
bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||||
|
bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id);
|
||||||
bool rasterClear(SwSurface* surface);
|
bool rasterClear(SwSurface* surface);
|
||||||
|
|
||||||
static inline void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
|
static inline void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
|
||||||
|
|
|
@ -817,6 +817,15 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
|
||||||
|
{
|
||||||
|
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
|
||||||
|
return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool rasterClear(SwSurface* surface)
|
bool rasterClear(SwSurface* surface)
|
||||||
{
|
{
|
||||||
if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
|
if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
|
||||||
|
|
|
@ -76,6 +76,7 @@ struct SwShapeTask : SwTask
|
||||||
if (HALF_STROKE(strokeWidth) > 0) {
|
if (HALF_STROKE(strokeWidth) > 0) {
|
||||||
sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
|
sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
|
||||||
}
|
}
|
||||||
|
bool validStroke = (strokeAlpha > 0) || sdata->strokeFill();
|
||||||
|
|
||||||
SwSize clip = {static_cast<SwCoord>(surface->w), static_cast<SwCoord>(surface->h)};
|
SwSize clip = {static_cast<SwCoord>(surface->w), static_cast<SwCoord>(surface->h)};
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ struct SwShapeTask : SwTask
|
||||||
sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
|
sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
|
||||||
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
|
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
|
||||||
bool renderShape = (alpha > 0 || sdata->fill());
|
bool renderShape = (alpha > 0 || sdata->fill());
|
||||||
if (renderShape || strokeAlpha) {
|
if (renderShape || validStroke) {
|
||||||
shapeReset(&shape);
|
shapeReset(&shape);
|
||||||
if (!shapePrepare(&shape, sdata, tid, clip, transform, bbox)) goto err;
|
if (!shapePrepare(&shape, sdata, tid, clip, transform, bbox)) goto err;
|
||||||
if (renderShape) {
|
if (renderShape) {
|
||||||
|
@ -118,10 +119,18 @@ struct SwShapeTask : SwTask
|
||||||
|
|
||||||
//Stroke
|
//Stroke
|
||||||
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||||
if (strokeAlpha > 0) {
|
if (validStroke) {
|
||||||
shapeResetStroke(&shape, sdata, transform);
|
shapeResetStroke(&shape, sdata, transform);
|
||||||
if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip, bbox)) goto err;
|
if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip, bbox)) goto err;
|
||||||
++addStroking;
|
++addStroking;
|
||||||
|
|
||||||
|
if (auto fill = sdata->strokeFill()) {
|
||||||
|
auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false;
|
||||||
|
if (ctable) shapeResetStrokeFill(&shape);
|
||||||
|
if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err;
|
||||||
|
} else {
|
||||||
|
shapeDelStrokeFill(&shape);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
shapeDelStroke(&shape);
|
shapeDelStroke(&shape);
|
||||||
}
|
}
|
||||||
|
@ -324,6 +333,9 @@ bool SwRenderer::renderShape(RenderData data)
|
||||||
if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a);
|
if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto strokeFill = task->sdata->strokeFill()) {
|
||||||
|
rasterGradientStroke(surface, &task->shape, strokeFill->id());
|
||||||
|
} else {
|
||||||
if (task->sdata->strokeColor(&r, &g, &b, &a) == Result::Success) {
|
if (task->sdata->strokeColor(&r, &g, &b, &a) == Result::Success) {
|
||||||
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
|
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
|
||||||
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
|
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
|
||||||
|
|
|
@ -650,6 +650,12 @@ bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable)
|
||||||
|
{
|
||||||
|
return fillGenColorTable(shape->stroke->fill, fill, transform, surface, opacity, ctable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void shapeResetFill(SwShape* shape)
|
void shapeResetFill(SwShape* shape)
|
||||||
{
|
{
|
||||||
if (!shape->fill) {
|
if (!shape->fill) {
|
||||||
|
@ -660,9 +666,28 @@ void shapeResetFill(SwShape* shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void shapeResetStrokeFill(SwShape* shape)
|
||||||
|
{
|
||||||
|
if (!shape->stroke->fill) {
|
||||||
|
shape->stroke->fill = static_cast<SwFill*>(calloc(1, sizeof(SwFill)));
|
||||||
|
if (!shape->stroke->fill) return;
|
||||||
|
}
|
||||||
|
fillReset(shape->stroke->fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void shapeDelFill(SwShape* shape)
|
void shapeDelFill(SwShape* shape)
|
||||||
{
|
{
|
||||||
if (!shape->fill) return;
|
if (!shape->fill) return;
|
||||||
fillFree(shape->fill);
|
fillFree(shape->fill);
|
||||||
shape->fill = nullptr;
|
shape->fill = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void shapeDelStrokeFill(SwShape* shape)
|
||||||
|
{
|
||||||
|
if (!shape->stroke->fill) return;
|
||||||
|
fillFree(shape->stroke->fill);
|
||||||
|
shape->stroke->fill = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "tvgSwCommon.h"
|
#include "tvgSwCommon.h"
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
@ -821,6 +820,9 @@ void strokeFree(SwStroke* stroke)
|
||||||
if (stroke->borders[1].pts) free(stroke->borders[1].pts);
|
if (stroke->borders[1].pts) free(stroke->borders[1].pts);
|
||||||
if (stroke->borders[1].tags) free(stroke->borders[1].tags);
|
if (stroke->borders[1].tags) free(stroke->borders[1].tags);
|
||||||
|
|
||||||
|
fillFree(stroke->fill);
|
||||||
|
stroke->fill = nullptr;
|
||||||
|
|
||||||
free(stroke);
|
free(stroke);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ struct Compositor {
|
||||||
uint32_t opacity;
|
uint32_t opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 63};
|
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, All = 127};
|
||||||
|
|
||||||
struct RenderTransform
|
struct RenderTransform
|
||||||
{
|
{
|
||||||
|
|
|
@ -335,6 +335,20 @@ Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Result Shape::stroke(unique_ptr<Fill> f) noexcept
|
||||||
|
{
|
||||||
|
return pImpl->strokeFill(move(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Fill* Shape::strokeFill() const noexcept
|
||||||
|
{
|
||||||
|
if (!pImpl->stroke) return nullptr;
|
||||||
|
|
||||||
|
return pImpl->stroke->fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept
|
Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept
|
||||||
{
|
{
|
||||||
if (cnt < 2 || !dashPattern) return Result::InvalidArguments;
|
if (cnt < 2 || !dashPattern) return Result::InvalidArguments;
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct ShapeStroke
|
||||||
{
|
{
|
||||||
float width = 0;
|
float width = 0;
|
||||||
uint8_t color[4] = {0, 0, 0, 0};
|
uint8_t color[4] = {0, 0, 0, 0};
|
||||||
|
Fill *fill = nullptr;
|
||||||
float* dashPattern = nullptr;
|
float* dashPattern = nullptr;
|
||||||
uint32_t dashCnt = 0;
|
uint32_t dashCnt = 0;
|
||||||
StrokeCap cap = StrokeCap::Square;
|
StrokeCap cap = StrokeCap::Square;
|
||||||
|
@ -49,11 +50,14 @@ struct ShapeStroke
|
||||||
memcpy(color, src->color, sizeof(color));
|
memcpy(color, src->color, sizeof(color));
|
||||||
dashPattern = static_cast<float*>(malloc(sizeof(float) * dashCnt));
|
dashPattern = static_cast<float*>(malloc(sizeof(float) * dashCnt));
|
||||||
memcpy(dashPattern, src->dashPattern, sizeof(float) * dashCnt);
|
memcpy(dashPattern, src->dashPattern, sizeof(float) * dashCnt);
|
||||||
|
if (src->fill)
|
||||||
|
fill = src->fill->duplicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
~ShapeStroke()
|
~ShapeStroke()
|
||||||
{
|
{
|
||||||
if (dashPattern) free(dashPattern);
|
if (dashPattern) free(dashPattern);
|
||||||
|
if (fill) delete(fill);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -291,6 +295,12 @@ struct Shape::Impl
|
||||||
if (!stroke) stroke = new ShapeStroke();
|
if (!stroke) stroke = new ShapeStroke();
|
||||||
if (!stroke) return false;
|
if (!stroke) return false;
|
||||||
|
|
||||||
|
if (stroke->fill) {
|
||||||
|
delete(stroke->fill);
|
||||||
|
stroke->fill = nullptr;
|
||||||
|
flag |= RenderUpdateFlag::GradientStroke;
|
||||||
|
}
|
||||||
|
|
||||||
stroke->color[0] = r;
|
stroke->color[0] = r;
|
||||||
stroke->color[1] = g;
|
stroke->color[1] = g;
|
||||||
stroke->color[2] = b;
|
stroke->color[2] = b;
|
||||||
|
@ -301,6 +311,23 @@ struct Shape::Impl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result strokeFill(unique_ptr<Fill> f)
|
||||||
|
{
|
||||||
|
auto p = f.release();
|
||||||
|
if (!p) return Result::MemoryCorruption;
|
||||||
|
|
||||||
|
if (!stroke) stroke = new ShapeStroke();
|
||||||
|
if (!stroke) return Result::FailedAllocation;
|
||||||
|
|
||||||
|
if (stroke->fill && stroke->fill != p) delete(stroke->fill);
|
||||||
|
stroke->fill = p;
|
||||||
|
|
||||||
|
flag |= RenderUpdateFlag::Stroke;
|
||||||
|
flag |= RenderUpdateFlag::GradientStroke;
|
||||||
|
|
||||||
|
return Result::Success;
|
||||||
|
}
|
||||||
|
|
||||||
bool strokeDash(const float* pattern, uint32_t cnt)
|
bool strokeDash(const float* pattern, uint32_t cnt)
|
||||||
{
|
{
|
||||||
if (!stroke) stroke = new ShapeStroke();
|
if (!stroke) stroke = new ShapeStroke();
|
||||||
|
@ -363,6 +390,9 @@ struct Shape::Impl
|
||||||
if (stroke) {
|
if (stroke) {
|
||||||
dup->stroke = new ShapeStroke(stroke);
|
dup->stroke = new ShapeStroke(stroke);
|
||||||
dup->flag |= RenderUpdateFlag::Stroke;
|
dup->flag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
|
if (stroke->fill)
|
||||||
|
dup->flag |= RenderUpdateFlag::GradientStroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fill
|
//Fill
|
||||||
|
|
Loading…
Add table
Reference in a new issue