sw_engine: convert colorspace ARGB -> RGBA in default.

We can use RGBA colorspace rather ARGB for pixel data.
This would be better for many rendering system,
since it's more widely preferred than ARGB including opengl.

Change-Id: Ibbfe6a511d77bf0ef30ce261995467c11164d306
This commit is contained in:
Hermet Park 2020-08-15 16:29:46 +09:00
parent 7ab71c52d0
commit f4d1065d52
34 changed files with 157 additions and 97 deletions

View file

@ -311,7 +311,9 @@ class TVG_EXPORT SwCanvas final : public Canvas
public: public:
~SwCanvas(); ~SwCanvas();
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; enum Colorspace { RGBA8888 = 0, ARGB8888 };
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept;
static std::unique_ptr<SwCanvas> gen() noexcept; static std::unique_ptr<SwCanvas> gen() noexcept;

View file

@ -23,6 +23,8 @@ typedef struct _Tvg_Gradient Tvg_Gradient;
#define TVG_ENGINE_SW (1 << 1) #define TVG_ENGINE_SW (1 << 1)
#define TVG_ENGINE_GL (1 << 2) #define TVG_ENGINE_GL (1 << 2)
#define TVG_COLORSPACE_RGBA8888 0
#define TVG_COLORSPACE_ARGB8888 1
typedef enum { typedef enum {
TVG_RESULT_SUCCESS = 0, TVG_RESULT_SUCCESS = 0,
@ -94,7 +96,7 @@ TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method);
/* SwCanvas API */ /* SwCanvas API */
/************************************************************************/ /************************************************************************/
TVG_EXPORT Tvg_Canvas* tvg_swcanvas_create(); TVG_EXPORT Tvg_Canvas* tvg_swcanvas_create();
TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
/************************************************************************/ /************************************************************************/

View file

@ -88,9 +88,9 @@ TVG_EXPORT Tvg_Result tvg_canvas_destroy(Tvg_Canvas* canvas)
} }
TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
{ {
return (Tvg_Result) reinterpret_cast<SwCanvas*>(canvas)->target(buffer, stride, w, h); return (Tvg_Result) reinterpret_cast<SwCanvas*>(canvas)->target(buffer, stride, w, h, static_cast<SwCanvas::Colorspace>(cs));
} }

View file

