summaryrefslogtreecommitdiff
path: root/thirdparty/thorvg/src/loaders/tvg
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/thorvg/src/loaders/tvg')
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp450
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h54
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp232
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h61
4 files changed, 797 insertions, 0 deletions
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp b/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
new file mode 100644
index 0000000000..b0364b1055
--- /dev/null
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <memory.h>
+
+#ifdef _WIN32
+ #include <malloc.h>
+#else
+ #include <alloca.h>
+#endif
+
+#include "tvgTvgCommon.h"
+
+
+/************************************************************************/
+/* Internal Class Implementation */
+/************************************************************************/
+
+struct TvgBinBlock
+{
+ TvgBinTag type;
+ TvgBinCounter length;
+ const char* data;
+ const char* end;
+};
+
+static Paint* _parsePaint(TvgBinBlock baseBlock);
+
+
+static TvgBinBlock _readBlock(const char *ptr)
+{
+ TvgBinBlock block;
+ block.type = *ptr;
+ READ_UI32(&block.length, ptr + SIZE(TvgBinTag));
+ block.data = ptr + SIZE(TvgBinTag) + SIZE(TvgBinCounter);
+ block.end = block.data + block.length;
+ return block;
+}
+
+
+static bool _parseCmpTarget(const char *ptr, const char *end, Paint *paint)
+{
+ auto block = _readBlock(ptr);
+ if (block.end > end) return false;
+
+ if (block.type != TVG_TAG_PAINT_CMP_METHOD) return false;
+ if (block.length != SIZE(TvgBinFlag)) return false;
+
+ auto cmpMethod = static_cast<CompositeMethod>(*block.data);
+
+ ptr = block.end;
+
+ auto cmpBlock = _readBlock(ptr);
+ if (cmpBlock.end > end) return false;
+
+ paint->composite(unique_ptr<Paint>(_parsePaint(cmpBlock)), cmpMethod);
+
+ return true;
+}
+
+
+static bool _parsePaintProperty(TvgBinBlock block, Paint *paint)
+{
+ switch (block.type) {
+ case TVG_TAG_PAINT_OPACITY: {
+ if (block.length != SIZE(uint8_t)) return false;
+ paint->opacity(*block.data);
+ return true;
+ }
+ case TVG_TAG_PAINT_TRANSFORM: {
+ if (block.length != SIZE(Matrix)) return false;
+ Matrix matrix;
+ memcpy(&matrix, block.data, SIZE(Matrix));
+ paint->transform(matrix);
+ return true;
+ }
+ case TVG_TAG_PAINT_CMP_TARGET: {
+ if (block.length < SIZE(TvgBinTag) + SIZE(TvgBinCounter)) return false;
+ return _parseCmpTarget(block.data, block.end, paint);
+ }
+ }
+ return false;
+}
+
+
+static bool _parseScene(TvgBinBlock block, Paint *paint)
+{
+ auto scene = static_cast<Scene*>(paint);
+
+ //Case1: scene reserve count
+ if (block.type == TVG_TAG_SCENE_RESERVEDCNT) {
+ if (block.length != SIZE(uint32_t)) return false;
+ uint32_t reservedCnt;
+ READ_UI32(&reservedCnt, block.data);
+ scene->reserve(reservedCnt);
+ return true;
+ }
+
+ //Case2: Base Paint Properties
+ if (_parsePaintProperty(block, scene)) return true;
+
+ //Case3: A Child paint
+ if (auto paint = _parsePaint(block)) {
+ scene->push(unique_ptr<Paint>(paint));
+ return true;
+ }
+
+ return false;
+}
+
+
+static bool _parseShapePath(const char *ptr, const char *end, Shape *shape)
+{
+ uint32_t cmdCnt, ptsCnt;
+
+ READ_UI32(&cmdCnt, ptr);
+ ptr += SIZE(cmdCnt);
+
+ READ_UI32(&ptsCnt, ptr);
+ ptr += SIZE(ptsCnt);
+
+ auto cmds = (TvgBinFlag*) ptr;
+ ptr += SIZE(TvgBinFlag) * cmdCnt;
+
+ auto pts = (Point*) ptr;
+ ptr += SIZE(Point) * ptsCnt;
+
+ if (ptr > end) return false;
+
+ /* Recover to PathCommand(4 bytes) from TvgBinFlag(1 byte) */
+ PathCommand* inCmds = (PathCommand*)alloca(sizeof(PathCommand) * cmdCnt);
+ for (uint32_t i = 0; i < cmdCnt; ++i) {
+ inCmds[i] = static_cast<PathCommand>(cmds[i]);
+ }
+
+ shape->appendPath(inCmds, cmdCnt, pts, ptsCnt);
+
+ return true;
+}
+
+
+static unique_ptr<Fill> _parseShapeFill(const char *ptr, const char *end)
+{
+ unique_ptr<Fill> fillGrad;
+
+ while (ptr < end) {
+ auto block = _readBlock(ptr);
+ if (block.end > end) return nullptr;
+
+ switch (block.type) {
+ case TVG_TAG_FILL_RADIAL_GRADIENT: {
+ if (block.length != 3 * SIZE(float)) return nullptr;
+
+ auto ptr = block.data;
+ float x, y, radius;
+
+ READ_FLOAT(&x, ptr);
+ ptr += SIZE(float);
+ READ_FLOAT(&y, ptr);
+ ptr += SIZE(float);
+ READ_FLOAT(&radius, ptr);
+
+ auto fillGradRadial = RadialGradient::gen();
+ fillGradRadial->radial(x, y, radius);
+ fillGrad = move(fillGradRadial);
+ break;
+ }
+ case TVG_TAG_FILL_LINEAR_GRADIENT: {
+ if (block.length != 4 * SIZE(float)) return nullptr;
+
+ auto ptr = block.data;
+ float x1, y1, x2, y2;
+
+ READ_FLOAT(&x1, ptr);
+ ptr += SIZE(float);
+ READ_FLOAT(&y1, ptr);
+ ptr += SIZE(float);
+ READ_FLOAT(&x2, ptr);
+ ptr += SIZE(float);
+ READ_FLOAT(&y2, ptr);
+
+ auto fillGradLinear = LinearGradient::gen();
+ fillGradLinear->linear(x1, y1, x2, y2);
+ fillGrad = move(fillGradLinear);
+ break;
+ }
+ case TVG_TAG_FILL_FILLSPREAD: {
+ if (!fillGrad) return nullptr;
+ if (block.length != SIZE(TvgBinFlag)) return nullptr;
+ fillGrad->spread((FillSpread) *block.data);
+ break;
+ }
+ case TVG_TAG_FILL_COLORSTOPS: {
+ if (!fillGrad) return nullptr;
+ if (block.length == 0 || block.length & 0x07) return nullptr;
+ uint32_t stopsCnt = block.length >> 3; // 8 bytes per ColorStop
+ if (stopsCnt > 1023) return nullptr;
+ Fill::ColorStop* stops = (Fill::ColorStop*)alloca(sizeof(Fill::ColorStop) * stopsCnt);
+ auto p = block.data;
+ for (uint32_t i = 0; i < stopsCnt; i++, p += 8) {
+ READ_FLOAT(&stops[i].offset, p);
+ stops[i].r = p[4];
+ stops[i].g = p[5];
+ stops[i].b = p[6];
+ stops[i].a = p[7];
+ }
+ fillGrad->colorStops(stops, stopsCnt);
+ break;
+ }
+ case TVG_TAG_FILL_TRANSFORM: {
+ if (!fillGrad || block.length != SIZE(Matrix)) return nullptr;
+ Matrix gradTransform;
+ memcpy(&gradTransform, block.data, SIZE(Matrix));
+ fillGrad->transform(gradTransform);
+ break;
+ }
+ default: {
+ TVGLOG("TVG", "Unsupported tag %d (0x%x) used as one of the fill properties, %d bytes skipped", block.type, block.type, block.length);
+ break;
+ }
+ }
+ ptr = block.end;
+ }
+ return fillGrad;
+}
+
+
+static bool _parseShapeStrokeDashPattern(const char *ptr, const char *end, Shape *shape)
+{
+ uint32_t dashPatternCnt;
+ READ_UI32(&dashPatternCnt, ptr);
+ ptr += SIZE(uint32_t);
+ if (dashPatternCnt > 0) {
+ float* dashPattern = static_cast<float*>(malloc(sizeof(float) * dashPatternCnt));
+ if (!dashPattern) return false;
+ memcpy(dashPattern, ptr, sizeof(float) * dashPatternCnt);
+ ptr += SIZE(float) * dashPatternCnt;
+
+ if (ptr > end) {
+ free(dashPattern);
+ return false;
+ }
+
+ shape->stroke(dashPattern, dashPatternCnt);
+ free(dashPattern);
+ }
+ return true;
+}
+
+
+static bool _parseShapeStroke(const char *ptr, const char *end, Shape *shape)
+{
+ while (ptr < end) {
+ auto block = _readBlock(ptr);
+ if (block.end > end) return false;
+
+ switch (block.type) {
+ case TVG_TAG_SHAPE_STROKE_CAP: {
+ if (block.length != SIZE(TvgBinFlag)) return false;
+ shape->stroke((StrokeCap) *block.data);
+ break;
+ }
+ case TVG_TAG_SHAPE_STROKE_JOIN: {
+ if (block.length != SIZE(TvgBinFlag)) return false;
+ shape->stroke((StrokeJoin) *block.data);
+ break;
+ }
+ case TVG_TAG_SHAPE_STROKE_WIDTH: {
+ if (block.length != SIZE(float)) return false;
+ float width;
+ READ_FLOAT(&width, block.data);
+ shape->stroke(width);
+ break;
+ }
+ case TVG_TAG_SHAPE_STROKE_COLOR: {
+ if (block.length != 4) return false;
+ shape->stroke(block.data[0], block.data[1], block.data[2], block.data[3]);
+ break;
+ }
+ case TVG_TAG_SHAPE_STROKE_FILL: {
+ auto fill = _parseShapeFill(block.data, block.end);
+ if (!fill) return false;
+ shape->stroke(move(move(fill)));
+ break;
+ }
+ case TVG_TAG_SHAPE_STROKE_DASHPTRN: {
+ if (!_parseShapeStrokeDashPattern(block.data, block.end, shape)) return false;
+ break;
+ }
+ default: {
+ TVGLOG("TVG", "Unsupported tag %d (0x%x) used as one of stroke properties, %d bytes skipped", block.type, block.type, block.length);
+ break;
+ }
+ }
+ ptr = block.end;
+ }
+ return true;
+}
+
+
+static bool _parseShape(TvgBinBlock block, Paint* paint)
+{
+ auto shape = static_cast<Shape*>(paint);
+
+ //Case1: Shape specific properties
+ switch (block.type) {
+ case TVG_TAG_SHAPE_PATH: {
+ return _parseShapePath(block.data, block.end, shape);
+ }
+ case TVG_TAG_SHAPE_STROKE: {
+ return _parseShapeStroke(block.data, block.end, shape);
+ }
+ case TVG_TAG_SHAPE_FILL: {
+ auto fill = _parseShapeFill(block.data, block.end);
+ if (!fill) return false;
+ shape->fill(move(fill));
+ return true;
+ }
+ case TVG_TAG_SHAPE_COLOR: {
+ if (block.length != 4) return false;
+ shape->fill(block.data[0], block.data[1], block.data[2], block.data[3]);
+ return true;
+ }
+ case TVG_TAG_SHAPE_FILLRULE: {
+ if (block.length != SIZE(TvgBinFlag)) return false;
+ shape->fill((FillRule)*block.data);
+ return true;
+ }
+ }
+
+ //Case2: Base Paint Properties
+ return _parsePaintProperty(block, shape);
+}
+
+
+static bool _parsePicture(TvgBinBlock block, Paint* paint)
+{
+ auto picture = static_cast<Picture*>(paint);
+
+ //Case1: Image Picture
+ if (block.type == TVG_TAG_PICTURE_RAW_IMAGE) {
+ if (block.length < 2 * SIZE(uint32_t)) return false;
+
+ auto ptr = block.data;
+ uint32_t w, h;
+
+ READ_UI32(&w, ptr);
+ ptr += SIZE(uint32_t);
+ READ_UI32(&h, ptr);
+ ptr += SIZE(uint32_t);
+
+ auto size = w * h * SIZE(uint32_t);
+ if (block.length != 2 * SIZE(uint32_t) + size) return false;
+
+ picture->load((uint32_t*) ptr, w, h, true);
+ return true;
+ }
+
+ //Case2: Base Paint Properties
+ if (_parsePaintProperty(block, picture)) return true;
+
+ //Vector Picture won't be requested since Saver replaces it with the Scene
+ return false;
+}
+
+
+static Paint* _parsePaint(TvgBinBlock baseBlock)
+{
+ bool (*parser)(TvgBinBlock, Paint*);
+ Paint *paint;
+
+ //1. Decide the type of paint.
+ switch (baseBlock.type) {
+ case TVG_TAG_CLASS_SCENE: {
+ paint = Scene::gen().release();
+ parser = _parseScene;
+ break;
+ }
+ case TVG_TAG_CLASS_SHAPE: {
+ paint = Shape::gen().release();
+ parser = _parseShape;
+ break;
+ }
+ case TVG_TAG_CLASS_PICTURE: {
+ paint = Picture::gen().release();
+ parser = _parsePicture;
+ break;
+ }
+ default: {
+ TVGERR("TVG", "Invalid Paint Type %d (0x%x)", baseBlock.type, baseBlock.type);
+ return nullptr;
+ }
+ }
+
+ auto ptr = baseBlock.data;
+
+ //2. Read Subsquent properties of the current paint.
+ while (ptr < baseBlock.end) {
+ auto block = _readBlock(ptr);
+ if (block.end > baseBlock.end) return paint;
+ if (!parser(block, paint)) {
+ TVGERR("TVG", "Encountered the wrong paint properties... Paint Class %d (0x%x)", baseBlock.type, baseBlock.type);
+ return paint;
+ }
+ ptr = block.end;
+ }
+ return paint;
+}
+
+
+
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+unique_ptr<Scene> TvgBinInterpreter::run(const char *ptr, const char* end)
+{
+ auto scene = Scene::gen();
+ if (!scene) return nullptr;
+
+ while (ptr < end) {
+ auto block = _readBlock(ptr);
+ if (block.end > end) {
+ TVGERR("TVG", "Corrupted tvg file.");
+ return nullptr;
+ }
+ scene->push(unique_ptr<Paint>(_parsePaint(block)));
+ ptr = block.end;
+ }
+
+ return scene;
+}
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h b/thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h
new file mode 100644
index 0000000000..e7c3eba488
--- /dev/null
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _TVG_TVG_COMMON_H_
+#define _TVG_TVG_COMMON_H_
+
+#include "tvgCommon.h"
+#include "tvgBinaryDesc.h"
+
+#define SIZE(A) sizeof(A)
+#define READ_UI32(dst, src) memcpy(dst, (src), sizeof(uint32_t))
+#define READ_FLOAT(dst, src) memcpy(dst, (src), sizeof(float))
+
+
+/* Interface for Tvg Binary Interpreter */
+class TvgBinInterpreterBase
+{
+public:
+ virtual ~TvgBinInterpreterBase() {}
+
+ /* ptr: points the tvg binary body (after header)
+ end: end of the tvg binary data */
+ virtual unique_ptr<Scene> run(const char* ptr, const char* end) = 0;
+};
+
+
+/* Version 0 */
+class TvgBinInterpreter : public TvgBinInterpreterBase
+{
+public:
+ unique_ptr<Scene> run(const char* ptr, const char* end) override;
+};
+
+
+#endif //_TVG_TVG_COMMON_H_ \ No newline at end of file
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp
new file mode 100644
index 0000000000..d7f3184435
--- /dev/null
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <memory.h>
+#include <fstream>
+#include "tvgLoader.h"
+#include "tvgTvgLoader.h"
+#include "tvgLzw.h"
+
+
+/************************************************************************/
+/* Internal Class Implementation */
+/************************************************************************/
+
+
+void TvgLoader::clear()
+{
+ if (copy) free((char*)data);
+ ptr = data = nullptr;
+ size = 0;
+ copy = false;
+
+ if (interpreter) {
+ delete(interpreter);
+ interpreter = nullptr;
+ }
+}
+
+
+/* WARNING: Header format shall not change! */
+bool TvgLoader::readHeader()
+{
+ if (!ptr) return false;
+
+ //Make sure the size is large enough to hold the header
+ if (size < TVG_HEADER_SIZE) return false;
+
+ //1. Signature
+ if (memcmp(ptr, TVG_HEADER_SIGNATURE, TVG_HEADER_SIGNATURE_LENGTH)) return false;
+ ptr += TVG_HEADER_SIGNATURE_LENGTH;
+
+ //2. Version
+ char version[TVG_HEADER_VERSION_LENGTH + 1];
+ memcpy(version, ptr, TVG_HEADER_VERSION_LENGTH);
+ version[TVG_HEADER_VERSION_LENGTH - 1] = '\0';
+ ptr += TVG_HEADER_VERSION_LENGTH;
+ this->version = atoi(version);
+ if (this->version > THORVG_VERSION_NUMBER()) {
+ TVGLOG("TVG", "This TVG file expects a higher version(%d) of ThorVG symbol(%d)", this->version, THORVG_VERSION_NUMBER());
+ }
+
+ //3. View Size
+ READ_FLOAT(&w, ptr);
+ ptr += SIZE(float);
+ READ_FLOAT(&h, ptr);
+ ptr += SIZE(float);
+
+ //4. Reserved
+ if (*ptr & TVG_HEAD_FLAG_COMPRESSED) compressed = true;
+ ptr += TVG_HEADER_RESERVED_LENGTH;
+
+ //5. Compressed Size if any
+ if (compressed) {
+ auto p = ptr;
+
+ //TVG_HEADER_UNCOMPRESSED_SIZE
+ memcpy(&uncompressedSize, p, sizeof(uint32_t));
+ p += SIZE(uint32_t);
+
+ //TVG_HEADER_COMPRESSED_SIZE
+ memcpy(&compressedSize, p, sizeof(uint32_t));
+ p += SIZE(uint32_t);
+
+ //TVG_HEADER_COMPRESSED_SIZE_BITS
+ memcpy(&compressedSizeBits, p, sizeof(uint32_t));
+ }
+
+ ptr += TVG_HEADER_COMPRESS_SIZE;
+
+ //Decide the proper Tvg Binary Interpreter based on the current file version
+ if (this->version >= 0) interpreter = new TvgBinInterpreter;
+
+ return true;
+}
+
+
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+TvgLoader::~TvgLoader()
+{
+ close();
+}
+
+
+bool TvgLoader::open(const string &path)
+{
+ clear();
+
+ ifstream f;
+ f.open(path, ifstream::in | ifstream::binary | ifstream::ate);
+
+ if (!f.is_open()) return false;
+
+ size = f.tellg();
+ f.seekg(0, ifstream::beg);
+
+ copy = true;
+ data = (char*)malloc(size);
+ if (!data) {
+ clear();
+ f.close();
+ return false;
+ }
+
+ if (!f.read((char*)data, size))
+ {
+ clear();
+ f.close();
+ return false;
+ }
+
+ f.close();
+
+ ptr = data;
+
+ return readHeader();
+}
+
+
+bool TvgLoader::open(const char *data, uint32_t size, bool copy)
+{
+ clear();
+
+ if (copy) {
+ this->data = (char*)malloc(size);
+ if (!this->data) return false;
+ memcpy((char*)this->data, data, size);
+ } else this->data = data;
+
+ this->ptr = this->data;
+ this->size = size;
+ this->copy = copy;
+
+ return readHeader();
+}
+
+
+bool TvgLoader::resize(Paint* paint, float w, float h)
+{
+ if (!paint) return false;
+
+ auto sx = w / this->w;
+ auto sy = h / this->h;
+
+ //Scale
+ auto scale = sx < sy ? sx : sy;
+ paint->scale(scale);
+
+ //Align
+ float tx = 0, ty = 0;
+ auto sw = this->w * scale;
+ auto sh = this->h * scale;
+ if (sw > sh) ty -= (h - sh) * 0.5f;
+ else tx -= (w - sw) * 0.5f;
+ paint->translate(-tx, -ty);
+
+ return true;
+}
+
+
+bool TvgLoader::read()
+{
+ if (!ptr || size == 0) return false;
+
+ TaskScheduler::request(this);
+
+ return true;
+}
+
+
+bool TvgLoader::close()
+{
+ this->done();
+ clear();
+ return true;
+}
+
+
+void TvgLoader::run(unsigned tid)
+{
+ if (root) root.reset();
+
+ auto data = const_cast<char*>(ptr);
+
+ if (compressed) {
+ data = (char*) lzwDecode((uint8_t*) data, compressedSize, compressedSizeBits, uncompressedSize);
+ root = interpreter->run(data, data + uncompressedSize);
+ free(data);
+ } else {
+ root = interpreter->run(data, this->data + size);
+ }
+
+ if (!root) clear();
+}
+
+
+unique_ptr<Paint> TvgLoader::paint()
+{
+ this->done();
+ if (root) return move(root);
+ return nullptr;
+}
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h
new file mode 100644
index 0000000000..d276ded33a
--- /dev/null
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _TVG_TVG_LOADER_H_
+#define _TVG_TVG_LOADER_H_
+
+#include "tvgTaskScheduler.h"
+#include "tvgTvgCommon.h"
+
+
+class TvgLoader : public LoadModule, public Task
+{
+public:
+ const char* data = nullptr;
+ const char* ptr = nullptr;
+ uint32_t size = 0;
+ uint16_t version = 0;
+ unique_ptr<Scene> root = nullptr;
+ TvgBinInterpreterBase* interpreter = nullptr;
+ uint32_t uncompressedSize = 0;
+ uint32_t compressedSize = 0;
+ uint32_t compressedSizeBits = 0;
+ bool copy = false;
+ bool compressed = false;
+
+ ~TvgLoader();
+
+ using LoadModule::open;
+ bool open(const string &path) override;
+ bool open(const char *data, uint32_t size, bool copy) override;
+ bool read() override;
+ bool close() override;
+ bool resize(Paint* paint, float w, float h) override;
+ unique_ptr<Paint> paint() override;
+
+private:
+ bool readHeader();
+ void run(unsigned tid) override;
+ void clear();
+};
+
+#endif //_TVG_TVG_LOADER_H_