Merge pull request #75508 from RedworkDE/thorvg-0.8.4
Update thorvg to 0.8.4
This commit is contained in:
commit
2a43ebd9be
|
@ -686,7 +686,7 @@ instead of `miniz.h` as an external dependency.
|
||||||
## thorvg
|
## thorvg
|
||||||
|
|
||||||
- Upstream: https://github.com/Samsung/thorvg
|
- Upstream: https://github.com/Samsung/thorvg
|
||||||
- Version: 0.8.3 (a0fcf51f80a75f63a066df085f60cdaf715188b6, 2022)
|
- Version: 0.8.4 (b0b7f207c6235691d694fc3f76e0b96e4858e606, 2023)
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|
||||||
Files extracted from upstream source:
|
Files extracted from upstream source:
|
||||||
|
|
|
@ -4,7 +4,7 @@ Junsu Choi <jsuya.choi@samsung.com>
|
||||||
Pranay Samanta <pranay.ks@samsung.com>
|
Pranay Samanta <pranay.ks@samsung.com>
|
||||||
Mateusz Palkowski <m.palkowski@samsung.com>
|
Mateusz Palkowski <m.palkowski@samsung.com>
|
||||||
Subhransu Mohanty <sub.mohanty@samsung.com>
|
Subhransu Mohanty <sub.mohanty@samsung.com>
|
||||||
Mira Grudzinska <m.grudzinska@samsung.com>
|
Mira Grudzinska <veleveta@gmail.com>
|
||||||
Michal Szczecinski <m.szczecinsk@partner.samsung.com>
|
Michal Szczecinski <m.szczecinsk@partner.samsung.com>
|
||||||
Shinwoo Kim <cinoo.kim@samsung.com>
|
Shinwoo Kim <cinoo.kim@samsung.com>
|
||||||
Piotr Kalota <p.kalota@samsung.com>
|
Piotr Kalota <p.kalota@samsung.com>
|
||||||
|
|
|
@ -13,5 +13,5 @@
|
||||||
|
|
||||||
#define THORVG_JPG_LOADER_SUPPORT 1
|
#define THORVG_JPG_LOADER_SUPPORT 1
|
||||||
|
|
||||||
#define THORVG_VERSION_STRING "0.8.3"
|
#define THORVG_VERSION_STRING "0.8.4"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -335,6 +335,20 @@ public:
|
||||||
*/
|
*/
|
||||||
CompositeMethod composite(const Paint** target) const noexcept;
|
CompositeMethod composite(const Paint** target) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the composition source object and the composition method.
|
||||||
|
*
|
||||||
|
* @param[out] source The paint of the composition source object.
|
||||||
|
* @param[out] method The method used to composite the source object with the target.
|
||||||
|
*
|
||||||
|
* @return Result::Success when the paint object used as a composition target, Result::InsufficientCondition otherwise.
|
||||||
|
*
|
||||||
|
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
|
||||||
|
*
|
||||||
|
* @BETA_API
|
||||||
|
*/
|
||||||
|
Result composite(const Paint** source, CompositeMethod* method) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the unique id value of the paint instance.
|
* @brief Return the unique id value of the paint instance.
|
||||||
*
|
*
|
||||||
|
|
|
@ -76,7 +76,9 @@ struct SwShapeTask : SwTask
|
||||||
|
|
||||||
void run(unsigned tid) override
|
void run(unsigned tid) override
|
||||||
{
|
{
|
||||||
if (opacity == 0) return; //Invisible
|
auto compMethod = CompositeMethod::None;
|
||||||
|
auto usedAsClip = (sdata->composite(nullptr, &compMethod) == Result::Success) && (compMethod == CompositeMethod::ClipPath);
|
||||||
|
if (opacity == 0 && !usedAsClip) return; //Invisible
|
||||||
|
|
||||||
uint8_t strokeAlpha = 0;
|
uint8_t strokeAlpha = 0;
|
||||||
auto visibleStroke = false;
|
auto visibleStroke = false;
|
||||||
|
@ -98,7 +100,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);
|
||||||
visibleFill = (alpha > 0 || sdata->fill());
|
visibleFill = (alpha > 0 || sdata->fill());
|
||||||
if (visibleFill || visibleStroke) {
|
if (visibleFill || visibleStroke || usedAsClip) {
|
||||||
shapeReset(&shape);
|
shapeReset(&shape);
|
||||||
if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
|
if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +112,7 @@ struct SwShapeTask : SwTask
|
||||||
|
|
||||||
//Fill
|
//Fill
|
||||||
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
|
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
|
||||||
if (visibleFill) {
|
if (visibleFill || usedAsClip) {
|
||||||
/* We assume that if stroke width is bigger than 2,
|
/* We assume that if stroke width is bigger than 2,
|
||||||
shape outline below stroke could be full covered by stroke drawing.
|
shape outline below stroke could be full covered by stroke drawing.
|
||||||
Thus it turns off antialising in that condition.
|
Thus it turns off antialising in that condition.
|
||||||
|
@ -291,7 +293,7 @@ bool SwRenderer::viewport(const RenderRegion& vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
|
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace)
|
||||||
{
|
{
|
||||||
if (!buffer || stride == 0 || w == 0 || h == 0 || w > stride) return false;
|
if (!buffer || stride == 0 || w == 0 || h == 0 || w > stride) return false;
|
||||||
|
|
||||||
|
@ -301,7 +303,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;
|
surface->cs = colorSpace;
|
||||||
|
|
||||||
vport.x = vport.y = 0;
|
vport.x = vport.y = 0;
|
||||||
vport.w = surface->w;
|
vport.w = surface->w;
|
||||||
|
@ -644,6 +646,13 @@ SwRenderer::SwRenderer():mpool(globalMpool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t SwRenderer::colorSpace()
|
||||||
|
{
|
||||||
|
if (surface) return surface->cs;
|
||||||
|
return tvg::SwCanvas::ARGB8888;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SwRenderer::init(uint32_t threads)
|
bool SwRenderer::init(uint32_t threads)
|
||||||
{
|
{
|
||||||
if ((initEngineCnt++) > 0) return true;
|
if ((initEngineCnt++) > 0) return true;
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
|
|
||||||
bool clear() override;
|
bool clear() override;
|
||||||
bool sync() override;
|
bool sync() override;
|
||||||
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
|
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace);
|
||||||
bool mempool(bool shared);
|
bool mempool(bool shared);
|
||||||
|
|
||||||
Compositor* target(const RenderRegion& region) override;
|
Compositor* target(const RenderRegion& region) override;
|
||||||
|
@ -56,6 +56,8 @@ public:
|
||||||
bool endComposite(Compositor* cmp) override;
|
bool endComposite(Compositor* cmp) override;
|
||||||
void clearCompositors();
|
void clearCompositors();
|
||||||
|
|
||||||
|
uint32_t colorSpace() override;
|
||||||
|
|
||||||
static SwRenderer* gen();
|
static SwRenderer* gen();
|
||||||
static bool init(uint32_t threads);
|
static bool init(uint32_t threads);
|
||||||
static int32_t init();
|
static int32_t init();
|
||||||
|
|
|
@ -72,7 +72,7 @@ Accessor::~Accessor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Accessor::Accessor()
|
Accessor::Accessor() : pImpl(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
float vw = 0;
|
float vw = 0;
|
||||||
float vh = 0;
|
float vh = 0;
|
||||||
float w = 0, h = 0; //default image size
|
float w = 0, h = 0; //default image size
|
||||||
|
uint32_t colorSpace = SwCanvas::ARGB8888;
|
||||||
|
|
||||||
virtual ~LoadModule() {}
|
virtual ~LoadModule() {}
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ public:
|
||||||
|
|
||||||
virtual bool read() = 0;
|
virtual bool read() = 0;
|
||||||
virtual bool close() = 0;
|
virtual bool close() = 0;
|
||||||
virtual unique_ptr<Surface> bitmap() { return nullptr; }
|
virtual unique_ptr<Surface> bitmap(uint32_t colorSpace) { return nullptr; }
|
||||||
virtual unique_ptr<Paint> paint() { return nullptr; }
|
virtual unique_ptr<Paint> paint() { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,12 @@ static inline bool mathRightAngle(const Matrix* m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool mathSkewed(const Matrix* m)
|
||||||
|
{
|
||||||
|
return (fabsf(m->e21 + m->e12) > FLT_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool mathIdentity(const Matrix* m)
|
static inline bool mathIdentity(const Matrix* m)
|
||||||
{
|
{
|
||||||
if (!mathEqual(m->e11, 1.0f) || !mathZero(m->e12) || !mathZero(m->e13) ||
|
if (!mathEqual(m->e11, 1.0f) || !mathZero(m->e12) || !mathZero(m->e13) ||
|
||||||
|
|
|
@ -38,9 +38,9 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform,
|
||||||
|
|
||||||
if (rTransform) rTransform->update();
|
if (rTransform) rTransform->update();
|
||||||
|
|
||||||
//No rotational.
|
//No rotation and no skewing
|
||||||
if (pTransform && !mathRightAngle(&pTransform->m)) return false;
|
if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return false;
|
||||||
if (rTransform && !mathRightAngle(&rTransform->m)) return false;
|
if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return false;
|
||||||
|
|
||||||
//Perpendicular Rectangle?
|
//Perpendicular Rectangle?
|
||||||
auto pt1 = pts + 0;
|
auto pt1 = pts + 0;
|
||||||
|
@ -384,6 +384,19 @@ CompositeMethod Paint::composite(const Paint** target) const noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Result Paint::composite(const Paint** source, CompositeMethod* method) const noexcept
|
||||||
|
{
|
||||||
|
if (source) *source = pImpl->compSource;
|
||||||
|
auto met = (pImpl->compSource && pImpl->compSource->pImpl->compData ?
|
||||||
|
pImpl->compSource->pImpl->compData->method : CompositeMethod::None);
|
||||||
|
if (method) *method = met;
|
||||||
|
|
||||||
|
if (pImpl->compSource != nullptr && met != CompositeMethod::None)
|
||||||
|
return Result::Success;
|
||||||
|
return Result::InsufficientCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Result Paint::opacity(uint8_t o) noexcept
|
Result Paint::opacity(uint8_t o) noexcept
|
||||||
{
|
{
|
||||||
if (pImpl->opacity == o) return Result::Success;
|
if (pImpl->opacity == o) return Result::Success;
|
||||||
|
|
|
@ -62,6 +62,7 @@ namespace tvg
|
||||||
StrategyMethod* smethod = nullptr;
|
StrategyMethod* smethod = nullptr;
|
||||||
RenderTransform* rTransform = nullptr;
|
RenderTransform* rTransform = nullptr;
|
||||||
Composite* compData = nullptr;
|
Composite* compData = nullptr;
|
||||||
|
Paint* compSource = nullptr;
|
||||||
uint32_t renderFlag = RenderUpdateFlag::None;
|
uint32_t renderFlag = RenderUpdateFlag::None;
|
||||||
uint32_t ctxFlag = ContextFlag::Invalid;
|
uint32_t ctxFlag = ContextFlag::Invalid;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
@ -136,6 +137,7 @@ namespace tvg
|
||||||
if (!target && method == CompositeMethod::None) return true;
|
if (!target && method == CompositeMethod::None) return true;
|
||||||
compData = static_cast<Composite*>(calloc(1, sizeof(Composite)));
|
compData = static_cast<Composite*>(calloc(1, sizeof(Composite)));
|
||||||
}
|
}
|
||||||
|
target->pImpl->compSource = source;
|
||||||
compData->target = target;
|
compData->target = target;
|
||||||
compData->source = source;
|
compData->source = source;
|
||||||
compData->method = method;
|
compData->method = method;
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct Picture::Impl
|
||||||
void* rdata = nullptr; //engine data
|
void* rdata = nullptr; //engine data
|
||||||
float w = 0, h = 0;
|
float w = 0, h = 0;
|
||||||
bool resizing = false;
|
bool resizing = false;
|
||||||
|
uint32_t rendererColorSpace = 0;
|
||||||
|
|
||||||
~Impl()
|
~Impl()
|
||||||
{
|
{
|
||||||
|
@ -100,7 +101,7 @@ struct Picture::Impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(surface);
|
free(surface);
|
||||||
if ((surface = loader->bitmap().release())) {
|
if ((surface = loader->bitmap(rendererColorSpace).release())) {
|
||||||
loader->close();
|
loader->close();
|
||||||
return RenderUpdateFlag::Image;
|
return RenderUpdateFlag::Image;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +125,7 @@ struct Picture::Impl
|
||||||
|
|
||||||
void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
|
void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
|
||||||
{
|
{
|
||||||
|
rendererColorSpace = renderer.colorSpace();
|
||||||
auto flag = reload();
|
auto flag = reload();
|
||||||
|
|
||||||
if (surface) {
|
if (surface) {
|
||||||
|
|
|
@ -106,6 +106,8 @@ public:
|
||||||
virtual Compositor* target(const RenderRegion& region) = 0;
|
virtual Compositor* target(const RenderRegion& region) = 0;
|
||||||
virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0;
|
virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0;
|
||||||
virtual bool endComposite(Compositor* cmp) = 0;
|
virtual bool endComposite(Compositor* cmp) = 0;
|
||||||
|
|
||||||
|
virtual uint32_t colorSpace() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
Scene::Scene() : pImpl(new Impl())
|
Scene::Scene() : pImpl(new Impl(this))
|
||||||
{
|
{
|
||||||
Paint::pImpl->id = TVG_CLASS_ID_SCENE;
|
Paint::pImpl->id = TVG_CLASS_ID_SCENE;
|
||||||
Paint::pImpl->method(new PaintMethod<Scene::Impl>(pImpl));
|
Paint::pImpl->method(new PaintMethod<Scene::Impl>(pImpl));
|
||||||
|
|
|
@ -60,6 +60,11 @@ struct Scene::Impl
|
||||||
Array<Paint*> paints;
|
Array<Paint*> paints;
|
||||||
uint8_t opacity; //for composition
|
uint8_t opacity; //for composition
|
||||||
RenderMethod* renderer = nullptr; //keep it for explicit clear
|
RenderMethod* renderer = nullptr; //keep it for explicit clear
|
||||||
|
Scene* scene = nullptr;
|
||||||
|
|
||||||
|
Impl(Scene* s) : scene(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
~Impl()
|
~Impl()
|
||||||
{
|
{
|
||||||
|
@ -81,8 +86,14 @@ struct Scene::Impl
|
||||||
|
|
||||||
bool needComposition(uint32_t opacity)
|
bool needComposition(uint32_t opacity)
|
||||||
{
|
{
|
||||||
|
if (opacity == 0 || paints.count == 0) return false;
|
||||||
|
|
||||||
|
//Masking may require composition (even if opacity == 255)
|
||||||
|
auto compMethod = scene->composite(nullptr);
|
||||||
|
if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) return true;
|
||||||
|
|
||||||
//Half translucent requires intermediate composition.
|
//Half translucent requires intermediate composition.
|
||||||
if (opacity == 255 || opacity == 0) return false;
|
if (opacity == 255) return false;
|
||||||
|
|
||||||
//If scene has several children or only scene, it may require composition.
|
//If scene has several children or only scene, it may require composition.
|
||||||
if (paints.count > 1) return true;
|
if (paints.count > 1) return true;
|
||||||
|
|
|
@ -42,6 +42,24 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
|
||||||
|
{
|
||||||
|
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
|
||||||
|
{
|
||||||
|
auto buffer = data;
|
||||||
|
for (uint32_t y = 0; y < h; ++y, buffer += w) {
|
||||||
|
auto src = buffer;
|
||||||
|
for (uint32_t x = 0; x < w; ++x, ++src) {
|
||||||
|
*src = CHANGE_COLORSPACE(*src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PngLoader::PngLoader()
|
PngLoader::PngLoader()
|
||||||
{
|
{
|
||||||
image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
|
image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
|
||||||
|
@ -110,16 +128,21 @@ bool PngLoader::close()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<Surface> PngLoader::bitmap()
|
unique_ptr<Surface> PngLoader::bitmap(uint32_t colorSpace)
|
||||||
{
|
{
|
||||||
if (!content) return nullptr;
|
if (!content) return nullptr;
|
||||||
|
if (this->colorSpace != colorSpace) {
|
||||||
|
this->colorSpace = colorSpace;
|
||||||
|
_changeColorSpace(content, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
||||||
surface->buffer = (uint32_t*)(content);
|
surface->buffer = content;
|
||||||
surface->stride = w;
|
surface->stride = w;
|
||||||
surface->w = w;
|
surface->w = w;
|
||||||
surface->h = h;
|
surface->h = h;
|
||||||
surface->cs = SwCanvas::ARGB8888;
|
surface->cs = colorSpace;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,11 @@ public:
|
||||||
bool read() override;
|
bool read() override;
|
||||||
bool close() override;
|
bool close() override;
|
||||||
|
|
||||||
unique_ptr<Surface> bitmap() override;
|
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
png_imagep image = nullptr;
|
png_imagep image = nullptr;
|
||||||
const uint32_t* content = nullptr;
|
uint32_t* content = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_TVG_PNG_LOADER_H_
|
#endif //_TVG_PNG_LOADER_H_
|
||||||
|
|
|
@ -28,6 +28,24 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
|
||||||
|
{
|
||||||
|
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
|
||||||
|
{
|
||||||
|
auto buffer = data;
|
||||||
|
for (uint32_t y = 0; y < h; ++y, buffer += w) {
|
||||||
|
auto src = buffer;
|
||||||
|
for (uint32_t x = 0; x < w; ++x, ++src) {
|
||||||
|
*src = CHANGE_COLORSPACE(*src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void JpgLoader::clear()
|
void JpgLoader::clear()
|
||||||
{
|
{
|
||||||
jpgdDelete(decoder);
|
jpgdDelete(decoder);
|
||||||
|
@ -110,18 +128,22 @@ bool JpgLoader::close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unique_ptr<Surface> JpgLoader::bitmap()
|
unique_ptr<Surface> JpgLoader::bitmap(uint32_t colorSpace)
|
||||||
{
|
{
|
||||||
this->done();
|
this->done();
|
||||||
|
|
||||||
if (!image) return nullptr;
|
if (!image) return nullptr;
|
||||||
|
if (this->colorSpace != colorSpace) {
|
||||||
|
this->colorSpace = colorSpace;
|
||||||
|
_changeColorSpace(reinterpret_cast<uint32_t*>(image), w, h);
|
||||||
|
}
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
||||||
surface->buffer = (uint32_t*)(image);
|
surface->buffer = reinterpret_cast<uint32_t*>(image);
|
||||||
surface->stride = static_cast<uint32_t>(w);
|
surface->stride = static_cast<uint32_t>(w);
|
||||||
surface->w = static_cast<uint32_t>(w);
|
surface->w = static_cast<uint32_t>(w);
|
||||||
surface->h = static_cast<uint32_t>(h);
|
surface->h = static_cast<uint32_t>(h);
|
||||||
surface->cs = SwCanvas::ARGB8888;
|
surface->cs = colorSpace;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
bool read() override;
|
bool read() override;
|
||||||
bool close() override;
|
bool close() override;
|
||||||
|
|
||||||
unique_ptr<Surface> bitmap() override;
|
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
|
||||||
void run(unsigned tid) override;
|
void run(unsigned tid) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,23 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
|
||||||
|
{
|
||||||
|
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
|
||||||
|
{
|
||||||
|
auto buffer = data;
|
||||||
|
for (uint32_t y = 0; y < h; ++y, buffer += w) {
|
||||||
|
auto src = buffer;
|
||||||
|
for (uint32_t x = 0; x < w; ++x, ++src) {
|
||||||
|
*src = CHANGE_COLORSPACE(*src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
@ -54,7 +71,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
|
||||||
if (!content) return false;
|
if (!content) return false;
|
||||||
memcpy((void*)content, data, sizeof(uint32_t) * w * h);
|
memcpy((void*)content, data, sizeof(uint32_t) * w * h);
|
||||||
}
|
}
|
||||||
else content = data;
|
else content = const_cast<uint32_t*>(data);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -72,16 +89,20 @@ bool RawLoader::close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unique_ptr<Surface> RawLoader::bitmap()
|
unique_ptr<Surface> RawLoader::bitmap(uint32_t colorSpace)
|
||||||
{
|
{
|
||||||
if (!content) return nullptr;
|
if (!content) return nullptr;
|
||||||
|
if (this->colorSpace != colorSpace) {
|
||||||
|
this->colorSpace = colorSpace;
|
||||||
|
_changeColorSpace(content, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
|
||||||
surface->buffer = (uint32_t*)(content);
|
surface->buffer = content;
|
||||||
surface->stride = (uint32_t)w;
|
surface->stride = static_cast<uint32_t>(w);
|
||||||
surface->w = (uint32_t)w;
|
surface->w = static_cast<uint32_t>(w);
|
||||||
surface->h = (uint32_t)h;
|
surface->h = static_cast<uint32_t>(h);
|
||||||
surface->cs = SwCanvas::ARGB8888;
|
surface->cs = colorSpace;
|
||||||
|
|
||||||
return unique_ptr<Surface>(surface);
|
return unique_ptr<Surface>(surface);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
class RawLoader : public LoadModule
|
class RawLoader : public LoadModule
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const uint32_t* content = nullptr;
|
uint32_t* content = nullptr;
|
||||||
bool copy = false;
|
bool copy = false;
|
||||||
|
|
||||||
~RawLoader();
|
~RawLoader();
|
||||||
|
@ -35,7 +35,7 @@ public:
|
||||||
bool read() override;
|
bool read() override;
|
||||||
bool close() override;
|
bool close() override;
|
||||||
|
|
||||||
unique_ptr<Surface> bitmap() override;
|
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -180,9 +180,9 @@ static float _toFloat(const SvgParser* svgParse, const char* str, SvgParserLengt
|
||||||
else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w;
|
else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w;
|
||||||
else //if other then it's radius
|
else //if other then it's radius
|
||||||
{
|
{
|
||||||
float max = (float)svgParse->global.w;
|
float max = svgParse->global.w;
|
||||||
if (max < svgParse->global.h)
|
if (max < svgParse->global.h)
|
||||||
max = (float)svgParse->global.h;
|
max = svgParse->global.h;
|
||||||
parsedValue = (parsedValue / 100.0) * max;
|
parsedValue = (parsedValue / 100.0) * max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,7 +341,7 @@ static void _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* das
|
||||||
++end;
|
++end;
|
||||||
//Refers to the diagonal length of the viewport.
|
//Refers to the diagonal length of the viewport.
|
||||||
//https://www.w3.org/TR/SVG2/coords.html#Units
|
//https://www.w3.org/TR/SVG2/coords.html#Units
|
||||||
parsedValue = (sqrtf(pow(loader->svgParse->global.w, 2) + pow(loader->svgParse->global.h, 2)) / sqrtf(2.0f)) * (parsedValue / 100.0f);
|
parsedValue = (sqrtf(powf(loader->svgParse->global.w, 2) + powf(loader->svgParse->global.h, 2)) / sqrtf(2.0f)) * (parsedValue / 100.0f);
|
||||||
}
|
}
|
||||||
(*dash).array.push(parsedValue);
|
(*dash).array.push(parsedValue);
|
||||||
str = end;
|
str = end;
|
||||||
|
@ -376,7 +376,7 @@ static char* _idFromUrl(const char* url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned char _parserColor(const char* value, char** end)
|
static unsigned char _parseColor(const char* value, char** end)
|
||||||
{
|
{
|
||||||
float r;
|
float r;
|
||||||
|
|
||||||
|
@ -586,11 +586,11 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
|
||||||
*b = strtol(tmp, nullptr, 16);
|
*b = strtol(tmp, nullptr, 16);
|
||||||
}
|
}
|
||||||
} else if (len >= 10 && (str[0] == 'r' || str[0] == 'R') && (str[1] == 'g' || str[1] == 'G') && (str[2] == 'b' || str[2] == 'B') && str[3] == '(' && str[len - 1] == ')') {
|
} else if (len >= 10 && (str[0] == 'r' || str[0] == 'R') && (str[1] == 'g' || str[1] == 'G') && (str[2] == 'b' || str[2] == 'B') && str[3] == '(' && str[len - 1] == ')') {
|
||||||
tr = _parserColor(str + 4, &red);
|
tr = _parseColor(str + 4, &red);
|
||||||
if (red && *red == ',') {
|
if (red && *red == ',') {
|
||||||
tg = _parserColor(red + 1, &green);
|
tg = _parseColor(red + 1, &green);
|
||||||
if (green && *green == ',') {
|
if (green && *green == ',') {
|
||||||
tb = _parserColor(green + 1, &blue);
|
tb = _parseColor(green + 1, &blue);
|
||||||
if (blue && blue[0] == ')' && blue[1] == '\0') {
|
if (blue && blue[0] == ')' && blue[1] == '\0') {
|
||||||
*r = tr;
|
*r = tr;
|
||||||
*g = tg;
|
*g = tg;
|
||||||
|
@ -840,13 +840,13 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
|
||||||
if (_parseNumber(&value, &doc->vy)) {
|
if (_parseNumber(&value, &doc->vy)) {
|
||||||
if (_parseNumber(&value, &doc->vw)) {
|
if (_parseNumber(&value, &doc->vw)) {
|
||||||
_parseNumber(&value, &doc->vh);
|
_parseNumber(&value, &doc->vh);
|
||||||
loader->svgParse->global.h = (uint32_t)doc->vh;
|
loader->svgParse->global.h = doc->vh;
|
||||||
}
|
}
|
||||||
loader->svgParse->global.w = (uint32_t)doc->vw;
|
loader->svgParse->global.w = doc->vw;
|
||||||
}
|
}
|
||||||
loader->svgParse->global.y = (int)doc->vy;
|
loader->svgParse->global.y = doc->vy;
|
||||||
}
|
}
|
||||||
loader->svgParse->global.x = (int)doc->vx;
|
loader->svgParse->global.x = doc->vx;
|
||||||
} else if (!strcmp(key, "preserveAspectRatio")) {
|
} else if (!strcmp(key, "preserveAspectRatio")) {
|
||||||
_parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
|
_parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
|
||||||
} else if (!strcmp(key, "style")) {
|
} else if (!strcmp(key, "style")) {
|
||||||
|
@ -1300,11 +1300,11 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha
|
||||||
|
|
||||||
if (loader->svgParse->global.w == 0) {
|
if (loader->svgParse->global.w == 0) {
|
||||||
if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1;
|
if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1;
|
||||||
else loader->svgParse->global.w = (uint32_t)doc->w;
|
else loader->svgParse->global.w = doc->w;
|
||||||
}
|
}
|
||||||
if (loader->svgParse->global.h == 0) {
|
if (loader->svgParse->global.h == 0) {
|
||||||
if (doc->h < FLT_EPSILON) loader->svgParse->global.h = 1;
|
if (doc->h < FLT_EPSILON) loader->svgParse->global.h = 1;
|
||||||
else loader->svgParse->global.h = (uint32_t)doc->h;
|
else loader->svgParse->global.h = doc->h;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loader->svgParse->node;
|
return loader->svgParse->node;
|
||||||
|
@ -2375,7 +2375,7 @@ static void _recalcRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial
|
||||||
static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
|
static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
|
||||||
{
|
{
|
||||||
// scaling factor based on the Units paragraph from : https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
|
// scaling factor based on the Units paragraph from : https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
|
||||||
if (userSpace && !radial->isRPercentage) radial->r = radial->r / (sqrtf(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrtf(2.0));
|
if (userSpace && !radial->isRPercentage) radial->r = radial->r / (sqrtf(powf(loader->svgParse->global.h, 2) + powf(loader->svgParse->global.w, 2)) / sqrtf(2.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3180,6 +3180,12 @@ SvgLoader::~SvgLoader()
|
||||||
|
|
||||||
void SvgLoader::run(unsigned tid)
|
void SvgLoader::run(unsigned tid)
|
||||||
{
|
{
|
||||||
|
//According to the SVG standard the value of the width/height of the viewbox set to 0 disables rendering
|
||||||
|
if (renderingDisabled) {
|
||||||
|
root = Scene::gen();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
|
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
|
||||||
|
|
||||||
if (loaderData.doc) {
|
if (loaderData.doc) {
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
private:
|
private:
|
||||||
AspectRatioAlign align = AspectRatioAlign::XMidYMid;
|
AspectRatioAlign align = AspectRatioAlign::XMidYMid;
|
||||||
AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet;
|
AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet;
|
||||||
|
bool renderingDisabled = false;
|
||||||
|
|
||||||
bool header();
|
bool header();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -425,8 +425,7 @@ struct SvgParser
|
||||||
SvgStopStyleFlags flags;
|
SvgStopStyleFlags flags;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int x, y;
|
float x, y, w, h;
|
||||||
uint32_t w, h;
|
|
||||||
} global;
|
} global;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -255,7 +255,6 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
|
||||||
node->style->clipPath.applying = true;
|
node->style->clipPath.applying = true;
|
||||||
|
|
||||||
auto comp = Shape::gen();
|
auto comp = Shape::gen();
|
||||||
comp->fill(255, 255, 255, 255);
|
|
||||||
if (node->transform) comp->transform(*node->transform);
|
if (node->transform) comp->transform(*node->transform);
|
||||||
|
|
||||||
auto child = compNode->child.data;
|
auto child = compNode->child.data;
|
||||||
|
@ -348,7 +347,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, const Box& vBox, const stri
|
||||||
|
|
||||||
//If stroke property is nullptr then do nothing
|
//If stroke property is nullptr then do nothing
|
||||||
if (style->stroke.paint.none) {
|
if (style->stroke.paint.none) {
|
||||||
//Do nothing
|
vg->stroke(0.0f);
|
||||||
} else if (style->stroke.paint.gradient) {
|
} else if (style->stroke.paint.gradient) {
|
||||||
Box bBox = vBox;
|
Box bBox = vBox;
|
||||||
if (!style->stroke.paint.gradient->userSpace) bBox = _boundingBox(vg);
|
if (!style->stroke.paint.gradient->userSpace) bBox = _boundingBox(vg);
|
||||||
|
|
|
@ -137,7 +137,11 @@ float svgUtilStrtof(const char *nPtr, char **endPtr)
|
||||||
pow10 *= 10ULL;
|
pow10 *= 10ULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (isspace(*iter)) { //skip if there is a space after the dot.
|
||||||
|
a = iter;
|
||||||
|
goto success;
|
||||||
}
|
}
|
||||||
|
|
||||||
val += static_cast<float>(decimalPart) / static_cast<float>(pow10);
|
val += static_cast<float>(decimalPart) / static_cast<float>(pow10);
|
||||||
a = iter;
|
a = iter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,38 +304,38 @@ bool isIgnoreUnsupportedLogElements(TVG_UNUSED const char* tagName)
|
||||||
bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data)
|
bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data)
|
||||||
{
|
{
|
||||||
const char *itr = buf, *itrEnd = buf + bufLength;
|
const char *itr = buf, *itrEnd = buf + bufLength;
|
||||||
char* tmpBuf = (char*)alloca(bufLength + 1);
|
char* tmpBuf = (char*)malloc(bufLength + 1);
|
||||||
|
|
||||||
if (!buf || !func) return false;
|
if (!buf || !func || !tmpBuf) goto error;
|
||||||
|
|
||||||
while (itr < itrEnd) {
|
while (itr < itrEnd) {
|
||||||
const char* p = _skipWhiteSpacesAndXmlEntities(itr, itrEnd);
|
const char* p = _skipWhiteSpacesAndXmlEntities(itr, itrEnd);
|
||||||
const char *key, *keyEnd, *value, *valueEnd;
|
const char *key, *keyEnd, *value, *valueEnd;
|
||||||
char* tval;
|
char* tval;
|
||||||
|
|
||||||
if (p == itrEnd) return true;
|
if (p == itrEnd) goto success;
|
||||||
|
|
||||||
key = p;
|
key = p;
|
||||||
for (keyEnd = key; keyEnd < itrEnd; keyEnd++) {
|
for (keyEnd = key; keyEnd < itrEnd; keyEnd++) {
|
||||||
if ((*keyEnd == '=') || (isspace((unsigned char)*keyEnd))) break;
|
if ((*keyEnd == '=') || (isspace((unsigned char)*keyEnd))) break;
|
||||||
}
|
}
|
||||||
if (keyEnd == itrEnd) return false;
|
if (keyEnd == itrEnd) goto error;
|
||||||
if (keyEnd == key) continue;
|
if (keyEnd == key) continue;
|
||||||
|
|
||||||
if (*keyEnd == '=') value = keyEnd + 1;
|
if (*keyEnd == '=') value = keyEnd + 1;
|
||||||
else {
|
else {
|
||||||
value = (const char*)memchr(keyEnd, '=', itrEnd - keyEnd);
|
value = (const char*)memchr(keyEnd, '=', itrEnd - keyEnd);
|
||||||
if (!value) return false;
|
if (!value) goto error;
|
||||||
value++;
|
value++;
|
||||||
}
|
}
|
||||||
keyEnd = _simpleXmlUnskipXmlEntities(keyEnd, key);
|
keyEnd = _simpleXmlUnskipXmlEntities(keyEnd, key);
|
||||||
|
|
||||||
value = _skipWhiteSpacesAndXmlEntities(value, itrEnd);
|
value = _skipWhiteSpacesAndXmlEntities(value, itrEnd);
|
||||||
if (value == itrEnd) return false;
|
if (value == itrEnd) goto error;
|
||||||
|
|
||||||
if ((*value == '"') || (*value == '\'')) {
|
if ((*value == '"') || (*value == '\'')) {
|
||||||
valueEnd = (const char*)memchr(value + 1, *value, itrEnd - value);
|
valueEnd = (const char*)memchr(value + 1, *value, itrEnd - value);
|
||||||
if (!valueEnd) return false;
|
if (!valueEnd) goto error;
|
||||||
value++;
|
value++;
|
||||||
} else {
|
} else {
|
||||||
valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd);
|
valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd);
|
||||||
|
@ -364,7 +364,14 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
success:
|
||||||
|
free(tmpBuf);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(tmpBuf);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
VERSION=0.8.3
|
VERSION=0.8.4
|
||||||
rm -rf AUTHORS inc LICENSE src *.zip
|
rm -rf AUTHORS inc LICENSE src *.zip
|
||||||
curl -L -O https://github.com/Samsung/thorvg/archive/v$VERSION.zip
|
curl -L -O https://github.com/thorvg/thorvg/archive/v$VERSION.zip
|
||||||
bsdtar --strip-components=1 -xvf *.zip
|
bsdtar --strip-components=1 -xvf *.zip
|
||||||
rm *.zip
|
rm *.zip
|
||||||
rm -rf .github docs pc res test tools tvgcompat .git* *.md *.txt wasm_build.sh
|
rm -rf .github docs pc res test tools tvgcompat .git* *.md *.txt wasm_build.sh
|
||||||
|
|
Loading…
Reference in New Issue