@ -222,20 +222,26 @@ static inline SwCoord TO_SWCOORD(float val)
} }
static inline uint32_t COLOR_ALPHA(uint32_t rgba) static inline uint32_t RGBA_ALPHA(uint32_t rgba)
{ {
return (rgba >> 24) & 0xff; return rgba & 0x000000ff;
} }
static inline uint32_t COLOR_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) static inline uint32_t ARGB_ALPHA(uint32_t argb)
{
return (argb >> 24) & 0xff;
}
static inline uint32_t RGBA_ALPHA_BLEND(uint32_t rgba, uint32_t alpha)
{ {
return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) +
((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff));
} }
static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) static inline uint32_t RGBA_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b)
{ {
auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff;
rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00;
@ -243,13 +249,19 @@ static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rg
} }
static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) static inline uint32_t RGBA_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
return (r << 24 | g << 16 | b << 8 | a);
}
static inline uint32_t ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{ {
return (a << 24 | r << 16 | g << 8 | b); return (a << 24 | r << 16 | g << 8 | b);
} }
static inline uint8_t COLOR_ALPHA_MULTIPLY(uint32_t c, uint32_t a) static inline uint8_t ALPHA_MULTIPLY(uint32_t c, uint32_t a)
{ {
return (c * a) >> 8; return (c * a) >> 8;
} }
@ -278,7 +290,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip);
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, bool ctable); bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable);
void shapeResetFill(SwShape* shape); void shapeResetFill(SwShape* shape);
void shapeDelFill(SwShape* shape); void shapeDelFill(SwShape* shape);
@ -287,7 +299,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
SwOutline* strokeExportOutline(SwStroke* stroke); SwOutline* strokeExportOutline(SwStroke* stroke);
void strokeFree(SwStroke* stroke); void strokeFree(SwStroke* stroke);
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable); bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, bool ctable);
void fillReset(SwFill* fill); void fillReset(SwFill* fill);
void fillFree(SwFill* fill); void fillFree(SwFill* fill);
void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len);
@ -302,7 +314,7 @@ bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_
bool rasterClear(Surface& surface); bool rasterClear(Surface& surface);
static inline void rasterARGB32(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)
{ {
#ifdef THORVG_AVX_VECTOR_SUPPORT #ifdef THORVG_AVX_VECTOR_SUPPORT
int32_t align = (8 - (offset % 8)) % 8; int32_t align = (8 - (offset % 8)) % 8;

View file

@ -34,7 +34,7 @@
#define FIXPT_SIZE (1<<FIXPT_BITS) #define FIXPT_SIZE (1<<FIXPT_BITS)
static bool _updateColorTable(SwFill* fill, const Fill* fdata) static bool _updateColorTable(SwFill* fill, const Fill* fdata, uint32_t cs)
{ {
assert(fill && fdata); assert(fill && fdata);
@ -51,11 +51,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata)
if (pColors->a < 255) fill->translucent = true; if (pColors->a < 255) fill->translucent = true;
auto r = COLOR_ALPHA_MULTIPLY(pColors->r, pColors->a); auto r = ALPHA_MULTIPLY(pColors->r, pColors->a);
auto g = COLOR_ALPHA_MULTIPLY(pColors->g, pColors->a); auto g = ALPHA_MULTIPLY(pColors->g, pColors->a);
auto b = COLOR_ALPHA_MULTIPLY(pColors->b, pColors->a); auto b = ALPHA_MULTIPLY(pColors->b, pColors->a);
auto rgba = COLOR_ARGB_JOIN(r, g, b, pColors->a); auto rgba = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, pColors->a) : ARGB_JOIN(r, g, b, pColors->a);
auto inc = 1.0f / static_cast<float>(GRADIENT_STOP_SIZE); auto inc = 1.0f / static_cast<float>(GRADIENT_STOP_SIZE);
auto pos = 1.5f * inc; auto pos = 1.5f * inc;
uint32_t i = 0; uint32_t i = 0;
@ -75,17 +75,17 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata)
auto delta = 1.0f / (next->offset - curr->offset); auto delta = 1.0f / (next->offset - curr->offset);
if (next->a < 255) fill->translucent = true; if (next->a < 255) fill->translucent = true;
auto r = COLOR_ALPHA_MULTIPLY(next->r, next->a); auto r = ALPHA_MULTIPLY(next->r, next->a);
auto g = COLOR_ALPHA_MULTIPLY(next->g, next->a); auto g = ALPHA_MULTIPLY(next->g, next->a);
auto b = COLOR_ALPHA_MULTIPLY(next->b, next->a); auto b = ALPHA_MULTIPLY(next->b, next->a);
auto rgba2 = COLOR_ARGB_JOIN(r, g, b, next->a); auto rgba2 = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, next->a) : ARGB_JOIN(r, g, b, next->a);
while (pos < next->offset && i < GRADIENT_STOP_SIZE) { while (pos < next->offset && i < GRADIENT_STOP_SIZE) {
auto t = (pos - curr->offset) * delta; auto t = (pos - curr->offset) * delta;
auto dist = static_cast<int32_t>(256 * t); auto dist = static_cast<int32_t>(256 * t);
auto dist2 = 256 - dist; auto dist2 = 256 - dist;
fill->ctable[i] = COLOR_INTERPOLATE(rgba, dist2, rgba2, dist); fill->ctable[i] = RGBA_INTERPOLATE(rgba, dist2, rgba2, dist);
++i; ++i;
pos += inc; pos += inc;
} }
@ -252,7 +252,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x,
if (fabsf(inc) < FLT_EPSILON) { if (fabsf(inc) < FLT_EPSILON) {
auto color = _fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE)); auto color = _fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE));
rasterARGB32(dst, color, offset, len); rasterRGBA32(dst, color, offset, len);
return; return;
} }
@ -282,7 +282,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x,
} }
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable) bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, bool ctable)
{ {
if (!fill) return false; if (!fill) return false;
@ -291,7 +291,7 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform,
fill->spread = fdata->spread(); fill->spread = fdata->spread();
if (ctable) { if (ctable) {
if (!_updateColorTable(fill, fdata)) return false; if (!_updateColorTable(fill, fdata, cs)) return false;
} }
if (fdata->id() == FILL_ID_LINEAR) { if (fdata->id() == FILL_ID_LINEAR) {

View file

@ -45,12 +45,12 @@ static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint3
auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x; auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y); auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x); auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto ialpha = 255 - COLOR_ALPHA(color); auto ialpha = 255 - (surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(color) : ARGB_ALPHA(color);
for (uint32_t y = 0; y < h; ++y) { for (uint32_t y = 0; y < h; ++y) {
auto dst = &buffer[y * surface.stride]; auto dst = &buffer[y * surface.stride];
for (uint32_t x = 0; x < w; ++x) { for (uint32_t x = 0; x < w; ++x) {
dst[x] = color + COLOR_ALPHA_BLEND(dst[x], ialpha); dst[x] = color + RGBA_ALPHA_BLEND(dst[x], ialpha);
} }
} }
return true; return true;
@ -64,7 +64,7 @@ static bool _rasterSolidRect(Surface& surface, const SwBBox& region, uint32_t co
auto h = static_cast<uint32_t>(region.max.y - region.min.y); auto h = static_cast<uint32_t>(region.max.y - region.min.y);
for (uint32_t y = 0; y < h; ++y) { for (uint32_t y = 0; y < h; ++y) {
rasterARGB32(buffer + y * surface.stride, color, region.min.x, w); rasterRGBA32(buffer + y * surface.stride, color, region.min.x, w);
} }
return true; return true;
} }
@ -79,11 +79,11 @@ static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t col
for (uint32_t i = 0; i < rle->size; ++i) { for (uint32_t i = 0; i < rle->size; ++i) {
auto dst = &surface.buffer[span->y * surface.stride + span->x]; auto dst = &surface.buffer[span->y * surface.stride + span->x];
if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage); if (span->coverage < 255) src = RGBA_ALPHA_BLEND(color, span->coverage);
else src = color; else src = color;
auto ialpha = 255 - COLOR_ALPHA(src); auto ialpha = 255 - ((surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(src) : ARGB_ALPHA(src));
for (uint32_t i = 0; i < span->len; ++i) { for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha);
} }
++span; ++span;
} }
@ -99,13 +99,13 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color)
for (uint32_t i = 0; i < rle->size; ++i) { for (uint32_t i = 0; i < rle->size; ++i) {
if (span->coverage == 255) { if (span->coverage == 255) {
rasterARGB32(surface.buffer + span->y * surface.stride, color, span->x, span->len); rasterRGBA32(surface.buffer + span->y * surface.stride, color, span->x, span->len);
} else { } else {
auto dst = &surface.buffer[span->y * surface.stride + span->x]; auto dst = &surface.buffer[span->y * surface.stride + span->x];
auto src = COLOR_ALPHA_BLEND(color, span->coverage); auto src = RGBA_ALPHA_BLEND(color, span->coverage);
auto ialpha = 255 - span->coverage; auto ialpha = 255 - span->coverage;
for (uint32_t i = 0; i < span->len; ++i) { for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha);
} }
} }
++span; ++span;
@ -131,8 +131,14 @@ static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, co
for (uint32_t y = 0; y < h; ++y) { for (uint32_t y = 0; y < h; ++y) {
auto dst = &buffer[y * surface.stride]; auto dst = &buffer[y * surface.stride];
fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w); fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w);
for (uint32_t x = 0; x < w; ++x) { if (surface.cs == SwCanvas::RGBA8888) {
dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); for (uint32_t x = 0; x < w; ++x) {
dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x]));
}
} else {
for (uint32_t x = 0; x < w; ++x) {
dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x]));
}
} }
} }
//Opaque Gradient //Opaque Gradient
@ -162,8 +168,14 @@ static bool _rasterRadialGradientRect(Surface& surface, const SwBBox& region, co
for (uint32_t y = 0; y < h; ++y) { for (uint32_t y = 0; y < h; ++y) {
auto dst = &buffer[y * surface.stride]; auto dst = &buffer[y * surface.stride];
fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w); fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w);
for (uint32_t x = 0; x < w; ++x) { if (surface.cs == SwCanvas::RGBA8888) {
dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); for (uint32_t x = 0; x < w; ++x) {
dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x]));
}
} else {
for (uint32_t x = 0; x < w; ++x) {
dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x]));
}
} }
} }
//Opaque Gradient //Opaque Gradient
@ -191,14 +203,27 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF
for (uint32_t i = 0; i < rle->size; ++i) { for (uint32_t i = 0; i < rle->size; ++i) {
auto dst = &surface.buffer[span->y * surface.stride + span->x]; auto dst = &surface.buffer[span->y * surface.stride + span->x];
fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); fillFetchLinear(fill, buf, span->y, span->x, 0, span->len);
if (span->coverage == 255) { if (surface.cs == SwCanvas::RGBA8888) {
for (uint32_t i = 0; i < span->len; ++i) { if (span->coverage == 255) {
dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i]));
}
} else {
for (uint32_t i = 0; i < span->len; ++i) {
auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage);
dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp));
}
} }
} else { } else {
for (uint32_t i = 0; i < span->len; ++i) { if (span->coverage == 255) {
auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i]));
}
} else {
for (uint32_t i = 0; i < span->len; ++i) {
auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage);
dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp));
}
} }
} }
++span; ++span;
@ -213,7 +238,7 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF
fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); fillFetchLinear(fill, buf, span->y, span->x, 0, span->len);
auto ialpha = 255 - span->coverage; auto ialpha = 255 - span->coverage;
for (uint32_t i = 0; i < span->len; ++i) { for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha);
} }
} }
++span; ++span;
@ -237,14 +262,27 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
for (uint32_t i = 0; i < rle->size; ++i) { for (uint32_t i = 0; i < rle->size; ++i) {
auto dst = &surface.buffer[span->y * surface.stride + span->x]; auto dst = &surface.buffer[span->y * surface.stride + span->x];
fillFetchRadial(fill, buf, span->y, span->x, span->len); fillFetchRadial(fill, buf, span->y, span->x, span->len);
if (span->coverage == 255) { if (surface.cs == SwCanvas::RGBA8888) {
for (uint32_t i = 0; i < span->len; ++i) { if (span->coverage == 255) {
dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i]));
}
} else {
for (uint32_t i = 0; i < span->len; ++i) {
auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage);
dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp));
}
} }
} else { } else {
for (uint32_t i = 0; i < span->len; ++i) { if (span->coverage == 255) {
auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i]));
}
} else {
for (uint32_t i = 0; i < span->len; ++i) {
auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage);
dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp));
}
} }
} }
++span; ++span;
@ -259,7 +297,7 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
fillFetchRadial(fill, buf, span->y, span->x, span->len); fillFetchRadial(fill, buf, span->y, span->x, span->len);
auto ialpha = 255 - span->coverage; auto ialpha = 255 - span->coverage;
for (uint32_t i = 0; i < span->len; ++i) { for (uint32_t i = 0; i < span->len; ++i) {
dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha);
} }
} }
++span; ++span;
@ -290,18 +328,20 @@ bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id)
bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{ {
r = COLOR_ALPHA_MULTIPLY(r, a); r = ALPHA_MULTIPLY(r, a);
g = COLOR_ALPHA_MULTIPLY(g, a); g = ALPHA_MULTIPLY(g, a);
b = COLOR_ALPHA_MULTIPLY(b, a); b = ALPHA_MULTIPLY(b, a);
auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a);
//Fast Track //Fast Track
if (shape->rect) { if (shape->rect) {
auto region = _clipRegion(surface, shape->bbox); auto region = _clipRegion(surface, shape->bbox);
if (a == 255) return _rasterSolidRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); if (a == 255) return _rasterSolidRect(surface, region, color);
return _rasterTranslucentRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); return _rasterTranslucentRect(surface, region, color);
} else{ } else{
if (a == 255) return _rasterSolidRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); if (a == 255) return _rasterSolidRle(surface, shape->rle, color);
return _rasterTranslucentRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); return _rasterTranslucentRle(surface, shape->rle, color);
} }
return false; return false;
} }
@ -309,12 +349,14 @@ bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, ui
bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{ {
r = COLOR_ALPHA_MULTIPLY(r, a); r = ALPHA_MULTIPLY(r, a);
g = COLOR_ALPHA_MULTIPLY(g, a); g = ALPHA_MULTIPLY(g, a);
b = COLOR_ALPHA_MULTIPLY(b, a); b = ALPHA_MULTIPLY(b, a);
if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a);
return _rasterTranslucentRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a));
if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, color);
return _rasterTranslucentRle(surface, shape->strokeRle, color);
} }
@ -323,10 +365,10 @@ bool rasterClear(Surface& surface)
if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false; if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false;
if (surface.w == surface.stride) { if (surface.w == surface.stride) {
rasterARGB32(surface.buffer, 0x00000000, 0, surface.w * surface.h); rasterRGBA32(surface.buffer, 0x00000000, 0, surface.w * surface.h);
} else { } else {
for (uint32_t i = 0; i < surface.h; i++) { for (uint32_t i = 0; i < surface.h; i++) {
rasterARGB32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w); rasterRGBA32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w);
} }
} }
return true; return true;

