tvg_loader: code refactoring.

revise it under the tvg coding convention.
This commit is contained in:
Hermet Park 2021-06-11 15:08:40 +09:00 committed by Hermet Park
parent 52d95dcb59
commit 15b56a66de
9 changed files with 259 additions and 285 deletions

View file

@ -6,7 +6,7 @@ option('engines',
option('loaders', option('loaders',
type: 'array', type: 'array',
choices: ['', 'svg', 'png'], choices: ['', 'svg', 'tvg', 'png'],
value: ['svg'], value: ['svg'],
description: 'Enable File Loaders in thorvg') description: 'Enable File Loaders in thorvg')

View file

@ -14,6 +14,7 @@ source_file = [
'tvgCanvasImpl.h', 'tvgCanvasImpl.h',
'tvgCommon.h', 'tvgCommon.h',
'tvgBezier.h', 'tvgBezier.h',
'tvgBinaryDesc.h',
'tvgFill.h', 'tvgFill.h',
'tvgLoader.h', 'tvgLoader.h',
'tvgLoaderMgr.h', 'tvgLoaderMgr.h',
@ -22,7 +23,6 @@ source_file = [
'tvgSceneImpl.h', 'tvgSceneImpl.h',
'tvgShapeImpl.h', 'tvgShapeImpl.h',
'tvgTaskScheduler.h', 'tvgTaskScheduler.h',
'tvgTvgHelper.h',
'tvgBezier.cpp', 'tvgBezier.cpp',
'tvgCanvas.cpp', 'tvgCanvas.cpp',
'tvgFill.cpp', 'tvgFill.cpp',

View file

@ -19,8 +19,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
#ifndef _TVG_TVG_HELPER_H_ #ifndef _TVG_BINARY_DESC_H_
#define _TVG_TVG_HELPER_H_ #define _TVG_BINARY_DESC_H_
// now only little endian // now only little endian
#define _read_tvg_ui16(dst, src) memcpy(dst, (src), sizeof(uint16_t)) #define _read_tvg_ui16(dst, src) memcpy(dst, (src), sizeof(uint16_t))
@ -30,6 +30,7 @@
using TvgIndicator = uint8_t; using TvgIndicator = uint8_t;
using ByteCounter = uint32_t; using ByteCounter = uint32_t;
using TvgFlag = uint8_t; using TvgFlag = uint8_t;
#define TVG_INDICATOR_SIZE sizeof(TvgIndicator) #define TVG_INDICATOR_SIZE sizeof(TvgIndicator)
#define BYTE_COUNTER_SIZE sizeof(ByteCounter) #define BYTE_COUNTER_SIZE sizeof(ByteCounter)
#define TVG_FLAG_SIZE sizeof(TvgFlag) #define TVG_FLAG_SIZE sizeof(TvgFlag)
@ -39,17 +40,25 @@ struct tvgBlock
TvgIndicator type; TvgIndicator type;
ByteCounter length; ByteCounter length;
const char* data; const char* data;
const char* blockEnd; const char* end;
}; };
#define TVG_HEADER_TVG_SIGN_CODE "TVG" //TODO: replace it when this feature is completed.
#define TVG_HEADER_TVG_VERSION_CODE "000" #if 0
#define TVG_HEADER_TVG_SIGN_CODE_LENGTH 3 #define TVG_BIN_HEADER_SIGNATURE "ThorVG"
#define TVG_HEADER_TVG_VERSION_CODE_LENGTH 3 #define TVG_BIN_HEADER_SIGNATURE_LENGTH 6
#define TVG_BIN_HEADER_VERSION "000200"
#define TVG_BIN_HEADER_VERSION_LENGTH 6
#else
#define TVG_BIN_HEADER_SIGNATURE "TVG"
#define TVG_BIN_HEADER_SIGNATURE_LENGTH 3
#define TVG_BIN_HEADER_VERSION "000"
#define TVG_BIN_HEADER_VERSION_LENGTH 3
#endif
#define TVG_SCENE_BEGIN_INDICATOR (TvgIndicator)0xfe // Scene indicator #define TVG_SCENE_BEGIN_INDICATOR (TvgIndicator)0xfe
#define TVG_SHAPE_BEGIN_INDICATOR (TvgIndicator)0xfd // Shape indicator #define TVG_SHAPE_BEGIN_INDICATOR (TvgIndicator)0xfd
#define TVG_PICTURE_BEGIN_INDICATOR (TvgIndicator)0xfc // Picture indicator #define TVG_PICTURE_BEGIN_INDICATOR (TvgIndicator)0xfc
// Paint // Paint
#define TVG_PAINT_OPACITY_INDICATOR (TvgIndicator)0x10 // Paint opacity #define TVG_PAINT_OPACITY_INDICATOR (TvgIndicator)0x10 // Paint opacity
@ -100,4 +109,4 @@ struct tvgBlock
// Picture // Picture
#define TVG_RAW_IMAGE_BEGIN_INDICATOR (TvgIndicator)0x70 // Picture raw data #define TVG_RAW_IMAGE_BEGIN_INDICATOR (TvgIndicator)0x70 // Picture raw data
#endif //_TVG_TVG_HELPER_H_ #endif //_TVG_BINARY_DESC_H_

View file

@ -10,8 +10,12 @@ if get_option('loaders').contains('png') == true
message('Enable PNG Loader') message('Enable PNG Loader')
endif endif
if get_option('loaders').contains('tvg') == true
subdir('tvg')
message('Enable TVG Loader')
endif
subdir('raw') subdir('raw')
subdir('tvg')
loader_dep = declare_dependency( loader_dep = declare_dependency(
dependencies: subloader_dep, dependencies: subloader_dep,

View file

@ -2630,6 +2630,8 @@ bool SvgLoader::header()
bool SvgLoader::open(const char* data, uint32_t size) bool SvgLoader::open(const char* data, uint32_t size)
{ {
//TODO: verify memory leak if open() is called multiple times.
this->content = data; this->content = data;
this->size = size; this->size = size;
@ -2639,22 +2641,20 @@ bool SvgLoader::open(const char* data, uint32_t size)
bool SvgLoader::open(const string& path) bool SvgLoader::open(const string& path)
{ {
//TODO: verify memory leak if open() is called multiple times.
ifstream f; ifstream f;
f.open(path); f.open(path);
if (!f.is_open()) if (!f.is_open()) return false;
{
//LOG: Failed to open file
return false;
} else {
getline(f, filePath, '\0');
f.close();
if (filePath.empty()) return false; getline(f, filePath, '\0');
f.close();
this->content = filePath.c_str(); if (filePath.empty()) return false;
this->size = filePath.size();
} content = filePath.c_str();
size = filePath.size();
return header(); return header();
} }

View file

@ -20,76 +20,85 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <string.h> #include <memory.h>
#include "tvgTvgLoadParser.h" #include "tvgTvgLoadParser.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
enum class LoaderResult { InvalidType, Success, SizeCorruption, MemoryCorruption, LogicalCorruption }; enum class LoaderResult { InvalidType, Success, SizeCorruption, MemoryCorruption, LogicalCorruption };
static LoaderResult _parsePaint(tvgBlock block, Paint ** paint); static LoaderResult _parsePaint(tvgBlock block, Paint ** paint);
static tvgBlock _readTvgBlock(const char *pointer) static tvgBlock _readTvgBlock(const char *ptr)
{ {
tvgBlock block; tvgBlock block;
block.type = *pointer; block.type = *ptr;
_read_tvg_ui32(&block.length, pointer + TVG_INDICATOR_SIZE); _read_tvg_ui32(&block.length, ptr + TVG_INDICATOR_SIZE);
block.data = pointer + TVG_INDICATOR_SIZE + BYTE_COUNTER_SIZE; block.data = ptr + TVG_INDICATOR_SIZE + BYTE_COUNTER_SIZE;
block.blockEnd = block.data + block.length; block.end = block.data + block.length;
return block; return block;
} }
static bool _readTvgHeader(const char **pointer) static bool _readTvgHeader(const char **ptr)
{ {
// Sign phase, always "TVG" declared in TVG_HEADER_TVG_SIGN_CODE //Sign phase, always TVG_BIN_HEADER_SIGNATURE is declared
if (memcmp(*pointer, TVG_HEADER_TVG_SIGN_CODE, TVG_HEADER_TVG_SIGN_CODE_LENGTH)) return false; if (memcmp(*ptr, TVG_BIN_HEADER_SIGNATURE, TVG_BIN_HEADER_SIGNATURE_LENGTH)) return false;
*pointer += TVG_HEADER_TVG_SIGN_CODE_LENGTH; // move after sing code *ptr += TVG_BIN_HEADER_SIGNATURE_LENGTH;
// Standard version number, declared in TVG_HEADER_TVG_VERSION_CODE //Version number, declared in TVG_BIN_HEADER_VERSION
if (memcmp(*pointer, TVG_HEADER_TVG_VERSION_CODE, TVG_HEADER_TVG_VERSION_CODE_LENGTH)) return false; if (memcmp(*ptr, TVG_BIN_HEADER_VERSION, TVG_BIN_HEADER_VERSION_LENGTH)) return false;
*pointer += TVG_HEADER_TVG_VERSION_CODE_LENGTH; // move after version code *ptr += TVG_BIN_HEADER_VERSION_LENGTH;
// Matadata phase //Mata data for proof?
uint16_t meta_length; // Matadata phase length uint16_t metaLen;
_read_tvg_ui16(&meta_length, *pointer); _read_tvg_ui16(&metaLen, *ptr);
*pointer += 2; // move after length *ptr += 2;
//Meta data... Necessary?
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
char metadata[meta_length + 1]; char metadata[metaLen + 1];
memcpy(metadata, *pointer, meta_length); memcpy(metadata, *ptr, metaLen);
metadata[meta_length] = '\0'; metadata[metaLen] = '\0';
printf("TVG_LOADER: Header is valid, metadata[%d]: %s.\n", meta_length, metadata); printf("TVG_LOADER: Header is valid, metadata[%d]: %s.\n", metaLen, metadata);
#endif #endif
*pointer += meta_length; *ptr += metaLen;
return true; return true;
} }
// Paint
static LoaderResult _parseCmpTarget(const char *pointer, const char *end, Paint *paint) static LoaderResult _parseCmpTarget(const char *ptr, const char *end, Paint *paint)
{ {
auto block = _readTvgBlock(pointer); auto block = _readTvgBlock(ptr);
if (block.blockEnd > end) return LoaderResult::SizeCorruption; if (block.end > end) return LoaderResult::SizeCorruption;
CompositeMethod cmpMethod; CompositeMethod cmpMethod;
if (block.type != TVG_PAINT_CMP_METHOD_INDICATOR) return LoaderResult::LogicalCorruption; if (block.type != TVG_PAINT_CMP_METHOD_INDICATOR) return LoaderResult::LogicalCorruption;
if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption; if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption;
switch (*block.data) switch (*block.data) {
{ case TVG_PAINT_CMP_METHOD_CLIPPATH_FLAG: {
case TVG_PAINT_CMP_METHOD_CLIPPATH_FLAG:
cmpMethod = CompositeMethod::ClipPath; cmpMethod = CompositeMethod::ClipPath;
break; break;
case TVG_PAINT_CMP_METHOD_ALPHAMASK_FLAG: }
case TVG_PAINT_CMP_METHOD_ALPHAMASK_FLAG: {
cmpMethod = CompositeMethod::AlphaMask; cmpMethod = CompositeMethod::AlphaMask;
break; break;
case TVG_PAINT_CMP_METHOD_INV_ALPHAMASK_FLAG: }
case TVG_PAINT_CMP_METHOD_INV_ALPHAMASK_FLAG: {
cmpMethod = CompositeMethod::InvAlphaMask; cmpMethod = CompositeMethod::InvAlphaMask;
break; break;
default: }
return LoaderResult::LogicalCorruption; default: return LoaderResult::LogicalCorruption;
} }
pointer = block.blockEnd; ptr = block.end;
auto block_paint = _readTvgBlock(pointer); auto block_paint = _readTvgBlock(ptr);
if (block_paint.blockEnd > end) return LoaderResult::SizeCorruption; if (block_paint.end > end) return LoaderResult::SizeCorruption;
Paint* cmpTarget; Paint* cmpTarget;
auto result = _parsePaint(block_paint, &cmpTarget); auto result = _parsePaint(block_paint, &cmpTarget);
@ -99,40 +108,35 @@ static LoaderResult _parseCmpTarget(const char *pointer, const char *end, Paint
return LoaderResult::Success; return LoaderResult::Success;
} }
static LoaderResult _parsePaintProperty(tvgBlock block, Paint *paint) static LoaderResult _parsePaintProperty(tvgBlock block, Paint *paint)
{ {
switch (block.type) switch (block.type) {
{ case TVG_PAINT_OPACITY_INDICATOR: {
case TVG_PAINT_OPACITY_INDICATOR:
{ // opacity
if (block.length != sizeof(uint8_t)) return LoaderResult::SizeCorruption; if (block.length != sizeof(uint8_t)) return LoaderResult::SizeCorruption;
paint->opacity(*block.data); paint->opacity(*block.data);
return LoaderResult::Success; return LoaderResult::Success;
} }
case TVG_PAINT_TRANSFORM_MATRIX_INDICATOR: case TVG_PAINT_TRANSFORM_MATRIX_INDICATOR: {
{ // transform matrix
if (block.length != sizeof(Matrix)) return LoaderResult::SizeCorruption; if (block.length != sizeof(Matrix)) return LoaderResult::SizeCorruption;
Matrix matrix; Matrix matrix;
memcpy(&matrix, block.data, sizeof(Matrix)); memcpy(&matrix, block.data, sizeof(Matrix));
if (paint->transform(matrix) != Result::Success) return LoaderResult::MemoryCorruption; if (paint->transform(matrix) != Result::Success) return LoaderResult::MemoryCorruption;
return LoaderResult::Success; return LoaderResult::Success;
} }
case TVG_PAINT_CMP_TARGET_INDICATOR: case TVG_PAINT_CMP_TARGET_INDICATOR: {
{ // cmp target
if (block.length < TVG_INDICATOR_SIZE + BYTE_COUNTER_SIZE) return LoaderResult::SizeCorruption; if (block.length < TVG_INDICATOR_SIZE + BYTE_COUNTER_SIZE) return LoaderResult::SizeCorruption;
return _parseCmpTarget(block.data, block.blockEnd, paint); return _parseCmpTarget(block.data, block.end, paint);
} }
} }
return LoaderResult::InvalidType; return LoaderResult::InvalidType;
} }
// Scene
static LoaderResult _parseSceneProperty(tvgBlock block, Scene *scene) static LoaderResult _parseSceneProperty(tvgBlock block, Scene *scene)
{ {
switch (block.type) switch (block.type) {
{ case TVG_SCENE_FLAG_RESERVEDCNT: {
case TVG_SCENE_FLAG_RESERVEDCNT:
{
if (block.length != sizeof(uint32_t)) return LoaderResult::SizeCorruption; if (block.length != sizeof(uint32_t)) return LoaderResult::SizeCorruption;
uint32_t reservedCnt; uint32_t reservedCnt;
_read_tvg_ui32(&reservedCnt, block.data); _read_tvg_ui32(&reservedCnt, block.data);
@ -151,104 +155,100 @@ static LoaderResult _parseSceneProperty(tvgBlock block, Scene *scene)
return result; return result;
} }
// Shape
static LoaderResult _parseShapePath(const char *pointer, const char *end, Shape *shape) static LoaderResult _parseShapePath(const char *ptr, const char *end, Shape *shape)
{ {
// ShapePath //Shape Path
uint32_t cmdCnt, ptsCnt; uint32_t cmdCnt, ptsCnt;
_read_tvg_ui32(&cmdCnt, pointer); _read_tvg_ui32(&cmdCnt, ptr);
pointer += sizeof(uint32_t); ptr += sizeof(uint32_t);
_read_tvg_ui32(&ptsCnt, pointer); _read_tvg_ui32(&ptsCnt, ptr);
pointer += sizeof(uint32_t); ptr += sizeof(uint32_t);
const PathCommand* cmds = (PathCommand*) pointer; const PathCommand* cmds = (PathCommand*) ptr;
pointer += sizeof(PathCommand) * cmdCnt; ptr += sizeof(PathCommand) * cmdCnt;
const Point* pts = (Point*) pointer; const Point* pts = (Point*) ptr;
pointer += sizeof(Point) * ptsCnt; ptr += sizeof(Point) * ptsCnt;
if (pointer > end) return LoaderResult::SizeCorruption; if (ptr > end) return LoaderResult::SizeCorruption;
shape->appendPath(cmds, cmdCnt, pts, ptsCnt); shape->appendPath(cmds, cmdCnt, pts, ptsCnt);
return LoaderResult::Success; return LoaderResult::Success;
} }
static LoaderResult _parseShapeFill(const char *pointer, const char *end, Fill **fillOutside)
static LoaderResult _parseShapeFill(const char *ptr, const char *end, Fill **fillOutside)
{ {
unique_ptr<Fill> fillGrad; unique_ptr<Fill> fillGrad;
while (pointer < end) while (ptr < end) {
{ auto block = _readTvgBlock(ptr);
auto block = _readTvgBlock(pointer); if (block.end > end) return LoaderResult::SizeCorruption;
if (block.blockEnd > end) return LoaderResult::SizeCorruption;
switch (block.type) switch (block.type) {
{ case TVG_FILL_RADIAL_GRADIENT_INDICATOR: {
case TVG_FILL_RADIAL_GRADIENT_INDICATOR:
{ // radial gradient
if (block.length != 3 * sizeof(float)) return LoaderResult::SizeCorruption; if (block.length != 3 * sizeof(float)) return LoaderResult::SizeCorruption;
const char* pointer = block.data; auto ptr = block.data;
float x, y, radius; float x, y, radius;
_read_tvg_float(&x, pointer); _read_tvg_float(&x, ptr);
pointer += sizeof(float); ptr += sizeof(float);
_read_tvg_float(&y, pointer); _read_tvg_float(&y, ptr);
pointer += sizeof(float); ptr += sizeof(float);
_read_tvg_float(&radius, pointer); _read_tvg_float(&radius, ptr);
auto fillGradRadial = RadialGradient::gen(); auto fillGradRadial = RadialGradient::gen();
fillGradRadial->radial(x, y, radius); fillGradRadial->radial(x, y, radius);
fillGrad = move(fillGradRadial); fillGrad = move(fillGradRadial);
break; break;
} }
case TVG_FILL_LINEAR_GRADIENT_INDICATOR: case TVG_FILL_LINEAR_GRADIENT_INDICATOR: {
{ // linear gradient
if (block.length != 4 * sizeof(float)) return LoaderResult::SizeCorruption; if (block.length != 4 * sizeof(float)) return LoaderResult::SizeCorruption;
const char* pointer = block.data; auto ptr = block.data;
float x1, y1, x2, y2; float x1, y1, x2, y2;
_read_tvg_float(&x1, pointer); _read_tvg_float(&x1, ptr);
pointer += sizeof(float); ptr += sizeof(float);
_read_tvg_float(&y1, pointer); _read_tvg_float(&y1, ptr);
pointer += sizeof(float); ptr += sizeof(float);
_read_tvg_float(&x2, pointer); _read_tvg_float(&x2, ptr);
pointer += sizeof(float); ptr += sizeof(float);
_read_tvg_float(&y2, pointer); _read_tvg_float(&y2, ptr);
auto fillGradLinear = LinearGradient::gen(); auto fillGradLinear = LinearGradient::gen();
fillGradLinear->linear(x1, y1, x2, y2); fillGradLinear->linear(x1, y1, x2, y2);
fillGrad = move(fillGradLinear); fillGrad = move(fillGradLinear);
break; break;
} }
case TVG_FILL_FILLSPREAD_INDICATOR: case TVG_FILL_FILLSPREAD_INDICATOR: {
{ // fill spread
if (!fillGrad) return LoaderResult::LogicalCorruption; if (!fillGrad) return LoaderResult::LogicalCorruption;
if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption; if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption;
switch (*block.data) switch (*block.data) {
{ case TVG_FILL_FILLSPREAD_PAD_FLAG: {
case TVG_FILL_FILLSPREAD_PAD_FLAG:
fillGrad->spread(FillSpread::Pad); fillGrad->spread(FillSpread::Pad);
break; break;
case TVG_FILL_FILLSPREAD_REFLECT_FLAG: }
case TVG_FILL_FILLSPREAD_REFLECT_FLAG: {
fillGrad->spread(FillSpread::Reflect); fillGrad->spread(FillSpread::Reflect);
break; break;
case TVG_FILL_FILLSPREAD_REPEAT_FLAG: }
case TVG_FILL_FILLSPREAD_REPEAT_FLAG: {
fillGrad->spread(FillSpread::Repeat); fillGrad->spread(FillSpread::Repeat);
break; break;
}
} }
break; break;
} }
case TVG_FILL_COLORSTOPS_INDICATOR: case TVG_FILL_COLORSTOPS_INDICATOR: {
{ // color stops
if (!fillGrad) return LoaderResult::LogicalCorruption; if (!fillGrad) return LoaderResult::LogicalCorruption;
if (block.length == 0 || block.length & 0x07) return LoaderResult::SizeCorruption; if (block.length == 0 || block.length & 0x07) return LoaderResult::SizeCorruption;
uint32_t stopsCnt = block.length >> 3; // 8 bytes per ColorStop uint32_t stopsCnt = block.length >> 3; // 8 bytes per ColorStop
if (stopsCnt > 1023) return LoaderResult::SizeCorruption; if (stopsCnt > 1023) return LoaderResult::SizeCorruption;
Fill::ColorStop stops[stopsCnt]; Fill::ColorStop stops[stopsCnt];
const char* p = block.data; auto p = block.data;
for (uint32_t i = 0; i < stopsCnt; i++, p += 8) for (uint32_t i = 0; i < stopsCnt; i++, p += 8) {
{
_read_tvg_float(&stops[i].offset, p); _read_tvg_float(&stops[i].offset, p);
stops[i].r = p[4]; stops[i].r = p[4];
stops[i].g = p[5]; stops[i].g = p[5];
@ -259,42 +259,38 @@ static LoaderResult _parseShapeFill(const char *pointer, const char *end, Fill *
break; break;
} }
} }
ptr = block.end;
pointer = block.blockEnd;
} }
*fillOutside = fillGrad.release(); *fillOutside = fillGrad.release();
return LoaderResult::Success; return LoaderResult::Success;
} }
static LoaderResult _parseShapeStrokeDashPattern(const char *pointer, const char *end, Shape *shape)
static LoaderResult _parseShapeStrokeDashPattern(const char *ptr, const char *end, Shape *shape)
{ {
uint32_t dashPatternCnt; uint32_t dashPatternCnt;
_read_tvg_ui32(&dashPatternCnt, pointer); _read_tvg_ui32(&dashPatternCnt, ptr);
pointer += sizeof(uint32_t); ptr += sizeof(uint32_t);
const float* dashPattern = (float*) pointer; const float* dashPattern = (float*) ptr;
pointer += sizeof(float) * dashPatternCnt; ptr += sizeof(float) * dashPatternCnt;
if (pointer > end) return LoaderResult::SizeCorruption; if (ptr > end) return LoaderResult::SizeCorruption;
shape->stroke(dashPattern, dashPatternCnt); shape->stroke(dashPattern, dashPatternCnt);
return LoaderResult::Success; return LoaderResult::Success;
} }
static LoaderResult _parseShapeStroke(const char *pointer, const char *end, Shape *shape)
{
while (pointer < end)
{
auto block = _readTvgBlock(pointer);
if (block.blockEnd > end) return LoaderResult::SizeCorruption;
switch (block.type) static LoaderResult _parseShapeStroke(const char *ptr, const char *end, Shape *shape)
{ {
case TVG_SHAPE_STROKE_CAP_INDICATOR: while (ptr < end) {
{ // stroke cap auto block = _readTvgBlock(ptr);
if (block.end > end) return LoaderResult::SizeCorruption;
switch (block.type) {
case TVG_SHAPE_STROKE_CAP_INDICATOR: {
if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption; if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption;
switch (*block.data) switch (*block.data) {
{
case TVG_SHAPE_STROKE_CAP_SQUARE_FLAG: case TVG_SHAPE_STROKE_CAP_SQUARE_FLAG:
shape->stroke(StrokeCap::Square); shape->stroke(StrokeCap::Square);
break; break;
@ -307,11 +303,9 @@ static LoaderResult _parseShapeStroke(const char *pointer, const char *end, Shap
} }
break; break;
} }
case TVG_SHAPE_STROKE_JOIN_INDICATOR: case TVG_SHAPE_STROKE_JOIN_INDICATOR: {
{ // stroke join
if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption; if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption;
switch (*block.data) switch (*block.data) {
{
case TVG_SHAPE_STROKE_JOIN_BEVEL_FLAG: case TVG_SHAPE_STROKE_JOIN_BEVEL_FLAG:
shape->stroke(StrokeJoin::Bevel); shape->stroke(StrokeJoin::Bevel);
break; break;
@ -324,77 +318,65 @@ static LoaderResult _parseShapeStroke(const char *pointer, const char *end, Shap
} }
break; break;
} }
case TVG_SHAPE_STROKE_WIDTH_INDICATOR: case TVG_SHAPE_STROKE_WIDTH_INDICATOR: {
{ // stroke width
if (block.length != sizeof(float)) return LoaderResult::SizeCorruption; if (block.length != sizeof(float)) return LoaderResult::SizeCorruption;
float width; float width;
_read_tvg_float(&width, block.data); _read_tvg_float(&width, block.data);
shape->stroke(width); shape->stroke(width);
break; break;
} }
case TVG_SHAPE_STROKE_COLOR_INDICATOR: case TVG_SHAPE_STROKE_COLOR_INDICATOR: {
{ // stroke color
if (block.length != 4) return LoaderResult::SizeCorruption; if (block.length != 4) return LoaderResult::SizeCorruption;
shape->stroke(block.data[0], block.data[1], block.data[2], block.data[3]); shape->stroke(block.data[0], block.data[1], block.data[2], block.data[3]);
break; break;
} }
case TVG_SHAPE_STROKE_FILL_INDICATOR: case TVG_SHAPE_STROKE_FILL_INDICATOR: {
{ // stroke fill
Fill* fill; Fill* fill;
auto result = _parseShapeFill(block.data, block.blockEnd, &fill); auto result = _parseShapeFill(block.data, block.end, &fill);
if (result != LoaderResult::Success) return result; if (result != LoaderResult::Success) return result;
shape->stroke(unique_ptr < Fill > (fill)); shape->stroke(unique_ptr < Fill > (fill));
break; break;
} }
case TVG_SHAPE_STROKE_DASHPTRN_INDICATOR: case TVG_SHAPE_STROKE_DASHPTRN_INDICATOR: {
{ // dashed stroke auto result = _parseShapeStrokeDashPattern(block.data, block.end, shape);
auto result = _parseShapeStrokeDashPattern(block.data, block.blockEnd, shape);
if (result != LoaderResult::Success) return result; if (result != LoaderResult::Success) return result;
break; break;
} }
} }
ptr = block.end;
pointer = block.blockEnd;
} }
return LoaderResult::Success; return LoaderResult::Success;
} }
static LoaderResult _parseShapeProperty(tvgBlock block, Shape *shape) static LoaderResult _parseShapeProperty(tvgBlock block, Shape *shape)
{ {
switch (block.type) switch (block.type) {
{ case TVG_SHAPE_PATH_INDICATOR: {
case TVG_SHAPE_PATH_INDICATOR: auto result = _parseShapePath(block.data, block.end, shape);
{ // path
auto result = _parseShapePath(block.data, block.blockEnd, shape);
if (result != LoaderResult::Success) return result; if (result != LoaderResult::Success) return result;
break; break;
} }
case TVG_SHAPE_STROKE_INDICATOR: case TVG_SHAPE_STROKE_INDICATOR: {
{ // stroke section auto result = _parseShapeStroke(block.data, block.end, shape);
auto result = _parseShapeStroke(block.data, block.blockEnd, shape);
if (result != LoaderResult::Success) return result; if (result != LoaderResult::Success) return result;
break; break;
} }
case TVG_SHAPE_FILL_INDICATOR: case TVG_SHAPE_FILL_INDICATOR: {
{ // fill (gradient)
Fill* fill; Fill* fill;
auto result = _parseShapeFill(block.data, block.blockEnd, &fill); auto result = _parseShapeFill(block.data, block.end, &fill);
if (result != LoaderResult::Success) return result; if (result != LoaderResult::Success) return result;
shape->fill(unique_ptr < Fill > (fill)); shape->fill(unique_ptr < Fill > (fill));
break; break;
} }
case TVG_SHAPE_COLOR_INDICATOR: case TVG_SHAPE_COLOR_INDICATOR: {
{ // color
if (block.length != 4) return LoaderResult::SizeCorruption; if (block.length != 4) return LoaderResult::SizeCorruption;
shape->fill(block.data[0], block.data[1], block.data[2], block.data[3]); shape->fill(block.data[0], block.data[1], block.data[2], block.data[3]);
break; break;
} }
case TVG_SHAPE_FILLRULE_INDICATOR: case TVG_SHAPE_FILLRULE_INDICATOR: {
{ // fill rule
if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption; if (block.length != sizeof(TvgFlag)) return LoaderResult::SizeCorruption;
switch (*block.data) switch (*block.data) {
{
case TVG_SHAPE_FILLRULE_WINDING_FLAG: case TVG_SHAPE_FILLRULE_WINDING_FLAG:
shape->fill(FillRule::Winding); shape->fill(FillRule::Winding);
break; break;
@ -404,36 +386,30 @@ static LoaderResult _parseShapeProperty(tvgBlock block, Shape *shape)
} }
break; break;
} }
default: default: return LoaderResult::InvalidType;
{
return LoaderResult::InvalidType;
}
} }
return LoaderResult::Success; return LoaderResult::Success;
} }
// Picture
static LoaderResult _parsePicture(tvgBlock block, Picture *picture) static LoaderResult _parsePicture(tvgBlock block, Picture *picture)
{ {
switch (block.type) switch (block.type) {
{ case TVG_RAW_IMAGE_BEGIN_INDICATOR: {
case TVG_RAW_IMAGE_BEGIN_INDICATOR:
{
if (block.length < 2*sizeof(uint32_t)) return LoaderResult::SizeCorruption; if (block.length < 2*sizeof(uint32_t)) return LoaderResult::SizeCorruption;
const char* pointer = block.data; const char* ptr = block.data;
uint32_t w, h; uint32_t w, h;
_read_tvg_ui32(&w, pointer); _read_tvg_ui32(&w, ptr);
pointer += sizeof(uint32_t); ptr += sizeof(uint32_t);
_read_tvg_ui32(&h, pointer); _read_tvg_ui32(&h, ptr);
pointer += sizeof(uint32_t); ptr += sizeof(uint32_t);
uint32_t size = w * h * sizeof(uint32_t); uint32_t size = w * h * sizeof(uint32_t);
if (block.length != 2*sizeof(uint32_t) + size) return LoaderResult::SizeCorruption; if (block.length != 2*sizeof(uint32_t) + size) return LoaderResult::SizeCorruption;
uint32_t* pixels = (uint32_t*) pointer; uint32_t* pixels = (uint32_t*) ptr;
picture->load(pixels, w, h, true); picture->load(pixels, w, h, true);
return LoaderResult::Success; return LoaderResult::Success;
} }
@ -452,97 +428,87 @@ static LoaderResult _parsePicture(tvgBlock block, Picture *picture)
static LoaderResult _parsePaint(tvgBlock base_block, Paint **paint) static LoaderResult _parsePaint(tvgBlock base_block, Paint **paint)
{ {
switch (base_block.type) switch (base_block.type) {
{ case TVG_SCENE_BEGIN_INDICATOR: {
case TVG_SCENE_BEGIN_INDICATOR:
{
auto s = Scene::gen(); auto s = Scene::gen();
const char* pointer = base_block.data; auto ptr = base_block.data;
while (pointer < base_block.blockEnd) while (ptr < base_block.end) {
{ auto block = _readTvgBlock(ptr);
auto block = _readTvgBlock(pointer); if (block.end > base_block.end) return LoaderResult::SizeCorruption;
if (block.blockEnd > base_block.blockEnd) return LoaderResult::SizeCorruption;
auto result = _parseSceneProperty(block, s.get()); auto result = _parseSceneProperty(block, s.get());
if (result == LoaderResult::InvalidType) result = _parsePaintProperty(block, s.get()); if (result == LoaderResult::InvalidType) result = _parsePaintProperty(block, s.get());
if (result > LoaderResult::Success) if (result > LoaderResult::Success) {
{
// LOG: tvg parsing error
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: Loading scene error[type: 0x%02x]: %d\n", (int) block.type, (int) result); printf("TVG_LOADER: Loading scene error[type: 0x%02x]: %d\n", (int) block.type, (int) result);
#endif #endif
return result; return result;
} }
pointer = block.blockEnd; ptr = block.end;
} }
*paint = s.release(); *paint = s.release();
break; break;
} }
case TVG_SHAPE_BEGIN_INDICATOR: case TVG_SHAPE_BEGIN_INDICATOR: {
{
auto s = Shape::gen(); auto s = Shape::gen();
const char* pointer = base_block.data; auto ptr = base_block.data;
while (pointer < base_block.blockEnd) while (ptr < base_block.end) {
{ auto block = _readTvgBlock(ptr);
auto block = _readTvgBlock(pointer); if (block.end > base_block.end) return LoaderResult::SizeCorruption;
if (block.blockEnd > base_block.blockEnd) return LoaderResult::SizeCorruption;
auto result = _parseShapeProperty(block, s.get()); auto result = _parseShapeProperty(block, s.get());
if (result == LoaderResult::InvalidType) result = _parsePaintProperty(block, s.get()); if (result == LoaderResult::InvalidType) result = _parsePaintProperty(block, s.get());
if (result > LoaderResult::Success) if (result > LoaderResult::Success) {
{
// LOG: tvg parsing error
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: Loading shape error[type: 0x%02x]: %d\n", (int) block.type, (int) result); printf("TVG_LOADER: Loading shape error[type: 0x%02x]: %d\n", (int) block.type, (int) result);
#endif #endif
return result; return result;
} }
pointer = block.blockEnd; ptr = block.end;
} }
*paint = s.release(); *paint = s.release();
break; break;
} }
case TVG_PICTURE_BEGIN_INDICATOR: case TVG_PICTURE_BEGIN_INDICATOR: {
{
auto s = Picture::gen(); auto s = Picture::gen();
const char* pointer = base_block.data; auto ptr = base_block.data;
while (pointer < base_block.blockEnd) while (ptr < base_block.end) {
{ auto block = _readTvgBlock(ptr);
auto block = _readTvgBlock(pointer); if (block.end > base_block.end) return LoaderResult::SizeCorruption;
if (block.blockEnd > base_block.blockEnd) return LoaderResult::SizeCorruption;
auto result = _parsePicture(block, s.get()); auto result = _parsePicture(block, s.get());
if (result == LoaderResult::InvalidType) result = _parsePaintProperty(block, s.get()); if (result == LoaderResult::InvalidType) result = _parsePaintProperty(block, s.get());
if (result > LoaderResult::Success) if (result > LoaderResult::Success) {
{
// LOG: tvg parsing error
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: Loading picture error[type: 0x%02x]: %d\n", (int) block.type, (int) result); printf("TVG_LOADER: Loading picture error[type: 0x%02x]: %d\n", (int) block.type, (int) result);
#endif #endif
return result; return result;
} }
pointer = block.blockEnd; ptr = block.end;
} }
*paint = s.release(); *paint = s.release();
break; break;
} }
default: default: return LoaderResult::InvalidType;
return LoaderResult::InvalidType;
} }
return LoaderResult::Success; return LoaderResult::Success;
} }
unique_ptr<Scene> tvgParseTvgFile(const char *pointer, uint32_t size)
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
unique_ptr<Scene> tvgLoadTvgData(const char *ptr, uint32_t size)
{ {
const char* end = pointer + size; auto end = ptr + size;
if (!_readTvgHeader(&pointer) || pointer >= end)
{ if (!_readTvgHeader(&ptr) || ptr >= end) {
// LOG: Header is improper
#ifdef THORVG_LOG_ENABLED #ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: Header is improper.\n"); printf("TVG_LOADER: Invalid TVG Data!\n");
#endif #endif
return nullptr; return nullptr;
} }
@ -551,10 +517,10 @@ unique_ptr<Scene> tvgParseTvgFile(const char *pointer, uint32_t size)
if (!scene) return nullptr; if (!scene) return nullptr;
Paint* paint; Paint* paint;
while (pointer < end)
{ while (ptr < end) {
auto block = _readTvgBlock(pointer); auto block = _readTvgBlock(ptr);
if (block.blockEnd > end) return nullptr; if (block.end > end) return nullptr;
auto result = _parsePaint(block, &paint); auto result = _parsePaint(block, &paint);
if (result > LoaderResult::Success) return nullptr; if (result > LoaderResult::Success) return nullptr;
@ -563,13 +529,8 @@ unique_ptr<Scene> tvgParseTvgFile(const char *pointer, uint32_t size)
return nullptr; return nullptr;
} }
} }
ptr = block.end;
pointer = block.blockEnd;
} }
// LOG: File parsed correctly
#ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: File parsed correctly.\n");
#endif
return move(scene); return move(scene);
} }

View file

@ -24,8 +24,8 @@
#define _TVG_TVG_LOAD_PARSER_H_ #define _TVG_TVG_LOAD_PARSER_H_
#include "tvgCommon.h" #include "tvgCommon.h"
#include "tvgTvgHelper.h" #include "tvgBinaryDesc.h"
unique_ptr<Scene> tvgParseTvgFile(const char *pointer, uint32_t size); unique_ptr<Scene> tvgLoadTvgData(const char *ptr, uint32_t size);
#endif //_TVG_TVG_LOAD_PARSER_H_ #endif //_TVG_TVG_LOAD_PARSER_H_

View file

@ -21,48 +21,50 @@
*/ */
#include <fstream> #include <fstream>
#include <string.h>
#include "tvgLoaderMgr.h" #include "tvgLoaderMgr.h"
#include "tvgTvgLoader.h" #include "tvgTvgLoader.h"
#include "tvgTvgLoadParser.h" #include "tvgTvgLoadParser.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
void TvgLoader::clearBuffer()
{
free(buffer);
size = 0;
buffer = nullptr;
pointer = nullptr;
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
TvgLoader::~TvgLoader() TvgLoader::~TvgLoader()
{ {
close(); close();
} }
void TvgLoader::clearBuffer()
{
size = 0;
free(buffer);
buffer = nullptr;
pointer = nullptr;
}
bool TvgLoader::open(const string &path) bool TvgLoader::open(const string &path)
{ {
//TODO: verify memory leak if open() is called multiple times.
ifstream f; ifstream f;
f.open(path, ifstream::in | ifstream::binary | ifstream::ate); f.open(path, ifstream::in | ifstream::binary | ifstream::ate);
if (!f.is_open()) if (!f.is_open()) return false;
{
#ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: Failed to open file\n");
#endif
return false;
}
size = f.tellg(); size = f.tellg();
f.seekg(0, ifstream::beg); f.seekg(0, ifstream::beg);
buffer = (char*) malloc(size); buffer = (char*)malloc(size);
if (!buffer) if (!buffer) {
{
size = 0; size = 0;
f.close(); f.close();
#ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: Failed to alloc buffer\n");
#endif
return false; return false;
} }
@ -77,13 +79,20 @@ bool TvgLoader::open(const string &path)
pointer = buffer; pointer = buffer;
//FIXME: verify TVG format here.
return true; return true;
} }
bool TvgLoader::open(const char *data, uint32_t size) bool TvgLoader::open(const char *data, uint32_t size)
{ {
//TODO: verify memory leak if open() is called multiple times.
pointer = data; pointer = data;
size = size; size = size;
//FIXME: verify TVG format here.
return true; return true;
} }
@ -106,15 +115,8 @@ bool TvgLoader::close()
void TvgLoader::run(unsigned tid) void TvgLoader::run(unsigned tid)
{ {
if (root) root.reset(); if (root) root.reset();
root = tvgParseTvgFile(pointer, size); root = tvgLoadTvgData(pointer, size);
if (!root) clearBuffer();
if (!root)
{
#ifdef THORVG_LOG_ENABLED
printf("TVG_LOADER: File parsing error\n");
#endif
clearBuffer();
}
} }
unique_ptr<Scene> TvgLoader::scene() unique_ptr<Scene> TvgLoader::scene()
@ -122,4 +124,4 @@ unique_ptr<Scene> TvgLoader::scene()
this->done(); this->done();
if (root) return move(root); if (root) return move(root);
return nullptr; return nullptr;
} }

View file

@ -23,7 +23,6 @@
#ifndef _TVG_TVG_LOADER_H_ #ifndef _TVG_TVG_LOADER_H_
#define _TVG_TVG_LOADER_H_ #define _TVG_TVG_LOADER_H_
#include "tvgLoader.h"
#include "tvgTaskScheduler.h" #include "tvgTaskScheduler.h"
class TvgLoader : public Loader, public Task class TvgLoader : public Loader, public Task
@ -33,14 +32,13 @@ public:
const char* pointer = nullptr; const char* pointer = nullptr;
uint32_t size = 0; uint32_t size = 0;
unique_ptr<Scene> root; unique_ptr<Scene> root = nullptr;
~TvgLoader(); ~TvgLoader();
using Loader::open; using Loader::open;
bool open(const string &path) override; bool open(const string &path) override;
bool open(const char *data, uint32_t size) override; bool open(const char *data, uint32_t size) override;
bool read() override; bool read() override;
bool close() override; bool close() override;