From 361b8609eeb439ee15a88160277078664a54b49e Mon Sep 17 00:00:00 2001 From: overtake <> Date: Wed, 4 Sep 2019 13:34:05 +0300 Subject: [PATCH 01/24] no message --- src/vector/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vector/config.h b/src/vector/config.h index 528115bc..4fc34aa9 100644 --- a/src/vector/config.h +++ b/src/vector/config.h @@ -2,7 +2,7 @@ #define CONFIG_H // enable threading -#define LOTTIE_THREAD_SUPPORT +//#define LOTTIE_THREAD_SUPPORT //enable logging //#define LOTTIE_LOGGING_SUPPORT From b579347124cb7831ce7564c9f29b7f321f5af556 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 19 Oct 2019 17:51:28 +0400 Subject: [PATCH 02/24] Fixes --- src/vector/config.h | 19 ------------------- src/vector/freetype/v_ft_raster.cpp | 4 ++++ src/vector/vdrawhelper.cpp | 4 ++-- 3 files changed, 6 insertions(+), 21 deletions(-) delete mode 100644 src/vector/config.h diff --git a/src/vector/config.h b/src/vector/config.h deleted file mode 100644 index 528115bc..00000000 --- a/src/vector/config.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -// enable threading -#define LOTTIE_THREAD_SUPPORT - -//enable logging -//#define LOTTIE_LOGGING_SUPPORT - -//enable module building of image loader -//#define LOTTIE_IMAGE_MODULE_SUPPORT - -//enable lottie model caching -//#define LOTTIE_CACHE_SUPPORT - -// disable image loader -#define LOTTIE_IMAGE_MODULE_DISABLED - -#endif // CONFIG_H diff --git a/src/vector/freetype/v_ft_raster.cpp b/src/vector/freetype/v_ft_raster.cpp index 51cb1f2c..a5d2c754 100644 --- a/src/vector/freetype/v_ft_raster.cpp +++ b/src/vector/freetype/v_ft_raster.cpp @@ -536,6 +536,10 @@ static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y) dx = to_x - ras.x; dy = to_y - ras.y; + + if (SW_FT_ABS(dx) > 10000000 || SW_FT_ABS(dy) > 10000000) { + goto End; + } fx1 = ras.x - SUBPIXELS(ex1); fy1 = ras.y - SUBPIXELS(ey1); diff --git a/src/vector/vdrawhelper.cpp b/src/vector/vdrawhelper.cpp index 771228ed..00e4605a 100644 --- a/src/vector/vdrawhelper.cpp +++ b/src/vector/vdrawhelper.cpp @@ -867,7 +867,7 @@ void VSpanData::updateSpanFunc() } } -#if !defined(__SSE2__) && !defined(__ARM_NEON__) +#if !defined(__SSE2__) && (!defined(__ARM_NEON__) || defined(LOTTIE_DISABLE_ARM_NEON)) void memfill32(uint32_t *dest, uint32_t value, int length) { int n; @@ -912,7 +912,7 @@ void vInitDrawhelperFunctions() { vInitBlendFunctions(); -#if defined(__ARM_NEON__) +#if defined(__ARM_NEON__) && !defined(LOTTIE_DISABLE_ARM_NEON) // update fast path for NEON extern void Vcomp_func_solid_SourceOver_neon( uint32_t * dest, int length, uint32_t color, uint32_t const_alpha); From c490c7a098b9b3cbc3195b00e90d6fc3989e2ba2 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 19 Oct 2019 21:34:10 +0400 Subject: [PATCH 03/24] Don't try entering object if it's not one --- src/lottie/lottieparser.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 1cc7febf..893a4ea2 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -925,9 +925,10 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) } else if (0 == strcmp(key, "bm")) { layer->mBlendMode = getBlendMode(); } else if (0 == strcmp(key, "ks")) { - RAPIDJSON_ASSERT(PeekType() == kObjectType); - EnterObject(); - layer->mTransform = parseTransformObject(ddd); + if (PeekType() == kObjectType) { + EnterObject(); + layer->mTransform = parseTransformObject(ddd); + } } else if (0 == strcmp(key, "shapes")) { parseShapesAttr(layer); } else if (0 == strcmp(key, "w")) { From a09896b3e72e76681c12e80572a7d570108cf885 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 22 Oct 2019 03:11:17 +0400 Subject: [PATCH 04/24] Disable asserts in lottieparser --- src/lottie/lottieparser.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 893a4ea2..07231e27 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -313,7 +313,7 @@ bool LottieParserImpl::EnterObject() { if (st_ != kEnteringObject) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return false; } @@ -325,7 +325,7 @@ bool LottieParserImpl::EnterArray() { if (st_ != kEnteringArray) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return false; } @@ -355,7 +355,7 @@ const char *LottieParserImpl::NextObjectKey() } if (st_ != kExitingObject) { - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); st_ = kError; return nullptr; } @@ -379,7 +379,7 @@ bool LottieParserImpl::NextArrayValue() } if (st_ == kError || st_ == kHasKey) { - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); st_ = kError; return false; } @@ -391,7 +391,7 @@ int LottieParserImpl::GetInt() { if (st_ != kHasNumber || !v_.IsInt()) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return 0; } @@ -404,7 +404,7 @@ double LottieParserImpl::GetDouble() { if (st_ != kHasNumber) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return 0.; } @@ -417,7 +417,7 @@ bool LottieParserImpl::GetBool() { if (st_ != kHasBool) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return false; } @@ -440,7 +440,7 @@ const char *LottieParserImpl::GetString() { if (st_ != kHasString) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return nullptr; } @@ -457,7 +457,7 @@ void LottieParserImpl::SkipOut(int depth) } else if (st_ == kExitingArray || st_ == kExitingObject) { --depth; } else if (st_ == kError) { - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return; } From d531c4af55c5985db1e6798ab342854993bfa505 Mon Sep 17 00:00:00 2001 From: overtake Date: Wed, 6 Nov 2019 13:57:38 +0400 Subject: [PATCH 05/24] no message --- src/lottie/rapidjson/rapidjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lottie/rapidjson/rapidjson.h b/src/lottie/rapidjson/rapidjson.h index 549936ff..7c4fd7be 100644 --- a/src/lottie/rapidjson/rapidjson.h +++ b/src/lottie/rapidjson/rapidjson.h @@ -403,7 +403,7 @@ RAPIDJSON_NAMESPACE_END */ #ifndef RAPIDJSON_ASSERT #include -#define RAPIDJSON_ASSERT(x) assert(x) +#define RAPIDJSON_ASSERT(x) //assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// From 19f69645dd373631c709cffb003533a9b2f64e75 Mon Sep 17 00:00:00 2001 From: overtake Date: Thu, 7 Nov 2019 12:28:05 +0400 Subject: [PATCH 06/24] no message --- src/lottie/lottieitem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 09d14a4e..aed4b26f 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -92,6 +92,7 @@ void LOTCompItem::setValue(const std::string &keypath, LOTVariant &value) { LOTKeyPath key(keypath); mRootLayer->resolveKeyPath(key, 0, value); + mCurFrameNo = -1; } std::unique_ptr LOTCompItem::createLayerItem( From 010860eb31a362071dbfc113b4317b6c0fd08ad3 Mon Sep 17 00:00:00 2001 From: overtake Date: Fri, 10 Jan 2020 19:48:39 +0400 Subject: [PATCH 07/24] - bugfixes and improvements --- src/vector/freetype/v_ft_raster.cpp | 807 ++++++++++++++-------------- 1 file changed, 410 insertions(+), 397 deletions(-) diff --git a/src/vector/freetype/v_ft_raster.cpp b/src/vector/freetype/v_ft_raster.cpp index 51cb1f2c..9d10578f 100644 --- a/src/vector/freetype/v_ft_raster.cpp +++ b/src/vector/freetype/v_ft_raster.cpp @@ -16,7 +16,7 @@ /***************************************************************************/ /*************************************************************************/ -/* */ +/* a */ /* This is a new anti-aliasing scan-converter for FreeType 2. The */ /* algorithm used here is _very_ different from the one in the standard */ /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ @@ -64,13 +64,14 @@ #define SW_FT_BEGIN_STMNT do { #define SW_FT_END_STMNT \ - } \ - while (0) +} \ +while (0) #include #include #include #include + #define SW_FT_UINT_MAX UINT_MAX #define SW_FT_INT_MAX INT_MAX #define SW_FT_ULONG_MAX ULONG_MAX @@ -113,13 +114,13 @@ typedef int (*SW_FT_Outline_LineToFunc)(const SW_FT_Vector* to, void* user); #define SW_FT_Outline_LineTo_Func SW_FT_Outline_LineToFunc typedef int (*SW_FT_Outline_ConicToFunc)(const SW_FT_Vector* control, - const SW_FT_Vector* to, void* user); +const SW_FT_Vector* to, void* user); #define SW_FT_Outline_ConicTo_Func SW_FT_Outline_ConicToFunc typedef int (*SW_FT_Outline_CubicToFunc)(const SW_FT_Vector* control1, - const SW_FT_Vector* control2, - const SW_FT_Vector* to, void* user); +const SW_FT_Vector* control2, +const SW_FT_Vector* to, void* user); #define SW_FT_Outline_CubicTo_Func SW_FT_Outline_CubicToFunc @@ -128,21 +129,21 @@ typedef struct SW_FT_Outline_Funcs_ { SW_FT_Outline_LineToFunc line_to; SW_FT_Outline_ConicToFunc conic_to; SW_FT_Outline_CubicToFunc cubic_to; - + int shift; SW_FT_Pos delta; - + } SW_FT_Outline_Funcs; #define SW_FT_DEFINE_OUTLINE_FUNCS(class_, move_to_, line_to_, conic_to_, \ - cubic_to_, shift_, delta_) \ - static const SW_FT_Outline_Funcs class_ = {move_to_, line_to_, conic_to_, \ - cubic_to_, shift_, delta_}; +cubic_to_, shift_, delta_) \ +static const SW_FT_Outline_Funcs class_ = {move_to_, line_to_, conic_to_, \ +cubic_to_, shift_, delta_}; #define SW_FT_DEFINE_RASTER_FUNCS(class_, raster_new_, raster_reset_, \ - raster_render_, raster_done_) \ - const SW_FT_Raster_Funcs class_ = {raster_new_, raster_reset_, \ - raster_render_, raster_done_}; +raster_render_, raster_done_) \ +const SW_FT_Raster_Funcs class_ = {raster_new_, raster_reset_, \ +raster_render_, raster_done_}; #ifndef SW_FT_MEM_SET #define SW_FT_MEM_SET(d, s, c) ft_memset(d, s, c) @@ -187,7 +188,8 @@ typedef struct SW_FT_Outline_Funcs_ { #define ONE_PIXEL (1L << PIXEL_BITS) #define PIXEL_MASK (-1L << PIXEL_BITS) #define TRUNC(x) ((TCoord)((x) >> PIXEL_BITS)) -#define SUBPIXELS(x) ((TPos)(x) << PIXEL_BITS) +#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) + #define FLOOR(x) ((x) & -ONE_PIXEL) #define CEILING(x) (((x) + ONE_PIXEL - 1) & -ONE_PIXEL) #define ROUND(x) (((x) + ONE_PIXEL / 2) & -ONE_PIXEL) @@ -204,13 +206,13 @@ typedef struct SW_FT_Outline_Funcs_ { /* remainder, cast to a specific type. This macro also ensures that */ /* the remainder is always positive. */ #define SW_FT_DIV_MOD(type, dividend, divisor, quotient, remainder) \ - SW_FT_BEGIN_STMNT(quotient) = (type)((dividend) / (divisor)); \ - (remainder) = (type)((dividend) % (divisor)); \ - if ((remainder) < 0) { \ - (quotient)--; \ - (remainder) += (type)(divisor); \ - } \ - SW_FT_END_STMNT +SW_FT_BEGIN_STMNT(quotient) = (type)((dividend) / (divisor)); \ +(remainder) = (type)((dividend) % (divisor)); \ +if ((remainder) < 0) { \ +(quotient)--; \ +(remainder) += (type)(divisor); \ +} \ +SW_FT_END_STMNT #ifdef __arm__ /* Work around a bug specific to GCC which make the compiler fail to */ @@ -220,22 +222,23 @@ typedef struct SW_FT_Outline_Funcs_ { /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721 */ #undef SW_FT_DIV_MOD #define SW_FT_DIV_MOD(type, dividend, divisor, quotient, remainder) \ - SW_FT_BEGIN_STMNT(quotient) = (type)((dividend) / (divisor)); \ - (remainder) = (type)((dividend) - (quotient) * (divisor)); \ - if ((remainder) < 0) { \ - (quotient)--; \ - (remainder) += (type)(divisor); \ - } \ - SW_FT_END_STMNT +SW_FT_BEGIN_STMNT(quotient) = (type)((dividend) / (divisor)); \ +(remainder) = (type)((dividend) - (quotient) * (divisor)); \ +if ((remainder) < 0) { \ +(quotient)--; \ +(remainder) += (type)(divisor); \ +} \ +SW_FT_END_STMNT #endif /* __arm__ */ /* These macros speed up repetitive divisions by replacing them */ /* with multiplications and right shifts. */ -#define SW_FT_UDIVPREP(b) \ - long b##_r = (long)(SW_FT_ULONG_MAX >> PIXEL_BITS) / (b) -#define SW_FT_UDIV(a, b) \ - (((unsigned long)(a) * (unsigned long)(b##_r)) >> \ - (sizeof(long) * SW_FT_CHAR_BIT - PIXEL_BITS)) +#define SW_FT_UDIVPREP( c, b ) \ +long b ## _r = c ? (long)( SW_FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \ +: 0 +#define SW_FT_UDIV( a, b ) \ +(TCoord)( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \ +( sizeof( long ) * SW_FT_CHAR_BIT - PIXEL_BITS ) ) /*************************************************************************/ /* */ @@ -278,7 +281,7 @@ typedef struct TCell_ { TCoord cover; /* same with gray_TWorker.cover */ TArea area; PCell next; - + } TCell; #if defined(_MSC_VER) /* Visual C++ (and Intel C++) */ @@ -290,49 +293,49 @@ typedef struct TCell_ { #endif /* _MSC_VER */ typedef struct gray_TWorker_ { + ft_jmp_buf jump_buffer; + TCoord ex, ey; TPos min_ex, max_ex; TPos min_ey, max_ey; TPos count_ex, count_ey; - + TArea area; TCoord cover; int invalid; - + PCell cells; SW_FT_PtrDist max_cells; SW_FT_PtrDist num_cells; - + TPos x, y; - + SW_FT_Vector bez_stack[32 * 3 + 1]; int lev_stack[32]; - + SW_FT_Outline outline; SW_FT_BBox clip_box; - + int bound_left; int bound_top; int bound_right; int bound_bottom; - + SW_FT_Span gray_spans[SW_FT_MAX_GRAY_SPANS]; int num_gray_spans; - + SW_FT_Raster_Span_Func render_span; void* render_span_data; - + int band_size; int band_shoot; - - ft_jmp_buf jump_buffer; - + void* buffer; long buffer_size; - + PCell* ycells; TPos ycount; - + } gray_TWorker, *gray_PWorker; #if defined(_MSC_VER) @@ -347,7 +350,7 @@ static gray_TWorker ras; typedef struct gray_TRaster_ { void* memory; - + } gray_TRaster, *gray_PRaster; /*************************************************************************/ @@ -358,7 +361,7 @@ static void gray_init_cells(RAS_ARG_ void* buffer, long byte_size) { ras.buffer = buffer; ras.buffer_size = byte_size; - + ras.ycells = (PCell*)buffer; ras.cells = NULL; ras.max_cells = 0; @@ -366,7 +369,7 @@ static void gray_init_cells(RAS_ARG_ void* buffer, long byte_size) ras.area = 0; ras.cover = 0; ras.invalid = 1; - + ras.bound_left = INT_MAX; ras.bound_top = INT_MAX; ras.bound_right = INT_MIN; @@ -382,28 +385,28 @@ static void gray_compute_cbox(RAS_ARG) SW_FT_Outline* outline = &ras.outline; SW_FT_Vector* vec = outline->points; SW_FT_Vector* limit = vec + outline->n_points; - + if (outline->n_points <= 0) { ras.min_ex = ras.max_ex = 0; ras.min_ey = ras.max_ey = 0; return; } - + ras.min_ex = ras.max_ex = vec->x; ras.min_ey = ras.max_ey = vec->y; - + vec++; - + for (; vec < limit; vec++) { TPos x = vec->x; TPos y = vec->y; - + if (x < ras.min_ex) ras.min_ex = x; if (x > ras.max_ex) ras.max_ex = x; if (y < ras.min_ey) ras.min_ey = y; if (y > ras.max_ey) ras.max_ey = y; } - + /* truncate the bounding box to integer pixels */ ras.min_ex = ras.min_ex >> 6; ras.min_ey = ras.min_ey >> 6; @@ -419,29 +422,29 @@ static PCell gray_find_cell(RAS_ARG) { PCell *pcell, cell; TPos x = ras.ex; - + if (x > ras.count_ex) x = ras.count_ex; - + pcell = &ras.ycells[ras.ey]; for (;;) { cell = *pcell; if (cell == NULL || cell->x > x) break; - + if (cell->x == x) goto Exit; - + pcell = &cell->next; } - + if (ras.num_cells >= ras.max_cells) ft_longjmp(ras.jump_buffer, 1); - + cell = ras.cells + ras.num_cells++; cell->x = x; cell->area = 0; cell->cover = 0; - + cell->next = *pcell; *pcell = cell; - + Exit: return cell; } @@ -450,7 +453,7 @@ static void gray_record_cell(RAS_ARG) { if (ras.area | ras.cover) { PCell cell = gray_find_cell(RAS_VAR); - + cell->area += ras.area; cell->cover += ras.cover; } @@ -471,29 +474,29 @@ static void gray_set_cell(RAS_ARG_ TCoord ex, TCoord ey) /* */ /* Note that if a cell is to the left of the clipping region, it is */ /* actually set to the (min_ex-1) horizontal position. */ - + /* All cells that are on the left of the clipping region go to the */ /* min_ex - 1 horizontal position. */ ey -= ras.min_ey; - + if (ex > ras.max_ex) ex = ras.max_ex; - + ex -= ras.min_ex; if (ex < 0) ex = -1; - + /* are we moving to a different cell ? */ if (ex != ras.ex || ey != ras.ey) { /* record the current one if it is valid */ if (!ras.invalid) gray_record_cell(RAS_VAR); - + ras.area = 0; ras.cover = 0; ras.ex = ex; ras.ey = ey; } - + ras.invalid = - ((unsigned)ey >= (unsigned)ras.count_ey || ex >= ras.count_ex); + ((unsigned)ey >= (unsigned)ras.count_ey || ex >= ras.count_ex); } /*************************************************************************/ @@ -503,15 +506,15 @@ static void gray_set_cell(RAS_ARG_ TCoord ex, TCoord ey) static void gray_start_cell(RAS_ARG_ TCoord ex, TCoord ey) { if (ex > ras.max_ex) ex = (TCoord)(ras.max_ex); - + if (ex < ras.min_ex) ex = (TCoord)(ras.min_ex - 1); - + ras.area = 0; ras.cover = 0; ras.ex = ex - ras.min_ex; ras.ey = ey - ras.min_ey; ras.invalid = 0; - + gray_set_cell(RAS_VAR_ ex, ey); } @@ -521,137 +524,148 @@ static void gray_start_cell(RAS_ARG_ TCoord ex, TCoord ey) /* */ static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y) { - TPos dx, dy, fx1, fy1, fx2, fy2; - TCoord ex1, ex2, ey1, ey2; - - ex1 = TRUNC(ras.x); - ex2 = TRUNC(to_x); - ey1 = TRUNC(ras.y); - ey2 = TRUNC(to_y); - + TPos dx, dy; + TCoord fx1, fy1, fx2, fy2; + TCoord ex1, ey1, ex2, ey2; + + ey1 = TRUNC( ras.y ); + ey2 = TRUNC( to_y ); + /* perform vertical clipping */ - if ((ey1 >= ras.max_ey && ey2 >= ras.max_ey) || - (ey1 < ras.min_ey && ey2 < ras.min_ey)) + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) goto End; - + + ex1 = TRUNC( ras.x ); + ex2 = TRUNC( to_x ); + + fx1 = FRACT( ras.x ); + fy1 = FRACT( ras.y ); + dx = to_x - ras.x; dy = to_y - ras.y; - - fx1 = ras.x - SUBPIXELS(ex1); - fy1 = ras.y - SUBPIXELS(ey1); - - if (ex1 == ex2 && ey1 == ey2) /* inside one cell */ + + if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ ; - else if (dy == 0) /* ex1 != ex2 */ /* any horizontal line */ + else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */ + { + gray_set_cell( RAS_VAR_ ex2, ey2 ); + goto End; + } + else if ( dx == 0 ) { - ex1 = ex2; - gray_set_cell(RAS_VAR_ ex1, ey1); - } else if (dx == 0) { - if (dy > 0) /* vertical line up */ - do { + if ( dy > 0 ) /* vertical line up */ + do + { fy2 = ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * fx1 * 2; + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * fx1 * 2; fy1 = 0; ey1++; - gray_set_cell(RAS_VAR_ ex1, ey1); - } while (ey1 != ey2); - else /* vertical line down */ - do { + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + else /* vertical line down */ + do + { fy2 = 0; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * fx1 * 2; + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * fx1 * 2; fy1 = ONE_PIXEL; ey1--; - gray_set_cell(RAS_VAR_ ex1, ey1); - } while (ey1 != ey2); - } else /* any other line */ + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + } + else /* any other line */ { - TArea prod = dx * fy1 - dy * fx1; - SW_FT_UDIVPREP(dx); - SW_FT_UDIVPREP(dy); - + TPos prod = dx * (TPos)fy1 - dy * (TPos)fx1; + SW_FT_UDIVPREP( ex1 != ex2, dx ); + SW_FT_UDIVPREP( ey1 != ey2, dy ); + + /* The fundamental value `prod' determines which side and the */ /* exact coordinate where the line exits current cell. It is */ /* also easily updated when moving from one cell to the next. */ - do { - if (prod <= 0 && prod - dx * ONE_PIXEL > 0) /* left */ + do + { + if ( prod <= 0 && + prod - dx * ONE_PIXEL > 0 ) /* left */ { fx2 = 0; - fy2 = (TPos)SW_FT_UDIV(-prod, -dx); + fy2 = SW_FT_UDIV( -prod, -dx ); prod -= dy * ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = ONE_PIXEL; fy1 = fy2; ex1--; - } else if (prod - dx * ONE_PIXEL <= 0 && - prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0) /* up */ + } + else if ( prod - dx * ONE_PIXEL <= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */ { prod -= dx * ONE_PIXEL; - fx2 = (TPos)SW_FT_UDIV(-prod, dy); + fx2 = SW_FT_UDIV( -prod, dy ); fy2 = ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = fx2; fy1 = 0; ey1++; - } else if (prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && - prod + dy * ONE_PIXEL >= 0) /* right */ + } + else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && + prod + dy * ONE_PIXEL >= 0 ) /* right */ { prod += dy * ONE_PIXEL; fx2 = ONE_PIXEL; - fy2 = (TPos)SW_FT_UDIV(prod, dx); - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + fy2 = SW_FT_UDIV( prod, dx ); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = 0; fy1 = fy2; ex1++; - } else /* ( prod + dy * ONE_PIXEL < 0 && - prod > 0 ) down */ + } + else /* ( prod + dy * ONE_PIXEL < 0 && + prod > 0 ) down */ { - fx2 = (TPos)SW_FT_UDIV(prod, -dy); + fx2 = SW_FT_UDIV( prod, -dy ); fy2 = 0; prod += dx * ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = fx2; fy1 = ONE_PIXEL; ey1--; } - - gray_set_cell(RAS_VAR_ ex1, ey1); - } while (ex1 != ex2 || ey1 != ey2); + + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ex1 != ex2 || ey1 != ey2 ); } - - fx2 = to_x - SUBPIXELS(ex2); - fy2 = to_y - SUBPIXELS(ey2); - - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); - + + fx2 = FRACT( to_x ); + fy2 = FRACT( to_y ); + + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + End: - ras.x = to_x; - ras.y = to_y; + ras.x = to_x; + ras.y = to_y; } static void gray_split_conic(SW_FT_Vector* base) { - TPos a, b; - + TPos a, b; + base[4].x = base[2].x; - a = base[0].x + base[1].x; - b = base[1].x + base[2].x; - base[3].x = b >> 1; - base[2].x = ( a + b ) >> 2; - base[1].x = a >> 1; - + b = base[1].x; + a = base[3].x = (base[2].x + b) / 2; + b = base[1].x = (base[0].x + b) / 2; + base[2].x = (a + b) / 2; + base[4].y = base[2].y; - a = base[0].y + base[1].y; - b = base[1].y + base[2].y; - base[3].y = b >> 1; - base[2].y = ( a + b ) >> 2; - base[1].y = a >> 1; + b = base[1].y; + a = base[3].y = (base[2].y + b) / 2; + b = base[1].y = (base[0].y + b) / 2; + base[2].y = (a + b) / 2; } static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, @@ -662,9 +676,9 @@ static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, int top, level; int* levels; SW_FT_Vector* arc; - + levels = ras.lev_stack; - + arc = ras.bez_stack; arc[0].x = UPSCALE(to->x); arc[0].y = UPSCALE(to->y); @@ -673,34 +687,34 @@ static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, arc[2].x = ras.x; arc[2].y = ras.y; top = 0; - + dx = SW_FT_ABS(arc[2].x + arc[0].x - 2 * arc[1].x); dy = SW_FT_ABS(arc[2].y + arc[0].y - 2 * arc[1].y); if (dx < dy) dx = dy; - + if (dx < ONE_PIXEL / 4) goto Draw; - + /* short-cut the arc that crosses the current band */ min = max = arc[0].y; - + y = arc[1].y; if (y < min) min = y; if (y > max) max = y; - + y = arc[2].y; if (y < min) min = y; if (y > max) max = y; - + if (TRUNC(min) >= ras.max_ey || TRUNC(max) < ras.min_ey) goto Draw; - + level = 0; do { dx >>= 2; level++; } while (dx > ONE_PIXEL / 4); - + levels[0] = level; - + do { level = levels[top]; if (level > 0) { @@ -710,43 +724,38 @@ static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, levels[top] = levels[top - 1] = level - 1; continue; } - + Draw: gray_render_line(RAS_VAR_ arc[0].x, arc[0].y); top--; arc -= 2; - + } while (top >= 0); } static void gray_split_cubic(SW_FT_Vector* base) { - TPos a, b, c; - - + TPos a, b, c, d; + base[6].x = base[3].x; - a = base[0].x + base[1].x; - b = base[1].x + base[2].x; - c = base[2].x + base[3].x; - base[5].x = c >> 1; - c += b; - base[4].x = c >> 2; - base[1].x = a >> 1; - a += b; - base[2].x = a >> 2; - base[3].x = ( a + c ) >> 3; - + c = base[1].x; + d = base[2].x; + base[1].x = a = (base[0].x + c) / 2; + base[5].x = b = (base[3].x + d) / 2; + c = (c + d) / 2; + base[2].x = a = (a + c) / 2; + base[4].x = b = (b + c) / 2; + base[3].x = (a + b) / 2; + base[6].y = base[3].y; - a = base[0].y + base[1].y; - b = base[1].y + base[2].y; - c = base[2].y + base[3].y; - base[5].y = c >> 1; - c += b; - base[4].y = c >> 2; - base[1].y = a >> 1; - a += b; - base[2].y = a >> 2; - base[3].y = ( a + c ) >> 3; + c = base[1].y; + d = base[2].y; + base[1].y = a = (base[0].y + c) / 2; + base[5].y = b = (base[3].y + d) / 2; + c = (c + d) / 2; + base[2].y = a = (a + c) / 2; + base[4].y = b = (b + c) / 2; + base[3].y = (a + b) / 2; } static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, @@ -755,7 +764,7 @@ static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, { SW_FT_Vector* arc; TPos min, max, y; - + arc = ras.bez_stack; arc[0].x = UPSCALE(to->x); arc[0].y = UPSCALE(to->y); @@ -765,83 +774,83 @@ static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, arc[2].y = UPSCALE(control1->y); arc[3].x = ras.x; arc[3].y = ras.y; - + /* Short-cut the arc that crosses the current band. */ min = max = arc[0].y; - + y = arc[1].y; if (y < min) min = y; if (y > max) max = y; - + y = arc[2].y; if (y < min) min = y; if (y > max) max = y; - + y = arc[3].y; if (y < min) min = y; if (y > max) max = y; - + if (TRUNC(min) >= ras.max_ey || TRUNC(max) < ras.min_ey) goto Draw; - + for (;;) { /* Decide whether to split or draw. See `Rapid Termination */ /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */ /* F. Hain, at */ /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */ - + { TPos dx, dy, dx_, dy_; TPos dx1, dy1, dx2, dy2; TPos L, s, s_limit; - + /* dx and dy are x and y components of the P0-P3 chord vector. */ dx = dx_ = arc[3].x - arc[0].x; dy = dy_ = arc[3].y - arc[0].y; - + L = SW_FT_HYPOT(dx_, dy_); - + /* Avoid possible arithmetic overflow below by splitting. */ if (L > 32767) goto Split; - + /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */ s_limit = L * (TPos)(ONE_PIXEL / 6); - + /* s is L * the perpendicular distance from P1 to the line P0-P3. */ dx1 = arc[1].x - arc[0].x; dy1 = arc[1].y - arc[0].y; s = SW_FT_ABS(dy * dx1 - dx * dy1); - + if (s > s_limit) goto Split; - + /* s is L * the perpendicular distance from P2 to the line P0-P3. */ dx2 = arc[2].x - arc[0].x; dy2 = arc[2].y - arc[0].y; s = SW_FT_ABS(dy * dx2 - dx * dy2); - + if (s > s_limit) goto Split; - + /* Split super curvy segments where the off points are so far - from the chord that the angles P0-P1-P3 or P0-P2-P3 become - acute as detected by appropriate dot products. */ + from the chord that the angles P0-P1-P3 or P0-P2-P3 become + acute as detected by appropriate dot products. */ if (dx1 * (dx1 - dx) + dy1 * (dy1 - dy) > 0 || dx2 * (dx2 - dx) + dy2 * (dy2 - dy) > 0) goto Split; - + /* No reason to split. */ goto Draw; } - + Split: gray_split_cubic(arc); arc += 3; continue; - + Draw: gray_render_line(RAS_VAR_ arc[0].x, arc[0].y); - + if (arc == ras.bez_stack) return; - + arc -= 3; } } @@ -849,16 +858,16 @@ static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, static int gray_move_to(const SW_FT_Vector* to, gray_PWorker worker) { TPos x, y; - + /* record current cell, if any */ if (!ras.invalid) gray_record_cell(RAS_VAR); - + /* start to a new position */ x = UPSCALE(to->x); y = UPSCALE(to->y); - + gray_start_cell(RAS_VAR_ TRUNC(x), TRUNC(y)); - + worker->x = x; worker->y = y; return 0; @@ -888,7 +897,7 @@ static int gray_cubic_to(const SW_FT_Vector* control1, static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) { int coverage; - + /* compute the coverage line's coverage, depending on the */ /* outline fill rule */ /* */ @@ -897,10 +906,10 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) coverage = (int)(area >> (PIXEL_BITS * 2 + 1 - 8)); /* use range 0..256 */ if (coverage < 0) coverage = -coverage; - + if (ras.outline.flags & SW_FT_OUTLINE_EVEN_ODD_FILL) { coverage &= 511; - + if (coverage > 256) coverage = 512 - coverage; else if (coverage == 256) @@ -909,26 +918,26 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) /* normal non-zero winding rule */ if (coverage >= 256) coverage = 255; } - + y += (TCoord)ras.min_ey; x += (TCoord)ras.min_ex; - + /* SW_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ if (x >= 32767) x = 32767; - + /* SW_FT_Span.y is an integer, so limit our coordinates appropriately */ if (y >= SW_FT_INT_MAX) y = SW_FT_INT_MAX; - + if (coverage) { SW_FT_Span* span; int count; - + // update bounding box. if (x < ras.bound_left) ras.bound_left = x; if (y < ras.bound_top) ras.bound_top = y; if (y > ras.bound_bottom) ras.bound_bottom = y; if (x + acount > ras.bound_right) ras.bound_right = x + acount; - + /* see whether we can add this span to the current list */ count = ras.num_gray_spans; span = ras.gray_spans + count - 1; @@ -937,16 +946,16 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) span->len = (unsigned short)(span->len + acount); return; } - + if (count >= SW_FT_MAX_GRAY_SPANS) { if (ras.render_span && count > 0) ras.render_span(count, ras.gray_spans, ras.render_span_data); - + #ifdef DEBUG_GRAYS - + if (1) { int n; - + fprintf(stderr, "count = %3d ", count); span = ras.gray_spans; for (n = 0; n < count; n++, span++) @@ -954,21 +963,21 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) span->x + span->len - 1, span->coverage); fprintf(stderr, "\n"); } - + #endif /* DEBUG_GRAYS */ - + ras.num_gray_spans = 0; - + span = ras.gray_spans; } else span++; - + /* add a gray span to the current list */ span->x = (short)x; span->y = (short)y; span->len = (unsigned short)acount; span->coverage = (unsigned char)coverage; - + ras.num_gray_spans++; } } @@ -976,37 +985,37 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) static void gray_sweep(RAS_ARG) { int yindex; - + if (ras.num_cells == 0) return; - + ras.num_gray_spans = 0; - + for (yindex = 0; yindex < ras.ycount; yindex++) { PCell cell = ras.ycells[yindex]; TCoord cover = 0; TCoord x = 0; - + for (; cell != NULL; cell = cell->next) { TPos area; - + if (cell->x > x && cover != 0) gray_hline(RAS_VAR_ x, yindex, cover * (ONE_PIXEL * 2), cell->x - x); - + cover += cell->cover; area = cover * (ONE_PIXEL * 2) - cell->area; - + if (area != 0 && cell->x >= 0) gray_hline(RAS_VAR_ cell->x, yindex, area, 1); - + x = cell->x + 1; } - + if (cover != 0) gray_hline(RAS_VAR_ x, yindex, cover * (ONE_PIXEL * 2), ras.count_ex - x); } - + if (ras.render_span && ras.num_gray_spans > 0) ras.render_span(ras.num_gray_spans, ras.gray_spans, ras.render_span_data); @@ -1052,54 +1061,58 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, { #undef SCALED #define SCALED(x) (((x) << shift) - delta) - + SW_FT_Vector v_last; SW_FT_Vector v_control; SW_FT_Vector v_start; - + SW_FT_Vector* point; SW_FT_Vector* limit; char* tags; - + int error; - + int n; /* index of contour in outline */ int first; /* index of first point in contour */ char tag; /* current point's state */ - + int shift; TPos delta; - - if (!outline || !func_interface) return SW_FT_THROW(Invalid_Argument); - + + if ( !outline ) + return SW_FT_THROW( Invalid_Outline ); + + if ( !func_interface ) + return SW_FT_THROW( Invalid_Argument ); + shift = func_interface->shift; delta = func_interface->delta; first = 0; - + for (n = 0; n < outline->n_contours; n++) { int last; /* index of last point in contour */ - + last = outline->contours[n]; if (last < 0) goto Invalid_Outline; limit = outline->points + last; - + v_start = outline->points[first]; v_start.x = SCALED(v_start.x); v_start.y = SCALED(v_start.y); - + v_last = outline->points[last]; v_last.x = SCALED(v_last.x); v_last.y = SCALED(v_last.y); - + v_control = v_start; - + point = outline->points + first; tags = outline->tags + first; tag = SW_FT_CURVE_TAG(tags[0]); - + /* A contour cannot start with a cubic control point! */ if (tag == SW_FT_CURVE_TAG_CUBIC) goto Invalid_Outline; - + /* check first point to determine origin */ if (tag == SW_FT_CURVE_TAG_CONIC) { /* first point is conic control. Yes, this happens. */ @@ -1117,122 +1130,122 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, point--; tags--; } - + error = func_interface->move_to(&v_start, user); if (error) goto Exit; - + while (point < limit) { point++; tags++; - + tag = SW_FT_CURVE_TAG(tags[0]); switch (tag) { - case SW_FT_CURVE_TAG_ON: /* emit a single line_to */ - { - SW_FT_Vector vec; - - vec.x = SCALED(point->x); - vec.y = SCALED(point->y); - - error = func_interface->line_to(&vec, user); - if (error) goto Exit; - continue; - } - - case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ - v_control.x = SCALED(point->x); - v_control.y = SCALED(point->y); - - Do_Conic: - if (point < limit) { + case SW_FT_CURVE_TAG_ON: /* emit a single line_to */ + { SW_FT_Vector vec; - SW_FT_Vector v_middle; - - point++; - tags++; - tag = SW_FT_CURVE_TAG(tags[0]); - + vec.x = SCALED(point->x); vec.y = SCALED(point->y); - - if (tag == SW_FT_CURVE_TAG_ON) { - error = + + error = func_interface->line_to(&vec, user); + if (error) goto Exit; + continue; + } + + case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED(point->x); + v_control.y = SCALED(point->y); + + Do_Conic: + if (point < limit) { + SW_FT_Vector vec; + SW_FT_Vector v_middle; + + point++; + tags++; + tag = SW_FT_CURVE_TAG(tags[0]); + + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + + if (tag == SW_FT_CURVE_TAG_ON) { + error = func_interface->conic_to(&v_control, &vec, user); + if (error) goto Exit; + continue; + } + + if (tag != SW_FT_CURVE_TAG_CONIC) goto Invalid_Outline; + + v_middle.x = (v_control.x + vec.x) / 2; + v_middle.y = (v_control.y + vec.y) / 2; + + error = + func_interface->conic_to(&v_control, &v_middle, user); + if (error) goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = func_interface->conic_to(&v_control, &v_start, user); + goto Close; + + default: /* SW_FT_CURVE_TAG_CUBIC */ + { + SW_FT_Vector vec1, vec2; + + if (point + 1 > limit || + SW_FT_CURVE_TAG(tags[1]) != SW_FT_CURVE_TAG_CUBIC) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED(point[-2].x); + vec1.y = SCALED(point[-2].y); + + vec2.x = SCALED(point[-1].x); + vec2.y = SCALED(point[-1].y); + + if (point <= limit) { + SW_FT_Vector vec; + + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + + error = func_interface->cubic_to(&vec1, &vec2, &vec, user); if (error) goto Exit; continue; } - - if (tag != SW_FT_CURVE_TAG_CONIC) goto Invalid_Outline; - - v_middle.x = (v_control.x + vec.x) / 2; - v_middle.y = (v_control.y + vec.y) / 2; - - error = - func_interface->conic_to(&v_control, &v_middle, user); - if (error) goto Exit; - - v_control = vec; - goto Do_Conic; - } - - error = func_interface->conic_to(&v_control, &v_start, user); - goto Close; - - default: /* SW_FT_CURVE_TAG_CUBIC */ - { - SW_FT_Vector vec1, vec2; - - if (point + 1 > limit || - SW_FT_CURVE_TAG(tags[1]) != SW_FT_CURVE_TAG_CUBIC) - goto Invalid_Outline; - - point += 2; - tags += 2; - - vec1.x = SCALED(point[-2].x); - vec1.y = SCALED(point[-2].y); - - vec2.x = SCALED(point[-1].x); - vec2.y = SCALED(point[-1].y); - - if (point <= limit) { - SW_FT_Vector vec; - - vec.x = SCALED(point->x); - vec.y = SCALED(point->y); - - error = func_interface->cubic_to(&vec1, &vec2, &vec, user); - if (error) goto Exit; - continue; + + error = func_interface->cubic_to(&vec1, &vec2, &v_start, user); + goto Close; } - - error = func_interface->cubic_to(&vec1, &vec2, &v_start, user); - goto Close; - } } } - + /* close the contour with a line segment */ error = func_interface->line_to(&v_start, user); - + Close: if (error) goto Exit; - + first = last + 1; } - + return 0; - + Exit: return error; - + Invalid_Outline: return SW_FT_THROW(Invalid_Outline); } typedef struct gray_TBand_ { TPos min, max; - + } gray_TBand; SW_FT_DEFINE_OUTLINE_FUNCS(func_interface, @@ -1244,13 +1257,13 @@ SW_FT_DEFINE_OUTLINE_FUNCS(func_interface, static int gray_convert_glyph_inner(RAS_ARG) { volatile int error = 0; - + if (ft_setjmp(ras.jump_buffer) == 0) { error = SW_FT_Outline_Decompose(&ras.outline, &func_interface, &ras); if (!ras.invalid) gray_record_cell(RAS_VAR); } else error = SW_FT_THROW(Memory_Overflow); - + return error; } @@ -1261,103 +1274,103 @@ static int gray_convert_glyph(RAS_ARG) int volatile n, num_bands; TPos volatile min, max, max_y; SW_FT_BBox* clip; - + /* Set up state in the raster object */ gray_compute_cbox(RAS_VAR); - + /* clip to target bitmap, exit if nothing to do */ clip = &ras.clip_box; - + if (ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax) return 0; - + if (ras.min_ex < clip->xMin) ras.min_ex = clip->xMin; if (ras.min_ey < clip->yMin) ras.min_ey = clip->yMin; - + if (ras.max_ex > clip->xMax) ras.max_ex = clip->xMax; if (ras.max_ey > clip->yMax) ras.max_ey = clip->yMax; - + ras.count_ex = ras.max_ex - ras.min_ex; ras.count_ey = ras.max_ey - ras.min_ey; - + /* set up vertical bands */ num_bands = (int)((ras.max_ey - ras.min_ey) / ras.band_size); if (num_bands == 0) num_bands = 1; if (num_bands >= 39) num_bands = 39; - + ras.band_shoot = 0; - + min = ras.min_ey; max_y = ras.max_ey; - + for (n = 0; n < num_bands; n++, min = max) { max = min + ras.band_size; if (n == num_bands - 1 || max > max_y) max = max_y; - + bands[0].min = min; bands[0].max = max; band = bands; - + while (band >= bands) { TPos bottom, top, middle; int error; - + { PCell cells_max; int yindex; long cell_start, cell_end, cell_mod; - + ras.ycells = (PCell*)ras.buffer; ras.ycount = band->max - band->min; - + cell_start = sizeof(PCell) * ras.ycount; cell_mod = cell_start % sizeof(TCell); if (cell_mod > 0) cell_start += sizeof(TCell) - cell_mod; - + cell_end = ras.buffer_size; cell_end -= cell_end % sizeof(TCell); - + cells_max = (PCell)((char*)ras.buffer + cell_end); ras.cells = (PCell)((char*)ras.buffer + cell_start); if (ras.cells >= cells_max) goto ReduceBands; - + ras.max_cells = cells_max - ras.cells; if (ras.max_cells < 2) goto ReduceBands; - + for (yindex = 0; yindex < ras.ycount; yindex++) ras.ycells[yindex] = NULL; } - + ras.num_cells = 0; ras.invalid = 1; ras.min_ey = band->min; ras.max_ey = band->max; ras.count_ey = band->max - band->min; - + error = gray_convert_glyph_inner(RAS_VAR); - + if (!error) { gray_sweep(RAS_VAR); band--; continue; } else if (error != ErrRaster_Memory_Overflow) return 1; - + ReduceBands: /* render pool overflow; we will reduce the render band by half */ bottom = band->min; top = band->max; middle = bottom + ((top - bottom) >> 1); - + /* This is too complex for a single scanline; there must */ /* be some problems. */ if (middle == bottom) { return 1; } - + if (bottom - top >= ras.band_size) ras.band_shoot++; - + band[1].min = bottom; band[1].max = middle; band[0].min = middle; @@ -1365,10 +1378,10 @@ static int gray_convert_glyph(RAS_ARG) band++; } } - + if (ras.band_shoot > 8 && ras.band_size > 16) ras.band_size = ras.band_size / 2; - + return 0; } @@ -1377,28 +1390,28 @@ static int gray_raster_render(gray_PRaster raster, { SW_FT_UNUSED(raster); const SW_FT_Outline* outline = (const SW_FT_Outline*)params->source; - + gray_TWorker worker[1]; - + TCell buffer[SW_FT_RENDER_POOL_SIZE / sizeof(TCell)]; long buffer_size = sizeof(buffer); int band_size = (int)(buffer_size / (long)(sizeof(TCell) * 8)); - + if (!outline) return SW_FT_THROW(Invalid_Outline); - + /* return immediately if the outline is empty */ if (outline->n_points == 0 || outline->n_contours <= 0) return 0; - + if (!outline->contours || !outline->points) return SW_FT_THROW(Invalid_Outline); - + if (outline->n_points != outline->contours[outline->n_contours - 1] + 1) return SW_FT_THROW(Invalid_Outline); - + /* this version does not support monochrome rendering */ if (!(params->flags & SW_FT_RASTER_FLAG_AA)) return SW_FT_THROW(Invalid_Mode); - + if (params->flags & SW_FT_RASTER_FLAG_CLIP) ras.clip_box = params->clip_box; else { @@ -1407,18 +1420,18 @@ static int gray_raster_render(gray_PRaster raster, ras.clip_box.xMax = 32767L; ras.clip_box.yMax = 32767L; } - + gray_init_cells(RAS_VAR_ buffer, buffer_size); - + ras.outline = *outline; ras.num_cells = 0; ras.invalid = 1; ras.band_size = band_size; ras.num_gray_spans = 0; - + ras.render_span = (SW_FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; - + gray_convert_glyph(RAS_VAR); params->bbox_cb(ras.bound_left, ras.bound_top, ras.bound_right - ras.bound_left, @@ -1432,10 +1445,10 @@ static int gray_raster_render(gray_PRaster raster, static int gray_raster_new(SW_FT_Raster* araster) { static gray_TRaster the_raster; - + *araster = (SW_FT_Raster)&the_raster; SW_FT_MEM_ZERO(&the_raster, sizeof(the_raster)); - + return 0; } @@ -1454,7 +1467,7 @@ static void gray_raster_reset(SW_FT_Raster raster, char* pool_base, } SW_FT_DEFINE_RASTER_FUNCS(sw_ft_grays_raster, - + (SW_FT_Raster_New_Func)gray_raster_new, (SW_FT_Raster_Reset_Func)gray_raster_reset, (SW_FT_Raster_Render_Func)gray_raster_render, From 1f3265b44fc1f02ae9e8c6cac140b56891c88896 Mon Sep 17 00:00:00 2001 From: overtake Date: Fri, 17 Jan 2020 12:05:54 +0400 Subject: [PATCH 08/24] return old raster --- src/vector/freetype/v_ft_raster.cpp | 219 +++++++++++++--------------- 1 file changed, 103 insertions(+), 116 deletions(-) diff --git a/src/vector/freetype/v_ft_raster.cpp b/src/vector/freetype/v_ft_raster.cpp index 9d10578f..8f387766 100644 --- a/src/vector/freetype/v_ft_raster.cpp +++ b/src/vector/freetype/v_ft_raster.cpp @@ -16,7 +16,7 @@ /***************************************************************************/ /*************************************************************************/ -/* a */ +/* */ /* This is a new anti-aliasing scan-converter for FreeType 2. The */ /* algorithm used here is _very_ different from the one in the standard */ /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ @@ -71,7 +71,6 @@ while (0) #include #include #include - #define SW_FT_UINT_MAX UINT_MAX #define SW_FT_INT_MAX INT_MAX #define SW_FT_ULONG_MAX ULONG_MAX @@ -188,8 +187,7 @@ raster_render_, raster_done_}; #define ONE_PIXEL (1L << PIXEL_BITS) #define PIXEL_MASK (-1L << PIXEL_BITS) #define TRUNC(x) ((TCoord)((x) >> PIXEL_BITS)) -#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) - +#define SUBPIXELS(x) ((TPos)(x) << PIXEL_BITS) #define FLOOR(x) ((x) & -ONE_PIXEL) #define CEILING(x) (((x) + ONE_PIXEL - 1) & -ONE_PIXEL) #define ROUND(x) (((x) + ONE_PIXEL / 2) & -ONE_PIXEL) @@ -233,12 +231,11 @@ SW_FT_END_STMNT /* These macros speed up repetitive divisions by replacing them */ /* with multiplications and right shifts. */ -#define SW_FT_UDIVPREP( c, b ) \ -long b ## _r = c ? (long)( SW_FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \ -: 0 -#define SW_FT_UDIV( a, b ) \ -(TCoord)( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \ -( sizeof( long ) * SW_FT_CHAR_BIT - PIXEL_BITS ) ) +#define SW_FT_UDIVPREP(b) \ +long b##_r = (long)(SW_FT_ULONG_MAX >> PIXEL_BITS) / (b) +#define SW_FT_UDIV(a, b) \ +(((unsigned long)(a) * (unsigned long)(b##_r)) >> \ +(sizeof(long) * SW_FT_CHAR_BIT - PIXEL_BITS)) /*************************************************************************/ /* */ @@ -293,8 +290,6 @@ typedef struct TCell_ { #endif /* _MSC_VER */ typedef struct gray_TWorker_ { - ft_jmp_buf jump_buffer; - TCoord ex, ey; TPos min_ex, max_ex; TPos min_ey, max_ey; @@ -330,6 +325,8 @@ typedef struct gray_TWorker_ { int band_size; int band_shoot; + ft_jmp_buf jump_buffer; + void* buffer; long buffer_size; @@ -524,148 +521,137 @@ static void gray_start_cell(RAS_ARG_ TCoord ex, TCoord ey) /* */ static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y) { - TPos dx, dy; - TCoord fx1, fy1, fx2, fy2; - TCoord ex1, ey1, ex2, ey2; + TPos dx, dy, fx1, fy1, fx2, fy2; + TCoord ex1, ex2, ey1, ey2; - ey1 = TRUNC( ras.y ); - ey2 = TRUNC( to_y ); + ex1 = TRUNC(ras.x); + ex2 = TRUNC(to_x); + ey1 = TRUNC(ras.y); + ey2 = TRUNC(to_y); /* perform vertical clipping */ - if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || - ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + if ((ey1 >= ras.max_ey && ey2 >= ras.max_ey) || + (ey1 < ras.min_ey && ey2 < ras.min_ey)) goto End; - ex1 = TRUNC( ras.x ); - ex2 = TRUNC( to_x ); - - fx1 = FRACT( ras.x ); - fy1 = FRACT( ras.y ); - dx = to_x - ras.x; dy = to_y - ras.y; - if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ + fx1 = ras.x - SUBPIXELS(ex1); + fy1 = ras.y - SUBPIXELS(ey1); + + if (ex1 == ex2 && ey1 == ey2) /* inside one cell */ ; - else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */ + else if (dy == 0) /* ex1 != ex2 */ /* any horizontal line */ { - gray_set_cell( RAS_VAR_ ex2, ey2 ); - goto End; - } - else if ( dx == 0 ) - { - if ( dy > 0 ) /* vertical line up */ - do - { + ex1 = ex2; + gray_set_cell(RAS_VAR_ ex1, ey1); + } else if (dx == 0) { + if (dy > 0) /* vertical line up */ + do { fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * fx1 * 2; fy1 = 0; ey1++; - gray_set_cell( RAS_VAR_ ex1, ey1 ); - } while ( ey1 != ey2 ); - else /* vertical line down */ - do - { + gray_set_cell(RAS_VAR_ ex1, ey1); + } while (ey1 != ey2); + else /* vertical line down */ + do { fy2 = 0; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * fx1 * 2; fy1 = ONE_PIXEL; ey1--; - gray_set_cell( RAS_VAR_ ex1, ey1 ); - } while ( ey1 != ey2 ); - } - else /* any other line */ + gray_set_cell(RAS_VAR_ ex1, ey1); + } while (ey1 != ey2); + } else /* any other line */ { - TPos prod = dx * (TPos)fy1 - dy * (TPos)fx1; - SW_FT_UDIVPREP( ex1 != ex2, dx ); - SW_FT_UDIVPREP( ey1 != ey2, dy ); - + TArea prod = dx * fy1 - dy * fx1; + SW_FT_UDIVPREP(dx); + SW_FT_UDIVPREP(dy); /* The fundamental value `prod' determines which side and the */ /* exact coordinate where the line exits current cell. It is */ /* also easily updated when moving from one cell to the next. */ - do - { - if ( prod <= 0 && - prod - dx * ONE_PIXEL > 0 ) /* left */ + do { + if (prod <= 0 && prod - dx * ONE_PIXEL > 0) /* left */ { fx2 = 0; - fy2 = SW_FT_UDIV( -prod, -dx ); + fy2 = (TPos)SW_FT_UDIV(-prod, -dx); prod -= dy * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = ONE_PIXEL; fy1 = fy2; ex1--; - } - else if ( prod - dx * ONE_PIXEL <= 0 && - prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */ + } else if (prod - dx * ONE_PIXEL <= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0) /* up */ { prod -= dx * ONE_PIXEL; - fx2 = SW_FT_UDIV( -prod, dy ); + fx2 = (TPos)SW_FT_UDIV(-prod, dy); fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = fx2; fy1 = 0; ey1++; - } - else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && - prod + dy * ONE_PIXEL >= 0 ) /* right */ + } else if (prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && + prod + dy * ONE_PIXEL >= 0) /* right */ { prod += dy * ONE_PIXEL; fx2 = ONE_PIXEL; - fy2 = SW_FT_UDIV( prod, dx ); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + fy2 = (TPos)SW_FT_UDIV(prod, dx); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = 0; fy1 = fy2; ex1++; - } - else /* ( prod + dy * ONE_PIXEL < 0 && - prod > 0 ) down */ + } else /* ( prod + dy * ONE_PIXEL < 0 && + prod > 0 ) down */ { - fx2 = SW_FT_UDIV( prod, -dy ); + fx2 = (TPos)SW_FT_UDIV(prod, -dy); fy2 = 0; prod += dx * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = fx2; fy1 = ONE_PIXEL; ey1--; } - gray_set_cell( RAS_VAR_ ex1, ey1 ); - } while ( ex1 != ex2 || ey1 != ey2 ); + gray_set_cell(RAS_VAR_ ex1, ey1); + } while (ex1 != ex2 || ey1 != ey2); } - fx2 = FRACT( to_x ); - fy2 = FRACT( to_y ); + fx2 = to_x - SUBPIXELS(ex2); + fy2 = to_y - SUBPIXELS(ey2); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); End: - ras.x = to_x; - ras.y = to_y; + ras.x = to_x; + ras.y = to_y; } static void gray_split_conic(SW_FT_Vector* base) { - TPos a, b; + TPos a, b; base[4].x = base[2].x; - b = base[1].x; - a = base[3].x = (base[2].x + b) / 2; - b = base[1].x = (base[0].x + b) / 2; - base[2].x = (a + b) / 2; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; base[4].y = base[2].y; - b = base[1].y; - a = base[3].y = (base[2].y + b) / 2; - b = base[1].y = (base[0].y + b) / 2; - base[2].y = (a + b) / 2; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; } static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, @@ -735,27 +721,32 @@ static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, static void gray_split_cubic(SW_FT_Vector* base) { - TPos a, b, c, d; + TPos a, b, c; + base[6].x = base[3].x; - c = base[1].x; - d = base[2].x; - base[1].x = a = (base[0].x + c) / 2; - base[5].x = b = (base[3].x + d) / 2; - c = (c + d) / 2; - base[2].x = a = (a + c) / 2; - base[4].x = b = (b + c) / 2; - base[3].x = (a + b) / 2; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; base[6].y = base[3].y; - c = base[1].y; - d = base[2].y; - base[1].y = a = (base[0].y + c) / 2; - base[5].y = b = (base[3].y + d) / 2; - c = (c + d) / 2; - base[2].y = a = (a + c) / 2; - base[4].y = b = (b + c) / 2; - base[3].y = (a + b) / 2; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; } static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, @@ -1079,11 +1070,7 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, int shift; TPos delta; - if ( !outline ) - return SW_FT_THROW( Invalid_Outline ); - - if ( !func_interface ) - return SW_FT_THROW( Invalid_Argument ); + if (!outline || !func_interface) return SW_FT_THROW(Invalid_Argument); shift = func_interface->shift; delta = func_interface->delta; From 05a40a3d55f6be88beeb43b6fe5d4f19b458c0be Mon Sep 17 00:00:00 2001 From: overtake <> Date: Sun, 19 Jan 2020 22:44:05 +0400 Subject: [PATCH 09/24] update raster --- src/vector/freetype/v_ft_raster.cpp | 349 +++++++++++++++------------- 1 file changed, 181 insertions(+), 168 deletions(-) diff --git a/src/vector/freetype/v_ft_raster.cpp b/src/vector/freetype/v_ft_raster.cpp index 8f387766..0b49ae45 100644 --- a/src/vector/freetype/v_ft_raster.cpp +++ b/src/vector/freetype/v_ft_raster.cpp @@ -16,7 +16,7 @@ /***************************************************************************/ /*************************************************************************/ -/* */ +/* a */ /* This is a new anti-aliasing scan-converter for FreeType 2. The */ /* algorithm used here is _very_ different from the one in the standard */ /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */ @@ -71,6 +71,7 @@ while (0) #include #include #include + #define SW_FT_UINT_MAX UINT_MAX #define SW_FT_INT_MAX INT_MAX #define SW_FT_ULONG_MAX ULONG_MAX @@ -187,7 +188,8 @@ raster_render_, raster_done_}; #define ONE_PIXEL (1L << PIXEL_BITS) #define PIXEL_MASK (-1L << PIXEL_BITS) #define TRUNC(x) ((TCoord)((x) >> PIXEL_BITS)) -#define SUBPIXELS(x) ((TPos)(x) << PIXEL_BITS) +#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) + #define FLOOR(x) ((x) & -ONE_PIXEL) #define CEILING(x) (((x) + ONE_PIXEL - 1) & -ONE_PIXEL) #define ROUND(x) (((x) + ONE_PIXEL / 2) & -ONE_PIXEL) @@ -231,11 +233,12 @@ SW_FT_END_STMNT /* These macros speed up repetitive divisions by replacing them */ /* with multiplications and right shifts. */ -#define SW_FT_UDIVPREP(b) \ -long b##_r = (long)(SW_FT_ULONG_MAX >> PIXEL_BITS) / (b) -#define SW_FT_UDIV(a, b) \ -(((unsigned long)(a) * (unsigned long)(b##_r)) >> \ -(sizeof(long) * SW_FT_CHAR_BIT - PIXEL_BITS)) +#define SW_FT_UDIVPREP( c, b ) \ +long b ## _r = c ? (long)( SW_FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \ +: 0 +#define SW_FT_UDIV( a, b ) \ +(TCoord)( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \ +( sizeof( long ) * SW_FT_CHAR_BIT - PIXEL_BITS ) ) /*************************************************************************/ /* */ @@ -290,6 +293,8 @@ typedef struct TCell_ { #endif /* _MSC_VER */ typedef struct gray_TWorker_ { + ft_jmp_buf jump_buffer; + TCoord ex, ey; TPos min_ex, max_ex; TPos min_ey, max_ey; @@ -325,8 +330,6 @@ typedef struct gray_TWorker_ { int band_size; int band_shoot; - ft_jmp_buf jump_buffer; - void* buffer; long buffer_size; @@ -521,137 +524,148 @@ static void gray_start_cell(RAS_ARG_ TCoord ex, TCoord ey) /* */ static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y) { - TPos dx, dy, fx1, fy1, fx2, fy2; - TCoord ex1, ex2, ey1, ey2; + TPos dx, dy; + TCoord fx1, fy1, fx2, fy2; + TCoord ex1, ey1, ex2, ey2; - ex1 = TRUNC(ras.x); - ex2 = TRUNC(to_x); - ey1 = TRUNC(ras.y); - ey2 = TRUNC(to_y); + ey1 = TRUNC( ras.y ); + ey2 = TRUNC( to_y ); /* perform vertical clipping */ - if ((ey1 >= ras.max_ey && ey2 >= ras.max_ey) || - (ey1 < ras.min_ey && ey2 < ras.min_ey)) - goto End; + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + goto End; + + ex1 = TRUNC( ras.x ); + ex2 = TRUNC( to_x ); + + fx1 = FRACT( ras.x ); + fy1 = FRACT( ras.y ); dx = to_x - ras.x; dy = to_y - ras.y; - fx1 = ras.x - SUBPIXELS(ex1); - fy1 = ras.y - SUBPIXELS(ey1); - - if (ex1 == ex2 && ey1 == ey2) /* inside one cell */ - ; - else if (dy == 0) /* ex1 != ex2 */ /* any horizontal line */ + if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ + ; + else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */ { - ex1 = ex2; - gray_set_cell(RAS_VAR_ ex1, ey1); - } else if (dx == 0) { - if (dy > 0) /* vertical line up */ - do { - fy2 = ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * fx1 * 2; - fy1 = 0; - ey1++; - gray_set_cell(RAS_VAR_ ex1, ey1); - } while (ey1 != ey2); - else /* vertical line down */ - do { - fy2 = 0; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * fx1 * 2; - fy1 = ONE_PIXEL; - ey1--; - gray_set_cell(RAS_VAR_ ex1, ey1); - } while (ey1 != ey2); - } else /* any other line */ + gray_set_cell( RAS_VAR_ ex2, ey2 ); + goto End; + } + else if ( dx == 0 ) + { + if ( dy > 0 ) /* vertical line up */ + do + { + fy2 = ONE_PIXEL; + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * fx1 * 2; + fy1 = 0; + ey1++; + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + else /* vertical line down */ + do + { + fy2 = 0; + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * fx1 * 2; + fy1 = ONE_PIXEL; + ey1--; + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ey1 != ey2 ); + } + else /* any other line */ { - TArea prod = dx * fy1 - dy * fx1; - SW_FT_UDIVPREP(dx); - SW_FT_UDIVPREP(dy); + TPos prod = dx * (TPos)fy1 - dy * (TPos)fx1; + SW_FT_UDIVPREP( ex1 != ex2, dx ); + SW_FT_UDIVPREP( ey1 != ey2, dy ); + /* The fundamental value `prod' determines which side and the */ /* exact coordinate where the line exits current cell. It is */ /* also easily updated when moving from one cell to the next. */ - do { - if (prod <= 0 && prod - dx * ONE_PIXEL > 0) /* left */ + do + { + if ( prod <= 0 && + prod - dx * ONE_PIXEL > 0 ) /* left */ { fx2 = 0; - fy2 = (TPos)SW_FT_UDIV(-prod, -dx); + fy2 = SW_FT_UDIV( -prod, -dx ); prod -= dy * ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = ONE_PIXEL; fy1 = fy2; ex1--; - } else if (prod - dx * ONE_PIXEL <= 0 && - prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0) /* up */ + } + else if ( prod - dx * ONE_PIXEL <= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */ { prod -= dx * ONE_PIXEL; - fx2 = (TPos)SW_FT_UDIV(-prod, dy); + fx2 = SW_FT_UDIV( -prod, dy ); fy2 = ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = fx2; fy1 = 0; ey1++; - } else if (prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && - prod + dy * ONE_PIXEL >= 0) /* right */ + } + else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && + prod + dy * ONE_PIXEL >= 0 ) /* right */ { prod += dy * ONE_PIXEL; fx2 = ONE_PIXEL; - fy2 = (TPos)SW_FT_UDIV(prod, dx); - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + fy2 = SW_FT_UDIV( prod, dx ); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = 0; fy1 = fy2; ex1++; - } else /* ( prod + dy * ONE_PIXEL < 0 && - prod > 0 ) down */ + } + else /* ( prod + dy * ONE_PIXEL < 0 && + prod > 0 ) down */ { - fx2 = (TPos)SW_FT_UDIV(prod, -dy); + fx2 = SW_FT_UDIV( prod, -dy ); fy2 = 0; prod += dx * ONE_PIXEL; - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); fx1 = fx2; fy1 = ONE_PIXEL; ey1--; } - gray_set_cell(RAS_VAR_ ex1, ey1); - } while (ex1 != ex2 || ey1 != ey2); + gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ex1 != ex2 || ey1 != ey2 ); } - fx2 = to_x - SUBPIXELS(ex2); - fy2 = to_y - SUBPIXELS(ey2); + fx2 = FRACT( to_x ); + fy2 = FRACT( to_y ); - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); + ras.cover += ( fy2 - fy1 ); + ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); End: - ras.x = to_x; - ras.y = to_y; + ras.x = to_x; + ras.y = to_y; } static void gray_split_conic(SW_FT_Vector* base) { - TPos a, b; + TPos a, b; base[4].x = base[2].x; - a = base[0].x + base[1].x; - b = base[1].x + base[2].x; - base[3].x = b >> 1; - base[2].x = ( a + b ) >> 2; - base[1].x = a >> 1; + b = base[1].x; + a = base[3].x = (base[2].x + b) / 2; + b = base[1].x = (base[0].x + b) / 2; + base[2].x = (a + b) / 2; base[4].y = base[2].y; - a = base[0].y + base[1].y; - b = base[1].y + base[2].y; - base[3].y = b >> 1; - base[2].y = ( a + b ) >> 2; - base[1].y = a >> 1; + b = base[1].y; + a = base[3].y = (base[2].y + b) / 2; + b = base[1].y = (base[0].y + b) / 2; + base[2].y = (a + b) / 2; } static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, @@ -721,32 +735,27 @@ static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, static void gray_split_cubic(SW_FT_Vector* base) { - TPos a, b, c; - + TPos a, b, c, d; base[6].x = base[3].x; - a = base[0].x + base[1].x; - b = base[1].x + base[2].x; - c = base[2].x + base[3].x; - base[5].x = c >> 1; - c += b; - base[4].x = c >> 2; - base[1].x = a >> 1; - a += b; - base[2].x = a >> 2; - base[3].x = ( a + c ) >> 3; + c = base[1].x; + d = base[2].x; + base[1].x = a = (base[0].x + c) / 2; + base[5].x = b = (base[3].x + d) / 2; + c = (c + d) / 2; + base[2].x = a = (a + c) / 2; + base[4].x = b = (b + c) / 2; + base[3].x = (a + b) / 2; base[6].y = base[3].y; - a = base[0].y + base[1].y; - b = base[1].y + base[2].y; - c = base[2].y + base[3].y; - base[5].y = c >> 1; - c += b; - base[4].y = c >> 2; - base[1].y = a >> 1; - a += b; - base[2].y = a >> 2; - base[3].y = ( a + c ) >> 3; + c = base[1].y; + d = base[2].y; + base[1].y = a = (base[0].y + c) / 2; + base[5].y = b = (base[3].y + d) / 2; + c = (c + d) / 2; + base[2].y = a = (a + c) / 2; + base[4].y = b = (b + c) / 2; + base[3].y = (a + b) / 2; } static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, @@ -826,7 +835,7 @@ static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, acute as detected by appropriate dot products. */ if (dx1 * (dx1 - dx) + dy1 * (dy1 - dy) > 0 || dx2 * (dx2 - dx) + dy2 * (dy2 - dy) > 0) - goto Split; + goto Split; /* No reason to split. */ goto Draw; @@ -902,9 +911,9 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) coverage &= 511; if (coverage > 256) - coverage = 512 - coverage; + coverage = 512 - coverage; else if (coverage == 256) - coverage = 255; + coverage = 255; } else { /* normal non-zero winding rule */ if (coverage >= 256) coverage = 255; @@ -940,7 +949,7 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) if (count >= SW_FT_MAX_GRAY_SPANS) { if (ras.render_span && count > 0) - ras.render_span(count, ras.gray_spans, ras.render_span_data); + ras.render_span(count, ras.gray_spans, ras.render_span_data); #ifdef DEBUG_GRAYS @@ -950,8 +959,8 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) fprintf(stderr, "count = %3d ", count); span = ras.gray_spans; for (n = 0; n < count; n++, span++) - fprintf(stderr, "[%d , %d..%d] : %d ", span->y, span->x, - span->x + span->len - 1, span->coverage); + fprintf(stderr, "[%d , %d..%d] : %d ", span->y, span->x, + span->x + span->len - 1, span->coverage); fprintf(stderr, "\n"); } @@ -961,7 +970,7 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) span = ras.gray_spans; } else - span++; + span++; /* add a gray span to the current list */ span->x = (short)x; @@ -990,26 +999,26 @@ static void gray_sweep(RAS_ARG) TPos area; if (cell->x > x && cover != 0) - gray_hline(RAS_VAR_ x, yindex, cover * (ONE_PIXEL * 2), - cell->x - x); + gray_hline(RAS_VAR_ x, yindex, cover * (ONE_PIXEL * 2), + cell->x - x); cover += cell->cover; area = cover * (ONE_PIXEL * 2) - cell->area; if (area != 0 && cell->x >= 0) - gray_hline(RAS_VAR_ cell->x, yindex, area, 1); + gray_hline(RAS_VAR_ cell->x, yindex, area, 1); x = cell->x + 1; } if (cover != 0) - gray_hline(RAS_VAR_ x, yindex, cover * (ONE_PIXEL * 2), - ras.count_ex - x); + gray_hline(RAS_VAR_ x, yindex, cover * (ONE_PIXEL * 2), + ras.count_ex - x); } if (ras.render_span && ras.num_gray_spans > 0) - ras.render_span(ras.num_gray_spans, ras.gray_spans, - ras.render_span_data); + ras.render_span(ras.num_gray_spans, ras.gray_spans, + ras.render_span_data); } /*************************************************************************/ @@ -1070,7 +1079,11 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, int shift; TPos delta; - if (!outline || !func_interface) return SW_FT_THROW(Invalid_Argument); + if ( !outline ) + return SW_FT_THROW( Invalid_Outline ); + + if ( !func_interface ) + return SW_FT_THROW( Invalid_Argument ); shift = func_interface->shift; delta = func_interface->delta; @@ -1138,53 +1151,53 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, if (error) goto Exit; continue; } - + case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ - v_control.x = SCALED(point->x); - v_control.y = SCALED(point->y); + v_control.x = SCALED(point->x); + v_control.y = SCALED(point->y); + + Do_Conic: + if (point < limit) { + SW_FT_Vector vec; + SW_FT_Vector v_middle; - Do_Conic: - if (point < limit) { - SW_FT_Vector vec; - SW_FT_Vector v_middle; - - point++; - tags++; - tag = SW_FT_CURVE_TAG(tags[0]); - - vec.x = SCALED(point->x); - vec.y = SCALED(point->y); - - if (tag == SW_FT_CURVE_TAG_ON) { - error = - func_interface->conic_to(&v_control, &vec, user); - if (error) goto Exit; - continue; - } - - if (tag != SW_FT_CURVE_TAG_CONIC) goto Invalid_Outline; - - v_middle.x = (v_control.x + vec.x) / 2; - v_middle.y = (v_control.y + vec.y) / 2; - + point++; + tags++; + tag = SW_FT_CURVE_TAG(tags[0]); + + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + + if (tag == SW_FT_CURVE_TAG_ON) { error = - func_interface->conic_to(&v_control, &v_middle, user); + func_interface->conic_to(&v_control, &vec, user); if (error) goto Exit; - - v_control = vec; - goto Do_Conic; + continue; } - error = func_interface->conic_to(&v_control, &v_start, user); - goto Close; + if (tag != SW_FT_CURVE_TAG_CONIC) goto Invalid_Outline; + + v_middle.x = (v_control.x + vec.x) / 2; + v_middle.y = (v_control.y + vec.y) / 2; + + error = + func_interface->conic_to(&v_control, &v_middle, user); + if (error) goto Exit; + v_control = vec; + goto Do_Conic; + } + + error = func_interface->conic_to(&v_control, &v_start, user); + goto Close; + default: /* SW_FT_CURVE_TAG_CUBIC */ { SW_FT_Vector vec1, vec2; if (point + 1 > limit || SW_FT_CURVE_TAG(tags[1]) != SW_FT_CURVE_TAG_CUBIC) - goto Invalid_Outline; + goto Invalid_Outline; point += 2; tags += 2; @@ -1249,7 +1262,7 @@ static int gray_convert_glyph_inner(RAS_ARG) error = SW_FT_Outline_Decompose(&ras.outline, &func_interface, &ras); if (!ras.invalid) gray_record_cell(RAS_VAR); } else - error = SW_FT_THROW(Memory_Overflow); + error = SW_FT_THROW(Memory_Overflow); return error; } @@ -1270,7 +1283,7 @@ static int gray_convert_glyph(RAS_ARG) if (ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax || ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax) - return 0; + return 0; if (ras.min_ex < clip->xMin) ras.min_ex = clip->xMin; if (ras.min_ey < clip->yMin) ras.min_ey = clip->yMin; @@ -1326,7 +1339,7 @@ static int gray_convert_glyph(RAS_ARG) if (ras.max_cells < 2) goto ReduceBands; for (yindex = 0; yindex < ras.ycount; yindex++) - ras.ycells[yindex] = NULL; + ras.ycells[yindex] = NULL; } ras.num_cells = 0; @@ -1342,7 +1355,7 @@ static int gray_convert_glyph(RAS_ARG) band--; continue; } else if (error != ErrRaster_Memory_Overflow) - return 1; + return 1; ReduceBands: /* render pool overflow; we will reduce the render band by half */ @@ -1367,7 +1380,7 @@ static int gray_convert_glyph(RAS_ARG) } if (ras.band_shoot > 8 && ras.band_size > 16) - ras.band_size = ras.band_size / 2; + ras.band_size = ras.band_size / 2; return 0; } @@ -1390,17 +1403,17 @@ static int gray_raster_render(gray_PRaster raster, if (outline->n_points == 0 || outline->n_contours <= 0) return 0; if (!outline->contours || !outline->points) - return SW_FT_THROW(Invalid_Outline); + return SW_FT_THROW(Invalid_Outline); if (outline->n_points != outline->contours[outline->n_contours - 1] + 1) - return SW_FT_THROW(Invalid_Outline); + return SW_FT_THROW(Invalid_Outline); /* this version does not support monochrome rendering */ if (!(params->flags & SW_FT_RASTER_FLAG_AA)) - return SW_FT_THROW(Invalid_Mode); + return SW_FT_THROW(Invalid_Mode); if (params->flags & SW_FT_RASTER_FLAG_CLIP) - ras.clip_box = params->clip_box; + ras.clip_box = params->clip_box; else { ras.clip_box.xMin = -32768L; ras.clip_box.yMin = -32768L; From 0ee2e9c5843257ccd11672611829b9bb5d02aa98 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 21 Jan 2020 12:30:31 +0300 Subject: [PATCH 10/24] Check buffer length in vrle. --- src/vector/vrle.cpp | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/vector/vrle.cpp b/src/vector/vrle.cpp index d56710d3..6e48bfc5 100644 --- a/src/vector/vrle.cpp +++ b/src/vector/vrle.cpp @@ -503,11 +503,14 @@ static void rleIntersectWithRect(const VRect &clip, VRleHelper *tmp_obj, result->size = result->alloc - available; } -void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blitXor(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l > bufferLen) { + return; + } uchar *ptr = buffer + x; while (l--) { int da = *ptr; @@ -519,12 +522,15 @@ void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, +void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l > bufferLen) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = divBy255((255 - spans->coverage) * (*ptr)); @@ -534,11 +540,14 @@ void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, } } -void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l > bufferLen) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr)); @@ -548,11 +557,14 @@ void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blit(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l > bufferLen) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = std::max(spans->coverage, *ptr); @@ -562,13 +574,16 @@ void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -size_t bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out) +size_t bufferToRle(uchar *buffer, std::size_t bufferLen, int size, int offsetX, int y, VRle::Span *out) { size_t count = 0; uchar value = buffer[0]; int curIndex = 0; size = offsetX < 0 ? size + offsetX : size; + if (size > bufferLen) { + return count; + } for (int i = 0; i < size; i++) { uchar curValue = buffer[0]; if (value != curValue) { @@ -627,13 +642,13 @@ static void rleOpGeneric(VRleHelper *a, VRleHelper *b, VRleHelper *result, int offset = std::min(aStart->x, bStart->x); std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), -offset); + blit(aStart, (aPtr - aStart), array.data(), array.size(), -offset); if (op == Operation::Add) - blitSrcOver(bStart, (bPtr - bStart), array.data(), -offset); + blitSrcOver(bStart, (bPtr - bStart), array.data(), array.size(), -offset); else if (op == Operation::Xor) - blitXor(bStart, (bPtr - bStart), array.data(), -offset); + blitXor(bStart, (bPtr - bStart), array.data(), array.size(), -offset); VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), std::max(aLength, bLength), + size_t size = bufferToRle(array.data(), array.size(), std::max(aLength, bLength), offset, y, tResult); if (available >= size) { while (size--) { @@ -690,10 +705,10 @@ static void rleSubstractWithRle(VRleHelper *a, VRleHelper *b, int offset = std::min(aStart->x, bStart->x); std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), -offset); - blitDestinationOut(bStart, (bPtr - bStart), array.data(), -offset); + blit(aStart, (aPtr - aStart), array.data(), array.size(), -offset); + blitDestinationOut(bStart, (bPtr - bStart), array.data(), array.size(), -offset); VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), std::max(aLength, bLength), + size_t size = bufferToRle(array.data(), array.size(), std::max(aLength, bLength), offset, y, tResult); if (available >= size) { while (size--) { From 2edff77a2604634c58fd4658686bcdc6fe1fd69f Mon Sep 17 00:00:00 2001 From: overtake Date: Tue, 21 Jan 2020 15:58:13 +0400 Subject: [PATCH 11/24] - bugfixes and improvements --- src/vector/vrle.cpp | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/vector/vrle.cpp b/src/vector/vrle.cpp index d56710d3..7478a17d 100644 --- a/src/vector/vrle.cpp +++ b/src/vector/vrle.cpp @@ -503,11 +503,14 @@ static void rleIntersectWithRect(const VRect &clip, VRleHelper *tmp_obj, result->size = result->alloc - available; } -void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX, int len) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l >= len) { + return; + } uchar *ptr = buffer + x; while (l--) { int da = *ptr; @@ -520,11 +523,14 @@ void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) } void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, - int offsetX) + int offsetX, int len) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l >= len) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = divBy255((255 - spans->coverage) * (*ptr)); @@ -534,11 +540,14 @@ void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, } } -void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX, int len) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l >= len) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr)); @@ -548,11 +557,14 @@ void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX, int len) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x + l >= len) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = std::max(spans->coverage, *ptr); @@ -562,13 +574,16 @@ void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -size_t bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out) +size_t bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out, int len) { size_t count = 0; uchar value = buffer[0]; int curIndex = 0; size = offsetX < 0 ? size + offsetX : size; + if (size >= len) { + return count; + } for (int i = 0; i < size; i++) { uchar curValue = buffer[0]; if (value != curValue) { @@ -627,14 +642,14 @@ static void rleOpGeneric(VRleHelper *a, VRleHelper *b, VRleHelper *result, int offset = std::min(aStart->x, bStart->x); std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), -offset); + blit(aStart, (aPtr - aStart), array.data(), -offset, 1024); if (op == Operation::Add) - blitSrcOver(bStart, (bPtr - bStart), array.data(), -offset); + blitSrcOver(bStart, (bPtr - bStart), array.data(), -offset, 1024); else if (op == Operation::Xor) - blitXor(bStart, (bPtr - bStart), array.data(), -offset); + blitXor(bStart, (bPtr - bStart), array.data(), -offset, 1024); VRle::Span *tResult = temp.data(); size_t size = bufferToRle(array.data(), std::max(aLength, bLength), - offset, y, tResult); + offset, y, tResult, 1024); if (available >= size) { while (size--) { *out++ = *tResult++; @@ -690,11 +705,11 @@ static void rleSubstractWithRle(VRleHelper *a, VRleHelper *b, int offset = std::min(aStart->x, bStart->x); std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), -offset); - blitDestinationOut(bStart, (bPtr - bStart), array.data(), -offset); + blit(aStart, (aPtr - aStart), array.data(), -offset, 1024); + blitDestinationOut(bStart, (bPtr - bStart), array.data(), -offset, 1024); VRle::Span *tResult = temp.data(); size_t size = bufferToRle(array.data(), std::max(aLength, bLength), - offset, y, tResult); + offset, y, tResult, 1024); if (available >= size) { while (size--) { *out++ = *tResult++; From 75b31e49b3c69355c4971ee2029eff23a22fcb75 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 23 Jan 2020 15:47:53 +0300 Subject: [PATCH 12/24] Try to silence compare signess warnings. --- src/vector/vrle.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/vector/vrle.cpp b/src/vector/vrle.cpp index 6e48bfc5..db40855a 100644 --- a/src/vector/vrle.cpp +++ b/src/vector/vrle.cpp @@ -503,12 +503,12 @@ static void rleIntersectWithRect(const VRect &clip, VRleHelper *tmp_obj, result->size = result->alloc - available; } -void blitXor(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, int offsetX) +void blitXor(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l > bufferLen) { + if (x > bufferLen || l > bufferLen || x + l > bufferLen) { return; } uchar *ptr = buffer + x; @@ -522,13 +522,13 @@ void blitXor(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, } } -void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, +void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l > bufferLen) { + if (x > bufferLen || l > bufferLen || x + l > bufferLen) { return; } uchar *ptr = buffer + x; @@ -540,12 +540,12 @@ void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, std::size_t } } -void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, int offsetX) +void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l > bufferLen) { + if (x > bufferLen || l > bufferLen || x + l > bufferLen) { return; } uchar *ptr = buffer + x; @@ -557,12 +557,12 @@ void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, std::size_t buffer } } -void blit(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, int offsetX) +void blit(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l > bufferLen) { + if (x > bufferLen || l > bufferLen || x + l > bufferLen) { return; } uchar *ptr = buffer + x; @@ -574,7 +574,7 @@ void blit(VRle::Span *spans, int count, uchar *buffer, std::size_t bufferLen, in } } -size_t bufferToRle(uchar *buffer, std::size_t bufferLen, int size, int offsetX, int y, VRle::Span *out) +size_t bufferToRle(uchar *buffer, int bufferLen, int size, int offsetX, int y, VRle::Span *out) { size_t count = 0; uchar value = buffer[0]; @@ -641,14 +641,15 @@ static void rleOpGeneric(VRleHelper *a, VRleHelper *b, VRleHelper *result, int bLength = (bPtr - 1)->x + (bPtr - 1)->len; int offset = std::min(aStart->x, bStart->x); - std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), array.size(), -offset); + constexpr auto kBufferSize = 1024; + std::array array = {{0}}; + blit(aStart, (aPtr - aStart), array.data(), kBufferSize, -offset); if (op == Operation::Add) - blitSrcOver(bStart, (bPtr - bStart), array.data(), array.size(), -offset); + blitSrcOver(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset); else if (op == Operation::Xor) - blitXor(bStart, (bPtr - bStart), array.data(), array.size(), -offset); + blitXor(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset); VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), array.size(), std::max(aLength, bLength), + size_t size = bufferToRle(array.data(), kBufferSize, std::max(aLength, bLength), offset, y, tResult); if (available >= size) { while (size--) { @@ -704,11 +705,12 @@ static void rleSubstractWithRle(VRleHelper *a, VRleHelper *b, int bLength = (bPtr - 1)->x + (bPtr - 1)->len; int offset = std::min(aStart->x, bStart->x); - std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), array.size(), -offset); - blitDestinationOut(bStart, (bPtr - bStart), array.data(), array.size(), -offset); + constexpr auto kBufferSize = 1024; + std::array array = {{0}}; + blit(aStart, (aPtr - aStart), array.data(), kBufferSize, -offset); + blitDestinationOut(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset); VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), array.size(), std::max(aLength, bLength), + size_t size = bufferToRle(array.data(), kBufferSize, std::max(aLength, bLength), offset, y, tResult); if (available >= size) { while (size--) { From d513b026d8d4b0472ffca3b494300a26f10f5b38 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 13 Apr 2020 21:15:08 +0400 Subject: [PATCH 13/24] Add LOTTIE_THREAD_SAFE to limit object sharing when LOTTIE_THREAD_SUPPORT is on --- src/vector/vraster.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/vector/vraster.cpp b/src/vector/vraster.cpp index 80e7537e..467fd7dc 100644 --- a/src/vector/vraster.cpp +++ b/src/vector/vraster.cpp @@ -483,8 +483,10 @@ class RleTaskScheduler { class RleTaskScheduler { public: +#ifndef LOTTIE_THREAD_SAFE FTOutline outlineRef{}; SW_FT_Stroker stroker; +#endif public: static RleTaskScheduler &instance() @@ -493,11 +495,29 @@ class RleTaskScheduler { return singleton; } - RleTaskScheduler() { SW_FT_Stroker_New(&stroker); } + RleTaskScheduler() { +#ifndef LOTTIE_THREAD_SAFE + SW_FT_Stroker_New(&stroker); +#endif + } - ~RleTaskScheduler() { SW_FT_Stroker_Done(stroker); } + ~RleTaskScheduler() { +#ifndef LOTTIE_THREAD_SAFE + SW_FT_Stroker_Done(stroker); +#endif + } - void process(VTask task) { (*task)(outlineRef, stroker); } + void process(VTask task) { +#ifdef LOTTIE_THREAD_SAFE + FTOutline outlineRef{}; + SW_FT_Stroker stroker; + SW_FT_Stroker_New(&stroker); +#endif + (*task)(outlineRef, stroker); +#ifdef LOTTIE_THREAD_SAFE + SW_FT_Stroker_Done(stroker); +#endif + } }; #endif From 3c280ce86f649c1ea07c7ace5ed58162607c0edd Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 1 May 2020 17:14:53 +0400 Subject: [PATCH 14/24] Fix crash in malformed lottie animations. --- src/lottie/lottiemodel.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 4a5473d2..d263e467 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -225,11 +225,13 @@ class LOTAnimInfo { public: T value(int frameNo) const { + if (mKeyFrames.empty()) + return T(); + if (mKeyFrames.front().mStartFrame >= frameNo) return mKeyFrames.front().mValue.mStartValue; - if(mKeyFrames.back().mEndFrame <= frameNo) + if (mKeyFrames.back().mEndFrame <= frameNo) return mKeyFrames.back().mValue.mEndValue; - for(const auto &keyFrame : mKeyFrames) { if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) return keyFrame.value(frameNo); @@ -238,7 +240,8 @@ class LOTAnimInfo } float angle(int frameNo) const { - if ((mKeyFrames.front().mStartFrame >= frameNo) || + if (mKeyFrames.empty() || + (mKeyFrames.front().mStartFrame >= frameNo) || (mKeyFrames.back().mEndFrame <= frameNo) ) return 0; @@ -250,6 +253,9 @@ class LOTAnimInfo } bool changed(int prevFrame, int curFrame) const { + if (mKeyFrames.empty()) + return false; + auto first = mKeyFrames.front().mStartFrame; auto last = mKeyFrames.back().mEndFrame; From 7bfda261c8cfc8725f57dcdecf2bc6d759854882 Mon Sep 17 00:00:00 2001 From: overtake <> Date: Mon, 4 May 2020 18:58:08 +0400 Subject: [PATCH 15/24] - crash fix --- src/lottie/lottiemodel.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 4a5473d2..0a94b792 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -225,6 +225,10 @@ class LOTAnimInfo { public: T value(int frameNo) const { + if (mKeyFrames.empty()) + return T(); + + if (mKeyFrames.front().mStartFrame >= frameNo) return mKeyFrames.front().mValue.mStartValue; if(mKeyFrames.back().mEndFrame <= frameNo) @@ -238,7 +242,8 @@ class LOTAnimInfo } float angle(int frameNo) const { - if ((mKeyFrames.front().mStartFrame >= frameNo) || + if (mKeyFrames.empty() || + (mKeyFrames.front().mStartFrame >= frameNo) || (mKeyFrames.back().mEndFrame <= frameNo) ) return 0; @@ -250,6 +255,8 @@ class LOTAnimInfo } bool changed(int prevFrame, int curFrame) const { + if (mKeyFrames.empty()) + return false; auto first = mKeyFrames.front().mStartFrame; auto last = mKeyFrames.back().mEndFrame; From e0ea6af518345c4a46195c4951e023e621a9eb8f Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 11 May 2020 11:43:41 +0400 Subject: [PATCH 16/24] Fix some crashes on invalid data. --- src/lottie/lottieitem.cpp | 3 +++ src/lottie/lottiemodel.cpp | 8 +++++++- src/vector/vdrawhelper.cpp | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 09d14a4e..2d636e01 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -518,6 +518,9 @@ LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel) { // 1. create layer item for (auto &i : mLayerData->mChildren) { + if (i->type() != LOTData::Type::Layer) { + continue; + } auto model = static_cast(i.get()); auto item = LOTCompItem::createLayerItem(model); if (item) mLayers.push_back(std::move(item)); diff --git a/src/lottie/lottiemodel.cpp b/src/lottie/lottiemodel.cpp index ab7e984a..3c15a264 100644 --- a/src/lottie/lottiemodel.cpp +++ b/src/lottie/lottiemodel.cpp @@ -185,10 +185,13 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo) auto size = gradData.mGradient.size(); float * ptr = gradData.mGradient.data(); int colorPoints = mColorPoints; - if (colorPoints == -1) { // for legacy bodymovin (ref: lottie-android) + if (colorPoints < 0 || colorPoints * 4 > size) { // for legacy bodymovin (ref: lottie-android) colorPoints = int(size / 4); } auto opacityArraySize = size - colorPoints * 4; + if ((opacityArraySize % 2 != 0) || (colorPoints > opacityArraySize / 2 && opacityArraySize < 4)) { + opacityArraySize = 0; + } float *opacityPtr = ptr + (colorPoints * 4); stops.clear(); size_t j = 0; @@ -242,6 +245,9 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo) } ptr += 4; } + if (stops.empty()) { + stops.push_back(std::make_pair(0.0f, VColor(255, 255, 255, 255))); + } } void LOTGradient::update(std::unique_ptr &grad, int frameNo) diff --git a/src/vector/vdrawhelper.cpp b/src/vector/vdrawhelper.cpp index 00e4605a..462bad82 100644 --- a/src/vector/vdrawhelper.cpp +++ b/src/vector/vdrawhelper.cpp @@ -156,7 +156,7 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, colorTable[pos++] = curColor; - while (fpos <= curr->first) { + while (fpos <= curr->first && pos < size) { colorTable[pos] = colorTable[pos - 1]; pos++; fpos += incr; From 598f54078b5a7c029a85bea8a710760e986ac536 Mon Sep 17 00:00:00 2001 From: overtake <> Date: Sat, 30 May 2020 22:17:11 +0300 Subject: [PATCH 17/24] no message --- src/vector/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vector/config.h b/src/vector/config.h index 4fc34aa9..528115bc 100644 --- a/src/vector/config.h +++ b/src/vector/config.h @@ -2,7 +2,7 @@ #define CONFIG_H // enable threading -//#define LOTTIE_THREAD_SUPPORT +#define LOTTIE_THREAD_SUPPORT //enable logging //#define LOTTIE_LOGGING_SUPPORT From d369d84e868352886cee48eecb60b462f6dfe067 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Aug 2020 17:46:31 +0400 Subject: [PATCH 18/24] Add some more checks for invalid data. --- src/lottie/lottieparser.cpp | 3 ++- src/vector/freetype/v_ft_raster.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 07231e27..9fee36c4 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -1136,7 +1136,8 @@ std::shared_ptr LottieParserImpl::parseGroupObject() RAPIDJSON_ASSERT(PeekType() == kObjectType); parseObject(group); } - if (group->mChildren.back()->mType == LOTData::Type::Transform) { + if (!group->mChildren.empty() + && group->mChildren.back()->mType == LOTData::Type::Transform) { group->mTransform = std::static_pointer_cast( group->mChildren.back()); group->mChildren.pop_back(); diff --git a/src/vector/freetype/v_ft_raster.cpp b/src/vector/freetype/v_ft_raster.cpp index a5d2c754..333e2196 100644 --- a/src/vector/freetype/v_ft_raster.cpp +++ b/src/vector/freetype/v_ft_raster.cpp @@ -536,7 +536,7 @@ static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y) dx = to_x - ras.x; dy = to_y - ras.y; - + if (SW_FT_ABS(dx) > 10000000 || SW_FT_ABS(dy) > 10000000) { goto End; } @@ -711,6 +711,9 @@ static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, gray_split_conic(arc); arc += 2; top++; + + if (top + 1 > 32) return; + levels[top] = levels[top - 1] = level - 1; continue; } @@ -839,6 +842,9 @@ static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, Split: gray_split_cubic(arc); arc += 3; + + if (arc + 4 > ras.bez_stack + 32 * 3 + 1) return; + continue; Draw: From 69ccd758db246dc48e76bc44dffbec9f6c661630 Mon Sep 17 00:00:00 2001 From: overtake Date: Fri, 4 Sep 2020 20:50:19 +0300 Subject: [PATCH 19/24] skip 3d keys. we don't support it --- src/lottie/lottieparser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 1cc7febf..59e9fec5 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -1456,11 +1456,11 @@ std::shared_ptr LottieParserImpl::parseTransformObject( } else if (0 == strcmp(key, "hd")) { sharedTransform->mHidden = GetBool(); } else if (0 == strcmp(key, "rx")) { - parseProperty(obj->mExtra->m3DRx); + Skip(key); } else if (0 == strcmp(key, "ry")) { - parseProperty(obj->mExtra->m3DRy); + Skip(key); } else if (0 == strcmp(key, "rz")) { - parseProperty(obj->mExtra->m3DRz); + Skip(key); } else { Skip(key); } From 839dcab7f083a51b8130061ea5ec245195af6c58 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 24 Sep 2020 09:20:50 +0300 Subject: [PATCH 20/24] Add some more checks for input data. --- src/lottie/lottiemodel.cpp | 5 ++++- src/lottie/lottieparser.cpp | 11 ++++++++++- src/vector/vdrawable.cpp | 3 +++ src/vector/vdrawhelper.cpp | 3 +++ src/vector/vrle.cpp | 2 +- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/lottie/lottiemodel.cpp b/src/lottie/lottiemodel.cpp index 3c15a264..bf0e3572 100644 --- a/src/lottie/lottiemodel.cpp +++ b/src/lottie/lottiemodel.cpp @@ -184,8 +184,11 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo) LottieGradient gradData = mGradient.value(frameNo); auto size = gradData.mGradient.size(); float * ptr = gradData.mGradient.data(); + if (!ptr) { + return; + } int colorPoints = mColorPoints; - if (colorPoints < 0 || colorPoints * 4 > size) { // for legacy bodymovin (ref: lottie-android) + if (colorPoints < 0 || colorPoints > size / 4) { // for legacy bodymovin (ref: lottie-android) colorPoints = int(size / 4); } auto opacityArraySize = size - colorPoints * 4; diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 9fee36c4..e8259580 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -982,7 +982,7 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) staticFlag &= child.get()->isStatic(); } - if (layer->hasMask()) { + if (layer->hasMask() && layer->mExtra) { for (const auto &mask : layer->mExtra->mMasks) { staticFlag &= mask->isStatic(); } @@ -1458,10 +1458,19 @@ std::shared_ptr LottieParserImpl::parseTransformObject( } else if (0 == strcmp(key, "hd")) { sharedTransform->mHidden = GetBool(); } else if (0 == strcmp(key, "rx")) { + if (!obj->mExtra) { + return sharedTransform; + } parseProperty(obj->mExtra->m3DRx); } else if (0 == strcmp(key, "ry")) { + if (!obj->mExtra) { + return sharedTransform; + } parseProperty(obj->mExtra->m3DRy); } else if (0 == strcmp(key, "rz")) { + if (!obj->mExtra) { + return sharedTransform; + } parseProperty(obj->mExtra->m3DRz); } else { Skip(key); diff --git a/src/vector/vdrawable.cpp b/src/vector/vdrawable.cpp index cba3288f..9d3e8fe3 100644 --- a/src/vector/vdrawable.cpp +++ b/src/vector/vdrawable.cpp @@ -77,6 +77,9 @@ void VDrawable::setDashInfo(std::vector &dashInfo) if (!hasChanged) return; mStroke.mDash = dashInfo; + if (mStroke.mDash.size() == 1) { + mStroke.mDash.push_back(20); + } mFlag |= DirtyState::Path; } diff --git a/src/vector/vdrawhelper.cpp b/src/vector/vdrawhelper.cpp index 462bad82..9bbdb6c6 100644 --- a/src/vector/vdrawhelper.cpp +++ b/src/vector/vdrawhelper.cpp @@ -137,6 +137,9 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, float opacity, uint32_t *colorTable, int size) { + if (stops.empty()) { + return false; + } int dist, idist, pos = 0; size_t i; bool alpha = false; diff --git a/src/vector/vrle.cpp b/src/vector/vrle.cpp index db40855a..a5deee1d 100644 --- a/src/vector/vrle.cpp +++ b/src/vector/vrle.cpp @@ -562,7 +562,7 @@ void blit(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offset while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x > bufferLen || l > bufferLen || x + l > bufferLen) { + if (x > bufferLen || l > bufferLen || x + l > bufferLen || x + l < 0) { return; } uchar *ptr = buffer + x; From 7fdc010d9e71a0c39d3f63d421d1bef762b6a034 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Thu, 24 Jun 2021 20:54:40 +0400 Subject: [PATCH 21/24] Fix check --- src/vector/freetype/v_ft_raster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vector/freetype/v_ft_raster.cpp b/src/vector/freetype/v_ft_raster.cpp index 333e2196..2fd2259c 100644 --- a/src/vector/freetype/v_ft_raster.cpp +++ b/src/vector/freetype/v_ft_raster.cpp @@ -840,11 +840,11 @@ static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, } Split: + if (arc + 7 > ras.bez_stack + 32 * 3 + 1) return; + gray_split_cubic(arc); arc += 3; - if (arc + 4 > ras.bez_stack + 32 * 3 + 1) return; - continue; Draw: From 67f103bc8b625f2a4a9e94f1d8c7bd84c5a08d1d Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 17 Nov 2021 13:49:48 +0400 Subject: [PATCH 22/24] Add Fitzpatrick skin type based color replacement --- inc/rlottie.h | 11 ++++- src/lottie/lottieanimation.cpp | 4 +- src/lottie/lottieloader.cpp | 4 +- src/lottie/lottieloader.h | 4 +- src/lottie/lottieparser.cpp | 83 +++++++++++++++++++++++++++++++--- src/lottie/lottieparser.h | 3 +- 6 files changed, 96 insertions(+), 13 deletions(-) diff --git a/inc/rlottie.h b/inc/rlottie.h index 1436539d..db81448d 100644 --- a/inc/rlottie.h +++ b/inc/rlottie.h @@ -43,6 +43,15 @@ struct LOTLayerNode; namespace rlottie { +enum class FitzModifier { + None, + Type12, + Type3, + Type4, + Type5, + Type6 +}; + /** * @brief Configures rlottie model cache policy. * @@ -293,7 +302,7 @@ class LOT_EXPORT Animation { loadFromData(std::string jsonData, const std::string &key, const std::string &resourcePath="", bool cachePolicy=true, const std::vector> - &colorReplacements = {}); + &colorReplacements = {}, FitzModifier fitzModifier = FitzModifier::None); /** * @brief Returns default framerate of the Lottie resource. diff --git a/src/lottie/lottieanimation.cpp b/src/lottie/lottieanimation.cpp index 58d1b13b..197d2597 100644 --- a/src/lottie/lottieanimation.cpp +++ b/src/lottie/lottieanimation.cpp @@ -242,7 +242,7 @@ std::unique_ptr Animation::loadFromData( std::string jsonData, const std::string &key, const std::string &resourcePath, bool cachePolicy, const std::vector> - &colorReplacements) + &colorReplacements, FitzModifier fitzModifier) { if (jsonData.empty()) { vWarning << "jason data is empty"; @@ -252,7 +252,7 @@ std::unique_ptr Animation::loadFromData( LottieLoader loader; if (loader.loadFromData(std::move(jsonData), key, (resourcePath.empty() ? " " : resourcePath), - cachePolicy, colorReplacements)) { + cachePolicy, colorReplacements, fitzModifier)) { auto animation = std::unique_ptr(new Animation); animation->d->init(loader.model()); return animation; diff --git a/src/lottie/lottieloader.cpp b/src/lottie/lottieloader.cpp index 8c067808..feacde0c 100644 --- a/src/lottie/lottieloader.cpp +++ b/src/lottie/lottieloader.cpp @@ -144,7 +144,7 @@ bool LottieLoader::loadFromData( std::string &&jsonData, const std::string &key, const std::string &resourcePath, bool cachePolicy, const std::vector> - &colorReplacements) + &colorReplacements, rlottie::FitzModifier fitzModifier) { if (cachePolicy) { mModel = LottieModelCache::instance().find(key); @@ -152,7 +152,7 @@ bool LottieLoader::loadFromData( } LottieParser parser(const_cast(jsonData.c_str()), - resourcePath.c_str(), colorReplacements); + resourcePath.c_str(), colorReplacements, fitzModifier); mModel = parser.model(); if (!mModel) return false; diff --git a/src/lottie/lottieloader.h b/src/lottie/lottieloader.h index 711d0d64..48c1bc4d 100644 --- a/src/lottie/lottieloader.h +++ b/src/lottie/lottieloader.h @@ -23,6 +23,8 @@ #include #include +#include "rlottie.h" + class LOTModel; class LottieLoader { @@ -32,7 +34,7 @@ class LottieLoader bool loadFromData(std::string &&jsonData, const std::string &key, const std::string &resourcePath, bool cachePolicy, const std::vector> - &colorReplacements); + &colorReplacements, rlottie::FitzModifier fitzModifier); std::shared_ptr model(); private: std::shared_ptr mModel; diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index e8259580..5dccf172 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -171,9 +171,10 @@ class LottieParserImpl : public LookaheadParserHandler { public: LottieParserImpl(char *str, const char *dir_path, const std::vector> - &colorReplacements) + &colorReplacements, rlottie::FitzModifier fitzModifier) : LookaheadParserHandler(str), mColorReplacements(colorReplacements), + mFitzModifier(fitzModifier), mDirPath(dir_path) { } @@ -259,7 +260,10 @@ class LottieParserImpl : public LookaheadParserHandler { void parseShapeKeyFrame(LOTAnimInfo &obj); void parseShapeProperty(LOTAnimatable &obj); void parseDashProperty(LOTDashProperty &dash); - + + void parseFitzColorReplacements(); + void parseFitzColorReplacement(); + std::shared_ptr interpolator(VPointF, VPointF, std::string); LottieColor toColor(const char *str); @@ -268,8 +272,9 @@ class LottieParserImpl : public LookaheadParserHandler { void resolveLayerRefs(); protected: - const std::vector> - &mColorReplacements; + std::vector> + mColorReplacements; + const rlottie::FitzModifier mFitzModifier; std::unordered_map> mInterpolatorCache; std::shared_ptr mComposition; @@ -590,6 +595,8 @@ void LottieParserImpl::parseComposition() parseAssets(comp); } else if (0 == strcmp(key, "layers")) { parseLayers(comp); + } else if (0 == strcmp(key, "fitz")) { + parseFitzColorReplacements(); } else { #ifdef DEBUG_PARSER vWarning << "Composition Attribute Skipped : " << key; @@ -624,6 +631,70 @@ void LottieParserImpl::parseAssets(LOTCompositionData *composition) // update the precomp layers with the actual layer object } +void LottieParserImpl::parseFitzColorReplacements() +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); + EnterArray(); + while (NextArrayValue()) { + parseFitzColorReplacement(); + } +} + +void LottieParserImpl::parseFitzColorReplacement() +{ + uint32_t original = 0; + uint32_t type12 = 0; + uint32_t type3 = 0; + uint32_t type4 = 0; + uint32_t type5 = 0; + uint32_t type6 = 0; + + EnterObject(); + while (const char *key = NextObjectKey()) { + if (0 == strcmp(key, "o")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + original = GetInt(); + } else if (0 == strcmp(key, "f12")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type12 = GetInt(); + } else if (0 == strcmp(key, "f3")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type3 = GetInt(); + } else if (0 == strcmp(key, "f4")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type4 = GetInt(); + } else if (0 == strcmp(key, "f5")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type5 = GetInt(); + } else if (0 == strcmp(key, "f6")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type6 = GetInt(); + } else { + Skip(key); + } + } + + switch (mFitzModifier) { + case rlottie::FitzModifier::None: + break; + case rlottie::FitzModifier::Type12: + mColorReplacements.push_back(std::pair(original, type12)); + break; + case rlottie::FitzModifier::Type3: + mColorReplacements.push_back(std::pair(original, type3)); + break; + case rlottie::FitzModifier::Type4: + mColorReplacements.push_back(std::pair(original, type4)); + break; + case rlottie::FitzModifier::Type5: + mColorReplacements.push_back(std::pair(original, type5)); + break; + case rlottie::FitzModifier::Type6: + mColorReplacements.push_back(std::pair(original, type6)); + break; + } +} + static constexpr const unsigned char B64index[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2302,8 +2373,8 @@ LottieParser::~LottieParser() = default; LottieParser::LottieParser( char *str, const char *dir_path, const std::vector> - &colorReplacements) - : d(std::make_unique(str, dir_path, colorReplacements)) + &colorReplacements, rlottie::FitzModifier fitzModifier) + : d(std::make_unique(str, dir_path, colorReplacements, fitzModifier)) { if (d->VerifyType()) d->parseComposition(); diff --git a/src/lottie/lottieparser.h b/src/lottie/lottieparser.h index 06165f97..3a20e4f9 100644 --- a/src/lottie/lottieparser.h +++ b/src/lottie/lottieparser.h @@ -19,6 +19,7 @@ #ifndef LOTTIEPARSER_H #define LOTTIEPARSER_H +#include "rlottie.h" #include "lottiemodel.h" #include @@ -28,7 +29,7 @@ class LottieParser { ~LottieParser(); LottieParser(char *str, const char *dir_path, const std::vector> - &colorReplacements = {}); + &colorReplacements = {}, rlottie::FitzModifier fitzModifier = rlottie::FitzModifier::None); std::shared_ptr model(); private: std::unique_ptr d; From 0e8cb250a8008a3dae57876284bb206dbbc83606 Mon Sep 17 00:00:00 2001 From: Mike Renoir <> Date: Thu, 26 May 2022 16:24:23 +0400 Subject: [PATCH 23/24] cache lottie --- src/lottie/lottieloader.cpp | 5 +++-- src/vector/config.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lottie/lottieloader.cpp b/src/lottie/lottieloader.cpp index 8c067808..dd821ec3 100644 --- a/src/lottie/lottieloader.cpp +++ b/src/lottie/lottieloader.cpp @@ -71,7 +71,7 @@ class LottieModelCache { std::unordered_map> mHash; std::mutex mMutex; - size_t mcacheSize{10}; + size_t mcacheSize{10000}; }; #else @@ -148,7 +148,8 @@ bool LottieLoader::loadFromData( { if (cachePolicy) { mModel = LottieModelCache::instance().find(key); - if (mModel) return true; + if (mModel) + return true; } LottieParser parser(const_cast(jsonData.c_str()), diff --git a/src/vector/config.h b/src/vector/config.h index 528115bc..8a259506 100644 --- a/src/vector/config.h +++ b/src/vector/config.h @@ -11,7 +11,7 @@ //#define LOTTIE_IMAGE_MODULE_SUPPORT //enable lottie model caching -//#define LOTTIE_CACHE_SUPPORT +#define LOTTIE_CACHE_SUPPORT // disable image loader #define LOTTIE_IMAGE_MODULE_DISABLED From 78bfd252b6f31adca9050263c370374f83e4b4df Mon Sep 17 00:00:00 2001 From: "Mr. Nattapon Makchoo" <90859776+Nattapon43@users.noreply.github.com> Date: Fri, 4 Nov 2022 08:55:48 +0700 Subject: [PATCH 24/24] Create Lottie --- Lottie | 1 + 1 file changed, 1 insertion(+) create mode 100644 Lottie diff --git a/Lottie b/Lottie new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/Lottie @@ -0,0 +1 @@ +