View file

@ -40,7 +40,7 @@ SwRenderer::~SwRenderer()
} }
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
{ {
if (!buffer || stride == 0 || w == 0 || h == 0) return false; if (!buffer || stride == 0 || w == 0 || h == 0) return false;
@ -48,6 +48,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
surface.stride = stride; surface.stride = stride;
surface.w = w; surface.w = w;
surface.h = h; surface.h = h;
surface.cs = cs;
return true; return true;
} }
@ -129,7 +130,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform*
if (fill) { if (fill) {
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
if (ctable) shapeResetFill(shape); if (ctable) shapeResetFill(shape);
if (!shapeGenFillColors(shape, fill, matrix, ctable)) return shape; if (!shapeGenFillColors(shape, fill, matrix, surface.cs, ctable)) return shape;
} else { } else {
shapeDelFill(shape); shapeDelFill(shape);
} }

View file

@ -34,7 +34,7 @@ public:
bool dispose(const Shape& shape, void *data) override; bool dispose(const Shape& shape, void *data) override;
bool preRender() override; bool preRender() override;
bool render(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
uint32_t ref() override; uint32_t ref() override;
uint32_t unref() override; uint32_t unref() override;

View file

@ -672,9 +672,9 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo
} }
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, bool ctable) bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable)
{ {
return fillGenColorTable(shape->fill, fill, transform, ctable); return fillGenColorTable(shape->fill, fill, transform, cs, ctable);
} }

