struct GlShape
{
- const Shape* shape = nullptr;
+ const RenderShape* rshape = nullptr;
float viewWd;
float viewHt;
RenderUpdateFlag updateFlag = None;
}
-bool GlGeometry::decomposeOutline(const Shape& shape)
+bool GlGeometry::decomposeOutline(const RenderShape& rshape)
{
- const PathCommand* cmds = nullptr;
- auto cmdCnt = shape.pathCommands(&cmds);
-
- Point* pts = nullptr;
- auto ptsCnt = shape.pathCoords(const_cast<const Point**>(&pts));
+ auto cmds = rshape.path.cmds;
+ auto cmdCnt = rshape.path.cmdCnt;
+ auto pts = rshape.path.pts;
+ auto ptsCnt = rshape.path.ptsCnt;
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return false;
return true;
}
-bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, RenderUpdateFlag flag)
+bool GlGeometry::generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag)
{
for (auto& shapeGeometry : mPrimitives) {
vector<PointNormals> normalInfo;
return true;
}
-bool GlGeometry::tesselate(TVG_UNUSED const Shape& shape, float viewWd, float viewHt, RenderUpdateFlag flag)
+bool GlGeometry::tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag)
{
for (auto& shapeGeometry : mPrimitives) {
constexpr float opaque = 1.0f;
uint32_t getPrimitiveCount();
const GlSize getPrimitiveSize(const uint32_t primitiveIndex) const;
- bool decomposeOutline(const Shape& shape);
- bool generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, RenderUpdateFlag flag);
- bool tesselate(TVG_UNUSED const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag);
+ bool decomposeOutline(const RenderShape& rshape);
+ bool generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag);
+ bool tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag);
void disableVertex(uint32_t location);
void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag);
void updateTransform(const RenderTransform* transform, float w, float h);
{
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
{
- const Fill* gradient = sdata->shape->fill();
- if (gradient != nullptr)
- {
- drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
- }
+ auto gradient = sdata->rshape->fill;
+ if (gradient) drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
}
if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
{
- sdata->shape->fillColor(&r, &g, &b, &a);
+ sdata->rshape->fillColor(&r, &g, &b, &a);
if (a > 0)
{
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
{
- sdata->shape->strokeColor(&r, &g, &b, &a);
+ sdata->rshape->strokeColor(&r, &g, &b, &a);
if (a > 0)
{
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
}
-RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, TVG_UNUSED bool clipper)
+RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, TVG_UNUSED bool clipper)
{
//prepare shape data
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) {
sdata = new GlShape;
- sdata->shape = &shape;
+ sdata->rshape = &rshape;
}
sdata->viewWd = static_cast<float>(surface.w);
//invisible?
uint8_t alphaF, alphaS;
- shape.fillColor(nullptr, nullptr, nullptr, &alphaF);
- shape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
- auto strokeWd = shape.strokeWidth();
+ rshape.fillColor(nullptr, nullptr, nullptr, &alphaF);
+ rshape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
+ auto strokeWd = rshape.strokeWidth();
if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) &&
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
{
- if (!sdata->geometry->decomposeOutline(shape)) return sdata;
- if (!sdata->geometry->generateAAPoints(shape, static_cast<float>(strokeWd), sdata->updateFlag)) return sdata;
- if (!sdata->geometry->tesselate(shape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata;
+ if (!sdata->geometry->decomposeOutline(rshape)) return sdata;
+ if (!sdata->geometry->generateAAPoints(rshape, static_cast<float>(strokeWd), sdata->updateFlag)) return sdata;
+ if (!sdata->geometry->tesselate(rshape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata;
}
return sdata;
}
public:
Surface surface = {nullptr, 0, 0, 0};
- RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
+ RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
bool preRender() override;
bool renderShape(RenderData data) override;
bool mathClipBBox(const SwBBox& clipper, SwBBox& clipee);
void shapeReset(SwShape* shape);
-bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
+bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite);
bool shapePrepared(const SwShape* shape);
-bool shapeGenRle(SwShape* shape, const Shape* sdata, bool antiAlias);
+bool shapeGenRle(SwShape* shape, const RenderShape* rshape, bool antiAlias);
void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid);
-void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
+void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform);
+bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
void shapeFree(SwShape* shape);
void shapeDelStroke(SwShape* shape);
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
void shapeDelFill(SwShape* shape);
void shapeDelStrokeFill(SwShape* shape);
-void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform);
+void strokeReset(SwStroke* stroke, const RenderShape* shape, const Matrix* transform);
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
void strokeFree(SwStroke* stroke);
struct SwShapeTask : SwTask
{
SwShape shape;
- const Shape* sdata = nullptr;
+ const RenderShape* rshape = nullptr;
bool cmpStroking = false;
bool clipper = false;
bool visibleFill = false;
auto clipRegion = bbox;
- if (HALF_STROKE(sdata->strokeWidth()) > 0) {
- sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
- visibleStroke = sdata->strokeFill() || (static_cast<uint32_t>(strokeAlpha * opacity / 255) > 0);
+ if (HALF_STROKE(rshape->strokeWidth()) > 0) {
+ rshape->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
+ visibleStroke = rshape->strokeFill() || (static_cast<uint32_t>(strokeAlpha * opacity / 255) > 0);
}
//This checks also for the case, if the invisible shape turned to visible by alpha.
//Shape
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform) || prepareShape) {
uint8_t alpha = 0;
- sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
+ rshape->fillColor(nullptr, nullptr, nullptr, &alpha);
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
- visibleFill = (alpha > 0 || sdata->fill());
+ visibleFill = (alpha > 0 || rshape->fill);
if (visibleFill || visibleStroke || clipper) {
shapeReset(&shape);
- if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
+ if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
}
}
shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition.
Also, it shouldn't be dash style. */
- auto antiAlias = (strokeAlpha == 255 && sdata->strokeWidth() > 2 && sdata->strokeDash(nullptr) == 0) ? false : true;
+ auto antiAlias = (strokeAlpha == 255 && rshape->strokeWidth() > 2 && rshape->strokeDash(nullptr) == 0) ? false : true;
- if (!shapeGenRle(&shape, sdata, antiAlias)) goto err;
+ if (!shapeGenRle(&shape, rshape, antiAlias)) goto err;
}
- if (auto fill = sdata->fill()) {
+ if (auto fill = rshape->fill) {
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
if (ctable) shapeResetFill(&shape);
if (!shapeGenFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
//Stroke
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
if (visibleStroke) {
- shapeResetStroke(&shape, sdata, transform);
- if (!shapeGenStrokeRle(&shape, sdata, transform, clipRegion, bbox, mpool, tid)) goto err;
+ shapeResetStroke(&shape, rshape, transform);
+ if (!shapeGenStrokeRle(&shape, rshape, transform, clipRegion, bbox, mpool, tid)) goto err;
- if (auto fill = sdata->strokeFill()) {
+ if (auto fill = rshape->strokeFill()) {
auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false;
if (ctable) shapeResetStrokeFill(&shape);
if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
//Main raster stage
uint8_t r, g, b, a;
- if (auto fill = task->sdata->fill()) {
+ if (auto fill = task->rshape->fill) {
rasterGradientShape(surface, &task->shape, fill->identifier());
} else {
- task->sdata->fillColor(&r, &g, &b, &a);
+ task->rshape->fillColor(&r, &g, &b, &a);
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterShape(surface, &task->shape, r, g, b, a);
}
- if (auto strokeFill = task->sdata->strokeFill()) {
+ if (auto strokeFill = task->rshape->strokeFill()) {
rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
} else {
- if (task->sdata->strokeColor(&r, &g, &b, &a) == Result::Success) {
+ if (task->rshape->strokeColor(&r, &g, &b, &a)) {
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
}
}
-RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper)
+RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper)
{
//prepare task
auto task = static_cast<SwShapeTask*>(data);
if (!task) {
task = new SwShapeTask;
- task->sdata = &sdata;
+ task->rshape = &rshape;
task->clipper = clipper;
}
return prepareCommon(task, transform, opacity, clips, flags);
class SwRenderer : public RenderMethod
{
public:
- RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
+ RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) override;
RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
bool preRender() override;
bool renderShape(RenderData data) override;
}
-static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
+static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform)
{
- const PathCommand* cmds = nullptr;
- auto cmdCnt = sdata->pathCommands(&cmds);
+ const PathCommand* cmds = rshape->path.cmds;
+ auto cmdCnt = rshape->path.cmdCnt;
- const Point* pts = nullptr;
- auto ptsCnt = sdata->pathCoords(&pts);
+ const Point* pts = rshape->path.pts;
+ auto ptsCnt = rshape->path.ptsCnt;
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
dash.curOpGap = false;
const float* pattern;
- dash.cnt = sdata->strokeDash(&pattern);
+ dash.cnt = rshape->strokeDash(&pattern);
if (dash.cnt == 0) return nullptr;
//OPTMIZE ME: Use mempool???
-static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite)
+static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite)
{
- const PathCommand* cmds = nullptr;
- auto cmdCnt = sdata->pathCommands(&cmds);
+ const PathCommand* cmds = rshape->path.cmds;
+ auto cmdCnt = rshape->path.cmdCnt;
- const Point* pts = nullptr;
- auto ptsCnt = sdata->pathCoords(&pts);
+ const Point* pts = rshape->path.pts;
+ auto ptsCnt = rshape->path.ptsCnt;
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return false;
_outlineEnd(*outline);
- outline->fillRule = sdata->fillRule();
+ outline->fillRule = rshape->rule;
shape->outline = outline;
shape->fastTrack = (!hasComposite && _axisAlignedRect(shape->outline));
/* External Class Implementation */
/************************************************************************/
-bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
+bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
{
- if (!_genOutline(shape, sdata, transform, mpool, tid, hasComposite)) return false;
+ if (!_genOutline(shape, rshape, transform, mpool, tid, hasComposite)) return false;
if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false;
//Keep it for Rasterization Region
}
-bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias)
+bool shapeGenRle(SwShape* shape, TVG_UNUSED const RenderShape* rshape, bool antiAlias)
{
//FIXME: Should we draw it?
//Case: Stroke Line
}
-void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform)
+void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform)
{
if (!shape->stroke) shape->stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
auto stroke = shape->stroke;
if (!stroke) return;
- strokeReset(stroke, sdata, transform);
+ strokeReset(stroke, rshape, transform);
rleReset(shape->strokeRle);
}
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
+bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
{
SwOutline* shapeOutline = nullptr;
SwOutline* strokeOutline = nullptr;
bool ret = true;
//Dash Style Stroke
- if (sdata->strokeDash(nullptr) > 0) {
- shapeOutline = _genDashOutline(sdata, transform);
+ if (rshape->strokeDash(nullptr) > 0) {
+ shapeOutline = _genDashOutline(rshape, transform);
if (!shapeOutline) return false;
freeOutline = true;
//Normal Style stroke
} else {
if (!shape->outline) {
- if (!_genOutline(shape, sdata, transform, mpool, tid, false)) return false;
+ if (!_genOutline(shape, rshape, transform, mpool, tid, false)) return false;
}
shapeOutline = shape->outline;
}
}
-void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform)
+void strokeReset(SwStroke* stroke, const RenderShape* rshape, const Matrix* transform)
{
if (transform) {
stroke->sx = sqrtf(powf(transform->e11, 2.0f) + powf(transform->e21, 2.0f));
stroke->sx = stroke->sy = 1.0f;
}
- stroke->width = HALF_STROKE(sdata->strokeWidth());
- stroke->cap = sdata->strokeCap();
+ stroke->width = HALF_STROKE(rshape->strokeWidth());
+ stroke->cap = rshape->strokeCap();
//Save line join: it can be temporarily changed when stroking curves...
- stroke->joinSaved = stroke->join = sdata->strokeJoin();
+ stroke->joinSaved = stroke->join = rshape->strokeJoin();
stroke->borders[0].ptsCnt = 0;
stroke->borders[0].start = -1;
RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
};
+struct RenderStroke
+{
+ float width = 0.0f;
+ uint8_t color[4] = {0, 0, 0, 0};
+ Fill *fill = nullptr;
+ float* dashPattern = nullptr;
+ uint32_t dashCnt = 0;
+ StrokeCap cap = StrokeCap::Square;
+ StrokeJoin join = StrokeJoin::Bevel;
+
+ ~RenderStroke()
+ {
+ free(dashPattern);
+ if (fill) delete(fill);
+ }
+};
+
+struct RenderShape
+{
+ struct
+ {
+ PathCommand* cmds = nullptr;
+ uint32_t cmdCnt = 0;
+ uint32_t reservedCmdCnt = 0;
+
+ Point *pts = nullptr;
+ uint32_t ptsCnt = 0;
+ uint32_t reservedPtsCnt = 0;
+ } path;
+
+ Fill *fill = nullptr;
+ RenderStroke *stroke = nullptr;
+ uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
+ FillRule rule = FillRule::Winding;
+
+ ~RenderShape()
+ {
+ free(path.cmds);
+ free(path.pts);
+
+ if (fill) delete(fill);
+ if (stroke) delete(stroke);
+ }
+
+ void fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const
+ {
+ if (r) *r = color[0];
+ if (g) *g = color[1];
+ if (b) *b = color[2];
+ if (a) *a = color[3];
+ }
+
+ float strokeWidth() const
+ {
+ if (!stroke) return 0;
+ return stroke->width;
+ }
+
+ bool strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const
+ {
+ if (!stroke) return false;
+
+ if (r) *r = stroke->color[0];
+ if (g) *g = stroke->color[1];
+ if (b) *b = stroke->color[2];
+ if (a) *a = stroke->color[3];
+
+ return true;
+ }
+
+ const Fill* strokeFill() const
+ {
+ if (!stroke) return nullptr;
+ return stroke->fill;
+ }
+
+ uint32_t strokeDash(const float** dashPattern) const
+ {
+ if (!stroke) return 0;
+ if (dashPattern) *dashPattern = stroke->dashPattern;
+ return stroke->dashCnt;
+ }
+
+ StrokeCap strokeCap() const
+ {
+ if (!stroke) return StrokeCap::Square;
+ return stroke->cap;
+ }
+
+ StrokeJoin strokeJoin() const
+ {
+ if (!stroke) return StrokeJoin::Bevel;
+ return stroke->join;
+ }
+};
class RenderMethod
{
public:
virtual ~RenderMethod() {}
- virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) = 0;
+ virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags, bool clipper) = 0;
virtual RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
virtual bool preRender() = 0;
virtual bool renderShape(RenderData data) = 0;
/* External Class Implementation */
/************************************************************************/
-Shape :: Shape() : pImpl(new Impl(this))
+Shape :: Shape() : pImpl(new Impl())
{
Paint::pImpl->id = TVG_CLASS_ID_SHAPE;
Paint::pImpl->method(new PaintMethod<Shape::Impl>(pImpl));
Result Shape::reset() noexcept
{
- pImpl->path.reset();
- pImpl->flag = RenderUpdateFlag::Path;
+ pImpl->reset();
return Result::Success;
}
{
if (!cmds) return 0;
- *cmds = pImpl->path.cmds;
+ *cmds = pImpl->rs.path.cmds;
- return pImpl->path.cmdCnt;
+ return pImpl->rs.path.cmdCnt;
}
{
if (!pts) return 0;
- *pts = pImpl->path.pts;
+ *pts = pImpl->rs.path.pts;
- return pImpl->path.ptsCnt;
+ return pImpl->rs.path.ptsCnt;
}
{
if (cmdCnt == 0 || ptsCnt == 0 || !cmds || !pts) return Result::InvalidArguments;
- pImpl->path.grow(cmdCnt, ptsCnt);
- pImpl->path.append(cmds, cmdCnt, pts, ptsCnt);
-
- pImpl->flag |= RenderUpdateFlag::Path;
+ pImpl->grow(cmdCnt, ptsCnt);
+ pImpl->append(cmds, cmdCnt, pts, ptsCnt);
return Result::Success;
}
Result Shape::moveTo(float x, float y) noexcept
{
- pImpl->path.moveTo(x, y);
-
- pImpl->flag |= RenderUpdateFlag::Path;
+ pImpl->moveTo(x, y);
return Result::Success;
}
Result Shape::lineTo(float x, float y) noexcept
{
- pImpl->path.lineTo(x, y);
-
- pImpl->flag |= RenderUpdateFlag::Path;
+ pImpl->lineTo(x, y);
return Result::Success;
}
Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept
{
- pImpl->path.cubicTo(cx1, cy1, cx2, cy2, x, y);
-
- pImpl->flag |= RenderUpdateFlag::Path;
+ pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y);
return Result::Success;
}
Result Shape::close() noexcept
{
- pImpl->path.close();
-
- pImpl->flag |= RenderUpdateFlag::Path;
+ pImpl->close();
return Result::Success;
}
auto rxKappa = rx * PATH_KAPPA;
auto ryKappa = ry * PATH_KAPPA;
- pImpl->path.grow(6, 13);
- pImpl->path.moveTo(cx, cy - ry);
- pImpl->path.cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
- pImpl->path.cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
- pImpl->path.cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
- pImpl->path.cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
- pImpl->path.close();
-
- pImpl->flag |= RenderUpdateFlag::Path;
+ pImpl->grow(6, 13);
+ pImpl->moveTo(cx, cy - ry);
+ pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
+ pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
+ pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
+ pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
+ pImpl->close();
return Result::Success;
}
Point start = {radius * cosf(startAngle), radius * sinf(startAngle)};
if (pie) {
- pImpl->path.moveTo(cx, cy);
- pImpl->path.lineTo(start.x + cx, start.y + cy);
+ pImpl->moveTo(cx, cy);
+ pImpl->lineTo(start.x + cx, start.y + cy);
} else {
- pImpl->path.moveTo(start.x + cx, start.y + cy);
+ pImpl->moveTo(start.x + cx, start.y + cy);
}
for (int i = 0; i < nCurves; ++i) {
Point ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy};
Point ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy};
- pImpl->path.cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y);
+ pImpl->cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y);
startAngle = endAngle;
}
- if (pie) pImpl->path.close();
-
- pImpl->flag |= RenderUpdateFlag::Path;
+ if (pie) pImpl->close();
return Result::Success;
}
//rectangle
if (rx == 0 && ry == 0) {
- pImpl->path.grow(5, 4);
- pImpl->path.moveTo(x, y);
- pImpl->path.lineTo(x + w, y);
- pImpl->path.lineTo(x + w, y + h);
- pImpl->path.lineTo(x, y + h);
- pImpl->path.close();
+ pImpl->grow(5, 4);
+ pImpl->moveTo(x, y);
+ pImpl->lineTo(x + w, y);
+ pImpl->lineTo(x + w, y + h);
+ pImpl->lineTo(x, y + h);
+ pImpl->close();
//circle
} else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) {
return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry);
} else {
auto hrx = rx * 0.5f;
auto hry = ry * 0.5f;
- pImpl->path.grow(10, 17);
- pImpl->path.moveTo(x + rx, y);
- pImpl->path.lineTo(x + w - rx, y);
- pImpl->path.cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
- pImpl->path.lineTo(x + w, y + h - ry);
- pImpl->path.cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
- pImpl->path.lineTo(x + rx, y + h);
- pImpl->path.cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
- pImpl->path.lineTo(x, y + ry);
- pImpl->path.cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
- pImpl->path.close();
+ pImpl->grow(10, 17);
+ pImpl->moveTo(x + rx, y);
+ pImpl->lineTo(x + w - rx, y);
+ pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
+ pImpl->lineTo(x + w, y + h - ry);
+ pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
+ pImpl->lineTo(x + rx, y + h);
+ pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
+ pImpl->lineTo(x, y + ry);
+ pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
+ pImpl->close();
}
- pImpl->flag |= RenderUpdateFlag::Path;
-
return Result::Success;
}
Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
{
- pImpl->color[0] = r;
- pImpl->color[1] = g;
- pImpl->color[2] = b;
- pImpl->color[3] = a;
+ pImpl->rs.color[0] = r;
+ pImpl->rs.color[1] = g;
+ pImpl->rs.color[2] = b;
+ pImpl->rs.color[3] = a;
pImpl->flag |= RenderUpdateFlag::Color;
- if (pImpl->fill) {
- delete(pImpl->fill);
- pImpl->fill = nullptr;
+ if (pImpl->rs.fill) {
+ delete(pImpl->rs.fill);
+ pImpl->rs.fill = nullptr;
pImpl->flag |= RenderUpdateFlag::Gradient;
}
auto p = f.release();
if (!p) return Result::MemoryCorruption;
- if (pImpl->fill && pImpl->fill != p) delete(pImpl->fill);
- pImpl->fill = p;
+ if (pImpl->rs.fill && pImpl->rs.fill != p) delete(pImpl->rs.fill);
+ pImpl->rs.fill = p;
pImpl->flag |= RenderUpdateFlag::Gradient;
return Result::Success;
Result Shape::fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
{
- if (r) *r = pImpl->color[0];
- if (g) *g = pImpl->color[1];
- if (b) *b = pImpl->color[2];
- if (a) *a = pImpl->color[3];
+ pImpl->rs.fillColor(r, g, b, a);
return Result::Success;
}
+
const Fill* Shape::fill() const noexcept
{
- return pImpl->fill;
+ return pImpl->rs.fill;
}
float Shape::strokeWidth() const noexcept
{
- if (!pImpl->stroke) return 0;
- return pImpl->stroke->width;
+ return pImpl->rs.strokeWidth();
}
Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept
{
- if (!pImpl->stroke) return Result::InsufficientCondition;
-
- if (r) *r = pImpl->stroke->color[0];
- if (g) *g = pImpl->stroke->color[1];
- if (b) *b = pImpl->stroke->color[2];
- if (a) *a = pImpl->stroke->color[3];
+ if (!pImpl->rs.strokeColor(r, g, b, a)) return Result::InsufficientCondition;
return Result::Success;
}
const Fill* Shape::strokeFill() const noexcept
{
- if (!pImpl->stroke) return nullptr;
-
- return pImpl->stroke->fill;
+ return pImpl->rs.strokeFill();
}
uint32_t Shape::strokeDash(const float** dashPattern) const noexcept
{
- if (!pImpl->stroke) return 0;
-
- if (dashPattern) *dashPattern = pImpl->stroke->dashPattern;
-
- return pImpl->stroke->dashCnt;
+ return pImpl->rs.strokeDash(dashPattern);
}
StrokeCap Shape::strokeCap() const noexcept
{
- if (!pImpl->stroke) return StrokeCap::Square;
-
- return pImpl->stroke->cap;
+ return pImpl->rs.strokeCap();
}
StrokeJoin Shape::strokeJoin() const noexcept
{
- if (!pImpl->stroke) return StrokeJoin::Bevel;
-
- return pImpl->stroke->join;
+ return pImpl->rs.strokeJoin();
}
Result Shape::fill(FillRule r) noexcept
{
- pImpl->rule = r;
+ pImpl->rs.rule = r;
return Result::Success;
}
FillRule Shape::fillRule() const noexcept
{
- return pImpl->rule;
+ return pImpl->rs.rule;
}
/* Internal Class Implementation */
/************************************************************************/
-struct ShapeStroke
+struct Shape::Impl
{
- float width;
- uint8_t color[4];
- Fill *fill;
- float* dashPattern;
- uint32_t dashCnt;
- StrokeCap cap;
- StrokeJoin join;
-
- void copy(const ShapeStroke* src)
+ RenderShape rs; //shape data
+ RenderData rdata = nullptr; //engine data
+ uint32_t flag = RenderUpdateFlag::None;
+
+ bool dispose(RenderMethod& renderer)
{
- width = src->width;
- dashCnt = src->dashCnt;
- cap = src->cap;
- join = src->join;
-
- memcpy(color, src->color, sizeof(color));
- if (dashCnt > 0) {
- dashPattern = static_cast<float*>(malloc(sizeof(float) * dashCnt));
- memcpy(dashPattern, src->dashPattern, sizeof(float) * dashCnt);
- }
- if (src->fill) fill = src->fill->duplicate();
+ auto ret = renderer.dispose(rdata);
+ rdata = nullptr;
+ return ret;
}
- void clear()
+ bool render(RenderMethod& renderer)
{
- if (dashPattern) free(dashPattern);
- if (fill) delete(fill);
+ return renderer.renderShape(rdata);
}
-};
-
-
-struct ShapePath
-{
- PathCommand* cmds = nullptr;
- uint32_t cmdCnt = 0;
- uint32_t reservedCmdCnt = 0;
-
- Point *pts = nullptr;
- uint32_t ptsCnt = 0;
- uint32_t reservedPtsCnt = 0;
- ~ShapePath()
+ void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag, bool clipper)
{
- if (cmds) free(cmds);
- if (pts) free(pts);
+ rdata = renderer.prepare(rs, rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
+ flag = RenderUpdateFlag::None;
+ return rdata;
}
- ShapePath()
+ RenderRegion bounds(RenderMethod& renderer)
{
+ return renderer.region(rdata);
}
- void duplicate(const ShapePath* src)
+ bool bounds(float* x, float* y, float* w, float* h)
{
- if (src->cmdCnt == 0 || src->ptsCnt == 0) return;
-
- cmdCnt = src->cmdCnt;
- reservedCmdCnt = src->reservedCmdCnt;
- ptsCnt = src->ptsCnt;
- reservedPtsCnt = src->reservedPtsCnt;
+ //Path bounding size
+ if (rs.path.ptsCnt > 0 ) {
+ Point min = { rs.path.pts[0].x, rs.path.pts[0].y };
+ Point max = { rs.path.pts[0].x, rs.path.pts[0].y };
+
+ for (uint32_t i = 1; i < rs.path.ptsCnt; ++i) {
+ if (rs.path.pts[i].x < min.x) min.x = rs.path.pts[i].x;
+ if (rs.path.pts[i].y < min.y) min.y = rs.path.pts[i].y;
+ if (rs.path.pts[i].x > max.x) max.x = rs.path.pts[i].x;
+ if (rs.path.pts[i].y > max.y) max.y = rs.path.pts[i].y;
+ }
- cmds = static_cast<PathCommand*>(malloc(sizeof(PathCommand) * reservedCmdCnt));
- if (!cmds) return;
- memcpy(cmds, src->cmds, sizeof(PathCommand) * cmdCnt);
+ if (x) *x = min.x;
+ if (y) *y = min.y;
+ if (w) *w = max.x - min.x;
+ if (h) *h = max.y - min.y;
+ }
- pts = static_cast<Point*>(malloc(sizeof(Point) * reservedPtsCnt));
- if (!pts) {
- free(cmds);
- return;
+ //Stroke feathering
+ if (rs.stroke) {
+ if (x) *x -= rs.stroke->width * 0.5f;
+ if (y) *y -= rs.stroke->width * 0.5f;
+ if (w) *w += rs.stroke->width;
+ if (h) *h += rs.stroke->width;
}
- memcpy(pts, src->pts, sizeof(Point) * ptsCnt);
+ return rs.path.ptsCnt > 0 ? true : false;
}
void reserveCmd(uint32_t cmdCnt)
{
- if (cmdCnt <= reservedCmdCnt) return;
- reservedCmdCnt = cmdCnt;
- cmds = static_cast<PathCommand*>(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt));
+ if (cmdCnt <= rs.path.reservedCmdCnt) return;
+ rs.path.reservedCmdCnt = cmdCnt;
+ rs.path.cmds = static_cast<PathCommand*>(realloc(rs.path.cmds, sizeof(PathCommand) * rs.path.reservedCmdCnt));
}
void reservePts(uint32_t ptsCnt)
{
- if (ptsCnt <= reservedPtsCnt) return;
- reservedPtsCnt = ptsCnt;
- pts = static_cast<Point*>(realloc(pts, sizeof(Point) * reservedPtsCnt));
+ if (ptsCnt <= rs.path.reservedPtsCnt) return;
+ rs.path.reservedPtsCnt = ptsCnt;
+ rs.path.pts = static_cast<Point*>(realloc(rs.path.pts, sizeof(Point) * rs.path.reservedPtsCnt));
}
void grow(uint32_t cmdCnt, uint32_t ptsCnt)
{
- reserveCmd(this->cmdCnt + cmdCnt);
- reservePts(this->ptsCnt + ptsCnt);
+ reserveCmd(rs.path.cmdCnt + cmdCnt);
+ reservePts(rs.path.ptsCnt + ptsCnt);
}
void reset()
{
- cmdCnt = 0;
- ptsCnt = 0;
- }
-
- void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt)
- {
- memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt);
- memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt);
- this->cmdCnt += cmdCnt;
- this->ptsCnt += ptsCnt;
- }
-
- void moveTo(float x, float y)
- {
- if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
- if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
+ rs.path.cmdCnt = 0;
+ rs.path.ptsCnt = 0;
- cmds[cmdCnt++] = PathCommand::MoveTo;
- pts[ptsCnt++] = {x, y};
+ flag = RenderUpdateFlag::Path;
}
- void lineTo(float x, float y)
+ void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt)
{
- if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
- if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2);
+ memcpy(rs.path.cmds + rs.path.cmdCnt, cmds, sizeof(PathCommand) * cmdCnt);
+ memcpy(rs.path.pts + rs.path.ptsCnt, pts, sizeof(Point) * ptsCnt);
+ rs.path.cmdCnt += cmdCnt;
+ rs.path.ptsCnt += ptsCnt;
- cmds[cmdCnt++] = PathCommand::LineTo;
- pts[ptsCnt++] = {x, y};
+ flag |= RenderUpdateFlag::Path;
}
- void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
+ void moveTo(float x, float y)
{
- if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
- if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2);
+ if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
+ if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2);
- cmds[cmdCnt++] = PathCommand::CubicTo;
- pts[ptsCnt++] = {cx1, cy1};
- pts[ptsCnt++] = {cx2, cy2};
- pts[ptsCnt++] = {x, y};
- }
+ rs.path.cmds[rs.path.cmdCnt++] = PathCommand::MoveTo;
+ rs.path.pts[rs.path.ptsCnt++] = {x, y};
- void close()
- {
- if (cmdCnt > 0 && cmds[cmdCnt - 1] == PathCommand::Close) return;
-
- if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2);
- cmds[cmdCnt++] = PathCommand::Close;
+ flag |= RenderUpdateFlag::Path;
}
- bool bounds(float* x, float* y, float* w, float* h) const
+ void lineTo(float x, float y)
{
- if (ptsCnt == 0) return false;
-
- Point min = { pts[0].x, pts[0].y };
- Point max = { pts[0].x, pts[0].y };
-
- for (uint32_t i = 1; i < ptsCnt; ++i) {
- if (pts[i].x < min.x) min.x = pts[i].x;
- if (pts[i].y < min.y) min.y = pts[i].y;
- if (pts[i].x > max.x) max.x = pts[i].x;
- if (pts[i].y > max.y) max.y = pts[i].y;
- }
-
- if (x) *x = min.x;
- if (y) *y = min.y;
- if (w) *w = max.x - min.x;
- if (h) *h = max.y - min.y;
-
- return true;
- }
-};
-
-
-struct Shape::Impl
-{
- ShapePath path;
- Fill *fill = nullptr;
- ShapeStroke *stroke = nullptr;
- uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
- FillRule rule = FillRule::Winding;
- RenderData rdata = nullptr; //engine data
- Shape *shape = nullptr;
- uint32_t flag = RenderUpdateFlag::None;
+ if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
+ if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2);
- Impl(Shape* s) : shape(s)
- {
- }
+ rs.path.cmds[rs.path.cmdCnt++] = PathCommand::LineTo;
+ rs.path.pts[rs.path.ptsCnt++] = {x, y};
- ~Impl()
- {
- if (fill) delete(fill);
- if (stroke) {
- stroke->clear();
- free (stroke);
- }
+ flag |= RenderUpdateFlag::Path;
}
- bool dispose(RenderMethod& renderer)
+ void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
{
- auto ret = renderer.dispose(rdata);
- rdata = nullptr;
- return ret;
- }
+ if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
+ if (rs.path.ptsCnt + 3 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 3) * 2);
- bool render(RenderMethod& renderer)
- {
- return renderer.renderShape(rdata);
- }
+ rs.path.cmds[rs.path.cmdCnt++] = PathCommand::CubicTo;
+ rs.path.pts[rs.path.ptsCnt++] = {cx1, cy1};
+ rs.path.pts[rs.path.ptsCnt++] = {cx2, cy2};
+ rs.path.pts[rs.path.ptsCnt++] = {x, y};
- void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag, bool clipper)
- {
- this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
- flag = RenderUpdateFlag::None;
- return this->rdata;
+ flag |= RenderUpdateFlag::Path;
}
- RenderRegion bounds(RenderMethod& renderer)
+ void close()
{
- return renderer.region(rdata);
- }
+ if (rs.path.cmdCnt > 0 && rs.path.cmds[rs.path.cmdCnt - 1] == PathCommand::Close) return;
- bool bounds(float* x, float* y, float* w, float* h)
- {
- auto ret = path.bounds(x, y, w, h);
+ if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2);
+ rs.path.cmds[rs.path.cmdCnt++] = PathCommand::Close;
- //Stroke feathering
- if (stroke) {
- if (x) *x -= stroke->width * 0.5f;
- if (y) *y -= stroke->width * 0.5f;
- if (w) *w += stroke->width;
- if (h) *h += stroke->width;
- }
- return ret;
+ flag |= RenderUpdateFlag::Path;
}
bool strokeWidth(float width)
{
//TODO: Size Exception?
- if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
- stroke->width = width;
+ if (!rs.stroke) rs.stroke = new RenderStroke();
+ rs.stroke->width = width;
flag |= RenderUpdateFlag::Stroke;
return true;
bool strokeCap(StrokeCap cap)
{
- if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
- stroke->cap = cap;
+ if (!rs.stroke) rs.stroke = new RenderStroke();
+ rs.stroke->cap = cap;
flag |= RenderUpdateFlag::Stroke;
return true;
bool strokeJoin(StrokeJoin join)
{
- if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
- stroke->join = join;
+ if (!rs.stroke) rs.stroke = new RenderStroke();
+ rs.stroke->join = join;
flag |= RenderUpdateFlag::Stroke;
return true;
bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
- if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
- if (stroke->fill) {
- delete(stroke->fill);
- stroke->fill = nullptr;
+ if (!rs.stroke) rs.stroke = new RenderStroke();
+ if (rs.stroke->fill) {
+ delete(rs.stroke->fill);
+ rs.stroke->fill = nullptr;
flag |= RenderUpdateFlag::GradientStroke;
}
- stroke->color[0] = r;
- stroke->color[1] = g;
- stroke->color[2] = b;
- stroke->color[3] = a;
+ rs.stroke->color[0] = r;
+ rs.stroke->color[1] = g;
+ rs.stroke->color[2] = b;
+ rs.stroke->color[3] = a;
flag |= RenderUpdateFlag::Stroke;
auto p = f.release();
if (!p) return Result::MemoryCorruption;
- if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
- if (stroke->fill && stroke->fill != p) delete(stroke->fill);
- stroke->fill = p;
+ if (!rs.stroke) rs.stroke = new RenderStroke();
+ if (rs.stroke->fill && rs.stroke->fill != p) delete(rs.stroke->fill);
+ rs.stroke->fill = p;
flag |= RenderUpdateFlag::Stroke;
flag |= RenderUpdateFlag::GradientStroke;
{
//Reset dash
if (!pattern && cnt == 0) {
- free(stroke->dashPattern);
- stroke->dashPattern = nullptr;
+ free(rs.stroke->dashPattern);
+ rs.stroke->dashPattern = nullptr;
} else {
- if (!stroke) stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
- if (stroke->dashCnt != cnt) {
- free(stroke->dashPattern);
- stroke->dashPattern = nullptr;
+ if (!rs.stroke) rs.stroke = new RenderStroke();
+ if (rs.stroke->dashCnt != cnt) {
+ free(rs.stroke->dashPattern);
+ rs.stroke->dashPattern = nullptr;
}
- if (!stroke->dashPattern) {
- stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * cnt));
- if (!stroke->dashPattern) return false;
+ if (!rs.stroke->dashPattern) {
+ rs.stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * cnt));
+ if (!rs.stroke->dashPattern) return false;
}
for (uint32_t i = 0; i < cnt; ++i) {
- stroke->dashPattern[i] = pattern[i];
+ rs.stroke->dashPattern[i] = pattern[i];
}
}
- stroke->dashCnt = cnt;
+ rs.stroke->dashCnt = cnt;
flag |= RenderUpdateFlag::Stroke;
return true;
auto ret = Shape::gen();
auto dup = ret.get()->pImpl;
- dup->rule = rule;
+ dup->rs.rule = rs.rule;
//Color
- memcpy(dup->color, color, sizeof(color));
+ memcpy(dup->rs.color, rs.color, sizeof(rs.color));
dup->flag = RenderUpdateFlag::Color;
//Path
- dup->path.duplicate(&path);
+ if (rs.path.cmdCnt > 0 && rs.path.ptsCnt > 0) {
+ dup->rs.path.cmdCnt = rs.path.cmdCnt;
+ dup->rs.path.reservedCmdCnt = rs.path.reservedCmdCnt;
+ dup->rs.path.ptsCnt = rs.path.ptsCnt;
+ dup->rs.path.reservedPtsCnt = rs.path.reservedPtsCnt;
+
+ dup->rs.path.cmds = static_cast<PathCommand*>(malloc(sizeof(PathCommand) * dup->rs.path.reservedCmdCnt));
+ if (dup->rs.path.cmds) memcpy(dup->rs.path.cmds, rs.path.cmds, sizeof(PathCommand) * dup->rs.path.cmdCnt);
+
+ dup->rs.path.pts = static_cast<Point*>(malloc(sizeof(Point) * dup->rs.path.reservedPtsCnt));
+ if (dup->rs.path.pts) memcpy(dup->rs.path.pts, rs.path.pts, sizeof(Point) * dup->rs.path.ptsCnt);
+ }
dup->flag |= RenderUpdateFlag::Path;
//Stroke
- if (stroke) {
- dup->stroke = static_cast<ShapeStroke*>(calloc(sizeof(ShapeStroke), 1));
- dup->stroke->copy(stroke);
+ if (rs.stroke) {
+ dup->rs.stroke = new RenderStroke();
+ dup->rs.stroke->width = rs.stroke->width;
+ dup->rs.stroke->dashCnt = rs.stroke->dashCnt;
+ dup->rs.stroke->cap = rs.stroke->cap;
+ dup->rs.stroke->join = rs.stroke->join;
+ memcpy(dup->rs.stroke->color, rs.stroke->color, sizeof(rs.stroke->color));
+
+ if (rs.stroke->dashCnt > 0) {
+ dup->rs.stroke->dashPattern = static_cast<float*>(malloc(sizeof(float) * rs.stroke->dashCnt));
+ memcpy(dup->rs.stroke->dashPattern, rs.stroke->dashPattern, sizeof(float) * rs.stroke->dashCnt);
+ }
+
dup->flag |= RenderUpdateFlag::Stroke;
- if (stroke->fill)
+ if (rs.stroke->fill) {
+ dup->rs.stroke->fill = rs.stroke->fill->duplicate();
dup->flag |= RenderUpdateFlag::GradientStroke;
+ }
}
//Fill
- if (fill) {
- dup->fill = fill->duplicate();
+ if (rs.fill) {
+ dup->rs.fill = rs.fill->duplicate();
dup->flag |= RenderUpdateFlag::Gradient;
}