ThorVG: Sync with upstream 0.8.0

This commit is contained in:
K. S. Ernest (iFire) Lee 2022-03-08 04:56:23 -08:00
parent 86b0faf2ec
commit f7a809603c
92 changed files with 870 additions and 227 deletions

View file

@ -399,7 +399,7 @@ License: Expat
Files: ./thirdparty/thorvg/
Comment: ThorVG
Copyright: 2020-2021, Samsung Electronics Co., Ltd.
Copyright: 2020-2022, Samsung Electronics Co., Ltd.
License: Expat
Files: ./thirdparty/tinyexr/

View file

@ -34,6 +34,7 @@ thirdparty_sources = [
"src/loaders/svg/tvgSvgSceneBuilder.cpp",
"src/loaders/svg/tvgSvgPath.cpp",
"src/loaders/svg/tvgSvgLoader.cpp",
"src/loaders/svg/tvgSvgCssStyle.cpp",
"src/loaders/tvg/tvgTvgBinInterpreter.cpp",
"src/loaders/tvg/tvgTvgLoader.cpp",
"src/loaders/jpg/tvgJpgLoader.cpp",

View file

@ -627,7 +627,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/Samsung/thorvg
- Version: 0.7.1 (d53eb2a880002cb770ace1c1ace9c5dfcfc28252, 2022)
- Version: 0.8.0 (41093c17b3cac440bdcc53f8b69abeb5734696b5, 2022)
- License: MIT
Files extracted from upstream source:

View file

@ -1,4 +1,4 @@
Hermet Park <chuneon.park@samsung.com>
Hermet Park <hermetpark@gmail.com>
Prudhvi Raj Vasireddi <prudhvi.raj@samsung.com>
Junsu Choi <jsuya.choi@samsung.com>
Pranay Samanta <pranay.ks@samsung.com>

View file

@ -1,4 +1,4 @@
Copyright (c) 2020 - 2021 notice for the ThorVG Project (see AUTHORS)
Copyright (c) 2020 - 2022 notice for the ThorVG Project (see AUTHORS)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -13,5 +13,5 @@
#define THORVG_JPG_LOADER_SUPPORT 1
#define THORVG_VERSION_STRING "0.7.1"
#define THORVG_VERSION_STRING "0.8.0"
#endif

View file

@ -145,8 +145,9 @@ enum class TVG_EXPORT CompositeMethod
{
None = 0, ///< No composition is applied.
ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered.
AlphaMask, ///< The pixels of the source and the target are alpha blended. As a result, only the part of the source, which intersects with the target is visible.
InvAlphaMask ///< The pixels of the source and the complement to the target's pixels are alpha blended. As a result, only the part of the source which is not covered by the target is visible.
AlphaMask, ///< The pixels of the source and the target are alpha blended. As a result, only the part of the source, which alpha intersects with the target is visible.
InvAlphaMask, ///< The pixels of the source and the complement to the target's pixels are alpha blended. As a result, only the part of the source which alpha is not covered by the target is visible.
LumaMask ///< @BETA_API The source pixels are converted to the grayscale (luma value) and alpha blended with the target. As a result, only the part of the source, which intersects with the target is visible.
};
/**

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -235,6 +235,7 @@ struct SwImage
struct SwBlender
{
uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
uint32_t (*lumaValue)(uint32_t c);
};
struct SwCompositor;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -47,6 +47,18 @@ static inline uint32_t _ialpha(uint32_t c)
}
static inline uint32_t _abgrLumaValue(uint32_t c)
{
return ((((c&0xff)*54) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
}
static inline uint32_t _argbLumaValue(uint32_t c)
{
return ((((c&0xff)*19) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
}
static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
return (a << 24 | b << 16 | g << 8 | r);
@ -139,7 +151,7 @@ static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
for (uint32_t y = 0; y < h; ++y) {
auto dst = &buffer[y * surface->stride];
@ -173,6 +185,8 @@ static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color
return _rasterMaskedRect(surface, region, color, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterMaskedRect(surface, region, color, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterMaskedRect(surface, region, color, surface->blender.lumaValue);
}
} else {
if (opacity == 255) {
@ -246,6 +260,8 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8
return _rasterMaskedRle(surface, rle, color, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterMaskedRle(surface, rle, color, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterMaskedRle(surface, rle, color, surface->blender.lumaValue);
}
} else {
if (opacity == 255) {
@ -275,6 +291,8 @@ static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, c
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, surface->blender.lumaValue);
}
} else {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr);
@ -494,12 +512,16 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const
return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
}
}
} else {
@ -616,12 +638,16 @@ static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32
return _rasterDirectMaskedRleRGBAImage(surface, image, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedRleRGBAImage(surface, image, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.lumaValue);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.lumaValue);
}
}
} else {
@ -643,6 +669,8 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, surface->blender.lumaValue);
}
} else {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, nullptr);
@ -832,12 +860,16 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat
return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
}
}
} else {
@ -861,7 +893,7 @@ static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* imag
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
for (uint32_t y = 0; y < h2; ++y) {
auto dst = buffer;
@ -888,7 +920,7 @@ static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
for (uint32_t y = 0; y < h2; ++y) {
auto dst = buffer;
@ -952,12 +984,16 @@ static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwB
return _rasterDirectMaskedRGBAImage(surface, image, region, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedRGBAImage(surface, image, region, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.lumaValue);
}
} else {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.lumaValue);
}
}
} else {
@ -1062,6 +1098,8 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region,
return _rasterLinearGradientMaskedRect(surface, region, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterLinearGradientMaskedRect(surface, region, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
}
} else {
if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill);
@ -1166,6 +1204,8 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c
return _rasterLinearGradientMaskedRle(surface, rle, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterLinearGradientMaskedRle(surface, rle, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
}
} else {
if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill);
@ -1253,6 +1293,8 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
return _rasterRadialGradientMaskedRect(surface, region, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterRadialGradientMaskedRect(surface, region, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
}
} else {
if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill);
@ -1356,6 +1398,8 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c
return _rasterRadialGradientMaskedRle(surface, rle, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterRadialGradientMaskedRle(surface, rle, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
}
} else {
if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill);
@ -1385,8 +1429,10 @@ bool rasterCompositor(SwSurface* surface)
{
if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
surface->blender.join = _abgrJoin;
surface->blender.lumaValue = _abgrLumaValue;
} else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
surface->blender.join = _argbJoin;
surface->blender.lumaValue = _argbLumaValue;
} else {
//What Color Space ???
return false;
@ -1500,4 +1546,4 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, co
//TODO: case: _rasterGrayscaleImage()
//TODO: case: _rasterAlphaImage()
return _rasterRGBAImage(surface, image, transform, bbox, opacity);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -26,8 +26,8 @@
static inline uint8x8_t ALPHA_BLEND(uint8x8_t c, uint8x8_t a)
{
uint16x8_t t = vmull_u8(c, a);
return vshrn_n_u16(t, 8);
uint16x8_t t = vmull_u8(c, a);
return vshrn_n_u16(t, 8);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -19,11 +19,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <math.h>
#include "tvgMath.h"
#include "tvgSwCommon.h"
#include "tvgTaskScheduler.h"
#include "tvgSwRenderer.h"
#include "tvgMath.h"
/************************************************************************/
/* Internal Class Implementation */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -79,8 +79,8 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform,
viewport.x = static_cast<int32_t>(v1.x);
viewport.y = static_cast<int32_t>(v1.y);
viewport.w = static_cast<int32_t>(v2.x - v1.x + 0.5f);
viewport.h = static_cast<int32_t>(v2.y - v1.y + 0.5f);
viewport.w = static_cast<int32_t>(ceil(v2.x - viewport.x));
viewport.h = static_cast<int32_t>(ceil(v2.y - viewport.y));
if (viewport.w < 0) viewport.w = 0;
if (viewport.h < 0) viewport.h = 0;
@ -404,4 +404,4 @@ uint8_t Paint::opacity() const noexcept
uint32_t Paint::identifier() const noexcept
{
return pImpl->id;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -93,7 +93,10 @@ bool PngLoader::read()
png_image_free(image);
return false;
}
if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) return false;
if (!png_image_finish_read(image, NULL, buffer, 0, NULL)) {
free(buffer);
return false;
}
content = reinterpret_cast<uint32_t*>(buffer);
_premultiply(reinterpret_cast<uint32_t*>(buffer), image->width, image->height);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -382,8 +382,8 @@ struct Row
const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
const int tmp0 = (ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS;
const int tmp1 = (ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS;
const int tmp0 = static_cast<unsigned int>(ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS;
const int tmp1 = static_cast<unsigned int>(ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS;
const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
@ -461,8 +461,8 @@ struct Col
const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
const int tmp0 = (ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS;
const int tmp1 = (ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS;
const int tmp0 = static_cast<unsigned int>(ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS;
const int tmp1 = static_cast<unsigned int>(ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS;
const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
@ -2557,7 +2557,7 @@ void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int
s = JPGD_HUFF_EXTEND(r, s);
}
pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]);
p[0] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
p[0] = static_cast<jpgd_block_t>(static_cast<unsigned int>(s) << pD->m_successive_low);
}
@ -2588,7 +2588,7 @@ void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int
if ((k += r) > 63) pD->stop_decoding(JPGD_DECODE_ERROR);
r = pD->get_bits_no_markers(s);
s = JPGD_HUFF_EXTEND(r, s);
p[g_ZAG[k]] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
p[g_ZAG[k]] = static_cast<jpgd_block_t>(static_cast<unsigned int>(s) << pD->m_successive_low);
} else {
if (r == 15) {
if ((k += 15) > 63) pD->stop_decoding(JPGD_DECODE_ERROR);
@ -2607,7 +2607,7 @@ void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, in
{
int s, k, r;
int p1 = 1 << pD->m_successive_low;
int m1 = (-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);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -0,0 +1,186 @@
/*
* Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tvgSvgCssStyle.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
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)) {
to->color = from->color;
to->curColorSet = true;
to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Color);
}
//Fill
if (((int)from->fill.flags & (int)SvgFillFlags::Paint) && !((int)to->flags & (int)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;
if (from->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);
}
if (((int)from->fill.flags & (int)SvgFillFlags::Opacity) && !((int)to->flags & (int)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);
}
if (((int)from->fill.flags & (int)SvgFillFlags::FillRule) && !((int)to->flags & (int)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);
}
//Stroke
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Paint) && !((int)to->flags & (int)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;
if (from->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);
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity) && !((int)to->flags & (int)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);
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Width) && !((int)to->flags & (int)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);
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Dash) && !((int)to->flags & (int)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);
}
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Cap) && !((int)to->flags & (int)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);
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Join) && !((int)to->flags & (int)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);
}
//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)) {
to->opacity = from->opacity;
to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Opacity);
}
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
void cssCopyStyleAttr(SvgNode* to, const SvgNode* from)
{
//Copy matrix attribute
if (from->transform && !((int)to->style->flags & (int)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);
}
}
//Copy style attribute
_copyStyle(to->style, from->style);
if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url);
if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url);
}
SvgNode* cssFindStyleNode(const SvgNode* style, const char* title, SvgNodeType type)
{
if (!style) return nullptr;
auto child = style->child.data;
for (uint32_t i = 0; i < style->child.count; ++i, ++child) {
if ((*child)->type == type) {
if ((!title && !(*child)->id) || (title && (*child)->id && !strcmp((*child)->id, title))) return (*child);
}
}
return nullptr;
}
SvgNode* cssFindStyleNode(const SvgNode* style, const char* title)
{
if (!style) 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);
}
}
return nullptr;
}
void cssUpdateStyle(SvgNode* doc, SvgNode* style)
{
if (doc->child.count > 0) {
auto child = doc->child.data;
for (uint32_t i = 0; i < doc->child.count; ++i, ++child) {
if (auto cssNode = cssFindStyleNode(style, nullptr, (*child)->type)) {
cssCopyStyleAttr(*child, cssNode);
}
if (auto cssNode = cssFindStyleNode(style, nullptr)) {
cssCopyStyleAttr(*child, cssNode);
}
cssUpdateStyle(*child, style);
}
}
}
void cssApplyStyleToPostponeds(Array<SvgNodeIdPair>& postponeds, SvgNode* style)
{
for (uint32_t i = 0; i < postponeds.count; ++i) {
auto nodeIdPair = postponeds.data[i];
//css styling: tag.name has higher priority than .name
if (auto cssNode = cssFindStyleNode(style, nodeIdPair.id, nodeIdPair.node->type)) {
cssCopyStyleAttr(nodeIdPair.node, cssNode);
}
if (auto cssNode = cssFindStyleNode(style, nodeIdPair.id)) {
cssCopyStyleAttr(nodeIdPair.node, cssNode);
}
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_SVG_CSS_STYLE_H_
#define _TVG_SVG_CSS_STYLE_H_
#include "tvgSvgLoaderCommon.h"
void cssCopyStyleAttr(SvgNode* to, const SvgNode* from);
SvgNode* cssFindStyleNode(const SvgNode* style, const char* title, SvgNodeType type);
SvgNode* cssFindStyleNode(const SvgNode* style, const char* title);
void cssUpdateStyle(SvgNode* doc, SvgNode* style);
void cssApplyStyleToPostponeds(Array<SvgNodeIdPair>& postponeds, SvgNode* style);
#endif //_TVG_SVG_CSS_STYLE_H_

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -60,6 +60,8 @@
#include "tvgSvgLoader.h"
#include "tvgSvgSceneBuilder.h"
#include "tvgSvgUtil.h"
#include "tvgSvgCssStyle.h"
#include "tvgMath.h"
/************************************************************************/
/* Internal Class Implementation */
@ -75,11 +77,10 @@
#define PX_PER_MM 3.779528f //1 in = 25.4 mm -> PX_PER_IN/25.4
#define PX_PER_CM 37.79528f //1 in = 2.54 cm -> PX_PER_IN/2.54
typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength);
typedef bool (*parseAttributes)(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data);
typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func);
typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength);
static char* _skipSpace(const char* str, const char* end)
{
while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) {
@ -200,6 +201,14 @@ static int _toOpacity(const char* str)
}
static SvgMaskType _toMaskType(const char* str)
{
if (!strcmp(str, "Alpha")) return SvgMaskType::Alpha;
return SvgMaskType::Luminance;
}
#define _PARSE_TAG(Type, Name, Name1, Tags_Array, Default) \
static Type _to##Name1(const char* str) \
{ \
@ -726,6 +735,12 @@ error:
}
static void _postpone(Array<SvgNodeIdPair>& nodes, SvgNode *node, char* id)
{
nodes.push({node, id});
}
/*
// TODO - remove?
static constexpr struct
@ -786,14 +801,12 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
} else if (!strcmp(key, "preserveAspectRatio")) {
if (!strcmp(value, "none")) doc->preserveAspect = false;
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
}
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
#ifdef THORVG_LOG_ENABLED
else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) {
} else if ((!strcmp(key, "x") || !strcmp(key, "y")) && fabsf(svgUtilStrtof(value, nullptr)) > FLT_EPSILON) {
TVGLOG("SVG", "Unsupported attributes used [Elements type: Svg][Attribute: %s][Value: %s]", key, value);
}
#endif
else {
} else {
return _parseStyleAttr(loader, key, value, false);
}
return true;
@ -922,6 +935,12 @@ static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, con
}
static void _handleMaskTypeAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
node->node.mask.type = _toMaskType(value);
}
static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
{
//TODO : The display attribute can have various values as well as "none".
@ -933,6 +952,29 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
}
static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char* value)
{
auto cssClass = &node->style->cssClass;
if (*cssClass && value) free(*cssClass);
*cssClass = _copyId(value);
bool cssClassFound = false;
//css styling: tag.name has higher priority than .name
if (auto cssNode = cssFindStyleNode(loader->cssStyle, *cssClass, node->type)) {
cssClassFound = true;
cssCopyStyleAttr(node, cssNode);
}
if (auto cssNode = cssFindStyleNode(loader->cssStyle, *cssClass)) {
cssClassFound = true;
cssCopyStyleAttr(node, cssNode);
}
if (!cssClassFound) _postpone(loader->nodesToStyle, node, *cssClass);
}
typedef void (*styleMethod)(SvgLoaderData* loader, SvgNode* node, const char* value);
#define STYLE_DEF(Name, Name1, Flag) { #Name, sizeof(#Name), _handle##Name1##Attr, Flag }
@ -959,6 +1001,7 @@ static constexpr struct
STYLE_DEF(transform, Transform, SvgStyleFlags::Transform),
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)
};
@ -1006,12 +1049,14 @@ static bool _attrParseGNode(void* data, const char* key, const char* value)
SvgNode* node = loader->svgParse->node;
if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "transform")) {
node->transform = _parseTransformationMatrix(value);
} else if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -1030,17 +1075,19 @@ static bool _attrParseClipPathNode(void* data, const char* key, const char* valu
{
SvgLoaderData* loader = (SvgLoaderData*)data;
SvgNode* node = loader->svgParse->node;
SvgCompositeNode* comp = &(node->node.comp);
SvgClipNode* clip = &(node->node.clip);
if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "transform")) {
node->transform = _parseTransformationMatrix(value);
} else if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else if (!strcmp(key, "clipPathUnits")) {
if (!strcmp(value, "objectBoundingBox")) comp->userSpace = false;
if (!strcmp(value, "objectBoundingBox")) clip->userSpace = false;
} else {
return _parseStyleAttr(loader, key, value, false);
}
@ -1052,17 +1099,21 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
SvgNode* node = loader->svgParse->node;
SvgCompositeNode* comp = &(node->node.comp);
SvgMaskNode* mask = &(node->node.mask);
if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "transform")) {
node->transform = _parseTransformationMatrix(value);
} else if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else if (!strcmp(key, "maskContentUnits")) {
if (!strcmp(value, "objectBoundingBox")) comp->userSpace = false;
if (!strcmp(value, "objectBoundingBox")) mask->userSpace = false;
} else if (!strcmp(key, "mask-type")) {
mask->type = _toMaskType(value);
} else {
return _parseStyleAttr(loader, key, value, false);
}
@ -1070,6 +1121,46 @@ static bool _attrParseMaskNode(void* data, const char* key, const char* value)
}
static bool _attrParseCssStyleNode(void* data, const char* key, const char* value)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
SvgNode* node = loader->svgParse->node;
if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else {
return _parseStyleAttr(loader, key, value, false);
}
return true;
}
static bool _attrParseSymbolNode(void* data, const char* key, const char* value)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
SvgNode* node = loader->svgParse->node;
SvgSymbolNode* symbol = &(node->node.symbol);
if (!strcmp(key, "viewBox")) {
if (!_parseNumber(&value, &symbol->vx) || !_parseNumber(&value, &symbol->vy)) return false;
if (!_parseNumber(&value, &symbol->vw) || !_parseNumber(&value, &symbol->vh)) return false;
} else if (!strcmp(key, "width")) {
symbol->w = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
} else if (!strcmp(key, "height")) {
symbol->h = _toFloat(loader->svgParse, value, SvgParserLengthType::Vertical);
} else if (!strcmp(key, "preserveAspectRatio")) {
if (!strcmp(value, "none")) symbol->preserveAspect = false;
} else if (!strcmp(key, "overflow")) {
if (!strcmp(value, "visible")) symbol->overflowVisible = true;
} else {
return _attrParseGNode(data, key, value);
}
return true;
}
static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
{
SvgNode* node = (SvgNode*)calloc(1, sizeof(SvgNode));
@ -1121,7 +1212,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
}
static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength, TVG_UNUSED parseAttributes func)
{
if (loader->def && loader->doc->node.doc.defs) return loader->def;
SvgNode* node = _createNode(nullptr, SvgNodeType::Defs);
@ -1132,17 +1223,17 @@ static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED Svg
}
static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::G);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParseGNode, loader);
func(buf, bufLength, _attrParseGNode, loader);
return loader->svgParse->node;
}
static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Doc);
if (!loader->svgParse->node) return nullptr;
@ -1152,7 +1243,7 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha
loader->svgParse->global.h = 0;
doc->preserveAspect = true;
simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader);
func(buf, bufLength, _attrParseSvgNode, loader);
if (loader->svgParse->global.w == 0) {
if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1;
@ -1167,32 +1258,60 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha
}
static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUSED const char* buf, TVG_UNUSED unsigned bufLength)
static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUSED const char* buf, TVG_UNUSED unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Mask);
if (!loader->svgParse->node) return nullptr;
loader->svgParse->node->node.comp.userSpace = true;
loader->svgParse->node->node.mask.userSpace = true;
loader->svgParse->node->node.mask.type = SvgMaskType::Luminance;
simpleXmlParseAttributes(buf, bufLength, _attrParseMaskNode, loader);
func(buf, bufLength, _attrParseMaskNode, loader);
return loader->svgParse->node;
}
static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath);
if (!loader->svgParse->node) return nullptr;
loader->svgParse->node->display = false;
loader->svgParse->node->node.comp.userSpace = true;
loader->svgParse->node->node.clip.userSpace = true;
simpleXmlParseAttributes(buf, bufLength, _attrParseClipPathNode, loader);
func(buf, bufLength, _attrParseClipPathNode, loader);
return loader->svgParse->node;
}
static SvgNode* _createCssStyleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::CssStyle);
if (!loader->svgParse->node) return nullptr;
func(buf, bufLength, _attrParseCssStyleNode, loader);
return loader->svgParse->node;
}
static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Symbol);
if (!loader->svgParse->node) return nullptr;
loader->svgParse->node->display = false;
loader->svgParse->node->node.symbol.preserveAspect = true;
loader->svgParse->node->node.symbol.overflowVisible = false;
func(buf, bufLength, _attrParseSymbolNode, loader);
return loader->svgParse->node;
}
static bool _attrParsePathNode(void* data, const char* key, const char* value)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
@ -1203,7 +1322,7 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value)
//Temporary: need to copy
path->path = _copyId(value);
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -1211,6 +1330,8 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value)
} else if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else {
return _parseStyleAttr(loader, key, value, false);
}
@ -1218,13 +1339,13 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value)
}
static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Path);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParsePathNode, loader);
func(buf, bufLength, _attrParsePathNode, loader);
return loader->svgParse->node;
}
@ -1263,7 +1384,7 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value)
}
if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -1271,6 +1392,8 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value)
} else if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else {
return _parseStyleAttr(loader, key, value, false);
}
@ -1278,13 +1401,13 @@ static bool _attrParseCircleNode(void* data, const char* key, const char* value)
}
static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Circle);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParseCircleNode, loader);
func(buf, bufLength, _attrParseCircleNode, loader);
return loader->svgParse->node;
}
@ -1325,8 +1448,10 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value
if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -1338,13 +1463,13 @@ static bool _attrParseEllipseNode(void* data, const char* key, const char* value
}
static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Ellipse);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParseEllipseNode, loader);
func(buf, bufLength, _attrParseEllipseNode, loader);
return loader->svgParse->node;
}
@ -1400,7 +1525,7 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value
if (!strcmp(key, "points")) {
return _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount);
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -1408,6 +1533,8 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value
} else if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else {
return _parseStyleAttr(loader, key, value, false);
}
@ -1415,24 +1542,24 @@ static bool _attrParsePolygonNode(void* data, const char* key, const char* value
}
static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Polygon);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader);
func(buf, bufLength, _attrParsePolygonNode, loader);
return loader->svgParse->node;
}
static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Polyline);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader);
func(buf, bufLength, _attrParsePolygonNode, loader);
return loader->svgParse->node;
}
@ -1482,8 +1609,10 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value)
if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else if (!strcmp(key, "style")) {
ret = simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
ret = simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -1496,7 +1625,7 @@ static bool _attrParseRectNode(void* data, const char* key, const char* value)
}
static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Rect);
@ -1504,7 +1633,7 @@ static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const ch
loader->svgParse->node->node.rect.hasRx = loader->svgParse->node->node.rect.hasRy = false;
simpleXmlParseAttributes(buf, bufLength, _attrParseRectNode, loader);
func(buf, bufLength, _attrParseRectNode, loader);
return loader->svgParse->node;
}
@ -1545,8 +1674,10 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value)
if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
@ -1558,13 +1689,13 @@ static bool _attrParseLineNode(void* data, const char* key, const char* value)
}
static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Line);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParseLineNode, loader);
func(buf, bufLength, _attrParseLineNode, loader);
return loader->svgParse->node;
}
@ -1616,12 +1747,16 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value)
} else if (!strcmp(key, "id")) {
if (node->id && value) free(node->id);
node->id = _copyId(value);
} else if (!strcmp(key, "class")) {
_handleCssClassAttr(loader, node, value);
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
} else if (!strcmp(key, "clip-path")) {
_handleClipPathAttr(loader, node, value);
} else if (!strcmp(key, "mask")) {
_handleMaskAttr(loader, node, value);
} else if (!strcmp(key, "transform")) {
node->transform = _parseTransformationMatrix(value);
} else {
return _parseStyleAttr(loader, key, value);
}
@ -1629,13 +1764,13 @@ static bool _attrParseImageNode(void* data, const char* key, const char* value)
}
static SvgNode* _createImageNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createImageNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Image);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParseImageNode, loader);
func(buf, bufLength, _attrParseImageNode, loader);
return loader->svgParse->node;
}
@ -1941,12 +2076,6 @@ static void _cloneNode(SvgNode* from, SvgNode* parent, int depth)
}
static void _postponeCloneNode(SvgLoaderData* loader, SvgNode *node, char* id)
{
loader->cloneNodes.push({node, id});
}
static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
{
for (uint32_t i = 0; i < cloneNodes->count; ++i) {
@ -1955,6 +2084,9 @@ static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
auto nodeFrom = _findChildById(defs, nodeIdPair.id);
if (!nodeFrom) nodeFrom = _findChildById(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);
}
}
@ -1967,10 +2099,10 @@ static constexpr struct
int sz;
size_t offset;
} useTags[] = {
{"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgRectNode, x)},
{"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgRectNode, y)},
{"width", SvgParserLengthType::Horizontal, sizeof("width"), offsetof(SvgRectNode, w)},
{"height", SvgParserLengthType::Vertical, sizeof("height"), offsetof(SvgRectNode, h)}
{"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgUseNode, x)},
{"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgUseNode, y)},
{"width", SvgParserLengthType::Horizontal, sizeof("width"), offsetof(SvgUseNode, w)},
{"height", SvgParserLengthType::Vertical, sizeof("height"), offsetof(SvgUseNode, h)}
};
@ -1986,6 +2118,10 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value)
for (unsigned int i = 0; i < sizeof(useTags) / sizeof(useTags[0]); i++) {
if (useTags[i].sz - 1 == sz && !strncmp(useTags[i].tag, key, sz)) {
*((float*)(array + useTags[i].offset)) = _toFloat(loader->svgParse, value, useTags[i].type);
if (useTags[i].offset == offsetof(SvgUseNode, w)) use->isWidthSet = true;
else if (useTags[i].offset == offsetof(SvgUseNode, h)) use->isHeightSet = true;
return true;
}
}
@ -1996,12 +2132,13 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value)
nodeFrom = _findChildById(defs, id);
if (nodeFrom) {
_cloneNode(nodeFrom, node, 0);
if (nodeFrom->type == SvgNodeType::Symbol) use->symbol = nodeFrom;
free(id);
} else {
//some svg export software include <defs> element at the end of the file
//if so the 'from' element won't be found now and we have to repeat finding
//after the whole file is parsed
_postponeCloneNode(loader, node, id);
_postpone(loader->cloneNodes, node, id);
}
} else {
return _attrParseGNode(data, key, value);
@ -2010,16 +2147,20 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value)
}
static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
{
loader->svgParse->node = _createNode(parent, SvgNodeType::Use);
if (!loader->svgParse->node) return nullptr;
simpleXmlParseAttributes(buf, bufLength, _attrParseUseNode, loader);
loader->svgParse->node->node.use.isWidthSet = false;
loader->svgParse->node->node.use.isHeightSet = false;
func(buf, bufLength, _attrParseUseNode, loader);
return loader->svgParse->node;
}
//TODO: Implement 'text' primitive
static constexpr struct
{
@ -2049,7 +2190,9 @@ static constexpr struct
{"g", sizeof("g"), _createGNode},
{"svg", sizeof("svg"), _createSvgNode},
{"mask", sizeof("mask"), _createMaskNode},
{"clipPath", sizeof("clipPath"), _createClipPathNode}
{"clipPath", sizeof("clipPath"), _createClipPathNode},
{"style", sizeof("style"), _createCssStyleNode},
{"symbol", sizeof("symbol"), _createSymbolNode}
};
@ -2204,8 +2347,8 @@ static bool _attrParseRadialGradientNode(void* data, const char* key, const char
} 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") && !strcmp(value, "userSpaceOnUse")) {
grad->userSpace = true;
} else if (!strcmp(key, "gradientUnits")) {
if (!strcmp(value, "userSpaceOnUse")) grad->userSpace = true;
} else if (!strcmp(key, "gradientTransform")) {
grad->transform = _parseTransformationMatrix(value);
} else {
@ -2291,7 +2434,7 @@ static bool _attrParseStops(void* data, const char* key, const char* value)
_toColor(value, &stop->r, &stop->g, &stop->b, nullptr);
}
} else if (!strcmp(key, "style")) {
simpleXmlParseW3CAttribute(value, _attrParseStopsStyle, data);
simpleXmlParseW3CAttribute(value, strlen(value), _attrParseStopsStyle, data);
} else {
return false;
}
@ -2394,8 +2537,8 @@ static bool _attrParseLinearGradientNode(void* data, const char* key, const char
} 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") && !strcmp(value, "userSpaceOnUse")) {
grad->userSpace = true;
} else if (!strcmp(key, "gradientUnits")) {
if (!strcmp(value, "userSpaceOnUse")) grad->userSpace = true;
} else if (!strcmp(key, "gradientTransform")) {
grad->transform = _parseTransformationMatrix(value);
} else {
@ -2479,11 +2622,13 @@ static constexpr struct
{"svg", sizeof("svg")},
{"defs", sizeof("defs")},
{"mask", sizeof("mask")},
{"clipPath", sizeof("clipPath")}
{"clipPath", sizeof("clipPath")},
{"style", sizeof("style")},
{"symbol", sizeof("symbol")}
};
static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content)
static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content)
{
content = _skipSpace(content, nullptr);
@ -2531,13 +2676,20 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
if (empty) return;
if (!loader->doc) {
if (strcmp(tagName, "svg")) return; //Not a valid svg document
node = method(loader, nullptr, attrs, attrsLength);
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
loader->doc = node;
} else {
if (!strcmp(tagName, "svg")) return; //Already loaded <svg>(SvgNodeType::Doc) tag
if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1];
else parent = loader->doc;
node = method(loader, parent, attrs, attrsLength);
if (!strcmp(tagName, "style")) {
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
loader->cssStyle = node;
loader->doc->node.doc.style = node;
loader->style = true;
} else {
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
}
}
if (!node) return;
@ -2547,7 +2699,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
} else if ((method = _findGraphicsFactory(tagName))) {
if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1];
else parent = loader->doc;
node = method(loader, parent, attrs, attrsLength);
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
} else if ((gradientMethod = _findGradientFactory(tagName))) {
SvgStyleGradient* gradient;
gradient = gradientMethod(loader, attrs, attrsLength);
@ -2578,6 +2730,42 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
}
static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* content, unsigned int length)
{
char* tag;
char* name;
const char* attrs = nullptr;
unsigned int attrsLength = 0;
FactoryMethod method;
GradientFactoryMethod gradientMethod;
SvgNode *node = nullptr;
while (auto next = simpleXmlParseCSSAttribute(content, length, &tag, &name, &attrs, &attrsLength)) {
if ((method = _findGroupFactory(tag))) {
if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name);
} else if ((method = _findGraphicsFactory(tag))) {
if ((node = method(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name);
} else if ((gradientMethod = _findGradientFactory(tag))) {
TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag);
} else if (!strcmp(tag, "stop")) {
TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag);
} else if (!strcmp(tag, "all")) {
if ((node = _createCssStyleNode(loader, loader->cssStyle, attrs, attrsLength, simpleXmlParseW3CAttribute))) node->id = _copyId(name);
} else if (!isIgnoreUnsupportedLogElements(tag)) {
TVGLOG("SVG", "Unsupported elements used in the internal CSS style sheets [Elements: %s]", tag);
}
length -= next - content;
content = next;
free(tag);
free(name);
}
loader->style = false;
}
static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int length)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
@ -2592,11 +2780,14 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content
break;
}
case SimpleXMLType::Close: {
_svgLoaderParerXmlClose(loader, content);
_svgLoaderParserXmlClose(loader, content);
break;
}
case SimpleXMLType::Data:
case SimpleXMLType::CData:
case SimpleXMLType::CData: {
if (loader->style) _svgLoaderParserXmlCssStyle(loader, content, length);
break;
}
case SimpleXMLType::DoctypeChild: {
break;
}
@ -2619,7 +2810,7 @@ static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node)
#ifdef THORVG_LOG_ENABLED
auto type = simpleXmlNodeTypeToString(node->type);
if (!node->display && node->type != SvgNodeType::ClipPath) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type);
if (!node->display && node->type != SvgNodeType::ClipPath && node->type != SvgNodeType::Symbol) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type);
if (node->style->opacity == 0) TVGLOG("SVG", "Inefficient elements used [Opacity is zero][Node Type : %s]", type);
if (node->style->fill.opacity == 0 && node->style->stroke.opacity == 0) TVGLOG("SVG", "Inefficient elements used [Fill opacity and stroke opacity are zero][Node Type : %s]", type);
@ -2749,6 +2940,7 @@ static void _freeNodeStyle(SvgStyleProperty* style)
//style->clipPath.node and style->mask.node has only the addresses of node. Therefore, node is released from _freeNode.
free(style->clipPath.url);
free(style->mask.url);
free(style->cssClass);
if (style->fill.paint.gradient) {
style->fill.paint.gradient->clear();
@ -2793,6 +2985,7 @@ static void _freeNode(SvgNode* node)
}
case SvgNodeType::Doc: {
_freeNode(node->node.doc.defs);
_freeNode(node->node.doc.style);
break;
}
case SvgNodeType::Defs: {
@ -2846,7 +3039,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch
if ((method = _findGroupFactory(tagName))) {
if (!loader->doc) {
if (strcmp(tagName, "svg")) return true; //Not a valid svg document
node = method(loader, nullptr, attrs, attrsLength);
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
loader->doc = node;
loader->stack.push(node);
return false;
@ -2906,16 +3099,20 @@ void SvgLoader::run(unsigned tid)
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
if (loaderData.doc) {
_updateStyle(loaderData.doc, nullptr);
auto defs = loaderData.doc->node.doc.defs;
if (loaderData.nodesToStyle.count > 0) cssApplyStyleToPostponeds(loaderData.nodesToStyle, loaderData.cssStyle);
if (loaderData.cssStyle) cssUpdateStyle(loaderData.doc, loaderData.cssStyle);
if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes, loaderData.doc);
_updateComposite(loaderData.doc, loaderData.doc);
if (defs) _updateComposite(loaderData.doc, defs);
if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes, loaderData.doc);
if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients);
if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients);
_updateStyle(loaderData.doc, nullptr);
}
root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -51,6 +51,8 @@ enum class SvgNodeType
Video,
ClipPath,
Mask,
CssStyle,
Symbol,
Unknown
};
@ -111,7 +113,8 @@ enum class SvgStyleFlags
Transform = 0x800,
ClipPath = 0x1000,
Mask = 0x2000,
Display = 0x4000
MaskType = 0x4000,
Display = 0x8000
};
enum class SvgStopStyleFlags
@ -127,6 +130,12 @@ enum class SvgFillRule
OddEven = 1
};
enum class SvgMaskType
{
Luminance = 0,
Alpha
};
//Length type to recalculate %, pt, pc, mm, cm etc
enum class SvgParserLengthType
{
@ -145,6 +154,7 @@ struct SvgDocNode
float vw;
float vh;
SvgNode* defs;
SvgNode* style;
bool preserveAspect;
};
@ -157,12 +167,22 @@ struct SvgDefsNode
Array<SvgStyleGradient*> gradients;
};
struct SvgSymbolNode
{
float w, h;
float vx, vy, vw, vh;
bool preserveAspect;
bool overflowVisible;
};
struct SvgUseNode
{
float x, y, w, h;
bool isWidthSet;
bool isHeightSet;
SvgNode* symbol;
};
struct SvgEllipseNode
{
float cx;
@ -215,11 +235,21 @@ struct SvgPolygonNode
float* points;
};
struct SvgCompositeNode
struct SvgClipNode
{
bool userSpace;
};
struct SvgMaskNode
{
SvgMaskType type;
bool userSpace;
};
struct SvgCssStyleNode
{
};
struct SvgLinearGradient
{
float x1;
@ -328,6 +358,7 @@ struct SvgStyleProperty
int opacity;
SvgColor color;
bool curColorSet;
char* cssClass;
SvgStyleFlags flags;
};
@ -352,7 +383,10 @@ struct SvgNode
SvgPathNode path;
SvgLineNode line;
SvgImageNode image;
SvgCompositeNode comp;
SvgMaskNode mask;
SvgClipNode clip;
SvgCssStyleNode cssStyle;
SvgSymbolNode symbol;
} node;
bool display;
~SvgNode();
@ -384,15 +418,18 @@ struct SvgNodeIdPair
struct SvgLoaderData
{
Array<SvgNode *> stack = {nullptr, 0, 0};
Array<SvgNode*> stack = {nullptr, 0, 0};
SvgNode* doc = nullptr;
SvgNode* def = nullptr;
SvgNode* cssStyle = nullptr;
Array<SvgStyleGradient*> gradients;
SvgStyleGradient* latestGradient = nullptr; //For stops
SvgParser* svgParse = nullptr;
Array<SvgNodeIdPair> cloneNodes;
Array<SvgNodeIdPair> nodesToStyle;
int level = 0;
bool result = false;
bool style = false;
};
/*

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -68,12 +68,12 @@ struct Box
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);
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite = nullptr);
static inline bool _isGroupType(SvgNodeType type)
{
if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::Use || type == SvgNodeType::ClipPath) return true;
if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::Use || type == SvgNodeType::ClipPath || type == SvgNodeType::Symbol) return true;
return false;
}
@ -276,15 +276,21 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
Composition can be applied recursively if its children nodes have composition target to this one. */
if (node->style->mask.applying) {
TVGLOG("SVG", "Multiple Composition Tried! Check out Circular dependency?");
} else {
} else {
auto compNode = node->style->mask.node;
if (compNode && compNode->child.count > 0) {
node->style->mask.applying = true;
auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true);
bool isMaskWhite = true;
auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, &isMaskWhite);
if (comp) {
if (node->transform) comp->transform(*node->transform);
paint->composite(move(comp), CompositeMethod::AlphaMask);
if (compNode->node.mask.type == SvgMaskType::Luminance && !isMaskWhite) {
paint->composite(move(comp), CompositeMethod::LumaMask);
} else {
paint->composite(move(comp), CompositeMethod::AlphaMask);
}
}
node->style->mask.applying = false;
@ -534,57 +540,137 @@ static unique_ptr<Picture> _imageBuildHelper(SvgNode* node, const Box& vBox, con
string imagePath = href;
if (strncmp(href, "/", 1)) {
auto last = svgPath.find_last_of("/");
imagePath = svgPath.substr(0, (last == string::npos ? 0 : last + 1 )) + imagePath;
imagePath = svgPath.substr(0, (last == string::npos ? 0 : last + 1)) + imagePath;
}
if (picture->load(imagePath) != Result::Success) return nullptr;
}
float w, h;
Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1};
if (picture->size(&w, &h) == Result::Success && w > 0 && h > 0) {
auto sx = node->node.image.w / w;
auto sy = node->node.image.h / h;
Matrix m = {sx, 0, node->node.image.x, 0, sy, node->node.image.y, 0, 0, 1};
picture->transform(m);
m = {sx, 0, node->node.image.x, 0, sy, node->node.image.y, 0, 0, 1};
}
if (node->transform) m = mathMultiply(node->transform, &m);
picture->transform(m);
_applyComposition(picture.get(), node, vBox, svgPath);
return picture;
}
static unique_ptr<Scene> _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath)
static unique_ptr<Scene> _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool* isMaskWhite)
{
auto scene = _sceneBuildHelper(node, vBox, svgPath, false);
unique_ptr<Scene> finalScene;
auto scene = _sceneBuildHelper(node, vBox, svgPath, false, isMaskWhite);
// mUseTransform = mUseTransform * mTranslate
Matrix mUseTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
if (node->transform) mUseTransform = *node->transform;
if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) {
scene->translate(node->node.use.x, node->node.use.y);
Matrix mTranslate = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1};
mUseTransform = mathMultiply(&mUseTransform, &mTranslate);
}
if (node->node.use.w > 0.0f && node->node.use.h > 0.0f) {
//TODO: handle width/height properties
if (node->node.use.symbol) {
auto symbol = node->node.use.symbol->node.symbol;
auto width = symbol.w;
if (node->node.use.isWidthSet) width = node->node.use.w;
auto height = symbol.h;
if (node->node.use.isHeightSet) height = node->node.use.h;
Matrix mViewBox = {1, 0, 0, 0, 1, 0, 0, 0, 1};
if ((!mathEqual(width, symbol.vw) || !mathEqual(height, symbol.vh)) && symbol.vw > 0 && symbol.vh > 0) {
auto sx = width / symbol.vw;
auto sy = height / symbol.vh;
if (symbol.preserveAspect) {
if (sx < sy) sy = sx;
else sx = sy;
}
auto tvx = symbol.vx * sx;
auto tvy = symbol.vy * sy;
auto tvw = symbol.vw * sx;
auto tvh = symbol.vh * sy;
tvy -= (symbol.h - tvh) * 0.5f;
tvx -= (symbol.w - tvw) * 0.5f;
mViewBox = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
} else if (!mathZero(symbol.vx) || !mathZero(symbol.vy)) {
mViewBox = {1, 0, -symbol.vx, 0, 1, -symbol.vy, 0, 0, 1};
}
// mSceneTransform = mUseTransform * mSymbolTransform * mViewBox
Matrix mSceneTransform = mViewBox;
if (node->node.use.symbol->transform) {
mSceneTransform = mathMultiply(node->node.use.symbol->transform, &mViewBox);
}
mSceneTransform = mathMultiply(&mUseTransform, &mSceneTransform);
scene->transform(mSceneTransform);
if (node->node.use.symbol->node.symbol.overflowVisible) {
finalScene = move(scene);
} else {
auto viewBoxClip = Shape::gen();
viewBoxClip->appendRect(0, 0, width, height, 0, 0);
// mClipTransform = mUseTransform * mSymbolTransform
Matrix mClipTransform = mUseTransform;
if (node->node.use.symbol->transform) {
mClipTransform = mathMultiply(&mUseTransform, node->node.use.symbol->transform);
}
viewBoxClip->transform(mClipTransform);
auto compositeLayer = Scene::gen();
compositeLayer->composite(move(viewBoxClip), CompositeMethod::ClipPath);
compositeLayer->push(move(scene));
auto root = Scene::gen();
root->push(move(compositeLayer));
finalScene = move(root);
}
} else {
if (!mathIdentity((const Matrix*)(&mUseTransform))) scene->transform(mUseTransform);
finalScene = move(scene);
}
return scene;
return finalScene;
}
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask)
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite)
{
if (_isGroupType(node->type) || mask) {
auto scene = Scene::gen();
if (!mask && node->transform) scene->transform(*node->transform);
// For a Symbol node, the viewBox transformation has to be applied first - see _useBuildHelper()
if (!mask && node->transform && node->type != SvgNodeType::Symbol) scene->transform(*node->transform);
if (node->display && node->style->opacity != 0) {
auto child = node->child.data;
for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
if (_isGroupType((*child)->type)) {
if ((*child)->type == SvgNodeType::Use)
scene->push(_useBuildHelper(*child, vBox, svgPath));
scene->push(_useBuildHelper(*child, vBox, svgPath, isMaskWhite));
else
scene->push(_sceneBuildHelper(*child, vBox, svgPath, false));
scene->push(_sceneBuildHelper(*child, vBox, svgPath, false, isMaskWhite));
} else if ((*child)->type == SvgNodeType::Image) {
auto image = _imageBuildHelper(*child, vBox, svgPath);
if (image) scene->push(move(image));
} else if ((*child)->type != SvgNodeType::Mask) {
auto shape = _shapeBuildHelper(*child, vBox, svgPath);
if (shape) scene->push(move(shape));
if (shape) {
if (isMaskWhite) {
uint8_t r, g, b;
shape->fillColor(&r, &g, &b, nullptr);
if (shape->fill() || r < 255 || g < 255 || b < 255 || shape->strokeFill() ||
(shape->strokeColor(&r, &g, &b, nullptr) == Result::Success && (r < 255 || g < 255 || b < 255))) {
*isMaskWhite = false;
}
}
scene->push(move(shape));
}
}
}
_applyComposition(scene.get(), node, vBox, svgPath);
@ -620,17 +706,13 @@ unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, flo
auto tvy = vy * scale;
auto tvw = vw * scale;
auto tvh = vh * scale;
if (vw > vh) tvy -= (h - tvh) * 0.5f;
else tvx -= (w - tvw) * 0.5f;
tvx -= (w - tvw) * 0.5f;
tvy -= (h - tvh) * 0.5f;
docNode->translate(-tvx, -tvy);
} else {
//Align
auto tvx = vx * sx;
auto tvy = vy * sy;
auto tvw = vw * sx;
auto tvh = vh * sy;
if (tvw > tvh) tvy -= (h - tvh) * 0.5f;
else tvx -= (w - tvw) * 0.5f;
Matrix m = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
docNode->transform(m);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -236,6 +236,14 @@ static SimpleXMLType _getXMLType(const char* itr, const char* itrEnd, size_t &to
}
static char* _strndup(const char* src, unsigned len)
{
auto ret = (char*)malloc(len + 1);
if (!ret) return nullptr;
ret[len] = '\0';
return (char*)memcpy(ret, src, len);
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@ -264,6 +272,7 @@ const char* simpleXmlNodeTypeToString(TVG_UNUSED SvgNodeType type)
"Video",
"ClipPath",
"Mask",
"Symbol",
"Unknown",
};
return TYPE_NAMES[(int) type];
@ -450,7 +459,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
}
bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data)
bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data)
{
const char* end;
char* key;
@ -459,7 +468,7 @@ bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, cons
if (!buf) return false;
end = buf + strlen(buf);
end = buf + bufLength;
key = (char*)alloca(end - buf + 1);
val = (char*)alloca(end - buf + 1);
@ -468,6 +477,11 @@ bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, cons
do {
char* sep = (char*)strchr(buf, ':');
next = (char*)strchr(buf, ';');
if (sep >= end) {
next = nullptr;
sep = nullptr;
}
if (next >= end) next = nullptr;
key[0] = '\0';
val[0] = '\0';
@ -509,6 +523,47 @@ bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, cons
}
/*
* Supported formats:
* tag {}, .name {}, tag.name{}
*/
const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength)
{
if (!buf) return nullptr;
*tag = *name = nullptr;
*attrsLength = 0;
auto itr = _simpleXmlSkipWhiteSpace(buf, buf + bufLength);
auto itrEnd = (const char*)memchr(buf, '{', bufLength);
if (!itrEnd || itr == itrEnd) return nullptr;
auto nextElement = (const char*)memchr(itrEnd, '}', bufLength - (itrEnd - buf));
if (!nextElement) return nullptr;
*attrs = itrEnd + 1;
*attrsLength = nextElement - *attrs;
const char *p;
itrEnd = _simpleXmlUnskipWhiteSpace(itrEnd, itr);
if (*(itrEnd - 1) == '.') return nullptr;
for (p = itr; p < itrEnd; p++) {
if (*p == '.') break;
}
if (p == itr) *tag = strdup("all");
else *tag = _strndup(itr, p - itr);
if (p == itrEnd) *name = nullptr;
else *name = _strndup(p + 1, itrEnd - p - 1);
return (nextElement ? nextElement + 1 : nullptr);
}
const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength)
{
const char *itr = buf, *itrEnd = buf + bufLength;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -32,7 +32,7 @@ const int xmlEntityLength[] = {6, 6, 6, 5, 4, 4, 6, 6};
enum class SimpleXMLType
{
Open = 0, //!< \<tag attribute="value"\>
OpenEmpty, //!< \<tag attribute="value" /\>
OpenEmpty, //!< \<tag attribute="value" /\>
Close, //!< \</tag\>
Data, //!< tag text data
CData, //!< \<![cdata[something]]\>
@ -41,16 +41,17 @@ enum class SimpleXMLType
Doctype, //!< \<!doctype html
Comment, //!< \<!-- something --\>
Ignored, //!< whatever is ignored by parser, like whitespace
DoctypeChild //!< \<!doctype_child
DoctypeChild //!< \<!doctype_child
};
typedef bool (*simpleXMLCb)(void* data, SimpleXMLType type, const char* content, unsigned int length);
typedef bool (*simpleXMLAttributeCb)(void* data, const char* key, const char* value);
bool simpleXmlParseAttributes(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data);
bool simpleXmlParse(const char* buf, unsigned buflen, bool strip, simpleXMLCb func, const void* data);
bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data);
const char *simpleXmlFindAttributesTag(const char* buf, unsigned buflen);
bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data);
bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb func, const void* data);
bool simpleXmlParseW3CAttribute(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data);
const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength);
const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength);
bool isIgnoreUnsupportedLogElements(const char* tagName);
const char* simpleXmlNodeTypeToString(SvgNodeType type);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
* Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View file

@ -1,4 +1,4 @@
VERSION=0.7.1
VERSION=0.8.0
rm -rf AUTHORS inc LICENSE src *.zip
curl -L -O https://github.com/Samsung/thorvg/archive/refs/tags/v$VERSION.zip
bsdtar --strip-components=1 -xvf *.zip