View file

@ -70,7 +70,7 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
auto renderer = static_cast<GlRenderer*>(Canvas::pImpl.get()->renderer); auto renderer = static_cast<GlRenderer*>(Canvas::pImpl.get()->renderer);
if (!renderer) return Result::MemoryCorruption; if (!renderer) return Result::MemoryCorruption;
if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; if (!renderer->target(buffer, stride, w, h, 0)) return Result::Unknown;
return Result::Success; return Result::Success;
#endif #endif

View file

@ -31,6 +31,7 @@ struct Surface
uint32_t* buffer; uint32_t* buffer;
uint32_t stride; uint32_t stride;
uint32_t w, h; uint32_t w, h;
uint32_t cs;
}; };
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, All = 32}; enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, All = 32};

View file

@ -62,14 +62,14 @@ SwCanvas::~SwCanvas()
} }
Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept
{ {
#ifdef THORVG_SW_RASTER_SUPPORT #ifdef THORVG_SW_RASTER_SUPPORT
//We know renderer type, avoid dynamic_cast for performance. //We know renderer type, avoid dynamic_cast for performance.
auto renderer = static_cast<SwRenderer*>(Canvas::pImpl.get()->renderer); auto renderer = static_cast<SwRenderer*>(Canvas::pImpl.get()->renderer);
if (!renderer) return Result::MemoryCorruption; if (!renderer) return Result::MemoryCorruption;
if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; if (!renderer->target(buffer, stride, w, h, cs)) return Result::InvalidArguments;
return Result::Success; return Result::Success;
#endif #endif

View file

@ -79,7 +79,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -68,7 +68,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
} }
Eina_Bool animSwCb(void* data) Eina_Bool animSwCb(void* data)

