summaryrefslogtreecommitdiff
path: root/thirdparty/thorvg/src/loaders
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/thorvg/src/loaders')
-rw-r--r--thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp62
-rw-r--r--thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h5
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp38
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h5
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp34
-rw-r--r--thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h2
-rw-r--r--thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp37
-rw-r--r--thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h5
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp75
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp1120
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h5
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h110
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp11
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp61
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h4
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp6
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h2
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp55
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h2
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp3
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h2
25 files changed, 1042 insertions, 610 deletions
diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp
index 1fb0681814..b0a9fdd579 100644
--- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -23,42 +23,14 @@
#include "tvgLoader.h"
#include "tvgPngLoader.h"
-static inline uint32_t PREMULTIPLY(uint32_t c)
-{
- auto a = (c >> 24);
- return (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
-}
+/************************************************************************/
+/* Internal Class Implementation */
+/************************************************************************/
-static void _premultiply(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 = PREMULTIPLY(*src);
- }
- }
-}
-
-
-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 */
+/************************************************************************/
PngLoader::PngLoader()
{
@@ -84,6 +56,7 @@ bool PngLoader::open(const string& path)
w = (float)image->width;
h = (float)image->height;
+ cs = ColorSpace::ARGB8888;
return true;
}
@@ -96,6 +69,7 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
w = (float)image->width;
h = (float)image->height;
+ cs = ColorSpace::ARGB8888;
return true;
}
@@ -117,8 +91,6 @@ bool PngLoader::read()
}
content = reinterpret_cast<uint32_t*>(buffer);
- _premultiply(reinterpret_cast<uint32_t*>(buffer), image->width, image->height);
-
return true;
}
@@ -128,20 +100,20 @@ bool PngLoader::close()
return true;
}
-unique_ptr<Surface> PngLoader::bitmap(uint32_t colorSpace)
+unique_ptr<Surface> PngLoader::bitmap()
{
if (!content) return nullptr;
- if (this->colorSpace != colorSpace) {
- this->colorSpace = colorSpace;
- _changeColorSpace(content, w, h);
- }
- auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
- surface->buffer = content;
+ //TODO: It's better to keep this surface instance in the loader side
+ auto surface = new Surface;
+ surface->buf32 = content;
surface->stride = w;
surface->w = w;
surface->h = h;
- surface->cs = colorSpace;
+ surface->cs = cs;
+ surface->channelSize = sizeof(uint32_t);
+ surface->owner = true;
+ surface->premultiplied = false;
return unique_ptr<Surface>(surface);
}
diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h
index f8c0daa61c..5354e1bdd6 100644
--- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h
+++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef _TVG_PNG_LOADER_H_
#define _TVG_PNG_LOADER_H_
@@ -36,7 +37,7 @@ public:
bool read() override;
bool close() override;
- unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
+ unique_ptr<Surface> bitmap() override;
private:
png_imagep image = nullptr;
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp
index f64b7110fe..6edda86cc1 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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
@@ -28,24 +28,6 @@
/* 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()
{
jpgdDelete(decoder);
@@ -79,6 +61,7 @@ bool JpgLoader::open(const string& path)
w = static_cast<float>(width);
h = static_cast<float>(height);
+ cs = ColorSpace::ARGB8888;
return true;
}
@@ -104,6 +87,7 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy)
w = static_cast<float>(width);
h = static_cast<float>(height);
+ cs = ColorSpace::ARGB8888;
return true;
}
@@ -128,22 +112,22 @@ bool JpgLoader::close()
}
-unique_ptr<Surface> JpgLoader::bitmap(uint32_t colorSpace)
+unique_ptr<Surface> JpgLoader::bitmap()
{
this->done();
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)));
- surface->buffer = reinterpret_cast<uint32_t*>(image);
+ //TODO: It's better to keep this surface instance in the loader side
+ auto surface = new Surface;
+ surface->buf8 = image;
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
- surface->cs = colorSpace;
+ surface->cs = cs;
+ surface->channelSize = sizeof(uint32_t);
+ surface->premultiplied = true;
+ surface->owner = true;
return unique_ptr<Surface>(surface);
}
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h
index c47cb6704f..6d2febe94f 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef _TVG_JPG_LOADER_H_
#define _TVG_JPG_LOADER_H_
@@ -44,7 +45,7 @@ public:
bool read() override;
bool close() override;
- unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
+ unique_ptr<Surface> bitmap() override;
void run(unsigned tid) override;
};
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp
index 56b40acf0b..6ea2efb054 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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
@@ -80,7 +80,7 @@ enum jpgd_status
enum
{
JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
- JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384
+ JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384
};
// Input stream interface.
@@ -151,7 +151,7 @@ public:
// If JPGD_SUCCESS is returned you may then call decode() on each scanline.
int begin_decoding();
// Returns the next scan line.
- // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
+ // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
// Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4).
// Returns JPGD_SUCCESS if a scan line has been returned.
// Returns JPGD_DONE if all scan lines have been returned.
@@ -1246,7 +1246,7 @@ void jpeg_decoder::read_sof_marker()
uint32_t num_left = get_bits(16);
if (get_bits(8) != 8) stop_decoding(JPGD_BAD_PRECISION); /* precision: sorry, only 8-bit precision is supported right now */
-
+
m_image_y_size = get_bits(16);
if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT)) stop_decoding(JPGD_BAD_HEIGHT);
@@ -1326,7 +1326,7 @@ void jpeg_decoder::read_sos_marker()
}
num_left -= 3;
- while (num_left) { /* read past whatever is num_left */
+ while (num_left) { /* read past whatever is num_left */
get_bits(8);
num_left--;
}
@@ -1411,7 +1411,7 @@ int jpeg_decoder::process_markers()
stop_decoding(JPGD_UNEXPECTED_MARKER);
break;
}
- default: { /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
+ default: { /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
skip_variable_marker();
break;
}
@@ -1441,7 +1441,7 @@ void jpeg_decoder::locate_soi_marker()
if (lastchar == 0xFF) {
if (thischar == M_SOI) break;
- else if (thischar == M_EOI) stop_decoding(JPGD_NOT_JPEG); // get_bits will keep returning M_EOI if we read past the end
+ else if (thischar == M_EOI) stop_decoding(JPGD_NOT_JPEG); // get_bits will keep returning M_EOI if we read past the end
}
}
@@ -1460,7 +1460,7 @@ void jpeg_decoder::locate_sof_marker()
switch (c) {
case M_SOF2: m_progressive_flag = true;
case M_SOF0: /* baseline DCT */
- case M_SOF1: { /* extended sequential DCT */
+ case M_SOF1: { /* extended sequential DCT */
read_sof_marker();
break;
}
@@ -1671,7 +1671,7 @@ void jpeg_decoder::transform_mcu_expand(int mcu_row)
JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] >= 1);
JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] <= 64);
- int max_zag = m_mcu_block_max_zag[mcu_block++] - 1;
+ int max_zag = m_mcu_block_max_zag[mcu_block++] - 1;
if (max_zag <= 0) max_zag = 0; // should never happen, only here to shut up static analysis
switch (s_max_rc[max_zag]) {
@@ -1789,7 +1789,7 @@ void jpeg_decoder::load_next_row()
p[0] = pDC[0];
memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_t));
- for (i = 63; i > 0; i--) {
+ for (i = 63; i > 0; i--) {
if (p[g_ZAG[i]]) break;
}
@@ -1809,7 +1809,7 @@ void jpeg_decoder::load_next_row()
if (++block_y_mcu_ofs == m_comp_v_samp[component_id]) {
block_y_mcu_ofs = 0;
block_x_mcu[component_id] += m_comp_h_samp[component_id];
- }
+ }
}
}
if (m_freq_domain_chroma_upsample) transform_mcu_expand(mcu_row);
@@ -1865,7 +1865,7 @@ void jpeg_decoder::process_restart()
static inline int dequantize_ac(int c, int q)
-{
+{
c *= q;
return c;
}
@@ -1910,7 +1910,7 @@ void jpeg_decoder::decode_next_row()
while (n--) p[g_ZAG[kt++]] = 0;
}
k += r;
- }
+ }
s = JPGD_HUFF_EXTEND(extra_bits, s);
JPGD_ASSERT(k < 64);
p[g_ZAG[k]] = static_cast<jpgd_block_t>(dequantize_ac(s, q[k])); //s * q[k];
@@ -2204,7 +2204,7 @@ int jpeg_decoder::decode(const void** pScan_line, uint32_t* pScan_line_len)
}
else *pScan_line = m_pScan_line_1;
break;
- }
+ }
case JPGD_YH2V1: {
H2V1Convert();
*pScan_line = m_pScan_line_0;
@@ -2609,11 +2609,11 @@ void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, in
int p1 = 1 << pD->m_successive_low;
int m1 = static_cast<unsigned int>(-1) << pD->m_successive_low;
jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
-
+
JPGD_ASSERT(pD->m_spectral_end <= 63);
-
+
k = pD->m_spectral_start;
-
+
if (pD->m_eob_run == 0) {
for ( ; k <= pD->m_spectral_end; k++) {
s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]);
diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h
index ca9cb35c32..030fdc2946 100644
--- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h
+++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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
diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp
index 19c1dd6668..5f5e72b0dd 100644
--- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include <fstream>
#include <string.h>
#include "tvgLoader.h"
@@ -28,22 +29,6 @@
/* 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 */
@@ -73,6 +58,8 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
}
else content = const_cast<uint32_t*>(data);
+ cs = ColorSpace::ARGB8888;
+
return true;
}
@@ -89,20 +76,20 @@ bool RawLoader::close()
}
-unique_ptr<Surface> RawLoader::bitmap(uint32_t colorSpace)
+unique_ptr<Surface> RawLoader::bitmap()
{
if (!content) return nullptr;
- if (this->colorSpace != colorSpace) {
- this->colorSpace = colorSpace;
- _changeColorSpace(content, w, h);
- }
- auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
- surface->buffer = content;
+ //TODO: It's better to keep this surface instance in the loader side
+ auto surface = new Surface;
+ surface->buf32 = content;
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
- surface->cs = colorSpace;
+ surface->cs = cs;
+ surface->channelSize = sizeof(uint32_t);
+ surface->premultiplied = true;
+ surface->owner = true;
return unique_ptr<Surface>(surface);
}
diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h
index 8789b0cf51..69f9bdc47a 100644
--- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h
+++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef _TVG_RAW_LOADER_H_
#define _TVG_RAW_LOADER_H_
@@ -35,7 +36,7 @@ public:
bool read() override;
bool close() override;
- unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
+ unique_ptr<Surface> bitmap() override;
};
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp
index 478ba5d3d1..694e6d1ebf 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2022 - 2023 the ThorVG project. 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
@@ -32,13 +32,13 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
{
if (from == nullptr) return;
//Copy the properties of 'from' only if they were explicitly set (not the default ones).
- if (from->curColorSet && !((int)to->flags & (int)SvgStyleFlags::Color)) {
+ if (from->curColorSet && !(to->flags & SvgStyleFlags::Color)) {
to->color = from->color;
to->curColorSet = true;
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Color);
+ to->flags = (to->flags | SvgStyleFlags::Color);
}
//Fill
- if (((int)from->fill.flags & (int)SvgFillFlags::Paint) && !((int)to->flags & (int)SvgStyleFlags::Fill)) {
+ if ((from->fill.flags & SvgFillFlags::Paint) && !(to->flags & SvgStyleFlags::Fill)) {
to->fill.paint.color = from->fill.paint.color;
to->fill.paint.none = from->fill.paint.none;
to->fill.paint.curColor = from->fill.paint.curColor;
@@ -46,21 +46,21 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
if (to->fill.paint.url) free(to->fill.paint.url);
to->fill.paint.url = strdup(from->fill.paint.url);
}
- to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::Paint);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Fill);
+ to->fill.flags = (to->fill.flags | SvgFillFlags::Paint);
+ to->flags = (to->flags | SvgStyleFlags::Fill);
}
- if (((int)from->fill.flags & (int)SvgFillFlags::Opacity) && !((int)to->flags & (int)SvgStyleFlags::FillOpacity)) {
+ if ((from->fill.flags & SvgFillFlags::Opacity) && !(to->flags & SvgStyleFlags::FillOpacity)) {
to->fill.opacity = from->fill.opacity;
- to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::Opacity);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::FillOpacity);
+ to->fill.flags = (to->fill.flags | SvgFillFlags::Opacity);
+ to->flags = (to->flags | SvgStyleFlags::FillOpacity);
}
- if (((int)from->fill.flags & (int)SvgFillFlags::FillRule) && !((int)to->flags & (int)SvgStyleFlags::FillRule)) {
+ if ((from->fill.flags & SvgFillFlags::FillRule) && !(to->flags & SvgStyleFlags::FillRule)) {
to->fill.fillRule = from->fill.fillRule;
- to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::FillRule);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::FillRule);
+ to->fill.flags = (to->fill.flags | SvgFillFlags::FillRule);
+ to->flags = (to->flags | SvgStyleFlags::FillRule);
}
//Stroke
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Paint) && !((int)to->flags & (int)SvgStyleFlags::Stroke)) {
+ if ((from->stroke.flags & SvgStrokeFlags::Paint) && !(to->flags & SvgStyleFlags::Stroke)) {
to->stroke.paint.color = from->stroke.paint.color;
to->stroke.paint.none = from->stroke.paint.none;
to->stroke.paint.curColor = from->stroke.paint.curColor;
@@ -68,45 +68,45 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
if (to->stroke.paint.url) free(to->stroke.paint.url);
to->stroke.paint.url = strdup(from->stroke.paint.url);
}
- to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Paint);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Stroke);
+ to->stroke.flags = (to->stroke.flags | SvgStrokeFlags::Paint);
+ to->flags = (to->flags | SvgStyleFlags::Stroke);
}
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity) && !((int)to->flags & (int)SvgStyleFlags::StrokeOpacity)) {
+ if ((from->stroke.flags & SvgStrokeFlags::Opacity) && !(to->flags & SvgStyleFlags::StrokeOpacity)) {
to->stroke.opacity = from->stroke.opacity;
- to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Opacity);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeOpacity);
+ to->stroke.flags = (to->stroke.flags | SvgStrokeFlags::Opacity);
+ to->flags = (to->flags | SvgStyleFlags::StrokeOpacity);
}
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Width) && !((int)to->flags & (int)SvgStyleFlags::StrokeWidth)) {
+ if ((from->stroke.flags & SvgStrokeFlags::Width) && !(to->flags & SvgStyleFlags::StrokeWidth)) {
to->stroke.width = from->stroke.width;
- to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Width);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeWidth);
+ to->stroke.flags = (to->stroke.flags | SvgStrokeFlags::Width);
+ to->flags = (to->flags | SvgStyleFlags::StrokeWidth);
}
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Dash) && !((int)to->flags & (int)SvgStyleFlags::StrokeDashArray)) {
+ if ((from->stroke.flags & SvgStrokeFlags::Dash) && !(to->flags & SvgStyleFlags::StrokeDashArray)) {
if (from->stroke.dash.array.count > 0) {
to->stroke.dash.array.clear();
to->stroke.dash.array.reserve(from->stroke.dash.array.count);
for (uint32_t i = 0; i < from->stroke.dash.array.count; ++i) {
to->stroke.dash.array.push(from->stroke.dash.array.data[i]);
}
- to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Dash);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeDashArray);
+ to->stroke.flags = (to->stroke.flags | SvgStrokeFlags::Dash);
+ to->flags = (to->flags | SvgStyleFlags::StrokeDashArray);
}
}
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Cap) && !((int)to->flags & (int)SvgStyleFlags::StrokeLineCap)) {
+ if ((from->stroke.flags & SvgStrokeFlags::Cap) && !(to->flags & SvgStyleFlags::StrokeLineCap)) {
to->stroke.cap = from->stroke.cap;
- to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Cap);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeLineCap);
+ to->stroke.flags = (to->stroke.flags | SvgStrokeFlags::Cap);
+ to->flags = (to->flags | SvgStyleFlags::StrokeLineCap);
}
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Join) && !((int)to->flags & (int)SvgStyleFlags::StrokeLineJoin)) {
+ if ((from->stroke.flags & SvgStrokeFlags::Join) && !(to->flags & SvgStyleFlags::StrokeLineJoin)) {
to->stroke.join = from->stroke.join;
- to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Join);
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::StrokeLineJoin);
+ to->stroke.flags = (to->stroke.flags | SvgStrokeFlags::Join);
+ to->flags = (to->flags | SvgStyleFlags::StrokeLineJoin);
}
//Opacity
//TODO: it can be set to be 255 and shouldn't be changed by attribute 'opacity'
- if (from->opacity < 255 && !((int)to->flags & (int)SvgStyleFlags::Opacity)) {
+ if (from->opacity < 255 && !(to->flags & SvgStyleFlags::Opacity)) {
to->opacity = from->opacity;
- to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Opacity);
+ to->flags = (to->flags | SvgStyleFlags::Opacity);
}
}
@@ -118,11 +118,11 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
void cssCopyStyleAttr(SvgNode* to, const SvgNode* from)
{
//Copy matrix attribute
- if (from->transform && !((int)to->style->flags & (int)SvgStyleFlags::Transform)) {
+ if (from->transform && !(to->style->flags & SvgStyleFlags::Transform)) {
to->transform = (Matrix*)malloc(sizeof(Matrix));
if (to->transform) {
*to->transform = *from->transform;
- to->style->flags = (SvgStyleFlags)((int)to->style->flags | (int)SvgStyleFlags::Transform);
+ to->style->flags = (to->style->flags | SvgStyleFlags::Transform);
}
}
//Copy style attribute
@@ -155,12 +155,12 @@ SvgNode* cssFindStyleNode(const SvgNode* style, const char* title, SvgNodeType t
SvgNode* cssFindStyleNode(const SvgNode* style, const char* title)
{
- if (!style) return nullptr;
+ if (!style || !title) return nullptr;
auto child = style->child.data;
for (uint32_t i = 0; i < style->child.count; ++i, ++child) {
if ((*child)->type == SvgNodeType::CssStyle) {
- if ((title && (*child)->id && !strcmp((*child)->id, title))) return (*child);
+ if ((*child)->id && !strcmp((*child)->id, title)) return (*child);
}
}
return nullptr;
@@ -175,9 +175,6 @@ void cssUpdateStyle(SvgNode* doc, SvgNode* style)
if (auto cssNode = cssFindStyleNode(style, nullptr, (*child)->type)) {
cssCopyStyleAttr(*child, cssNode);
}
- if (auto cssNode = cssFindStyleNode(style, nullptr)) {
- cssCopyStyleAttr(*child, cssNode);
- }
cssUpdateStyle(*child, style);
}
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h
index 66477c1a32..228c5996da 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2022 - 2023 the ThorVG project. 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
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
index bc350a0eb8..f9f08cdb81 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -137,11 +137,11 @@ static constexpr struct
};
-static bool _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice)
+static void _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice)
{
if (!strcmp(*content, "none")) {
*align = AspectRatioAlign::None;
- return true;
+ return;
}
for (unsigned int i = 0; i < sizeof(alignTags) / sizeof(alignTags[0]); i++) {
@@ -158,8 +158,6 @@ static bool _parseAspectRatio(const char** content, AspectRatioAlign* align, Asp
} else if (!strcmp(*content, "slice")) {
*meetOrSlice = AspectRatioMeetOrSlice::Slice;
}
-
- return true;
}
@@ -254,6 +252,36 @@ static SvgMaskType _toMaskType(const char* str)
}
+//The default rendering order: fill, stroke, markers
+//If any is omitted, will be rendered in its default order after the specified ones.
+static bool _toPaintOrder(const char* str)
+{
+ uint8_t position = 1;
+ uint8_t strokePosition = 0;
+ uint8_t fillPosition = 0;
+
+ while (*str != '\0') {
+ str = _skipSpace(str, nullptr);
+ if (!strncmp(str, "fill", 4)) {
+ fillPosition = position++;
+ str += 4;
+ } else if (!strncmp(str, "stroke", 6)) {
+ strokePosition = position++;
+ str += 6;
+ } else if (!strncmp(str, "markers", 7)) {
+ str += 7;
+ } else {
+ return _toPaintOrder("fill stroke");
+ }
+ }
+
+ if (fillPosition == 0) fillPosition = position++;
+ if (strokePosition == 0) strokePosition = position++;
+
+ return fillPosition < strokePosition;
+}
+
+
#define _PARSE_TAG(Type, Name, Name1, Tags_Array, Default) \
static Type _to##Name1(const char* str) \
{ \
@@ -833,20 +861,40 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
if (!strcmp(key, "width")) {
doc->w = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
+ if (strstr(value, "%") && !(doc->viewFlag & SvgViewFlag::Viewbox)) {
+ doc->viewFlag = (doc->viewFlag | SvgViewFlag::WidthInPercent);
+ } else {
+ doc->viewFlag = (doc->viewFlag | SvgViewFlag::Width);
+ }
} else if (!strcmp(key, "height")) {
doc->h = _toFloat(loader->svgParse, value, SvgParserLengthType::Vertical);
+ if (strstr(value, "%") && !(doc->viewFlag & SvgViewFlag::Viewbox)) {
+ doc->viewFlag = (doc->viewFlag | SvgViewFlag::HeightInPercent);
+ } else {
+ doc->viewFlag = (doc->viewFlag | SvgViewFlag::Height);
+ }
} else if (!strcmp(key, "viewBox")) {
if (_parseNumber(&value, &doc->vx)) {
if (_parseNumber(&value, &doc->vy)) {
if (_parseNumber(&value, &doc->vw)) {
- _parseNumber(&value, &doc->vh);
- loader->svgParse->global.h = doc->vh;
+ if (_parseNumber(&value, &doc->vh)) {
+ doc->viewFlag = (doc->viewFlag | SvgViewFlag::Viewbox);
+ loader->svgParse->global.h = doc->vh;
+ }
+ loader->svgParse->global.w = doc->vw;
}
- loader->svgParse->global.w = doc->vw;
+ loader->svgParse->global.y = doc->vy;
}
- loader->svgParse->global.y = doc->vy;
+ loader->svgParse->global.x = doc->vx;
+ }
+ if ((doc->viewFlag & SvgViewFlag::Viewbox) && (doc->vw < 0.0f || doc->vh < 0.0f)) {
+ doc->viewFlag = (SvgViewFlag)((uint32_t)doc->viewFlag & ~(uint32_t)SvgViewFlag::Viewbox);
+ TVGLOG("SVG", "Negative values of the <viewBox> width and/or height - the attribute invalidated.");
+ }
+ if (!(doc->viewFlag & SvgViewFlag::Viewbox)) {
+ loader->svgParse->global.x = loader->svgParse->global.y = 0.0f;
+ loader->svgParse->global.w = loader->svgParse->global.h = 1.0f;
}
- loader->svgParse->global.x = doc->vx;
} else if (!strcmp(key, "preserveAspectRatio")) {
_parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
} else if (!strcmp(key, "style")) {
@@ -890,7 +938,7 @@ static void _handleColorAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, co
static void _handleFillAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
SvgStyleProperty* style = node->style;
- style->fill.flags = (SvgFillFlags)((int)style->fill.flags | (int)SvgFillFlags::Paint);
+ style->fill.flags = (style->fill.flags | SvgFillFlags::Paint);
_handlePaintAttr(&style->fill.paint, value);
}
@@ -898,47 +946,47 @@ static void _handleFillAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, con
static void _handleStrokeAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
SvgStyleProperty* style = node->style;
- style->stroke.flags = (SvgStrokeFlags)((int)style->stroke.flags | (int)SvgStrokeFlags::Paint);
+ style->stroke.flags = (style->stroke.flags | SvgStrokeFlags::Paint);
_handlePaintAttr(&style->stroke.paint, value);
}
static void _handleStrokeOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
- node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Opacity);
+ node->style->stroke.flags = (node->style->stroke.flags | SvgStrokeFlags::Opacity);
node->style->stroke.opacity = _toOpacity(value);
}
static void _handleStrokeDashArrayAttr(SvgLoaderData* loader, SvgNode* node, const char* value)
{
- node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Dash);
+ node->style->stroke.flags = (node->style->stroke.flags | SvgStrokeFlags::Dash);
_parseDashArray(loader, value, &node->style->stroke.dash);
}
static void _handleStrokeWidthAttr(SvgLoaderData* loader, SvgNode* node, const char* value)
{
- node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Width);
+ node->style->stroke.flags = (node->style->stroke.flags | SvgStrokeFlags::Width);
node->style->stroke.width = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
}
static void _handleStrokeLineCapAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
- node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Cap);
+ node->style->stroke.flags = (node->style->stroke.flags | SvgStrokeFlags::Cap);
node->style->stroke.cap = _toLineCap(value);
}
static void _handleStrokeLineJoinAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
- node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Join);
+ node->style->stroke.flags = (node->style->stroke.flags | SvgStrokeFlags::Join);
node->style->stroke.join = _toLineJoin(value);
}
static void _handleFillRuleAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
- node->style->fill.flags = (SvgFillFlags)((int)node->style->fill.flags | (int)SvgFillFlags::FillRule);
+ node->style->fill.flags = (node->style->fill.flags | SvgFillFlags::FillRule);
node->style->fill.fillRule = _toFillRule(value);
}
@@ -951,7 +999,7 @@ static void _handleOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
static void _handleFillOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
- node->style->fill.flags = (SvgFillFlags)((int)node->style->fill.flags | (int)SvgFillFlags::Opacity);
+ node->style->fill.flags = (node->style->fill.flags | SvgFillFlags::Opacity);
node->style->fill.opacity = _toOpacity(value);
}
@@ -1001,6 +1049,13 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
}
+static void _handlePaintOrderAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
+{
+ node->style->flags = (node->style->flags | SvgStyleFlags::PaintOrder);
+ node->style->paintOrder = _toPaintOrder(value);
+}
+
+
static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char* value)
{
auto cssClass = &node->style->cssClass;
@@ -1051,7 +1106,8 @@ static constexpr struct
STYLE_DEF(clip-path, ClipPath, SvgStyleFlags::ClipPath),
STYLE_DEF(mask, Mask, SvgStyleFlags::Mask),
STYLE_DEF(mask-type, MaskType, SvgStyleFlags::MaskType),
- STYLE_DEF(display, Display, SvgStyleFlags::Display)
+ STYLE_DEF(display, Display, SvgStyleFlags::Display),
+ STYLE_DEF(paint-order, PaintOrder, SvgStyleFlags::PaintOrder)
};
@@ -1071,8 +1127,8 @@ static bool _parseStyleAttr(void* data, const char* key, const char* value, bool
if (styleTags[i].sz - 1 == sz && !strncmp(styleTags[i].tag, key, sz)) {
if (style) {
styleTags[i].tagHandler(loader, node, value);
- node->style->flags = (SvgStyleFlags)((int)node->style->flags | (int)styleTags[i].flag);
- } else if (!((int)node->style->flags & (int)styleTags[i].flag)) {
+ node->style->flags = (node->style->flags | styleTags[i].flag);
+ } else if (!(node->style->flags & styleTags[i].flag)) {
styleTags[i].tagHandler(loader, node, value);
}
return true;
@@ -1253,6 +1309,8 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
node->style->stroke.join = StrokeJoin::Miter;
node->style->stroke.scale = 1.0;
+ node->style->paintOrder = _toPaintOrder("fill stroke");
+
//Default display is true("inline").
node->display = true;
@@ -1291,22 +1349,22 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha
if (!loader->svgParse->node) return nullptr;
SvgDocNode* doc = &(loader->svgParse->node->node.doc);
- loader->svgParse->global.w = 0;
- loader->svgParse->global.h = 0;
+ loader->svgParse->global.w = 1.0f;
+ loader->svgParse->global.h = 1.0f;
doc->align = AspectRatioAlign::XMidYMid;
doc->meetOrSlice = AspectRatioMeetOrSlice::Meet;
+ doc->viewFlag = SvgViewFlag::None;
func(buf, bufLength, _attrParseSvgNode, loader);
- if (loader->svgParse->global.w == 0) {
- if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1;
- else loader->svgParse->global.w = doc->w;
- }
- if (loader->svgParse->global.h == 0) {
- if (doc->h < FLT_EPSILON) loader->svgParse->global.h = 1;
- else loader->svgParse->global.h = doc->h;
+ if (!(doc->viewFlag & SvgViewFlag::Viewbox)) {
+ if (doc->viewFlag & SvgViewFlag::Width) {
+ loader->svgParse->global.w = doc->w;
+ }
+ if (doc->viewFlag & SvgViewFlag::Height) {
+ loader->svgParse->global.h = doc->h;
+ }
}
-
return loader->svgParse->node;
}
@@ -1868,309 +1926,6 @@ static SvgNode* _findNodeById(SvgNode *node, const char* id)
}
-static void _cloneGradStops(Array<Fill::ColorStop>& dst, const Array<Fill::ColorStop>& src)
-{
- for (uint32_t i = 0; i < src.count; ++i) {
- dst.push(src.data[i]);
- }
-}
-
-
-static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
-{
- if (!from) return nullptr;
-
- auto grad = (SvgStyleGradient*)(calloc(1, sizeof(SvgStyleGradient)));
- if (!grad) return nullptr;
-
- grad->type = from->type;
- grad->id = from->id ? _copyId(from->id) : nullptr;
- grad->ref = from->ref ? _copyId(from->ref) : nullptr;
- grad->spread = from->spread;
- grad->userSpace = from->userSpace;
-
- if (from->transform) {
- grad->transform = (Matrix*)calloc(1, sizeof(Matrix));
- if (grad->transform) memcpy(grad->transform, from->transform, sizeof(Matrix));
- }
-
- if (grad->type == SvgGradientType::Linear) {
- grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
- if (!grad->linear) goto error_grad_alloc;
- memcpy(grad->linear, from->linear, sizeof(SvgLinearGradient));
- } else if (grad->type == SvgGradientType::Radial) {
- grad->radial = (SvgRadialGradient*)calloc(1, sizeof(SvgRadialGradient));
- if (!grad->radial) goto error_grad_alloc;
- memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient));
- }
-
- _cloneGradStops(grad->stops, from->stops);
-
- return grad;
-
-error_grad_alloc:
- if (grad) {
- grad->clear();
- free(grad);
- }
- return nullptr;
-}
-
-
-static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* parent)
-{
- if (parent == nullptr) return;
- //Inherit the property of parent if not present in child.
- if (!child->curColorSet) {
- child->color = parent->color;
- child->curColorSet = parent->curColorSet;
- }
- //Fill
- if (!((int)child->fill.flags & (int)SvgFillFlags::Paint)) {
- child->fill.paint.color = parent->fill.paint.color;
- child->fill.paint.none = parent->fill.paint.none;
- child->fill.paint.curColor = parent->fill.paint.curColor;
- if (parent->fill.paint.url) {
- if (child->fill.paint.url) free(child->fill.paint.url);
- child->fill.paint.url = _copyId(parent->fill.paint.url);
- }
- }
- if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) {
- child->fill.opacity = parent->fill.opacity;
- }
- if (!((int)child->fill.flags & (int)SvgFillFlags::FillRule)) {
- child->fill.fillRule = parent->fill.fillRule;
- }
- //Stroke
- if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Paint)) {
- child->stroke.paint.color = parent->stroke.paint.color;
- child->stroke.paint.none = parent->stroke.paint.none;
- child->stroke.paint.curColor = parent->stroke.paint.curColor;
- if (parent->stroke.paint.url) {
- if (child->stroke.paint.url) free(child->stroke.paint.url);
- child->stroke.paint.url = _copyId(parent->stroke.paint.url);
- } else {
- child->stroke.paint.url = nullptr;
- }
- }
- if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
- child->stroke.opacity = parent->stroke.opacity;
- }
- if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Width)) {
- child->stroke.width = parent->stroke.width;
- }
- if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Dash)) {
- if (parent->stroke.dash.array.count > 0) {
- child->stroke.dash.array.clear();
- child->stroke.dash.array.reserve(parent->stroke.dash.array.count);
- for (uint32_t i = 0; i < parent->stroke.dash.array.count; ++i) {
- child->stroke.dash.array.push(parent->stroke.dash.array.data[i]);
- }
- }
- }
- if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Cap)) {
- child->stroke.cap = parent->stroke.cap;
- }
- if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Join)) {
- child->stroke.join = parent->stroke.join;
- }
-}
-
-
-static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from)
-{
- if (from == nullptr) return;
- //Copy the properties of 'from' only if they were explicitly set (not the default ones).
- if (from->curColorSet) {
- to->color = from->color;
- to->curColorSet = true;
- }
- //Fill
- to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)from->fill.flags);
- if (((int)from->fill.flags & (int)SvgFillFlags::Paint)) {
- to->fill.paint.color = from->fill.paint.color;
- to->fill.paint.none = from->fill.paint.none;
- to->fill.paint.curColor = from->fill.paint.curColor;
- if (from->fill.paint.url) {
- if (to->fill.paint.url) free(to->fill.paint.url);
- to->fill.paint.url = _copyId(from->fill.paint.url);
- }
- }
- if (((int)from->fill.flags & (int)SvgFillFlags::Opacity)) {
- to->fill.opacity = from->fill.opacity;
- }
- if (((int)from->fill.flags & (int)SvgFillFlags::FillRule)) {
- to->fill.fillRule = from->fill.fillRule;
- }
- //Stroke
- to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)from->stroke.flags);
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Paint)) {
- to->stroke.paint.color = from->stroke.paint.color;
- to->stroke.paint.none = from->stroke.paint.none;
- to->stroke.paint.curColor = from->stroke.paint.curColor;
- if (from->stroke.paint.url) {
- if (to->stroke.paint.url) free(to->stroke.paint.url);
- to->stroke.paint.url = _copyId(from->stroke.paint.url);
- } else {
- to->stroke.paint.url = nullptr;
- }
- }
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
- to->stroke.opacity = from->stroke.opacity;
- }
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Width)) {
- to->stroke.width = from->stroke.width;
- }
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Dash)) {
- if (from->stroke.dash.array.count > 0) {
- to->stroke.dash.array.clear();
- to->stroke.dash.array.reserve(from->stroke.dash.array.count);
- for (uint32_t i = 0; i < from->stroke.dash.array.count; ++i) {
- to->stroke.dash.array.push(from->stroke.dash.array.data[i]);
- }
- }
- }
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Cap)) {
- to->stroke.cap = from->stroke.cap;
- }
- if (((int)from->stroke.flags & (int)SvgStrokeFlags::Join)) {
- to->stroke.join = from->stroke.join;
- }
-}
-
-
-static void _copyAttr(SvgNode* to, const SvgNode* from)
-{
- //Copy matrix attribute
- if (from->transform) {
- to->transform = (Matrix*)malloc(sizeof(Matrix));
- if (to->transform) *to->transform = *from->transform;
- }
- //Copy style attribute
- _styleCopy(to->style, from->style);
- to->style->flags = (SvgStyleFlags)((int)to->style->flags | (int)from->style->flags);
- if (from->style->clipPath.url) {
- if (to->style->clipPath.url) free(to->style->clipPath.url);
- to->style->clipPath.url = strdup(from->style->clipPath.url);
- }
- if (from->style->mask.url) {
- if (to->style->mask.url) free(to->style->mask.url);
- to->style->mask.url = strdup(from->style->mask.url);
- }
-
- //Copy node attribute
- switch (from->type) {
- case SvgNodeType::Circle: {
- to->node.circle.cx = from->node.circle.cx;
- to->node.circle.cy = from->node.circle.cy;
- to->node.circle.r = from->node.circle.r;
- break;
- }
- case SvgNodeType::Ellipse: {
- to->node.ellipse.cx = from->node.ellipse.cx;
- to->node.ellipse.cy = from->node.ellipse.cy;
- to->node.ellipse.rx = from->node.ellipse.rx;
- to->node.ellipse.ry = from->node.ellipse.ry;
- break;
- }
- case SvgNodeType::Rect: {
- to->node.rect.x = from->node.rect.x;
- to->node.rect.y = from->node.rect.y;
- to->node.rect.w = from->node.rect.w;
- to->node.rect.h = from->node.rect.h;
- to->node.rect.rx = from->node.rect.rx;
- to->node.rect.ry = from->node.rect.ry;
- to->node.rect.hasRx = from->node.rect.hasRx;
- to->node.rect.hasRy = from->node.rect.hasRy;
- break;
- }
- case SvgNodeType::Line: {
- to->node.line.x1 = from->node.line.x1;
- to->node.line.y1 = from->node.line.y1;
- to->node.line.x2 = from->node.line.x2;
- to->node.line.y2 = from->node.line.y2;
- break;
- }
- case SvgNodeType::Path: {
- if (from->node.path.path) {
- if (to->node.path.path) free(to->node.path.path);
- to->node.path.path = strdup(from->node.path.path);
- }
- break;
- }
- case SvgNodeType::Polygon: {
- if ((to->node.polygon.pointsCount = from->node.polygon.pointsCount)) {
- to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float));
- memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float));
- }
- break;
- }
- case SvgNodeType::Polyline: {
- if ((to->node.polyline.pointsCount = from->node.polyline.pointsCount)) {
- to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float));
- memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float));
- }
- break;
- }
- case SvgNodeType::Image: {
- to->node.image.x = from->node.image.x;
- to->node.image.y = from->node.image.y;
- to->node.image.w = from->node.image.w;
- to->node.image.h = from->node.image.h;
- if (from->node.image.href) {
- if (to->node.image.href) free(to->node.image.href);
- to->node.image.href = strdup(from->node.image.href);
- }
- break;
- }
- default: {
- break;
- }
- }
-}
-
-
-static void _cloneNode(SvgNode* from, SvgNode* parent, int depth)
-{
- /* Exception handling: Prevent invalid SVG data input.
- The size is the arbitrary value, we need an experimental size. */
- if (depth == 8192) {
- TVGERR("SVG", "Infinite recursive call - stopped after %d calls! Svg file may be incorrectly formatted.", depth);
- return;
- }
-
- SvgNode* newNode;
- if (!from || !parent || from == parent) return;
-
- newNode = _createNode(parent, from->type);
- if (!newNode) return;
-
- _styleInherit(newNode->style, parent->style);
- _copyAttr(newNode, from);
-
- auto child = from->child.data;
- for (uint32_t i = 0; i < from->child.count; ++i, ++child) {
- _cloneNode(*child, newNode, depth + 1);
- }
-}
-
-
-static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
-{
- for (uint32_t i = 0; i < cloneNodes->count; ++i) {
- auto nodeIdPair = cloneNodes->data[i];
- auto defs = _getDefsNode(nodeIdPair.node);
- auto nodeFrom = _findNodeById(defs, nodeIdPair.id);
- if (!nodeFrom) nodeFrom = _findNodeById(doc, nodeIdPair.id);
- _cloneNode(nodeFrom, nodeIdPair.node, 0);
- if (nodeFrom && nodeFrom->type == SvgNodeType::Symbol && nodeIdPair.node->type == SvgNodeType::Use) {
- nodeIdPair.node->node.use.symbol = nodeFrom;
- }
- free(nodeIdPair.id);
- }
-}
-
-
static constexpr struct
{
const char* tag;
@@ -2185,6 +1940,7 @@ static constexpr struct
};
+static void _cloneNode(SvgNode* from, SvgNode* parent, int depth);
static bool _attrParseUseNode(void* data, const char* key, const char* value)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
@@ -2379,13 +2135,99 @@ static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial,
}
+static void _recalcInheritedRadialCxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
+{
+ if (!radial->isCxPercentage) {
+ if (userSpace) radial->cx /= loader->svgParse->global.w;
+ else radial->cx *= loader->svgParse->global.w;
+ }
+}
+
+
+static void _recalcInheritedRadialCyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
+{
+ if (!radial->isCyPercentage) {
+ if (userSpace) radial->cy /= loader->svgParse->global.h;
+ else radial->cy *= loader->svgParse->global.h;
+ }
+}
+
+
+static void _recalcInheritedRadialFxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
+{
+ if (!radial->isFxPercentage) {
+ if (userSpace) radial->fx /= loader->svgParse->global.w;
+ else radial->fx *= loader->svgParse->global.w;
+ }
+}
+
+
+static void _recalcInheritedRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
+{
+ if (!radial->isFyPercentage) {
+ if (userSpace) radial->fy /= loader->svgParse->global.h;
+ else radial->fy *= loader->svgParse->global.h;
+ }
+}
+
+
+static void _recalcInheritedRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
+{
+ if (!radial->isRPercentage) {
+ if (userSpace) radial->r /= sqrtf(powf(loader->svgParse->global.h, 2) + powf(loader->svgParse->global.w, 2)) / sqrtf(2.0);
+ else radial->r *= sqrtf(powf(loader->svgParse->global.h, 2) + powf(loader->svgParse->global.w, 2)) / sqrtf(2.0);
+ }
+}
+
+
+static void _inheritRadialCxAttr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->radial->cx = from->radial->cx;
+ to->radial->isCxPercentage = from->radial->isCxPercentage;
+ to->flags = (to->flags | SvgGradientFlags::Cx);
+}
+
+
+static void _inheritRadialCyAttr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->radial->cy = from->radial->cy;
+ to->radial->isCyPercentage = from->radial->isCyPercentage;
+ to->flags = (to->flags | SvgGradientFlags::Cy);
+}
+
+
+static void _inheritRadialFxAttr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->radial->fx = from->radial->fx;
+ to->radial->isFxPercentage = from->radial->isFxPercentage;
+ to->flags = (to->flags | SvgGradientFlags::Fx);
+}
+
+
+static void _inheritRadialFyAttr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->radial->fy = from->radial->fy;
+ to->radial->isFyPercentage = from->radial->isFyPercentage;
+ to->flags = (to->flags | SvgGradientFlags::Fy);
+}
+
+
+static void _inheritRadialRAttr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->radial->r = from->radial->r;
+ to->radial->isRPercentage = from->radial->isRPercentage;
+ to->flags = (to->flags | SvgGradientFlags::R);
+}
+
+
typedef void (*radialMethod)(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value);
+typedef void (*radialInheritMethod)(SvgStyleGradient* to, SvgStyleGradient* from);
typedef void (*radialMethodRecalc)(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace);
-#define RADIAL_DEF(Name, Name1) \
+#define RADIAL_DEF(Name, Name1, Flag) \
{ \
-#Name, sizeof(#Name), _handleRadial##Name1##Attr, _recalcRadial##Name1##Attr \
+#Name, sizeof(#Name), _handleRadial##Name1##Attr, _inheritRadial##Name1##Attr, _recalcRadial##Name1##Attr, _recalcInheritedRadial##Name1##Attr, Flag \
}
@@ -2394,13 +2236,16 @@ static constexpr struct
const char* tag;
int sz;
radialMethod tagHandler;
+ radialInheritMethod tagInheritHandler;
radialMethodRecalc tagRecalc;
+ radialMethodRecalc tagInheritedRecalc;
+ SvgGradientFlags flag;
} radialTags[] = {
- RADIAL_DEF(cx, Cx),
- RADIAL_DEF(cy, Cy),
- RADIAL_DEF(fx, Fx),
- RADIAL_DEF(fy, Fy),
- RADIAL_DEF(r, R)
+ RADIAL_DEF(cx, Cx, SvgGradientFlags::Cx),
+ RADIAL_DEF(cy, Cy, SvgGradientFlags::Cy),
+ RADIAL_DEF(fx, Fx, SvgGradientFlags::Fx),
+ RADIAL_DEF(fy, Fy, SvgGradientFlags::Fy),
+ RADIAL_DEF(r, R, SvgGradientFlags::R)
};
@@ -2414,6 +2259,7 @@ static bool _attrParseRadialGradientNode(void* data, const char* key, const char
for (unsigned int i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) {
if (radialTags[i].sz - 1 == sz && !strncmp(radialTags[i].tag, key, sz)) {
radialTags[i].tagHandler(loader, radial, value);
+ grad->flags = (grad->flags | radialTags[i].flag);
return true;
}
}
@@ -2423,11 +2269,13 @@ static bool _attrParseRadialGradientNode(void* data, const char* key, const char
grad->id = _copyId(value);
} else if (!strcmp(key, "spreadMethod")) {
grad->spread = _parseSpreadValue(value);
+ grad->flags = (grad->flags | SvgGradientFlags::SpreadMethod);
} else if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) {
if (grad->ref && value) free(grad->ref);
grad->ref = _idFromHref(value);
} else if (!strcmp(key, "gradientUnits")) {
if (!strcmp(value, "userSpaceOnUse")) grad->userSpace = true;
+ grad->flags = (grad->flags | SvgGradientFlags::GradientUnits);
} else if (!strcmp(key, "gradientTransform")) {
grad->transform = _parseTransformationMatrix(value);
} else {
@@ -2443,6 +2291,7 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char
auto grad = (SvgStyleGradient*)(calloc(1, sizeof(SvgStyleGradient)));
loader->svgParse->styleGrad = grad;
+ grad->flags = SvgGradientFlags::None;
grad->type = SvgGradientType::Radial;
grad->userSpace = false;
grad->radial = (SvgRadialGradient*)calloc(1, sizeof(SvgRadialGradient));
@@ -2485,10 +2334,10 @@ static bool _attrParseStopsStyle(void* data, const char* key, const char* value)
if (!strcmp(key, "stop-opacity")) {
stop->a = _toOpacity(value);
- loader->svgParse->flags = (SvgStopStyleFlags)((int)loader->svgParse->flags | (int)SvgStopStyleFlags::StopOpacity);
+ loader->svgParse->flags = (loader->svgParse->flags | SvgStopStyleFlags::StopOpacity);
} else if (!strcmp(key, "stop-color")) {
_toColor(value, &stop->r, &stop->g, &stop->b, nullptr);
- loader->svgParse->flags = (SvgStopStyleFlags)((int)loader->svgParse->flags | (int)SvgStopStyleFlags::StopColor);
+ loader->svgParse->flags = (loader->svgParse->flags | SvgStopStyleFlags::StopColor);
} else {
return false;
}
@@ -2505,11 +2354,11 @@ static bool _attrParseStops(void* data, const char* key, const char* value)
if (!strcmp(key, "offset")) {
stop->offset = _toOffset(value);
} else if (!strcmp(key, "stop-opacity")) {
- if (!((int)loader->svgParse->flags & (int)SvgStopStyleFlags::StopOpacity)) {
+ if (!(loader->svgParse->flags & SvgStopStyleFlags::StopOpacity)) {
stop->a = _toOpacity(value);
}
} else if (!strcmp(key, "stop-color")) {
- if (!((int)loader->svgParse->flags & (int)SvgStopStyleFlags::StopColor)) {
+ if (!(loader->svgParse->flags & SvgStopStyleFlags::StopColor)) {
_toColor(value, &stop->r, &stop->g, &stop->b, nullptr);
}
} else if (!strcmp(key, "style")) {
@@ -2570,13 +2419,82 @@ static void _recalcLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear
}
+static void _recalcInheritedLinearX1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
+{
+ if (!linear->isX1Percentage) {
+ if (userSpace) linear->x1 /= loader->svgParse->global.w;
+ else linear->x1 *= loader->svgParse->global.w;
+ }
+}
+
+
+static void _recalcInheritedLinearX2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
+{
+ if (!linear->isX2Percentage) {
+ if (userSpace) linear->x2 /= loader->svgParse->global.w;
+ else linear->x2 *= loader->svgParse->global.w;
+ }
+}
+
+
+static void _recalcInheritedLinearY1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
+{
+ if (!linear->isY1Percentage) {
+ if (userSpace) linear->y1 /= loader->svgParse->global.h;
+ else linear->y1 *= loader->svgParse->global.h;
+ }
+}
+
+
+static void _recalcInheritedLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
+{
+ if (!linear->isY2Percentage) {
+ if (userSpace) linear->y2 /= loader->svgParse->global.h;
+ else linear->y2 *= loader->svgParse->global.h;
+ }
+}
+
+
+static void _inheritLinearX1Attr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->linear->x1 = from->linear->x1;
+ to->linear->isX1Percentage = from->linear->isX1Percentage;
+ to->flags = (to->flags | SvgGradientFlags::X1);
+}
+
+
+static void _inheritLinearX2Attr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->linear->x2 = from->linear->x2;
+ to->linear->isX2Percentage = from->linear->isX2Percentage;
+ to->flags = (to->flags | SvgGradientFlags::X2);
+}
+
+
+static void _inheritLinearY1Attr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->linear->y1 = from->linear->y1;
+ to->linear->isY1Percentage = from->linear->isY1Percentage;
+ to->flags = (to->flags | SvgGradientFlags::Y1);
+}
+
+
+static void _inheritLinearY2Attr(SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ to->linear->y2 = from->linear->y2;
+ to->linear->isY2Percentage = from->linear->isY2Percentage;
+ to->flags = (to->flags | SvgGradientFlags::Y2);
+}
+
+
typedef void (*Linear_Method)(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value);
+typedef void (*Linear_Inherit_Method)(SvgStyleGradient* to, SvgStyleGradient* from);
typedef void (*Linear_Method_Recalc)(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace);
-#define LINEAR_DEF(Name, Name1) \
+#define LINEAR_DEF(Name, Name1, Flag) \
{ \
-#Name, sizeof(#Name), _handleLinear##Name1##Attr, _recalcLinear##Name1##Attr \
+#Name, sizeof(#Name), _handleLinear##Name1##Attr, _inheritLinear##Name1##Attr, _recalcLinear##Name1##Attr, _recalcInheritedLinear##Name1##Attr, Flag \
}
@@ -2585,12 +2503,15 @@ static constexpr struct
const char* tag;
int sz;
Linear_Method tagHandler;
+ Linear_Inherit_Method tagInheritHandler;
Linear_Method_Recalc tagRecalc;
+ Linear_Method_Recalc tagInheritedRecalc;
+ SvgGradientFlags flag;
} linear_tags[] = {
- LINEAR_DEF(x1, X1),
- LINEAR_DEF(y1, Y1),
- LINEAR_DEF(x2, X2),
- LINEAR_DEF(y2, Y2)
+ LINEAR_DEF(x1, X1, SvgGradientFlags::X1),
+ LINEAR_DEF(y1, Y1, SvgGradientFlags::Y1),
+ LINEAR_DEF(x2, X2, SvgGradientFlags::X2),
+ LINEAR_DEF(y2, Y2, SvgGradientFlags::Y2)
};
@@ -2604,6 +2525,7 @@ static bool _attrParseLinearGradientNode(void* data, const char* key, const char
for (unsigned int i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) {
if (linear_tags[i].sz - 1 == sz && !strncmp(linear_tags[i].tag, key, sz)) {
linear_tags[i].tagHandler(loader, linear, value);
+ grad->flags = (grad->flags | linear_tags[i].flag);
return true;
}
}
@@ -2613,11 +2535,13 @@ static bool _attrParseLinearGradientNode(void* data, const char* key, const char
grad->id = _copyId(value);
} else if (!strcmp(key, "spreadMethod")) {
grad->spread = _parseSpreadValue(value);
+ grad->flags = (grad->flags | SvgGradientFlags::SpreadMethod);
} else if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) {
if (grad->ref && value) free(grad->ref);
grad->ref = _idFromHref(value);
} else if (!strcmp(key, "gradientUnits")) {
if (!strcmp(value, "userSpaceOnUse")) grad->userSpace = true;
+ grad->flags = (grad->flags | SvgGradientFlags::GradientUnits);
} else if (!strcmp(key, "gradientTransform")) {
grad->transform = _parseTransformationMatrix(value);
} else {
@@ -2633,6 +2557,7 @@ static SvgStyleGradient* _createLinearGradient(SvgLoaderData* loader, const char
auto grad = (SvgStyleGradient*)(calloc(1, sizeof(SvgStyleGradient)));
loader->svgParse->styleGrad = grad;
+ grad->flags = SvgGradientFlags::None;
grad->type = SvgGradientType::Linear;
grad->userSpace = false;
grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
@@ -2692,6 +2617,371 @@ static GradientFactoryMethod _findGradientFactory(const char* name)
}
+static void _cloneGradStops(Array<Fill::ColorStop>& dst, const Array<Fill::ColorStop>& src)
+{
+ for (uint32_t i = 0; i < src.count; ++i) {
+ dst.push(src.data[i]);
+ }
+}
+
+
+static void _inheritGradient(SvgLoaderData* loader, SvgStyleGradient* to, SvgStyleGradient* from)
+{
+ if (!to || !from) return;
+
+ if (!(to->flags & SvgGradientFlags::SpreadMethod) && (from->flags & SvgGradientFlags::SpreadMethod)) {
+ to->spread = from->spread;
+ to->flags = (to->flags | SvgGradientFlags::SpreadMethod);
+ }
+ bool gradUnitSet = (to->flags & SvgGradientFlags::GradientUnits);
+ if (!(to->flags & SvgGradientFlags::GradientUnits) && (from->flags & SvgGradientFlags::GradientUnits)) {
+ to->userSpace = from->userSpace;
+ to->flags = (to->flags | SvgGradientFlags::GradientUnits);
+ }
+
+ if (!to->transform && from->transform) {
+ to->transform = (Matrix*)malloc(sizeof(Matrix));
+ if (to->transform) memcpy(to->transform, from->transform, sizeof(Matrix));
+ }
+
+ if (to->type == SvgGradientType::Linear && from->type == SvgGradientType::Linear) {
+ for (unsigned int i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) {
+ bool coordSet = to->flags & linear_tags[i].flag;
+ if (!(to->flags & linear_tags[i].flag) && (from->flags & linear_tags[i].flag)) {
+ linear_tags[i].tagInheritHandler(to, from);
+ }
+
+ //GradUnits not set directly, coord set
+ if (!gradUnitSet && coordSet) {
+ linear_tags[i].tagRecalc(loader, to->linear, to->userSpace);
+ }
+ //GradUnits set, coord not set directly
+ if (to->userSpace == from->userSpace) continue;
+ if (gradUnitSet && !coordSet) {
+ linear_tags[i].tagInheritedRecalc(loader, to->linear, to->userSpace);
+ }
+ }
+ } else if (to->type == SvgGradientType::Radial && from->type == SvgGradientType::Radial) {
+ for (unsigned int i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) {
+ bool coordSet = (to->flags & radialTags[i].flag);
+ if (!(to->flags & radialTags[i].flag) && (from->flags & radialTags[i].flag)) {
+ radialTags[i].tagInheritHandler(to, from);
+ }
+
+ //GradUnits not set directly, coord set
+ if (!gradUnitSet && coordSet) {
+ radialTags[i].tagRecalc(loader, to->radial, to->userSpace);
+ }
+ //GradUnits set, coord not set directly
+ if (to->userSpace == from->userSpace) continue;
+ if (gradUnitSet && !coordSet) {
+ radialTags[i].tagInheritedRecalc(loader, to->radial, to->userSpace);
+ }
+ }
+ }
+
+ if (to->stops.count == 0) _cloneGradStops(to->stops, from->stops);
+}
+
+
+static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
+{
+ if (!from) return nullptr;
+
+ auto grad = (SvgStyleGradient*)(calloc(1, sizeof(SvgStyleGradient)));
+ if (!grad) return nullptr;
+
+ grad->type = from->type;
+ grad->id = from->id ? _copyId(from->id) : nullptr;
+ grad->ref = from->ref ? _copyId(from->ref) : nullptr;
+ grad->spread = from->spread;
+ grad->userSpace = from->userSpace;
+ grad->flags = from->flags;
+
+ if (from->transform) {
+ grad->transform = (Matrix*)calloc(1, sizeof(Matrix));
+ if (grad->transform) memcpy(grad->transform, from->transform, sizeof(Matrix));
+ }
+
+ if (grad->type == SvgGradientType::Linear) {
+ grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
+ if (!grad->linear) goto error_grad_alloc;
+ memcpy(grad->linear, from->linear, sizeof(SvgLinearGradient));
+ } else if (grad->type == SvgGradientType::Radial) {
+ grad->radial = (SvgRadialGradient*)calloc(1, sizeof(SvgRadialGradient));
+ if (!grad->radial) goto error_grad_alloc;
+ memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient));
+ }
+
+ _cloneGradStops(grad->stops, from->stops);
+
+ return grad;
+
+ error_grad_alloc:
+ if (grad) {
+ grad->clear();
+ free(grad);
+ }
+ return nullptr;
+}
+
+
+static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* parent)
+{
+ if (parent == nullptr) return;
+ //Inherit the property of parent if not present in child.
+ if (!child->curColorSet) {
+ child->color = parent->color;
+ child->curColorSet = parent->curColorSet;
+ }
+ if (!(child->flags & SvgStyleFlags::PaintOrder)) {
+ child->paintOrder = parent->paintOrder;
+ }
+ //Fill
+ if (!(child->fill.flags & SvgFillFlags::Paint)) {
+ child->fill.paint.color = parent->fill.paint.color;
+ child->fill.paint.none = parent->fill.paint.none;
+ child->fill.paint.curColor = parent->fill.paint.curColor;
+ if (parent->fill.paint.url) {
+ if (child->fill.paint.url) free(child->fill.paint.url);
+ child->fill.paint.url = _copyId(parent->fill.paint.url);
+ }
+ }
+ if (!(child->fill.flags & SvgFillFlags::Opacity)) {
+ child->fill.opacity = parent->fill.opacity;
+ }
+ if (!(child->fill.flags & SvgFillFlags::FillRule)) {
+ child->fill.fillRule = parent->fill.fillRule;
+ }
+ //Stroke
+ if (!(child->stroke.flags & SvgStrokeFlags::Paint)) {
+ child->stroke.paint.color = parent->stroke.paint.color;
+ child->stroke.paint.none = parent->stroke.paint.none;
+ child->stroke.paint.curColor = parent->stroke.paint.curColor;
+ if (parent->stroke.paint.url) {
+ if (child->stroke.paint.url) free(child->stroke.paint.url);
+ child->stroke.paint.url = _copyId(parent->stroke.paint.url);
+ }
+ }
+ if (!(child->stroke.flags & SvgStrokeFlags::Opacity)) {
+ child->stroke.opacity = parent->stroke.opacity;
+ }
+ if (!(child->stroke.flags & SvgStrokeFlags::Width)) {
+ child->stroke.width = parent->stroke.width;
+ }
+ if (!(child->stroke.flags & SvgStrokeFlags::Dash)) {
+ if (parent->stroke.dash.array.count > 0) {
+ child->stroke.dash.array.clear();
+ child->stroke.dash.array.reserve(parent->stroke.dash.array.count);
+ for (uint32_t i = 0; i < parent->stroke.dash.array.count; ++i) {
+ child->stroke.dash.array.push(parent->stroke.dash.array.data[i]);
+ }
+ }
+ }
+ if (!(child->stroke.flags & SvgStrokeFlags::Cap)) {
+ child->stroke.cap = parent->stroke.cap;
+ }
+ if (!(child->stroke.flags & SvgStrokeFlags::Join)) {
+ child->stroke.join = parent->stroke.join;
+ }
+}
+
+
+static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from)
+{
+ if (from == nullptr) return;
+ //Copy the properties of 'from' only if they were explicitly set (not the default ones).
+ if (from->curColorSet) {
+ to->color = from->color;
+ to->curColorSet = true;
+ }
+ if (from->flags & SvgStyleFlags::PaintOrder) {
+ to->paintOrder = from->paintOrder;
+ }
+ //Fill
+ to->fill.flags = (to->fill.flags | from->fill.flags);
+ if (from->fill.flags & SvgFillFlags::Paint) {
+ to->fill.paint.color = from->fill.paint.color;
+ to->fill.paint.none = from->fill.paint.none;
+ to->fill.paint.curColor = from->fill.paint.curColor;
+ if (from->fill.paint.url) {
+ if (to->fill.paint.url) free(to->fill.paint.url);
+ to->fill.paint.url = _copyId(from->fill.paint.url);
+ }
+ }
+ if (from->fill.flags & SvgFillFlags::Opacity) {
+ to->fill.opacity = from->fill.opacity;
+ }
+ if (from->fill.flags & SvgFillFlags::FillRule) {
+ to->fill.fillRule = from->fill.fillRule;
+ }
+ //Stroke
+ to->stroke.flags = (to->stroke.flags | from->stroke.flags);
+ if (from->stroke.flags & SvgStrokeFlags::Paint) {
+ to->stroke.paint.color = from->stroke.paint.color;
+ to->stroke.paint.none = from->stroke.paint.none;
+ to->stroke.paint.curColor = from->stroke.paint.curColor;
+ if (from->stroke.paint.url) {
+ if (to->stroke.paint.url) free(to->stroke.paint.url);
+ to->stroke.paint.url = _copyId(from->stroke.paint.url);
+ }
+ }
+ if (from->stroke.flags & SvgStrokeFlags::Opacity) {
+ to->stroke.opacity = from->stroke.opacity;
+ }
+ if (from->stroke.flags & SvgStrokeFlags::Width) {
+ to->stroke.width = from->stroke.width;
+ }
+ if (from->stroke.flags & SvgStrokeFlags::Dash) {
+ if (from->stroke.dash.array.count > 0) {
+ to->stroke.dash.array.clear();
+ to->stroke.dash.array.reserve(from->stroke.dash.array.count);
+ for (uint32_t i = 0; i < from->stroke.dash.array.count; ++i) {
+ to->stroke.dash.array.push(from->stroke.dash.array.data[i]);
+ }
+ }
+ }
+ if (from->stroke.flags & SvgStrokeFlags::Cap) {
+ to->stroke.cap = from->stroke.cap;
+ }
+ if (from->stroke.flags & SvgStrokeFlags::Join) {
+ to->stroke.join = from->stroke.join;
+ }
+}
+
+
+static void _copyAttr(SvgNode* to, const SvgNode* from)
+{
+ //Copy matrix attribute
+ if (from->transform) {
+ to->transform = (Matrix*)malloc(sizeof(Matrix));
+ if (to->transform) *to->transform = *from->transform;
+ }
+ //Copy style attribute
+ _styleCopy(to->style, from->style);
+ to->style->flags = (to->style->flags | from->style->flags);
+ if (from->style->clipPath.url) {
+ if (to->style->clipPath.url) free(to->style->clipPath.url);
+ to->style->clipPath.url = strdup(from->style->clipPath.url);
+ }
+ if (from->style->mask.url) {
+ if (to->style->mask.url) free(to->style->mask.url);
+ to->style->mask.url = strdup(from->style->mask.url);
+ }
+
+ //Copy node attribute
+ switch (from->type) {
+ case SvgNodeType::Circle: {
+ to->node.circle.cx = from->node.circle.cx;
+ to->node.circle.cy = from->node.circle.cy;
+ to->node.circle.r = from->node.circle.r;
+ break;
+ }
+ case SvgNodeType::Ellipse: {
+ to->node.ellipse.cx = from->node.ellipse.cx;
+ to->node.ellipse.cy = from->node.ellipse.cy;
+ to->node.ellipse.rx = from->node.ellipse.rx;
+ to->node.ellipse.ry = from->node.ellipse.ry;
+ break;
+ }
+ case SvgNodeType::Rect: {
+ to->node.rect.x = from->node.rect.x;
+ to->node.rect.y = from->node.rect.y;
+ to->node.rect.w = from->node.rect.w;
+ to->node.rect.h = from->node.rect.h;
+ to->node.rect.rx = from->node.rect.rx;
+ to->node.rect.ry = from->node.rect.ry;
+ to->node.rect.hasRx = from->node.rect.hasRx;
+ to->node.rect.hasRy = from->node.rect.hasRy;
+ break;
+ }
+ case SvgNodeType::Line: {
+ to->node.line.x1 = from->node.line.x1;
+ to->node.line.y1 = from->node.line.y1;
+ to->node.line.x2 = from->node.line.x2;
+ to->node.line.y2 = from->node.line.y2;
+ break;
+ }
+ case SvgNodeType::Path: {
+ if (from->node.path.path) {
+ if (to->node.path.path) free(to->node.path.path);
+ to->node.path.path = strdup(from->node.path.path);
+ }
+ break;
+ }
+ case SvgNodeType::Polygon: {
+ if ((to->node.polygon.pointsCount = from->node.polygon.pointsCount)) {
+ to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float));
+ memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float));
+ }
+ break;
+ }
+ case SvgNodeType::Polyline: {
+ if ((to->node.polyline.pointsCount = from->node.polyline.pointsCount)) {
+ to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float));
+ memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float));
+ }
+ break;
+ }
+ case SvgNodeType::Image: {
+ to->node.image.x = from->node.image.x;
+ to->node.image.y = from->node.image.y;
+ to->node.image.w = from->node.image.w;
+ to->node.image.h = from->node.image.h;
+ if (from->node.image.href) {
+ if (to->node.image.href) free(to->node.image.href);
+ to->node.image.href = strdup(from->node.image.href);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+
+static void _cloneNode(SvgNode* from, SvgNode* parent, int depth)
+{
+ /* Exception handling: Prevent invalid SVG data input.
+ The size is the arbitrary value, we need an experimental size. */
+ if (depth == 8192) {
+ TVGERR("SVG", "Infinite recursive call - stopped after %d calls! Svg file may be incorrectly formatted.", depth);
+ return;
+ }
+
+ SvgNode* newNode;
+ if (!from || !parent || from == parent) return;
+
+ newNode = _createNode(parent, from->type);
+ if (!newNode) return;
+
+ _styleInherit(newNode->style, parent->style);
+ _copyAttr(newNode, from);
+
+ auto child = from->child.data;
+ for (uint32_t i = 0; i < from->child.count; ++i, ++child) {
+ _cloneNode(*child, newNode, depth + 1);
+ }
+}
+
+
+static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
+{
+ for (uint32_t i = 0; i < cloneNodes->count; ++i) {
+ auto nodeIdPair = cloneNodes->data[i];
+ auto defs = _getDefsNode(nodeIdPair.node);
+ auto nodeFrom = _findNodeById(defs, nodeIdPair.id);
+ if (!nodeFrom) nodeFrom = _findNodeById(doc, nodeIdPair.id);
+ _cloneNode(nodeFrom, nodeIdPair.node, 0);
+ if (nodeFrom && nodeFrom->type == SvgNodeType::Symbol && nodeIdPair.node->type == SvgNodeType::Use) {
+ nodeIdPair.node->node.use.symbol = nodeFrom;
+ }
+ free(nodeIdPair.id);
+ }
+}
+
+
static constexpr struct
{
const char* tag;
@@ -2738,6 +3028,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
//Parse the empty tag
attrs = content;
while ((attrs != nullptr) && *attrs != '>') attrs++;
+ if (empty) attrs--;
}
if (attrs) {
@@ -2942,7 +3233,7 @@ static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle)
}
-static SvgStyleGradient* _gradientDup(Array<SvgStyleGradient*>* gradients, const char* id)
+static SvgStyleGradient* _gradientDup(SvgLoaderData* loader, Array<SvgStyleGradient*>* gradients, const char* id)
{
SvgStyleGradient* result = nullptr;
@@ -2960,8 +3251,7 @@ static SvgStyleGradient* _gradientDup(Array<SvgStyleGradient*>* gradients, const
gradList = gradients->data;
for (uint32_t i = 0; i < gradients->count; ++i) {
if ((*gradList)->id && !strcmp((*gradList)->id, result->ref)) {
- if (result->stops.count == 0) _cloneGradStops(result->stops, (*gradList)->stops);
- //TODO: Properly inherit other property
+ _inheritGradient(loader, result, *gradList);
break;
}
++gradList;
@@ -2972,27 +3262,33 @@ static SvgStyleGradient* _gradientDup(Array<SvgStyleGradient*>* gradients, const
}
-static void _updateGradient(SvgNode* node, Array<SvgStyleGradient*>* gradients)
+static void _updateGradient(SvgLoaderData* loader, SvgNode* node, Array<SvgStyleGradient*>* gradients)
{
if (node->child.count > 0) {
auto child = node->child.data;
for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
- _updateGradient(*child, gradients);
+ _updateGradient(loader, *child, gradients);
}
} else {
if (node->style->fill.paint.url) {
- if (node->style->fill.paint.gradient) {
- node->style->fill.paint.gradient->clear();
- free(node->style->fill.paint.gradient);
+ auto newGrad = _gradientDup(loader, gradients, node->style->fill.paint.url);
+ if (newGrad) {
+ if (node->style->fill.paint.gradient) {
+ node->style->fill.paint.gradient->clear();
+ free(node->style->fill.paint.gradient);
+ }
+ node->style->fill.paint.gradient = newGrad;
}
- node->style->fill.paint.gradient = _gradientDup(gradients, node->style->fill.paint.url);
}
if (node->style->stroke.paint.url) {
- if (node->style->stroke.paint.gradient) {
- node->style->stroke.paint.gradient->clear();
- free(node->style->stroke.paint.gradient);
+ auto newGrad = _gradientDup(loader, gradients, node->style->stroke.paint.url);
+ if (newGrad) {
+ if (node->style->stroke.paint.gradient) {
+ node->style->stroke.paint.gradient->clear();
+ free(node->style->stroke.paint.gradient);
+ }
+ node->style->stroke.paint.gradient = newGrad;
}
- node->style->stroke.paint.gradient = _gradientDup(gradients, node->style->stroke.paint.url);
}
}
}
@@ -3181,7 +3477,8 @@ SvgLoader::~SvgLoader()
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) {
+ if ((viewFlag & SvgViewFlag::Viewbox) && (fabsf(vw) <= FLT_EPSILON || fabsf(vh) <= FLT_EPSILON)) {
+ TVGLOG("SVG", "The <viewBox> width and/or height set to 0 - rendering disabled.");
root = Scene::gen();
return;
}
@@ -3199,12 +3496,12 @@ void SvgLoader::run(unsigned tid)
_updateComposite(loaderData.doc, loaderData.doc);
if (defs) _updateComposite(loaderData.doc, defs);
- if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients);
- if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients);
-
_updateStyle(loaderData.doc, nullptr);
+
+ if (loaderData.gradients.count > 0) _updateGradient(&loaderData, loaderData.doc, &loaderData.gradients);
+ if (defs) _updateGradient(&loaderData, loaderData.doc, &defs->node.defs.gradients);
}
- root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, align, meetOrSlice, svgPath);
+ root = svgSceneBuild(loaderData, {vx, vy, vw, vh}, w, h, align, meetOrSlice, svgPath, viewFlag);
}
@@ -3217,34 +3514,78 @@ bool SvgLoader::header()
if (!loaderData.svgParse) return false;
loaderData.svgParse->flags = SvgStopStyleFlags::StopDefault;
+ viewFlag = SvgViewFlag::None;
simpleXmlParse(content, size, true, _svgLoaderParserForValidCheck, &(loaderData));
if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) {
- //Return the brief resource info such as viewbox:
- vx = loaderData.doc->node.doc.vx;
- vy = loaderData.doc->node.doc.vy;
- w = vw = loaderData.doc->node.doc.vw;
- h = vh = loaderData.doc->node.doc.vh;
-
- //Override size
- if (loaderData.doc->node.doc.w > 0) {
+ viewFlag = loaderData.doc->node.doc.viewFlag;
+ align = loaderData.doc->node.doc.align;
+ meetOrSlice = loaderData.doc->node.doc.meetOrSlice;
+
+ if (viewFlag & SvgViewFlag::Viewbox) {
+ vx = loaderData.doc->node.doc.vx;
+ vy = loaderData.doc->node.doc.vy;
+ vw = loaderData.doc->node.doc.vw;
+ vh = loaderData.doc->node.doc.vh;
+
+ if (viewFlag & SvgViewFlag::Width) w = loaderData.doc->node.doc.w;
+ else {
+ w = loaderData.doc->node.doc.vw;
+ if (viewFlag & SvgViewFlag::WidthInPercent) {
+ w *= loaderData.doc->node.doc.w;
+ viewFlag = (viewFlag ^ SvgViewFlag::WidthInPercent);
+ }
+ viewFlag = (viewFlag | SvgViewFlag::Width);
+ }
+ if (viewFlag & SvgViewFlag::Height) h = loaderData.doc->node.doc.h;
+ else {
+ h = loaderData.doc->node.doc.vh;
+ if (viewFlag & SvgViewFlag::HeightInPercent) {
+ h *= loaderData.doc->node.doc.h;
+ viewFlag = (viewFlag ^ SvgViewFlag::HeightInPercent);
+ }
+ viewFlag = (viewFlag | SvgViewFlag::Height);
+ }
+ //In case no viewbox and width/height data is provided the completion of loading
+ //has to be forced, in order to establish this data based on the whole picture.
+ } else {
+ //Before loading, set default viewbox & size if they are empty
+ vx = vy = 0.0f;
+ if (viewFlag & SvgViewFlag::Width) {
+ vw = w = loaderData.doc->node.doc.w;
+ } else {
+ vw = 1.0f;
+ if (viewFlag & SvgViewFlag::WidthInPercent) {
+ w = loaderData.doc->node.doc.w;
+ } else w = 1.0f;
+ }
+
+ if (viewFlag & SvgViewFlag::Height) {
+ vh = h = loaderData.doc->node.doc.h;
+ } else {
+ vh = 1.0f;
+ if (viewFlag & SvgViewFlag::HeightInPercent) {
+ h = loaderData.doc->node.doc.h;
+ } else h = 1.0f;
+ }
+
+ run(0);
+
+ //Override viewbox & size again after svg loading.
+ vx = loaderData.doc->node.doc.vx;
+ vy = loaderData.doc->node.doc.vy;
+ vw = loaderData.doc->node.doc.vw;
+ vh = loaderData.doc->node.doc.vh;
w = loaderData.doc->node.doc.w;
- if (vw < FLT_EPSILON) vw = w;
- }
- if (loaderData.doc->node.doc.h > 0) {
h = loaderData.doc->node.doc.h;
- if (vh < FLT_EPSILON) vh = h;
}
- align = loaderData.doc->node.doc.align;
- meetOrSlice = loaderData.doc->node.doc.meetOrSlice;
- } else {
- TVGLOG("SVG", "No SVG File. There is no <svg/>");
- return false;
+ return true;
}
- return true;
+ TVGLOG("SVG", "No SVG File. There is no <svg/>");
+ return false;
}
@@ -3304,6 +3645,9 @@ bool SvgLoader::read()
{
if (!content || size == 0) return false;
+ //the loading has been already completed in header()
+ if (root) return true;
+
TaskScheduler::request(this);
return true;
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h
index c6fdde55af..5c74184ec8 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef _TVG_SVG_LOADER_H_
#define _TVG_SVG_LOADER_H_
@@ -50,9 +51,9 @@ public:
unique_ptr<Paint> paint() override;
private:
+ SvgViewFlag viewFlag = SvgViewFlag::None;
AspectRatioAlign align = AspectRatioAlign::XMidYMid;
AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet;
- bool renderingDisabled = false;
bool header();
void clear();
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
index 3588cabf0b..dec9fadebe 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#ifndef _TVG_SVG_LOADER_COMMON_H_
#define _TVG_SVG_LOADER_COMMON_H_
@@ -79,6 +80,16 @@ enum class SvgFillFlags
ClipPath = 0x16
};
+constexpr bool operator &(SvgFillFlags a, SvgFillFlags b)
+{
+ return int(a) & int(b);
+}
+
+constexpr SvgFillFlags operator |(SvgFillFlags a, SvgFillFlags b)
+{
+ return SvgFillFlags(int(a) | int(b));
+}
+
enum class SvgStrokeFlags
{
Paint = 0x1,
@@ -91,6 +102,17 @@ enum class SvgStrokeFlags
Dash = 0x80,
};
+constexpr bool operator &(SvgStrokeFlags a, SvgStrokeFlags b)
+{
+ return int(a) & int(b);
+}
+
+constexpr SvgStrokeFlags operator |(SvgStrokeFlags a, SvgStrokeFlags b)
+{
+ return SvgStrokeFlags(int(a) | int(b));
+}
+
+
enum class SvgGradientType
{
Linear,
@@ -114,9 +136,20 @@ enum class SvgStyleFlags
ClipPath = 0x1000,
Mask = 0x2000,
MaskType = 0x4000,
- Display = 0x8000
+ Display = 0x8000,
+ PaintOrder = 0x10000
};
+constexpr bool operator &(SvgStyleFlags a, SvgStyleFlags b)
+{
+ return int(a) & int(b);
+}
+
+constexpr SvgStyleFlags operator |(SvgStyleFlags a, SvgStyleFlags b)
+{
+ return SvgStyleFlags(int(a) | int(b));
+}
+
enum class SvgStopStyleFlags
{
StopDefault = 0x0,
@@ -124,6 +157,42 @@ enum class SvgStopStyleFlags
StopColor = 0x02
};
+constexpr bool operator &(SvgStopStyleFlags a, SvgStopStyleFlags b)
+{
+ return int(a) & int(b);
+}
+
+constexpr SvgStopStyleFlags operator |(SvgStopStyleFlags a, SvgStopStyleFlags b)
+{
+ return SvgStopStyleFlags(int(a) | int(b));
+}
+
+enum class SvgGradientFlags
+{
+ None = 0x0,
+ GradientUnits = 0x1,
+ SpreadMethod = 0x2,
+ X1 = 0x4,
+ X2 = 0x8,
+ Y1 = 0x10,
+ Y2 = 0x20,
+ Cx = 0x40,
+ Cy = 0x80,
+ R = 0x100,
+ Fx = 0x200,
+ Fy = 0x400
+};
+
+constexpr bool operator &(SvgGradientFlags a, SvgGradientFlags b)
+{
+ return int(a) & int(b);
+}
+
+constexpr SvgGradientFlags operator |(SvgGradientFlags a, SvgGradientFlags b)
+{
+ return SvgGradientFlags(int(a) | int(b));
+}
+
enum class SvgFillRule
{
Winding = 0,
@@ -145,6 +214,31 @@ enum class SvgParserLengthType
Other
};
+enum class SvgViewFlag
+{
+ None = 0x0,
+ Width = 0x01, //viewPort width
+ Height = 0x02, //viewPort height
+ Viewbox = 0x04, //viewBox x,y,w,h - used only if all 4 are correctly set
+ WidthInPercent = 0x08,
+ HeightInPercent = 0x10
+};
+
+constexpr bool operator &(SvgViewFlag a, SvgViewFlag b)
+{
+ return static_cast<int>(a) & static_cast<int>(b);
+}
+
+constexpr SvgViewFlag operator |(SvgViewFlag a, SvgViewFlag b)
+{
+ return SvgViewFlag(int(a) | int(b));
+}
+
+constexpr SvgViewFlag operator ^(SvgViewFlag a, SvgViewFlag b)
+{
+ return SvgViewFlag(int(a) ^ int(b));
+}
+
enum class AspectRatioAlign
{
None,
@@ -167,12 +261,13 @@ enum class AspectRatioMeetOrSlice
struct SvgDocNode
{
- float w;
- float h;
+ float w; //unit: point or in percentage see: SvgViewFlag
+ float h; //unit: point or in percentage see: SvgViewFlag
float vx;
float vy;
float vw;
float vh;
+ SvgViewFlag viewFlag;
SvgNode* defs;
SvgNode* style;
AspectRatioAlign align;
@@ -339,6 +434,7 @@ struct SvgStyleGradient
SvgLinearGradient* linear;
Matrix* transform;
Array<Fill::ColorStop> stops;
+ SvgGradientFlags flags;
bool userSpace;
void clear()
@@ -384,6 +480,7 @@ struct SvgStyleProperty
SvgColor color;
bool curColorSet;
char* cssClass;
+ bool paintOrder; //true if default (fill, stroke), false otherwise
SvgStyleFlags flags;
};
@@ -456,6 +553,11 @@ struct SvgLoaderData
bool style = false;
};
+struct Box
+{
+ float x, y, w, h;
+};
+
/*
* https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strtof-strtod-l-wcstod-wcstod-l?view=vs-2017
*
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
index a09a2797d0..e044931b51 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -52,7 +52,6 @@
#include <cstring>
#include <math.h>
-#include <clocale>
#include <ctype.h>
#include "tvgSvgLoaderCommon.h"
#include "tvgSvgPath.h"
@@ -545,11 +544,6 @@ bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point
char cmd = 0;
bool isQuadratic = false;
char* path = (char*)svgPath;
- char* curLocale;
-
- curLocale = setlocale(LC_NUMERIC, NULL);
- if (curLocale) curLocale = strdup(curLocale);
- setlocale(LC_NUMERIC, "POSIX");
while ((path[0] != '\0')) {
path = _nextCommand(path, &cmd, numberArray, &numberCount);
@@ -557,8 +551,5 @@ bool svgPathToTvgPath(const char* svgPath, Array<PathCommand>& cmds, Array<Point
if (!_processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &startPoint, &isQuadratic)) break;
}
- setlocale(LC_NUMERIC, curLocale);
- if (curLocale) free(curLocale);
-
return true;
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h
index 8f5f9035dc..4199088dc1 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
index 254ee2d008..c5e5df893e 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -61,12 +61,6 @@
/* Internal Class Implementation */
/************************************************************************/
-struct Box
-{
- float x, y, w, h;
-};
-
-
static bool _appendShape(SvgNode* node, Shape* shape, const Box& vBox, const string& svgPath);
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite = nullptr);
@@ -255,7 +249,6 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
node->style->clipPath.applying = true;
auto comp = Shape::gen();
- if (node->transform) comp->transform(*node->transform);
auto child = compNode->child.data;
auto valid = false; //Composite only when valid shapes are existed
@@ -264,6 +257,12 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
if (_appendChildShape(*child, comp.get(), vBox, svgPath)) valid = true;
}
+ if (node->transform) {
+ auto m = comp->transform();
+ m = mathMultiply(node->transform, &m);
+ comp->transform(m);
+ }
+
if (valid) paint->composite(move(comp), CompositeMethod::ClipPath);
node->style->clipPath.applying = false;
@@ -331,6 +330,8 @@ static void _applyProperty(SvgNode* node, Shape* vg, const Box& vBox, const stri
//Apply the fill rule
vg->fill((tvg::FillRule)style->fill.fillRule);
+ //Rendering order
+ vg->order(!style->paintOrder);
//Apply node opacity
if (style->opacity < 255) vg->opacity(style->opacity);
@@ -444,9 +445,11 @@ enum class imageMimeTypeEncoding
base64 = 0x1,
utf8 = 0x2
};
+
constexpr imageMimeTypeEncoding operator|(imageMimeTypeEncoding a, imageMimeTypeEncoding b) {
return static_cast<imageMimeTypeEncoding>(static_cast<int>(a) | static_cast<int>(b));
}
+
constexpr bool operator&(imageMimeTypeEncoding a, imageMimeTypeEncoding b) {
return (static_cast<int>(a) & static_cast<int>(b));
}
@@ -755,24 +758,45 @@ static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox,
}
+static void _updateInvalidViewSize(const Scene* scene, Box& vBox, float& w, float& h, SvgViewFlag viewFlag)
+{
+ bool validWidth = (viewFlag & SvgViewFlag::Width);
+ bool validHeight = (viewFlag & SvgViewFlag::Height);
+
+ float x, y;
+ scene->bounds(&x, &y, &vBox.w, &vBox.h, false);
+ if (!validWidth && !validHeight) {
+ vBox.x = x;
+ vBox.y = y;
+ } else {
+ if (validWidth) vBox.w = w;
+ if (validHeight) vBox.h = h;
+ }
+
+ //the size would have 1x1 or percentage values.
+ if (!validWidth) w *= vBox.w;
+ if (!validHeight) h *= vBox.h;
+}
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
-unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath)
+unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag)
{
//TODO: aspect ratio is valid only if viewBox was set
- if (!node || (node->type != SvgNodeType::Doc)) return nullptr;
+ if (!loaderData.doc || (loaderData.doc->type != SvgNodeType::Doc)) return nullptr;
- Box vBox = {vx, vy, vw, vh};
- auto docNode = _sceneBuildHelper(node, vBox, svgPath, false, 0);
+ auto docNode = _sceneBuildHelper(loaderData.doc, vBox, svgPath, false, 0);
- if (!mathEqual(w, vw) || !mathEqual(h, vh)) {
+ if (!(viewFlag & SvgViewFlag::Viewbox)) _updateInvalidViewSize(docNode.get(), vBox, w, h, viewFlag);
+
+ if (!mathEqual(w, vBox.w) || !mathEqual(h, vBox.h)) {
Matrix m = _calculateAspectRatioMatrix(align, meetOrSlice, w, h, vBox);
docNode->transform(m);
- } else if (!mathZero(vx) || !mathZero(vy)) {
- docNode->translate(-vx, -vy);
+ } else if (!mathZero(vBox.x) || !mathZero(vBox.y)) {
+ docNode->translate(-vBox.x, -vBox.y);
}
auto viewBoxClip = Shape::gen();
@@ -786,5 +810,12 @@ unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, flo
auto root = Scene::gen();
root->push(move(compositeLayer));
+ loaderData.doc->node.doc.vx = vBox.x;
+ loaderData.doc->node.doc.vy = vBox.y;
+ loaderData.doc->node.doc.vw = vBox.w;
+ loaderData.doc->node.doc.vh = vBox.h;
+ loaderData.doc->node.doc.w = w;
+ loaderData.doc->node.doc.h = h;
+
return root;
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h
index 311f3c80e6..f6a60f850d 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -25,6 +25,6 @@
#include "tvgCommon.h"
-unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath);
+unique_ptr<Scene> svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag);
#endif //_TVG_SVG_SCENE_BUILDER_H_
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
index 7fb108bc21..12d20c9731 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
@@ -94,8 +94,8 @@ float svgUtilStrtof(const char *nPtr, char **endPtr)
if ((tolower(*(iter + 1)) == 'n') && (tolower(*(iter + 2)) == 'f')) iter += 3;
else goto error;
- if (tolower(*(iter + 3)) == 'i') {
- if ((tolower(*(iter + 4)) == 'n') && (tolower(*(iter + 5)) == 'i') && (tolower(*(iter + 6)) == 't') && (tolower(*(iter + 7)) == 'y')) iter += 5;
+ if (tolower(*(iter)) == 'i') {
+ if ((tolower(*(iter + 1)) == 'n') && (tolower(*(iter + 2)) == 'i') && (tolower(*(iter + 3)) == 't') && (tolower(*(iter + 4)) == 'y')) iter += 5;
else goto error;
}
if (endPtr) *endPtr = (char *)(iter);
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h
index b5e6e1bdb2..6f94367aeb 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
index 0e2c3fa141..77467e071b 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h
index e2761ca8da..7333bb09fb 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2020 - 2023 the ThorVG project. 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
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp b/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
index 01a39b6e17..2b89d6bb59 100644
--- a/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
#include <memory.h>
#ifdef _WIN32
@@ -357,27 +358,45 @@ 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;
+ switch (block.type) {
+ case TVG_TAG_PICTURE_RAW_IMAGE: {
+ if (block.length < 2 * SIZE(uint32_t)) return false;
- auto ptr = block.data;
- uint32_t w, h;
+ auto ptr = block.data;
+ uint32_t w, h;
- READ_UI32(&w, ptr);
- ptr += SIZE(uint32_t);
- READ_UI32(&h, ptr);
- ptr += SIZE(uint32_t);
+ 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;
+ 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;
- }
+ picture->load((uint32_t*) ptr, w, h, true);
- //Case2: Base Paint Properties
- if (_parsePaintProperty(block, picture)) return true;
+ return true;
+ }
+ case TVG_TAG_PICTURE_MESH: {
+ if (block.length < 1 * SIZE(uint32_t)) return false;
+
+ auto ptr = block.data;
+ uint32_t meshCnt;
+ READ_UI32(&meshCnt, ptr);
+ ptr += SIZE(uint32_t);
+
+ auto size = meshCnt * SIZE(Polygon);
+ if (block.length != SIZE(uint32_t) + size) return false;
+
+ picture->mesh((Polygon*) ptr, meshCnt);
+
+ return true;
+ }
+ //Base Paint Properties
+ default: {
+ if (_parsePaintProperty(block, picture)) return true;
+ }
+ }
//Vector Picture won't be requested since Saver replaces it with the Scene
return false;
@@ -414,7 +433,7 @@ static Paint* _parsePaint(TvgBinBlock baseBlock)
auto ptr = baseBlock.data;
- //2. Read Subsquent properties of the current paint.
+ //2. Read Subsequent properties of the current paint.
while (ptr < baseBlock.end) {
auto block = _readBlock(ptr);
if (block.end > baseBlock.end) return paint;
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h b/thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h
index a0762d0fcc..29fa1025b0 100644
--- a/thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgCommon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp
index 95d629d1f6..82c578e6d4 100644
--- a/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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
@@ -19,6 +19,7 @@
* 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"
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h
index 3ae841aa85..b98dff83b0 100644
--- a/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2021 - 2023 the ThorVG project. 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