View file

@ -62,7 +62,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -51,7 +51,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -16,7 +16,7 @@ void testCapi()
tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL); tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL);
Tvg_Canvas* canvas = tvg_swcanvas_create(); Tvg_Canvas* canvas = tvg_swcanvas_create();
tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT); tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT, TVG_COLORSPACE_ARGB8888);
Tvg_Paint* shape = tvg_shape_new(); Tvg_Paint* shape = tvg_shape_new();
tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0); tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0);

View file

@ -92,7 +92,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -55,7 +55,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -120,7 +120,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -80,7 +80,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -40,7 +40,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -57,7 +57,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -94,7 +94,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -80,7 +80,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -87,7 +87,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -116,7 +116,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -30,7 +30,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -77,7 +77,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -114,7 +114,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -72,7 +72,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -55,7 +55,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -83,7 +83,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare

View file

@ -44,7 +44,7 @@ void tvgSwTest(uint32_t* buffer)
{ {
//Create a Canvas //Create a Canvas
swCanvas = tvg::SwCanvas::gen(); swCanvas = tvg::SwCanvas::gen();
swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);
/* Push the shape into the Canvas drawing list /* Push the shape into the Canvas drawing list
When this shape is into the canvas list, the shape could update & prepare When this shape is into the canvas list, the shape could update & prepare