From fd498ff35e6349ce60119a99d5bc615278da690d Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 16 Oct 2022 12:31:43 +0200 Subject: [PATCH] Squashed 'external/lunasvg/' changes from e0f786c9b..ead790126 ead790126 fix name conflict with rlottie #100 6192f2536 Fix fill default color #105 be5ec7a4f Release v2.3.4 29c32978d Fix std::clamp bug #105 41f21ccb1 Release v2.3.3 git-subtree-dir: external/lunasvg git-subtree-split: ead790126004b86a2dbbe9f4aaf27e82e419721e --- 3rdparty/plutovg/CMakeLists.txt | 3 + 3rdparty/{software => plutovg}/FTL.TXT | 0 .../plutovg-ft-math.c} | 303 ++- 3rdparty/plutovg/plutovg-ft-math.h | 436 +++++ 3rdparty/plutovg/plutovg-ft-raster.c | 1632 +++++++++++++++++ 3rdparty/plutovg/plutovg-ft-raster.h | 420 +++++ .../plutovg-ft-stroker.c} | 981 +++++----- 3rdparty/plutovg/plutovg-ft-stroker.h | 320 ++++ .../plutovg-ft-types.h} | 91 +- 3rdparty/plutovg/plutovg-private.h | 6 +- 3rdparty/plutovg/plutovg-rle.c | 215 ++- 3rdparty/software/CMakeLists.txt | 11 - 3rdparty/software/sw_ft_math.h | 438 ----- 3rdparty/software/sw_ft_raster.c | 1423 -------------- 3rdparty/software/sw_ft_raster.h | 607 ------ 3rdparty/software/sw_ft_stroker.h | 319 ---- CMakeLists.txt | 5 +- README.md | 2 +- source/canvas.cpp | 12 +- source/clippathelement.cpp | 4 +- source/defselement.cpp | 2 +- source/element.cpp | 24 +- source/element.h | 27 +- source/gelement.cpp | 2 +- source/geometryelement.cpp | 56 +- source/geometryelement.h | 4 +- source/graphicselement.cpp | 4 +- source/graphicselement.h | 2 +- source/layoutcontext.cpp | 12 +- source/layoutcontext.h | 6 +- source/lunasvg.cpp | 6 +- source/markerelement.cpp | 18 +- source/maskelement.cpp | 14 +- source/paintelement.cpp | 120 +- source/paintelement.h | 4 +- source/parser.cpp | 1052 +++++------ source/parser.h | 107 +- source/property.cpp | 23 +- source/property.h | 26 +- source/stopelement.cpp | 6 +- source/styledelement.cpp | 54 +- source/styledelement.h | 2 +- source/styleelement.cpp | 2 +- source/svgelement.cpp | 18 +- source/svgelement.h | 4 +- source/symbolelement.cpp | 14 +- source/useelement.cpp | 26 +- 47 files changed, 4466 insertions(+), 4397 deletions(-) rename 3rdparty/{software => plutovg}/FTL.TXT (100%) rename 3rdparty/{software/sw_ft_math.c => plutovg/plutovg-ft-math.c} (51%) create mode 100644 3rdparty/plutovg/plutovg-ft-math.h create mode 100644 3rdparty/plutovg/plutovg-ft-raster.c create mode 100644 3rdparty/plutovg/plutovg-ft-raster.h rename 3rdparty/{software/sw_ft_stroker.c => plutovg/plutovg-ft-stroker.c} (57%) create mode 100644 3rdparty/plutovg/plutovg-ft-stroker.h rename 3rdparty/{software/sw_ft_types.h => plutovg/plutovg-ft-types.h} (73%) delete mode 100755 3rdparty/software/CMakeLists.txt delete mode 100644 3rdparty/software/sw_ft_math.h delete mode 100644 3rdparty/software/sw_ft_raster.c delete mode 100644 3rdparty/software/sw_ft_raster.h delete mode 100644 3rdparty/software/sw_ft_stroker.h diff --git a/3rdparty/plutovg/CMakeLists.txt b/3rdparty/plutovg/CMakeLists.txt index 79cf3ee9e..62a92756c 100644 --- a/3rdparty/plutovg/CMakeLists.txt +++ b/3rdparty/plutovg/CMakeLists.txt @@ -6,6 +6,9 @@ PRIVATE "${CMAKE_CURRENT_LIST_DIR}/plutovg-blend.c" "${CMAKE_CURRENT_LIST_DIR}/plutovg-rle.c" "${CMAKE_CURRENT_LIST_DIR}/plutovg-dash.c" + "${CMAKE_CURRENT_LIST_DIR}/plutovg-ft-raster.c" + "${CMAKE_CURRENT_LIST_DIR}/plutovg-ft-stroker.c" + "${CMAKE_CURRENT_LIST_DIR}/plutovg-ft-math.c" ) target_include_directories(lunasvg diff --git a/3rdparty/software/FTL.TXT b/3rdparty/plutovg/FTL.TXT similarity index 100% rename from 3rdparty/software/FTL.TXT rename to 3rdparty/plutovg/FTL.TXT diff --git a/3rdparty/software/sw_ft_math.c b/3rdparty/plutovg/plutovg-ft-math.c similarity index 51% rename from 3rdparty/software/sw_ft_math.c rename to 3rdparty/plutovg/plutovg-ft-math.c index 79c9501b7..417242b23 100644 --- a/3rdparty/software/sw_ft_math.c +++ b/3rdparty/plutovg/plutovg-ft-math.c @@ -15,95 +15,87 @@ /* */ /***************************************************************************/ -#include "sw_ft_math.h" -#include - -//form https://github.com/chromium/chromium/blob/59afd8336009c9d97c22854c52e0382b62b3aa5e/third_party/abseil-cpp/absl/base/internal/bits.h +#include "plutovg-ft-math.h" #if defined(_MSC_VER) #include static unsigned int __inline clz(unsigned int x) { - unsigned long r = 0; - if (x != 0) - { - _BitScanReverse(&r, x); - } - return r; + unsigned long r = 0; + if (x != 0) + { + _BitScanReverse(&r, x); + } + return r; } -#define SW_FT_MSB(x) (clz(x)) +#define PVG_FT_MSB(x) (clz(x)) #elif defined(__GNUC__) -#define SW_FT_MSB(x) (31 - __builtin_clz(x)) +#define PVG_FT_MSB(x) (31 - __builtin_clz(x)) #else static unsigned int __inline clz(unsigned int x) { - int c = 31; - x &= ~x + 1; - if (n & 0x0000FFFF) c -= 16; - if (n & 0x00FF00FF) c -= 8; - if (n & 0x0F0F0F0F) c -= 4; - if (n & 0x33333333) c -= 2; - if (n & 0x55555555) c -= 1; - return c; + int c = 31; + x &= ~x + 1; + if (n & 0x0000FFFF) c -= 16; + if (n & 0x00FF00FF) c -= 8; + if (n & 0x0F0F0F0F) c -= 4; + if (n & 0x33333333) c -= 2; + if (n & 0x55555555) c -= 1; + return c; } -#define SW_FT_MSB(x) (clz(x)) +#define PVG_FT_MSB(x) (clz(x)) #endif +#define PVG_FT_PAD_FLOOR(x, n) ((x) & ~((n)-1)) +#define PVG_FT_PAD_ROUND(x, n) PVG_FT_PAD_FLOOR((x) + ((n) / 2), n) +#define PVG_FT_PAD_CEIL(x, n) PVG_FT_PAD_FLOOR((x) + ((n)-1), n) +#define PVG_FT_BEGIN_STMNT do { +#define PVG_FT_END_STMNT } while (0) - - -#define SW_FT_PAD_FLOOR(x, n) ((x) & ~((n)-1)) -#define SW_FT_PAD_ROUND(x, n) SW_FT_PAD_FLOOR((x) + ((n) / 2), n) -#define SW_FT_PAD_CEIL(x, n) SW_FT_PAD_FLOOR((x) + ((n)-1), n) - -#define SW_FT_BEGIN_STMNT do { -#define SW_FT_END_STMNT \ - } \ - while (0) /* transfer sign leaving a positive number */ -#define SW_FT_MOVE_SIGN(x, s) \ - SW_FT_BEGIN_STMNT \ +#define PVG_FT_MOVE_SIGN(x, s) \ + PVG_FT_BEGIN_STMNT \ if (x < 0) { \ x = -x; \ s = -s; \ } \ - SW_FT_END_STMNT + PVG_FT_END_STMNT -SW_FT_Long SW_FT_MulFix(SW_FT_Long a, SW_FT_Long b) +PVG_FT_Long PVG_FT_MulFix(PVG_FT_Long a, PVG_FT_Long b) { - SW_FT_Int s = 1; - SW_FT_Long c; + PVG_FT_Int s = 1; + PVG_FT_Long c; - SW_FT_MOVE_SIGN(a, s); - SW_FT_MOVE_SIGN(b, s); + PVG_FT_MOVE_SIGN(a, s); + PVG_FT_MOVE_SIGN(b, s); - c = (SW_FT_Long)(((SW_FT_Int64)a * b + 0x8000L) >> 16); + c = (PVG_FT_Long)(((PVG_FT_Int64)a * b + 0x8000L) >> 16); return (s > 0) ? c : -c; } -SW_FT_Long SW_FT_MulDiv(SW_FT_Long a, SW_FT_Long b, SW_FT_Long c) +PVG_FT_Long PVG_FT_MulDiv(PVG_FT_Long a, PVG_FT_Long b, PVG_FT_Long c) { - SW_FT_Int s = 1; - SW_FT_Long d; + PVG_FT_Int s = 1; + PVG_FT_Long d; - SW_FT_MOVE_SIGN(a, s); - SW_FT_MOVE_SIGN(b, s); - SW_FT_MOVE_SIGN(c, s); + PVG_FT_MOVE_SIGN(a, s); + PVG_FT_MOVE_SIGN(b, s); + PVG_FT_MOVE_SIGN(c, s); - d = (SW_FT_Long)(c > 0 ? ((SW_FT_Int64)a * b + (c >> 1)) / c : 0x7FFFFFFFL); + d = (PVG_FT_Long)(c > 0 ? ((PVG_FT_Int64)a * b + (c >> 1)) / c : 0x7FFFFFFFL); return (s > 0) ? d : -d; } -SW_FT_Long SW_FT_DivFix(SW_FT_Long a, SW_FT_Long b) +PVG_FT_Long PVG_FT_DivFix(PVG_FT_Long a, PVG_FT_Long b) { - SW_FT_Int s = 1; - SW_FT_Long q; + PVG_FT_Int s = 1; + PVG_FT_Long q; - SW_FT_MOVE_SIGN(a, s); - SW_FT_MOVE_SIGN(b, s); + PVG_FT_MOVE_SIGN(a, s); + PVG_FT_MOVE_SIGN(b, s); - q = (SW_FT_Long)(b > 0 ? (((SW_FT_UInt64)a << 16) + (b >> 1)) / b + q = (PVG_FT_Long)(b > 0 ? (((PVG_FT_UInt64)a << 16) + (b >> 1)) / b : 0x7FFFFFFFL); return (s < 0 ? -q : q); @@ -124,52 +116,52 @@ SW_FT_Long SW_FT_DivFix(SW_FT_Long a, SW_FT_Long b) /*************************************************************************/ /* the Cordic shrink factor 0.858785336480436 * 2^32 */ -#define SW_FT_TRIG_SCALE 0xDBD95B16UL +#define PVG_FT_TRIG_SCALE 0xDBD95B16UL /* the highest bit in overflow-safe vector components, */ /* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ -#define SW_FT_TRIG_SAFE_MSB 29 +#define PVG_FT_TRIG_SAFE_MSB 29 -/* this table was generated for SW_FT_PI = 180L << 16, i.e. degrees */ -#define SW_FT_TRIG_MAX_ITERS 23 +/* this table was generated for PVG_FT_PI = 180L << 16, i.e. degrees */ +#define PVG_FT_TRIG_MAX_ITERS 23 -static const SW_FT_Fixed ft_trig_arctan_table[] = { +static const PVG_FT_Fixed ft_trig_arctan_table[] = { 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, 57L, 29L, 14L, 7L, 4L, 2L, 1L}; /* multiply a given value by the CORDIC shrink factor */ -static SW_FT_Fixed ft_trig_downscale(SW_FT_Fixed val) +static PVG_FT_Fixed ft_trig_downscale(PVG_FT_Fixed val) { - SW_FT_Fixed s; - SW_FT_Int64 v; + PVG_FT_Fixed s; + PVG_FT_Int64 v; s = val; - val = SW_FT_ABS(val); + val = PVG_FT_ABS(val); - v = (val * (SW_FT_Int64)SW_FT_TRIG_SCALE) + 0x100000000UL; - val = (SW_FT_Fixed)(v >> 32); + v = (val * (PVG_FT_Int64)PVG_FT_TRIG_SCALE) + 0x100000000UL; + val = (PVG_FT_Fixed)(v >> 32); return (s >= 0) ? val : -val; } /* undefined and never called for zero vector */ -static SW_FT_Int ft_trig_prenorm(SW_FT_Vector* vec) +static PVG_FT_Int ft_trig_prenorm(PVG_FT_Vector* vec) { - SW_FT_Pos x, y; - SW_FT_Int shift; + PVG_FT_Pos x, y; + PVG_FT_Int shift; x = vec->x; y = vec->y; - shift = SW_FT_MSB(SW_FT_ABS(x) | SW_FT_ABS(y)); + shift = PVG_FT_MSB(PVG_FT_ABS(x) | PVG_FT_ABS(y)); - if (shift <= SW_FT_TRIG_SAFE_MSB) { - shift = SW_FT_TRIG_SAFE_MSB - shift; - vec->x = (SW_FT_Pos)((SW_FT_ULong)x << shift); - vec->y = (SW_FT_Pos)((SW_FT_ULong)y << shift); + if (shift <= PVG_FT_TRIG_SAFE_MSB) { + shift = PVG_FT_TRIG_SAFE_MSB - shift; + vec->x = (PVG_FT_Pos)((PVG_FT_ULong)x << shift); + vec->y = (PVG_FT_Pos)((PVG_FT_ULong)y << shift); } else { - shift -= SW_FT_TRIG_SAFE_MSB; + shift -= PVG_FT_TRIG_SAFE_MSB; vec->x = x >> shift; vec->y = y >> shift; shift = -shift; @@ -178,36 +170,36 @@ static SW_FT_Int ft_trig_prenorm(SW_FT_Vector* vec) return shift; } -static void ft_trig_pseudo_rotate(SW_FT_Vector* vec, SW_FT_Angle theta) +static void ft_trig_pseudo_rotate(PVG_FT_Vector* vec, PVG_FT_Angle theta) { - SW_FT_Int i; - SW_FT_Fixed x, y, xtemp, b; - const SW_FT_Fixed* arctanptr; + PVG_FT_Int i; + PVG_FT_Fixed x, y, xtemp, b; + const PVG_FT_Fixed* arctanptr; x = vec->x; y = vec->y; /* Rotate inside [-PI/4,PI/4] sector */ - while (theta < -SW_FT_ANGLE_PI4) { + while (theta < -PVG_FT_ANGLE_PI4) { xtemp = y; y = -x; x = xtemp; - theta += SW_FT_ANGLE_PI2; + theta += PVG_FT_ANGLE_PI2; } - while (theta > SW_FT_ANGLE_PI4) { + while (theta > PVG_FT_ANGLE_PI4) { xtemp = -y; y = x; x = xtemp; - theta -= SW_FT_ANGLE_PI2; + theta -= PVG_FT_ANGLE_PI2; } arctanptr = ft_trig_arctan_table; /* Pseudorotations, with right shifts */ - for (i = 1, b = 1; i < SW_FT_TRIG_MAX_ITERS; b <<= 1, i++) { - SW_FT_Fixed v1 = ((y + b) >> i); - SW_FT_Fixed v2 = ((x + b) >> i); + for (i = 1, b = 1; i < PVG_FT_TRIG_MAX_ITERS; b <<= 1, i++) { + PVG_FT_Fixed v1 = ((y + b) >> i); + PVG_FT_Fixed v2 = ((x + b) >> i); if (theta < 0) { xtemp = x + v1; y = y - v2; @@ -225,12 +217,12 @@ static void ft_trig_pseudo_rotate(SW_FT_Vector* vec, SW_FT_Angle theta) vec->y = y; } -static void ft_trig_pseudo_polarize(SW_FT_Vector* vec) +static void ft_trig_pseudo_polarize(PVG_FT_Vector* vec) { - SW_FT_Angle theta; - SW_FT_Int i; - SW_FT_Fixed x, y, xtemp, b; - const SW_FT_Fixed* arctanptr; + PVG_FT_Angle theta; + PVG_FT_Int i; + PVG_FT_Fixed x, y, xtemp, b; + const PVG_FT_Fixed* arctanptr; x = vec->x; y = vec->y; @@ -238,18 +230,18 @@ static void ft_trig_pseudo_polarize(SW_FT_Vector* vec) /* Get the vector into [-PI/4,PI/4] sector */ if (y > x) { if (y > -x) { - theta = SW_FT_ANGLE_PI2; + theta = PVG_FT_ANGLE_PI2; xtemp = y; y = -x; x = xtemp; } else { - theta = y > 0 ? SW_FT_ANGLE_PI : -SW_FT_ANGLE_PI; + theta = y > 0 ? PVG_FT_ANGLE_PI : -PVG_FT_ANGLE_PI; x = -x; y = -y; } } else { if (y < -x) { - theta = -SW_FT_ANGLE_PI2; + theta = -PVG_FT_ANGLE_PI2; xtemp = -y; y = x; x = xtemp; @@ -261,9 +253,9 @@ static void ft_trig_pseudo_polarize(SW_FT_Vector* vec) arctanptr = ft_trig_arctan_table; /* Pseudorotations, with right shifts */ - for (i = 1, b = 1; i < SW_FT_TRIG_MAX_ITERS; b <<= 1, i++) { - SW_FT_Fixed v1 = ((y + b) >> i); - SW_FT_Fixed v2 = ((x + b) >> i); + for (i = 1, b = 1; i < PVG_FT_TRIG_MAX_ITERS; b <<= 1, i++) { + PVG_FT_Fixed v1 = ((y + b) >> i); + PVG_FT_Fixed v2 = ((x + b) >> i); if (y > 0) { xtemp = x + v1; y = y - v2; @@ -279,9 +271,9 @@ static void ft_trig_pseudo_polarize(SW_FT_Vector* vec) /* round theta */ if (theta >= 0) - theta = SW_FT_PAD_ROUND(theta, 32); + theta = PVG_FT_PAD_ROUND(theta, 32); else - theta = -SW_FT_PAD_ROUND(-theta, 32); + theta = -PVG_FT_PAD_ROUND(-theta, 32); vec->x = x; vec->y = theta; @@ -289,11 +281,11 @@ static void ft_trig_pseudo_polarize(SW_FT_Vector* vec) /* documentation is in fttrigon.h */ -SW_FT_Fixed SW_FT_Cos(SW_FT_Angle angle) +PVG_FT_Fixed PVG_FT_Cos(PVG_FT_Angle angle) { - SW_FT_Vector v; + PVG_FT_Vector v; - v.x = SW_FT_TRIG_SCALE >> 8; + v.x = PVG_FT_TRIG_SCALE >> 8; v.y = 0; ft_trig_pseudo_rotate(&v, angle); @@ -302,29 +294,29 @@ SW_FT_Fixed SW_FT_Cos(SW_FT_Angle angle) /* documentation is in fttrigon.h */ -SW_FT_Fixed SW_FT_Sin(SW_FT_Angle angle) +PVG_FT_Fixed PVG_FT_Sin(PVG_FT_Angle angle) { - return SW_FT_Cos(SW_FT_ANGLE_PI2 - angle); + return PVG_FT_Cos(PVG_FT_ANGLE_PI2 - angle); } /* documentation is in fttrigon.h */ -SW_FT_Fixed SW_FT_Tan(SW_FT_Angle angle) +PVG_FT_Fixed PVG_FT_Tan(PVG_FT_Angle angle) { - SW_FT_Vector v; + PVG_FT_Vector v; - v.x = SW_FT_TRIG_SCALE >> 8; + v.x = PVG_FT_TRIG_SCALE >> 8; v.y = 0; ft_trig_pseudo_rotate(&v, angle); - return SW_FT_DivFix(v.y, v.x); + return PVG_FT_DivFix(v.y, v.x); } /* documentation is in fttrigon.h */ -SW_FT_Angle SW_FT_Atan2(SW_FT_Fixed dx, SW_FT_Fixed dy) +PVG_FT_Angle PVG_FT_Atan2(PVG_FT_Fixed dx, PVG_FT_Fixed dy) { - SW_FT_Vector v; + PVG_FT_Vector v; if (dx == 0 && dy == 0) return 0; @@ -338,65 +330,58 @@ SW_FT_Angle SW_FT_Atan2(SW_FT_Fixed dx, SW_FT_Fixed dy) /* documentation is in fttrigon.h */ -void SW_FT_Vector_Unit(SW_FT_Vector* vec, SW_FT_Angle angle) +void PVG_FT_Vector_Unit(PVG_FT_Vector* vec, PVG_FT_Angle angle) { - vec->x = SW_FT_TRIG_SCALE >> 8; + vec->x = PVG_FT_TRIG_SCALE >> 8; vec->y = 0; ft_trig_pseudo_rotate(vec, angle); vec->x = (vec->x + 0x80L) >> 8; vec->y = (vec->y + 0x80L) >> 8; } -/* these macros return 0 for positive numbers, - and -1 for negative ones */ -#define SW_FT_SIGN_LONG(x) ((x) >> (SW_FT_SIZEOF_LONG * 8 - 1)) -#define SW_FT_SIGN_INT(x) ((x) >> (SW_FT_SIZEOF_INT * 8 - 1)) -#define SW_FT_SIGN_INT32(x) ((x) >> 31) -#define SW_FT_SIGN_INT16(x) ((x) >> 15) - -/* documentation is in fttrigon.h */ - -void SW_FT_Vector_Rotate(SW_FT_Vector* vec, SW_FT_Angle angle) +void PVG_FT_Vector_Rotate(PVG_FT_Vector* vec, PVG_FT_Angle angle) { - SW_FT_Int shift; - SW_FT_Vector v; + PVG_FT_Int shift; + PVG_FT_Vector v = *vec; - v.x = vec->x; - v.y = vec->y; + if ( v.x == 0 && v.y == 0 ) + return; - if (angle && (v.x != 0 || v.y != 0)) { - shift = ft_trig_prenorm(&v); - ft_trig_pseudo_rotate(&v, angle); - v.x = ft_trig_downscale(v.x); - v.y = ft_trig_downscale(v.y); + shift = ft_trig_prenorm( &v ); + ft_trig_pseudo_rotate( &v, angle ); + v.x = ft_trig_downscale( v.x ); + v.y = ft_trig_downscale( v.y ); - if (shift > 0) { - SW_FT_Int32 half = (SW_FT_Int32)1L << (shift - 1); + if ( shift > 0 ) + { + PVG_FT_Int32 half = (PVG_FT_Int32)1L << ( shift - 1 ); - vec->x = (v.x + half + SW_FT_SIGN_LONG(v.x)) >> shift; - vec->y = (v.y + half + SW_FT_SIGN_LONG(v.y)) >> shift; - } else { - shift = -shift; - vec->x = (SW_FT_Pos)((SW_FT_ULong)v.x << shift); - vec->y = (SW_FT_Pos)((SW_FT_ULong)v.y << shift); - } + + vec->x = ( v.x + half - ( v.x < 0 ) ) >> shift; + vec->y = ( v.y + half - ( v.y < 0 ) ) >> shift; + } + else + { + shift = -shift; + vec->x = (PVG_FT_Pos)( (PVG_FT_ULong)v.x << shift ); + vec->y = (PVG_FT_Pos)( (PVG_FT_ULong)v.y << shift ); } } /* documentation is in fttrigon.h */ -SW_FT_Fixed SW_FT_Vector_Length(SW_FT_Vector* vec) +PVG_FT_Fixed PVG_FT_Vector_Length(PVG_FT_Vector* vec) { - SW_FT_Int shift; - SW_FT_Vector v; + PVG_FT_Int shift; + PVG_FT_Vector v; v = *vec; /* handle trivial cases */ if (v.x == 0) { - return SW_FT_ABS(v.y); + return PVG_FT_ABS(v.y); } else if (v.y == 0) { - return SW_FT_ABS(v.x); + return PVG_FT_ABS(v.x); } /* general case */ @@ -407,16 +392,16 @@ SW_FT_Fixed SW_FT_Vector_Length(SW_FT_Vector* vec) if (shift > 0) return (v.x + (1 << (shift - 1))) >> shift; - return (SW_FT_Fixed)((SW_FT_UInt32)v.x << -shift); + return (PVG_FT_Fixed)((PVG_FT_UInt32)v.x << -shift); } /* documentation is in fttrigon.h */ -void SW_FT_Vector_Polarize(SW_FT_Vector* vec, SW_FT_Fixed* length, - SW_FT_Angle* angle) +void PVG_FT_Vector_Polarize(PVG_FT_Vector* vec, PVG_FT_Fixed* length, + PVG_FT_Angle* angle) { - SW_FT_Int shift; - SW_FT_Vector v; + PVG_FT_Int shift; + PVG_FT_Vector v; v = *vec; @@ -428,34 +413,34 @@ void SW_FT_Vector_Polarize(SW_FT_Vector* vec, SW_FT_Fixed* length, v.x = ft_trig_downscale(v.x); *length = (shift >= 0) ? (v.x >> shift) - : (SW_FT_Fixed)((SW_FT_UInt32)v.x << -shift); + : (PVG_FT_Fixed)((PVG_FT_UInt32)v.x << -shift); *angle = v.y; } /* documentation is in fttrigon.h */ -void SW_FT_Vector_From_Polar(SW_FT_Vector* vec, SW_FT_Fixed length, - SW_FT_Angle angle) +void PVG_FT_Vector_From_Polar(PVG_FT_Vector* vec, PVG_FT_Fixed length, + PVG_FT_Angle angle) { vec->x = length; vec->y = 0; - SW_FT_Vector_Rotate(vec, angle); + PVG_FT_Vector_Rotate(vec, angle); } /* documentation is in fttrigon.h */ -SW_FT_Angle SW_FT_Angle_Diff( SW_FT_Angle angle1, SW_FT_Angle angle2 ) +PVG_FT_Angle PVG_FT_Angle_Diff( PVG_FT_Angle angle1, PVG_FT_Angle angle2 ) { - SW_FT_Angle delta = angle2 - angle1; + PVG_FT_Angle delta = angle2 - angle1; - while ( delta <= -SW_FT_ANGLE_PI ) - delta += SW_FT_ANGLE_2PI; + while ( delta <= -PVG_FT_ANGLE_PI ) + delta += PVG_FT_ANGLE_2PI; - while ( delta > SW_FT_ANGLE_PI ) - delta -= SW_FT_ANGLE_2PI; + while ( delta > PVG_FT_ANGLE_PI ) + delta -= PVG_FT_ANGLE_2PI; - return delta; + return delta; } /* END */ diff --git a/3rdparty/plutovg/plutovg-ft-math.h b/3rdparty/plutovg/plutovg-ft-math.h new file mode 100644 index 000000000..81c66b81b --- /dev/null +++ b/3rdparty/plutovg/plutovg-ft-math.h @@ -0,0 +1,436 @@ +/***************************************************************************/ +/* */ +/* fttrigon.h */ +/* */ +/* FreeType trigonometric functions (specification). */ +/* */ +/* Copyright 2001, 2003, 2005, 2007, 2013 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef PLUTOVG_FT_MATH_H +#define PLUTOVG_FT_MATH_H + +#include "plutovg-ft-types.h" + +/*************************************************************************/ +/* */ +/* The min and max functions missing in C. As usual, be careful not to */ +/* write things like PVG_FT_MIN( a++, b++ ) to avoid side effects. */ +/* */ +#define PVG_FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) +#define PVG_FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) + +#define PVG_FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) + +/* + * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' + * algorithm. We use alpha = 1, beta = 3/8, giving us results with a + * largest error less than 7% compared to the exact value. + */ +#define PVG_FT_HYPOT( x, y ) \ + ( x = PVG_FT_ABS( x ), \ + y = PVG_FT_ABS( y ), \ + x > y ? x + ( 3 * y >> 3 ) \ + : y + ( 3 * x >> 3 ) ) + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_MulFix */ +/* */ +/* */ +/* A very simple function used to perform the computation */ +/* `(a*b)/0x10000' with maximum accuracy. Most of the time this is */ +/* used to multiply a given value by a 16.16 fixed-point factor. */ +/* */ +/* */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. Use a 16.16 factor here whenever */ +/* possible (see note below). */ +/* */ +/* */ +/* The result of `(a*b)/0x10000'. */ +/* */ +/* */ +/* This function has been optimized for the case where the absolute */ +/* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ +/* As this happens mainly when scaling from notional units to */ +/* fractional pixels in FreeType, it resulted in noticeable speed */ +/* improvements between versions 2.x and 1.x. */ +/* */ +/* As a conclusion, always try to place a 16.16 factor as the */ +/* _second_ argument of this function; this can make a great */ +/* difference. */ +/* */ +PVG_FT_Long +PVG_FT_MulFix( PVG_FT_Long a, + PVG_FT_Long b ); + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_MulDiv */ +/* */ +/* */ +/* A very simple function used to perform the computation `(a*b)/c' */ +/* with maximum accuracy (it uses a 64-bit intermediate integer */ +/* whenever necessary). */ +/* */ +/* This function isn't necessarily as fast as some processor specific */ +/* operations, but is at least completely portable. */ +/* */ +/* */ +/* a :: The first multiplier. */ +/* b :: The second multiplier. */ +/* c :: The divisor. */ +/* */ +/* */ +/* The result of `(a*b)/c'. This function never traps when trying to */ +/* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ +/* on the signs of `a' and `b'. */ +/* */ +PVG_FT_Long +PVG_FT_MulDiv( PVG_FT_Long a, + PVG_FT_Long b, + PVG_FT_Long c ); + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_DivFix */ +/* */ +/* */ +/* A very simple function used to perform the computation */ +/* `(a*0x10000)/b' with maximum accuracy. Most of the time, this is */ +/* used to divide a given value by a 16.16 fixed-point factor. */ +/* */ +/* */ +/* a :: The numerator. */ +/* b :: The denominator. Use a 16.16 factor here. */ +/* */ +/* */ +/* The result of `(a*0x10000)/b'. */ +/* */ +PVG_FT_Long +PVG_FT_DivFix( PVG_FT_Long a, + PVG_FT_Long b ); + + + +/*************************************************************************/ +/* */ +/*
*/ +/* computations */ +/* */ +/*************************************************************************/ + + +/************************************************************************* + * + * @type: + * PVG_FT_Angle + * + * @description: + * This type is used to model angle values in FreeType. Note that the + * angle is a 16.16 fixed-point value expressed in degrees. + * + */ +typedef PVG_FT_Fixed PVG_FT_Angle; + + +/************************************************************************* + * + * @macro: + * PVG_FT_ANGLE_PI + * + * @description: + * The angle pi expressed in @PVG_FT_Angle units. + * + */ +#define PVG_FT_ANGLE_PI ( 180L << 16 ) + + +/************************************************************************* + * + * @macro: + * PVG_FT_ANGLE_2PI + * + * @description: + * The angle 2*pi expressed in @PVG_FT_Angle units. + * + */ +#define PVG_FT_ANGLE_2PI ( PVG_FT_ANGLE_PI * 2 ) + + +/************************************************************************* + * + * @macro: + * PVG_FT_ANGLE_PI2 + * + * @description: + * The angle pi/2 expressed in @PVG_FT_Angle units. + * + */ +#define PVG_FT_ANGLE_PI2 ( PVG_FT_ANGLE_PI / 2 ) + + +/************************************************************************* + * + * @macro: + * PVG_FT_ANGLE_PI4 + * + * @description: + * The angle pi/4 expressed in @PVG_FT_Angle units. + * + */ +#define PVG_FT_ANGLE_PI4 ( PVG_FT_ANGLE_PI / 4 ) + + +/************************************************************************* + * + * @function: + * PVG_FT_Sin + * + * @description: + * Return the sinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The sinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @PVG_FT_Vector_Unit. + * + */ +PVG_FT_Fixed +PVG_FT_Sin( PVG_FT_Angle angle ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Cos + * + * @description: + * Return the cosinus of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The cosinus value. + * + * @note: + * If you need both the sinus and cosinus for a given angle, use the + * function @PVG_FT_Vector_Unit. + * + */ +PVG_FT_Fixed +PVG_FT_Cos( PVG_FT_Angle angle ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Tan + * + * @description: + * Return the tangent of a given angle in fixed-point format. + * + * @input: + * angle :: + * The input angle. + * + * @return: + * The tangent value. + * + */ +PVG_FT_Fixed +PVG_FT_Tan( PVG_FT_Angle angle ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Atan2 + * + * @description: + * Return the arc-tangent corresponding to a given vector (x,y) in + * the 2d plane. + * + * @input: + * x :: + * The horizontal vector coordinate. + * + * y :: + * The vertical vector coordinate. + * + * @return: + * The arc-tangent value (i.e. angle). + * + */ +PVG_FT_Angle +PVG_FT_Atan2( PVG_FT_Fixed x, + PVG_FT_Fixed y ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Angle_Diff + * + * @description: + * Return the difference between two angles. The result is always + * constrained to the ]-PI..PI] interval. + * + * @input: + * angle1 :: + * First angle. + * + * angle2 :: + * Second angle. + * + * @return: + * Constrained value of `value2-value1'. + * + */ +PVG_FT_Angle +PVG_FT_Angle_Diff( PVG_FT_Angle angle1, + PVG_FT_Angle angle2 ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Vector_Unit + * + * @description: + * Return the unit vector corresponding to a given angle. After the + * call, the value of `vec.x' will be `sin(angle)', and the value of + * `vec.y' will be `cos(angle)'. + * + * This function is useful to retrieve both the sinus and cosinus of a + * given angle quickly. + * + * @output: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ +void +PVG_FT_Vector_Unit( PVG_FT_Vector* vec, + PVG_FT_Angle angle ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Vector_Rotate + * + * @description: + * Rotate a vector by a given angle. + * + * @inout: + * vec :: + * The address of target vector. + * + * @input: + * angle :: + * The input angle. + * + */ +void +PVG_FT_Vector_Rotate( PVG_FT_Vector* vec, + PVG_FT_Angle angle ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Vector_Length + * + * @description: + * Return the length of a given vector. + * + * @input: + * vec :: + * The address of target vector. + * + * @return: + * The vector length, expressed in the same units that the original + * vector coordinates. + * + */ +PVG_FT_Fixed +PVG_FT_Vector_Length( PVG_FT_Vector* vec ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Vector_Polarize + * + * @description: + * Compute both the length and angle of a given vector. + * + * @input: + * vec :: + * The address of source vector. + * + * @output: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ +void +PVG_FT_Vector_Polarize( PVG_FT_Vector* vec, + PVG_FT_Fixed *length, + PVG_FT_Angle *angle ); + + +/************************************************************************* + * + * @function: + * PVG_FT_Vector_From_Polar + * + * @description: + * Compute vector coordinates from a length and angle. + * + * @output: + * vec :: + * The address of source vector. + * + * @input: + * length :: + * The vector length. + * + * angle :: + * The vector angle. + * + */ +void +PVG_FT_Vector_From_Polar( PVG_FT_Vector* vec, + PVG_FT_Fixed length, + PVG_FT_Angle angle ); + +#endif /* PLUTOVG_FT_MATH_H */ diff --git a/3rdparty/plutovg/plutovg-ft-raster.c b/3rdparty/plutovg/plutovg-ft-raster.c new file mode 100644 index 000000000..5642c5ef2 --- /dev/null +++ b/3rdparty/plutovg/plutovg-ft-raster.c @@ -0,0 +1,1632 @@ +/***************************************************************************/ +/* */ +/* ftgrays.c */ +/* */ +/* A new `perfect' anti-aliasing renderer (body). */ +/* */ +/* Copyright 2000-2003, 2005-2014 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +/*************************************************************************/ +/* */ +/* 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_ */ +/* coverage of the outline on each pixel cell. */ +/* */ +/* It is based on ideas that I initially found in Raph Levien's */ +/* excellent LibArt graphics library (see http://www.levien.com/libart */ +/* for more information, though the web pages do not tell anything */ +/* about the renderer; you'll have to dive into the source code to */ +/* understand how it works). */ +/* */ +/* Note, however, that this is a _very_ different implementation */ +/* compared to Raph's. Coverage information is stored in a very */ +/* different way, and I don't use sorted vector paths. Also, it doesn't */ +/* use floating point values. */ +/* */ +/* This renderer has the following advantages: */ +/* */ +/* - It doesn't need an intermediate bitmap. Instead, one can supply a */ +/* callback function that will be called by the renderer to draw gray */ +/* spans on any target surface. You can thus do direct composition on */ +/* any kind of bitmap, provided that you give the renderer the right */ +/* callback. */ +/* */ +/* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ +/* each pixel cell. */ +/* */ +/* - It performs a single pass on the outline (the `standard' FT2 */ +/* renderer makes two passes). */ +/* */ +/* - It can easily be modified to render to _any_ number of gray levels */ +/* cheaply. */ +/* */ +/* - For small (< 20) pixel sizes, it is faster than the standard */ +/* renderer. */ +/* */ +/*************************************************************************/ + +#include "plutovg-ft-raster.h" +#include "plutovg-ft-math.h" + +#define PVG_FT_BEGIN_STMNT do { +#define PVG_FT_END_STMNT } while ( 0 ) + +#include + +#define pvg_ft_setjmp setjmp +#define pvg_ft_longjmp longjmp +#define pvg_ft_jmp_buf jmp_buf + +#include + +typedef ptrdiff_t PVG_FT_PtrDist; + +#define ErrRaster_Invalid_Mode -2 +#define ErrRaster_Invalid_Outline -1 +#define ErrRaster_Invalid_Argument -3 +#define ErrRaster_Memory_Overflow -4 +#define ErrRaster_OutOfMemory -6 + +#include +#include + +#define PVG_FT_MINIMUM_POOL_SIZE 8192 + +#define RAS_ARG PWorker worker +#define RAS_ARG_ PWorker worker, + +#define RAS_VAR worker +#define RAS_VAR_ worker, + +#define ras (*worker) + + /* must be at least 6 bits! */ +#define PIXEL_BITS 8 + +#define ONE_PIXEL ( 1L << PIXEL_BITS ) +#define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS ) +#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) + +#if PIXEL_BITS >= 6 +#define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) ) +#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) +#else +#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) +#define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) ) +#endif + +/* Compute `dividend / divisor' and return both its quotient and */ +/* remainder, cast to a specific type. This macro also ensures that */ +/* the remainder is always positive. */ +#define PVG_FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \ +PVG_FT_BEGIN_STMNT \ + (quotient) = (type)( (dividend) / (divisor) ); \ + (remainder) = (type)( (dividend) % (divisor) ); \ + if ( (remainder) < 0 ) \ + { \ + (quotient)--; \ + (remainder) += (type)(divisor); \ + } \ +PVG_FT_END_STMNT + + /* These macros speed up repetitive divisions by replacing them */ + /* with multiplications and right shifts. */ +#define PVG_FT_UDIVPREP( b ) \ + long b ## _r = (long)( ULONG_MAX >> PIXEL_BITS ) / ( b ) +#define PVG_FT_UDIV( a, b ) \ + ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \ + ( sizeof( long ) * CHAR_BIT - PIXEL_BITS ) ) + + + /*************************************************************************/ + /* */ + /* TYPE DEFINITIONS */ + /* */ + + /* don't change the following types to PVG_FT_Int or PVG_FT_Pos, since we might */ + /* need to define them to "float" or "double" when experimenting with */ + /* new algorithms */ + + typedef long TCoord; /* integer scanline/pixel coordinate */ + typedef long TPos; /* sub-pixel coordinate */ + typedef long TArea ; /* cell areas, coordinate products */ + + /* maximal number of gray spans in a call to the span callback */ +#define PVG_FT_MAX_GRAY_SPANS 256 + + + typedef struct TCell_* PCell; + + typedef struct TCell_ + { + int x; + int cover; + TArea area; + PCell next; + + } TCell; + + + typedef struct TWorker_ + { + TCoord ex, ey; + TPos min_ex, max_ex; + TPos min_ey, max_ey; + TPos count_ex, count_ey; + + TArea area; + int cover; + int invalid; + + PCell cells; + PVG_FT_PtrDist max_cells; + PVG_FT_PtrDist num_cells; + + TPos x, y; + + PVG_FT_Outline outline; + PVG_FT_BBox clip_box; + + PVG_FT_Span gray_spans[PVG_FT_MAX_GRAY_SPANS]; + int num_gray_spans; + int skip_spans; + + PVG_FT_Raster_Span_Func render_span; + void* render_span_data; + + int band_size; + int band_shoot; + + pvg_ft_jmp_buf jump_buffer; + + void* buffer; + long buffer_size; + + PCell* ycells; + TPos ycount; + } TWorker, *PWorker; + + + /*************************************************************************/ + /* */ + /* Initialize the cells table. */ + /* */ + 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; + ras.num_cells = 0; + ras.area = 0; + ras.cover = 0; + ras.invalid = 1; + } + + + /*************************************************************************/ + /* */ + /* Compute the outline bounding box. */ + /* */ + static void + gray_compute_cbox( RAS_ARG ) + { + PVG_FT_Outline* outline = &ras.outline; + PVG_FT_Vector* vec = outline->points; + PVG_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; + ras.max_ex = ( ras.max_ex + 63 ) >> 6; + ras.max_ey = ( ras.max_ey + 63 ) >> 6; + } + + + /*************************************************************************/ + /* */ + /* Record the current cell in the table. */ + /* */ + 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 ) + pvg_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; + } + + + 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; + } + } + + + /*************************************************************************/ + /* */ + /* Set the current cell to a new position. */ + /* */ + static void + gray_set_cell( RAS_ARG_ TCoord ex, + TCoord ey ) + { + /* Move the cell pointer to a new position. We set the `invalid' */ + /* flag to indicate that the cell isn't part of those we're interested */ + /* in during the render phase. This means that: */ + /* */ + /* . the new vertical position must be within min_ey..max_ey-1. */ + /* . the new horizontal position must be strictly less than max_ex */ + /* */ + /* 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 int)ey >= (unsigned int)ras.count_ey || + ex >= ras.count_ex ); + } + + + /*************************************************************************/ + /* */ + /* Start a new contour at a given cell. */ + /* */ + 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 ); + } + +// The new render-line implementation is not yet used +#if 1 + + /*************************************************************************/ + /* */ + /* Render a scanline as one or more cells. */ + /* */ + static void + gray_render_scanline( RAS_ARG_ TCoord ey, + TPos x1, + TCoord y1, + TPos x2, + TCoord y2 ) + { + TCoord ex1, ex2, fx1, fx2, first, dy, delta, mod; + TPos p, dx; + int incr; + + + ex1 = TRUNC( x1 ); + ex2 = TRUNC( x2 ); + + /* trivial case. Happens often */ + if ( y1 == y2 ) + { + gray_set_cell( RAS_VAR_ ex2, ey ); + return; + } + + fx1 = FRACT( x1 ); + fx2 = FRACT( x2 ); + + /* everything is located in a single cell. That is easy! */ + /* */ + if ( ex1 == ex2 ) + goto End; + + /* ok, we'll have to render a run of adjacent cells on the same */ + /* scanline... */ + /* */ + dx = x2 - x1; + dy = y2 - y1; + + if ( dx > 0 ) + { + p = ( ONE_PIXEL - fx1 ) * dy; + first = ONE_PIXEL; + incr = 1; + } else { + p = fx1 * dy; + first = 0; + incr = -1; + dx = -dx; + } + + PVG_FT_DIV_MOD( TCoord, p, dx, delta, mod ); + + ras.area += (TArea)( fx1 + first ) * delta; + ras.cover += delta; + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + + if ( ex1 != ex2 ) + { + TCoord lift, rem; + + + p = ONE_PIXEL * dy; + PVG_FT_DIV_MOD( TCoord, p, dx, lift, rem ); + + do + { + delta = lift; + mod += rem; + if ( mod >= (TCoord)dx ) + { + mod -= (TCoord)dx; + delta++; + } + + ras.area += (TArea)( ONE_PIXEL * delta ); + ras.cover += delta; + y1 += delta; + ex1 += incr; + gray_set_cell( RAS_VAR_ ex1, ey ); + } while ( ex1 != ex2 ); + } + fx1 = ONE_PIXEL - first; + + End: + dy = y2 - y1; + + ras.area += (TArea)( ( fx1 + fx2 ) * dy ); + ras.cover += dy; + } + + + /*************************************************************************/ + /* */ + /* Render a given line as a series of scanlines. */ + /* */ + static void + gray_render_line( RAS_ARG_ TPos to_x, + TPos to_y ) + { + TCoord ey1, ey2, fy1, fy2, first, delta, mod; + TPos p, dx, dy, x, x2; + int incr; + + ey1 = TRUNC( ras.y ); + ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ + + /* perform vertical clipping */ + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + goto End; + + fy1 = FRACT( ras.y ); + fy2 = FRACT( to_y ); + + /* everything is on a single scanline */ + if ( ey1 == ey2 ) + { + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ); + goto End; + } + + dx = to_x - ras.x; + dy = to_y - ras.y; + + /* vertical line - avoid calling gray_render_scanline */ + if ( dx == 0 ) + { + TCoord ex = TRUNC( ras.x ); + TCoord two_fx = FRACT( ras.x ) << 1; + TPos area, max_ey1; + + + if ( dy > 0) + { + first = ONE_PIXEL; + } + else + { + first = 0; + } + + delta = first - fy1; + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + + delta = first + first - ONE_PIXEL; + area = (TArea)two_fx * delta; + max_ey1 = ras.count_ey + ras.min_ey; + if (dy < 0) { + if (ey1 > max_ey1) { + ey1 = (max_ey1 > ey2) ? max_ey1 : ey2; + gray_set_cell( &ras, ex, ey1 ); + } else { + ey1--; + gray_set_cell( &ras, ex, ey1 ); + } + while ( ey1 > ey2 && ey1 >= ras.min_ey) + { + ras.area += area; + ras.cover += delta; + ey1--; + + gray_set_cell( &ras, ex, ey1 ); + } + if (ey1 != ey2) { + ey1 = ey2; + gray_set_cell( &ras, ex, ey1 ); + } + } else { + if (ey1 < ras.min_ey) { + ey1 = (ras.min_ey < ey2) ? ras.min_ey : ey2; + gray_set_cell( &ras, ex, ey1 ); + } else { + ey1++; + gray_set_cell( &ras, ex, ey1 ); + } + while ( ey1 < ey2 && ey1 < max_ey1) + { + ras.area += area; + ras.cover += delta; + ey1++; + + gray_set_cell( &ras, ex, ey1 ); + } + if (ey1 != ey2) { + ey1 = ey2; + gray_set_cell( &ras, ex, ey1 ); + } + } + + delta = (int)( fy2 - ONE_PIXEL + first ); + ras.area += (TArea)two_fx * delta; + ras.cover += delta; + + goto End; + } + + /* ok, we have to render several scanlines */ + if ( dy > 0) + { + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + } + else + { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + + /* the fractional part of x-delta is mod/dy. It is essential to */ + /* keep track of its accumulation for accurate rendering. */ + PVG_FT_DIV_MOD( TCoord, p, dy, delta, mod ); + + x = ras.x + delta; + gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + + if ( ey1 != ey2 ) + { + TCoord lift, rem; + + + p = ONE_PIXEL * dx; + PVG_FT_DIV_MOD( TCoord, p, dy, lift, rem ); + + do + { + delta = lift; + mod += rem; + if ( mod >= (TCoord)dy ) + { + mod -= (TCoord)dy; + delta++; + } + + x2 = x + delta; + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + x2, first ); + x = x2; + + ey1 += incr; + gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); + } while ( ey1 != ey2 ); + } + + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + to_x, fy2 ); + + End: + ras.x = to_x; + ras.y = to_y; + } + + +#else + + /*************************************************************************/ + /* */ + /* Render a straight line across multiple cells in any direction. */ + /* */ + 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 ); + + /* perform vertical clipping */ + if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || + ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + goto End; + + dx = to_x - ras.x; + dy = to_y - ras.y; + + fx1 = FRACT( ras.x ); + fy1 = FRACT( ras.y ); + + 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 */ + { + TArea prod = dx * fy1 - dy * fx1; + PVG_FT_UDIVPREP( dx ); + PVG_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 */ + { + fx2 = 0; + fy2 = (TPos)PVG_FT_UDIV( -prod, -dx ); + prod -= dy * ONE_PIXEL; + 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 */ + { + prod -= dx * ONE_PIXEL; + fx2 = (TPos)PVG_FT_UDIV( -prod, dy ); + fy2 = ONE_PIXEL; + 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 */ + { + prod += dy * ONE_PIXEL; + fx2 = ONE_PIXEL; + fy2 = (TPos)PVG_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 */ + { + fx2 = (TPos)PVG_FT_UDIV( prod, -dy ); + fy2 = 0; + prod += dx * ONE_PIXEL; + 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 ); + } + + 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; + } + +#endif + + static void + gray_split_conic( PVG_FT_Vector* base ) + { + 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; + + 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; + } + + + static void + gray_render_conic( RAS_ARG_ const PVG_FT_Vector* control, + const PVG_FT_Vector* to ) + { + PVG_FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ + PVG_FT_Vector* arc = bez_stack; + TPos dx, dy; + int draw, split; + + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control->x ); + arc[1].y = UPSCALE( control->y ); + arc[2].x = ras.x; + arc[2].y = ras.y; + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( arc[0].y ) >= ras.max_ey && + TRUNC( arc[1].y ) >= ras.max_ey && + TRUNC( arc[2].y ) >= ras.max_ey ) || + ( TRUNC( arc[0].y ) < ras.min_ey && + TRUNC( arc[1].y ) < ras.min_ey && + TRUNC( arc[2].y ) < ras.min_ey ) ) + { + ras.x = arc[0].x; + ras.y = arc[0].y; + return; + } + + dx = PVG_FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); + dy = PVG_FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); + if ( dx < dy ) + dx = dy; + + /* We can calculate the number of necessary bisections because */ + /* each bisection predictably reduces deviation exactly 4-fold. */ + /* Even 32-bit deviation would vanish after 16 bisections. */ + draw = 1; + while ( dx > ONE_PIXEL / 4 ) + { + dx >>= 2; + draw <<= 1; + } + + /* We use decrement counter to count the total number of segments */ + /* to draw starting from 2^level. Before each draw we split as */ + /* many times as there are trailing zeros in the counter. */ + do + { + split = 1; + while ( ( draw & split ) == 0 ) + { + gray_split_conic( arc ); + arc += 2; + split <<= 1; + } + + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + arc -= 2; + + } while ( --draw ); + } + + + static void + gray_split_cubic( PVG_FT_Vector* base ) + { + TPos a, b, c, d; + + + 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; + + 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; + } + + + static void + gray_render_cubic( RAS_ARG_ const PVG_FT_Vector* control1, + const PVG_FT_Vector* control2, + const PVG_FT_Vector* to ) + { + PVG_FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */ + PVG_FT_Vector* arc = bez_stack; + TPos dx, dy, dx_, dy_; + TPos dx1, dy1, dx2, dy2; + TPos L, s, s_limit; + + + arc[0].x = UPSCALE( to->x ); + arc[0].y = UPSCALE( to->y ); + arc[1].x = UPSCALE( control2->x ); + arc[1].y = UPSCALE( control2->y ); + arc[2].x = UPSCALE( control1->x ); + 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 */ + if ( ( TRUNC( arc[0].y ) >= ras.max_ey && + TRUNC( arc[1].y ) >= ras.max_ey && + TRUNC( arc[2].y ) >= ras.max_ey && + TRUNC( arc[3].y ) >= ras.max_ey ) || + ( TRUNC( arc[0].y ) < ras.min_ey && + TRUNC( arc[1].y ) < ras.min_ey && + TRUNC( arc[2].y ) < ras.min_ey && + TRUNC( arc[3].y ) < ras.min_ey ) ) + { + ras.x = arc[0].x; + ras.y = arc[0].y; + return; + } + + 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 */ + + + /* 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 = PVG_FT_HYPOT( dx_, dy_ ); + + /* Avoid possible arithmetic overflow below by splitting. */ + if ( L >= (1 << 23) ) + 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 = PVG_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 = PVG_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. */ + if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 || + dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 ) + goto Split; + + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + + if ( arc == bez_stack ) + return; + + arc -= 3; + continue; + + Split: + gray_split_cubic( arc ); + arc += 3; + } + } + + + + static int + gray_move_to( const PVG_FT_Vector* to, + PWorker worker ) + { + TPos x, y; + + + /* record current cell, if any */ + if ( !ras.invalid ) + gray_record_cell( worker ); + + /* start to a new position */ + x = UPSCALE( to->x ); + y = UPSCALE( to->y ); + + gray_start_cell( worker, TRUNC( x ), TRUNC( y ) ); + + ras.x = x; + ras.y = y; + return 0; + } + + + static void + gray_hline( RAS_ARG_ TCoord x, + TCoord y, + TPos area, + int acount ) + { + int coverage; + + + /* compute the coverage line's coverage, depending on the */ + /* outline fill rule */ + /* */ + /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ + /* */ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); + /* use range 0..256 */ + if ( coverage < 0 ) + coverage = -coverage; + + if ( ras.outline.flags & PVG_FT_OUTLINE_EVEN_ODD_FILL ) + { + coverage &= 511; + + if ( coverage > 256 ) + coverage = 512 - coverage; + else if ( coverage == 256 ) + coverage = 255; + } + else + { + /* normal non-zero winding rule */ + if ( coverage >= 256 ) + coverage = 255; + } + + y += (TCoord)ras.min_ey; + x += (TCoord)ras.min_ex; + + /* PVG_FT_Span.x is an int, so limit our coordinates appropriately */ + if ( x >= (1 << 23) ) + x = (1 << 23) - 1; + + /* PVG_FT_Span.y is an int, so limit our coordinates appropriately */ + if ( y >= (1 << 23) ) + y = (1 << 23) - 1; + + if ( coverage ) + { + PVG_FT_Span* span; + int count; + int skip; + + /* see whether we can add this span to the current list */ + count = ras.num_gray_spans; + span = ras.gray_spans + count - 1; + if ( count > 0 && + span->y == y && + span->x + span->len == x && + span->coverage == coverage ) + { + span->len = span->len + acount; + return; + } + + if ( count >= PVG_FT_MAX_GRAY_SPANS ) + { + if ( ras.render_span && count > ras.skip_spans ) + { + skip = ras.skip_spans > 0 ? ras.skip_spans : 0; + ras.render_span( ras.num_gray_spans - skip, + ras.gray_spans + skip, + ras.render_span_data ); + } + + ras.skip_spans -= ras.num_gray_spans; + /* ras.render_span( span->y, ras.gray_spans, count ); */ + ras.num_gray_spans = 0; + + span = ras.gray_spans; + } + else + span++; + + /* add a gray span to the current list */ + span->x = x; + span->len = acount; + span->y = y; + span->coverage = (unsigned char)coverage; + + ras.num_gray_spans++; + } + } + + + + static void + gray_sweep( RAS_ARG) + { + int yindex; + + if ( ras.num_cells == 0 ) + return; + + for ( yindex = 0; yindex < ras.ycount; yindex++ ) + { + PCell cell = ras.ycells[yindex]; + TCoord cover = 0; + TCoord x = 0; + + + for ( ; cell != NULL; cell = cell->next ) + { + TArea 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 ( ras.count_ex > x && cover != 0 ) + gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ), + ras.count_ex - x ); + } + } + + /*************************************************************************/ + /* */ + /* The following function should only compile in stand_alone mode, */ + /* i.e., when building this component without the rest of FreeType. */ + /* */ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* */ + /* PVG_FT_Outline_Decompose */ + /* */ + /* */ + /* Walks over an outline's structure to decompose it into individual */ + /* segments and Bezier arcs. This function is also able to emit */ + /* `move to' and `close to' operations to indicate the start and end */ + /* of new contours in the outline. */ + /* */ + /* */ + /* outline :: A pointer to the source target. */ + /* */ + /* user :: A typeless pointer which is passed to each */ + /* emitter during the decomposition. It can be */ + /* used to store the state during the */ + /* decomposition. */ + /* */ + /* */ + /* Error code. 0 means success. */ + /* */ + static + int PVG_FT_Outline_Decompose( const PVG_FT_Outline* outline, + void* user ) + { +#undef SCALED +#define SCALED( x ) (x) + + PVG_FT_Vector v_last; + PVG_FT_Vector v_control; + PVG_FT_Vector v_start; + + PVG_FT_Vector* point; + PVG_FT_Vector* limit; + char* tags; + + int n; /* index of contour in outline */ + int first; /* index of first point in contour */ + int error; + char tag; /* current point's state */ + + if ( !outline ) + return ErrRaster_Invalid_Outline; + + 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 = PVG_FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == PVG_FT_CURVE_TAG_CUBIC ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == PVG_FT_CURVE_TAG_CONIC ) + { + /* first point is conic control. Yes, this happens. */ + if ( PVG_FT_CURVE_TAG( outline->tags[last] ) == PVG_FT_CURVE_TAG_ON ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + error = gray_move_to( &v_start, user ); + if ( error ) + goto Exit; + + while ( point < limit ) + { + point++; + tags++; + + tag = PVG_FT_CURVE_TAG( tags[0] ); + switch ( tag ) + { + case PVG_FT_CURVE_TAG_ON: /* emit a single line_to */ + { + PVG_FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + gray_render_line(user, UPSCALE(vec.x), UPSCALE(vec.y)); + continue; + } + + case PVG_FT_CURVE_TAG_CONIC: /* consume conic arcs */ + { + v_control.x = SCALED( point->x ); + v_control.y = SCALED( point->y ); + + Do_Conic: + if ( point < limit ) + { + PVG_FT_Vector vec; + PVG_FT_Vector v_middle; + + + point++; + tags++; + tag = PVG_FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + if ( tag == PVG_FT_CURVE_TAG_ON ) + { + gray_render_conic(user, &v_control, &vec); + continue; + } + + if ( tag != PVG_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; + + gray_render_conic(user, &v_control, &v_middle); + + v_control = vec; + goto Do_Conic; + } + + gray_render_conic(user, &v_control, &v_start); + goto Close; + } + + default: /* PVG_FT_CURVE_TAG_CUBIC */ + { + PVG_FT_Vector vec1, vec2; + + + if ( point + 1 > limit || + PVG_FT_CURVE_TAG( tags[1] ) != PVG_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 ) + { + PVG_FT_Vector vec; + + + vec.x = SCALED( point->x ); + vec.y = SCALED( point->y ); + + gray_render_cubic(user, &vec1, &vec2, &vec); + continue; + } + + gray_render_cubic(user, &vec1, &vec2, &v_start); + goto Close; + } + } + } + + /* close the contour with a line segment */ + gray_render_line(user, UPSCALE(v_start.x), UPSCALE(v_start.y)); + + Close: + first = last + 1; + } + + return 0; + + Exit: + return error; + + Invalid_Outline: + return ErrRaster_Invalid_Outline; + } + + typedef struct TBand_ + { + TPos min, max; + + } TBand; + + static int + gray_convert_glyph_inner( RAS_ARG ) + { + volatile int error = 0; + + if ( pvg_ft_setjmp( ras.jump_buffer ) == 0 ) + { + error = PVG_FT_Outline_Decompose( &ras.outline, &ras ); + if ( !ras.invalid ) + gray_record_cell( RAS_VAR ); + } + else + { + error = ErrRaster_Memory_Overflow; + } + + return error; + } + + + static int + gray_convert_glyph( RAS_ARG ) + { + TBand bands[40]; + TBand* volatile band; + int volatile n, num_bands; + TPos volatile min, max, max_y; + PVG_FT_BBox* clip; + int skip; + + ras.num_gray_spans = 0; + + /* 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; + int 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 = (int)(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 ErrRaster_OutOfMemory; + } + + if ( bottom-top >= ras.band_size ) + ras.band_shoot++; + + band[1].min = bottom; + band[1].max = middle; + band[0].min = middle; + band[0].max = top; + band++; + } + } + + if ( ras.render_span && ras.num_gray_spans > ras.skip_spans ) + { + skip = ras.skip_spans > 0 ? ras.skip_spans : 0; + ras.render_span( ras.num_gray_spans - skip, + ras.gray_spans + skip, + ras.render_span_data ); + } + + ras.skip_spans -= ras.num_gray_spans; + + if ( ras.band_shoot > 8 && ras.band_size > 16 ) + ras.band_size = ras.band_size / 2; + + return 0; + } + + + static int + gray_raster_render( RAS_ARG_ void* buffer, long buffer_size, + const PVG_FT_Raster_Params* params ) + { + const PVG_FT_Outline* outline = (const PVG_FT_Outline*)params->source; + if ( outline == NULL ) + return ErrRaster_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 ErrRaster_Invalid_Outline; + + if ( outline->n_points != + outline->contours[outline->n_contours - 1] + 1 ) + return ErrRaster_Invalid_Outline; + + /* this version does not support monochrome rendering */ + if ( !( params->flags & PVG_FT_RASTER_FLAG_AA ) ) + return ErrRaster_Invalid_Mode; + + if ( !( params->flags & PVG_FT_RASTER_FLAG_DIRECT ) ) + return ErrRaster_Invalid_Mode; + + /* compute clipping box */ + if ( params->flags & PVG_FT_RASTER_FLAG_CLIP ) + { + ras.clip_box = params->clip_box; + } + else + { + ras.clip_box.xMin = -(1 << 23); + ras.clip_box.yMin = -(1 << 23); + ras.clip_box.xMax = (1 << 23) - 1; + ras.clip_box.yMax = (1 << 23) - 1; + } + + gray_init_cells( RAS_VAR_ buffer, buffer_size ); + + ras.outline = *outline; + ras.num_cells = 0; + ras.invalid = 1; + ras.band_size = (int)(buffer_size / (long)(sizeof(TCell) * 8)); + + ras.render_span = (PVG_FT_Raster_Span_Func)params->gray_spans; + ras.render_span_data = params->user; + + return gray_convert_glyph( RAS_VAR ); + } + + void + PVG_FT_Raster_Render(const PVG_FT_Raster_Params *params) + { + char stack[PVG_FT_MINIMUM_POOL_SIZE]; + size_t length = PVG_FT_MINIMUM_POOL_SIZE; + + TWorker worker; + worker.skip_spans = 0; + int rendered_spans = 0; + int error = gray_raster_render(&worker, stack, length, params); + while(error == ErrRaster_OutOfMemory) { + if(worker.skip_spans < 0) + rendered_spans += -worker.skip_spans; + worker.skip_spans = rendered_spans; + length *= 2; + void* heap = malloc(length); + error = gray_raster_render(&worker, heap, length, params); + free(heap); + } + } + +/* END */ diff --git a/3rdparty/plutovg/plutovg-ft-raster.h b/3rdparty/plutovg/plutovg-ft-raster.h new file mode 100644 index 000000000..5f5d934c6 --- /dev/null +++ b/3rdparty/plutovg/plutovg-ft-raster.h @@ -0,0 +1,420 @@ +/***************************************************************************/ +/* */ +/* ftimage.h */ +/* */ +/* FreeType glyph image formats and default raster interface */ +/* (specification). */ +/* */ +/* Copyright 1996-2010, 2013 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef PLUTOVG_FT_RASTER_H +#define PLUTOVG_FT_RASTER_H + +#include "plutovg-ft-types.h" + +/*************************************************************************/ +/* */ +/* */ +/* FT_BBox */ +/* */ +/* */ +/* A structure used to hold an outline's bounding box, i.e., the */ +/* coordinates of its extrema in the horizontal and vertical */ +/* directions. */ +/* */ +/* */ +/* xMin :: The horizontal minimum (left-most). */ +/* */ +/* yMin :: The vertical minimum (bottom-most). */ +/* */ +/* xMax :: The horizontal maximum (right-most). */ +/* */ +/* yMax :: The vertical maximum (top-most). */ +/* */ +/* */ +/* The bounding box is specified with the coordinates of the lower */ +/* left and the upper right corner. In PostScript, those values are */ +/* often called (llx,lly) and (urx,ury), respectively. */ +/* */ +/* If `yMin' is negative, this value gives the glyph's descender. */ +/* Otherwise, the glyph doesn't descend below the baseline. */ +/* Similarly, if `ymax' is positive, this value gives the glyph's */ +/* ascender. */ +/* */ +/* `xMin' gives the horizontal distance from the glyph's origin to */ +/* the left edge of the glyph's bounding box. If `xMin' is negative, */ +/* the glyph extends to the left of the origin. */ +/* */ +typedef struct PVG_FT_BBox_ +{ + PVG_FT_Pos xMin, yMin; + PVG_FT_Pos xMax, yMax; + +} PVG_FT_BBox; + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_Outline */ +/* */ +/* */ +/* This structure is used to describe an outline to the scan-line */ +/* converter. */ +/* */ +/* */ +/* n_contours :: The number of contours in the outline. */ +/* */ +/* n_points :: The number of points in the outline. */ +/* */ +/* points :: A pointer to an array of `n_points' @PVG_FT_Vector */ +/* elements, giving the outline's point coordinates. */ +/* */ +/* tags :: A pointer to an array of `n_points' chars, giving */ +/* each outline point's type. */ +/* */ +/* If bit~0 is unset, the point is `off' the curve, */ +/* i.e., a Bézier control point, while it is `on' if */ +/* set. */ +/* */ +/* Bit~1 is meaningful for `off' points only. If set, */ +/* it indicates a third-order Bézier arc control point; */ +/* and a second-order control point if unset. */ +/* */ +/* If bit~2 is set, bits 5-7 contain the drop-out mode */ +/* (as defined in the OpenType specification; the value */ +/* is the same as the argument to the SCANMODE */ +/* instruction). */ +/* */ +/* Bits 3 and~4 are reserved for internal purposes. */ +/* */ +/* contours :: An array of `n_contours' shorts, giving the end */ +/* point of each contour within the outline. For */ +/* example, the first contour is defined by the points */ +/* `0' to `contours[0]', the second one is defined by */ +/* the points `contours[0]+1' to `contours[1]', etc. */ +/* */ +/* flags :: A set of bit flags used to characterize the outline */ +/* and give hints to the scan-converter and hinter on */ +/* how to convert/grid-fit it. See @PVG_FT_OUTLINE_FLAGS.*/ +/* */ +typedef struct PVG_FT_Outline_ +{ + int n_contours; /* number of contours in glyph */ + int n_points; /* number of points in the glyph */ + + PVG_FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + int* contours; /* the contour end points */ + char* contours_flag; /* the contour open flags */ + + int flags; /* outline masks */ + +} PVG_FT_Outline; + + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_OUTLINE_FLAGS */ +/* */ +/* */ +/* A list of bit-field constants use for the flags in an outline's */ +/* `flags' field. */ +/* */ +/* */ +/* PVG_FT_OUTLINE_NONE :: */ +/* Value~0 is reserved. */ +/* */ +/* PVG_FT_OUTLINE_OWNER :: */ +/* If set, this flag indicates that the outline's field arrays */ +/* (i.e., `points', `flags', and `contours') are `owned' by the */ +/* outline object, and should thus be freed when it is destroyed. */ +/* */ +/* PVG_FT_OUTLINE_EVEN_ODD_FILL :: */ +/* By default, outlines are filled using the non-zero winding rule. */ +/* If set to 1, the outline will be filled using the even-odd fill */ +/* rule (only works with the smooth rasterizer). */ +/* */ +/* PVG_FT_OUTLINE_REVERSE_FILL :: */ +/* By default, outside contours of an outline are oriented in */ +/* clock-wise direction, as defined in the TrueType specification. */ +/* This flag is set if the outline uses the opposite direction */ +/* (typically for Type~1 fonts). This flag is ignored by the scan */ +/* converter. */ +/* */ +/* */ +/* */ +/* There exists a second mechanism to pass the drop-out mode to the */ +/* B/W rasterizer; see the `tags' field in @PVG_FT_Outline. */ +/* */ +/* Please refer to the description of the `SCANTYPE' instruction in */ +/* the OpenType specification (in file `ttinst1.doc') how simple */ +/* drop-outs, smart drop-outs, and stubs are defined. */ +/* */ +#define PVG_FT_OUTLINE_NONE 0x0 +#define PVG_FT_OUTLINE_OWNER 0x1 +#define PVG_FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define PVG_FT_OUTLINE_REVERSE_FILL 0x4 + +/* */ + +#define PVG_FT_CURVE_TAG( flag ) ( flag & 3 ) + +#define PVG_FT_CURVE_TAG_ON 1 +#define PVG_FT_CURVE_TAG_CONIC 0 +#define PVG_FT_CURVE_TAG_CUBIC 2 + + +#define PVG_FT_Curve_Tag_On PVG_FT_CURVE_TAG_ON +#define PVG_FT_Curve_Tag_Conic PVG_FT_CURVE_TAG_CONIC +#define PVG_FT_Curve_Tag_Cubic PVG_FT_CURVE_TAG_CUBIC + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_Outline_Check */ +/* */ +/* */ +/* Check the contents of an outline descriptor. */ +/* */ +/* */ +/* outline :: A handle to a source outline. */ +/* */ +/* */ +/* FreeType error code. 0~means success. */ +/* */ +PVG_FT_Error +PVG_FT_Outline_Check( PVG_FT_Outline* outline ); + + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_Outline_Get_CBox */ +/* */ +/* */ +/* Return an outline's `control box'. The control box encloses all */ +/* the outline's points, including Bézier control points. Though it */ +/* coincides with the exact bounding box for most glyphs, it can be */ +/* slightly larger in some situations (like when rotating an outline */ +/* that contains Bézier outside arcs). */ +/* */ +/* Computing the control box is very fast, while getting the bounding */ +/* box can take much more time as it needs to walk over all segments */ +/* and arcs in the outline. To get the latter, you can use the */ +/* `ftbbox' component, which is dedicated to this single task. */ +/* */ +/* */ +/* outline :: A pointer to the source outline descriptor. */ +/* */ +/* */ +/* acbox :: The outline's control box. */ +/* */ +/* */ +/* See @PVG_FT_Glyph_Get_CBox for a discussion of tricky fonts. */ +/* */ +void +PVG_FT_Outline_Get_CBox( const PVG_FT_Outline* outline, + PVG_FT_BBox *acbox ); + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_Span */ +/* */ +/* */ +/* A structure used to model a single span of gray (or black) pixels */ +/* when rendering a monochrome or anti-aliased bitmap. */ +/* */ +/* */ +/* x :: The span's horizontal start position. */ +/* */ +/* len :: The span's length in pixels. */ +/* */ +/* coverage :: The span color/coverage, ranging from 0 (background) */ +/* to 255 (foreground). Only used for anti-aliased */ +/* rendering. */ +/* */ +/* */ +/* This structure is used by the span drawing callback type named */ +/* @PVG_FT_SpanFunc that takes the y~coordinate of the span as a */ +/* parameter. */ +/* */ +/* The coverage value is always between 0 and 255. If you want less */ +/* gray values, the callback function has to reduce them. */ +/* */ +typedef struct PVG_FT_Span_ +{ + int x; + int len; + int y; + unsigned char coverage; + +} PVG_FT_Span; + + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_SpanFunc */ +/* */ +/* */ +/* A function used as a call-back by the anti-aliased renderer in */ +/* order to let client applications draw themselves the gray pixel */ +/* spans on each scan line. */ +/* */ +/* */ +/* y :: The scanline's y~coordinate. */ +/* */ +/* count :: The number of spans to draw on this scanline. */ +/* */ +/* spans :: A table of `count' spans to draw on the scanline. */ +/* */ +/* user :: User-supplied data that is passed to the callback. */ +/* */ +/* */ +/* This callback allows client applications to directly render the */ +/* gray spans of the anti-aliased bitmap to any kind of surfaces. */ +/* */ +/* This can be used to write anti-aliased outlines directly to a */ +/* given background bitmap, and even perform translucency. */ +/* */ +/* Note that the `count' field cannot be greater than a fixed value */ +/* defined by the `PVG_FT_MAX_GRAY_SPANS' configuration macro in */ +/* `ftoption.h'. By default, this value is set to~32, which means */ +/* that if there are more than 32~spans on a given scanline, the */ +/* callback is called several times with the same `y' parameter in */ +/* order to draw all callbacks. */ +/* */ +/* Otherwise, the callback is only called once per scan-line, and */ +/* only for those scanlines that do have `gray' pixels on them. */ +/* */ +typedef void + (*PVG_FT_SpanFunc)( int count, + const PVG_FT_Span* spans, + void* user ); + +#define PVG_FT_Raster_Span_Func PVG_FT_SpanFunc + + + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_RASTER_FLAG_XXX */ +/* */ +/* */ +/* A list of bit flag constants as used in the `flags' field of a */ +/* @PVG_FT_Raster_Params structure. */ +/* */ +/* */ +/* PVG_FT_RASTER_FLAG_DEFAULT :: This value is 0. */ +/* */ +/* PVG_FT_RASTER_FLAG_AA :: This flag is set to indicate that an */ +/* anti-aliased glyph image should be */ +/* generated. Otherwise, it will be */ +/* monochrome (1-bit). */ +/* */ +/* PVG_FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */ +/* rendering. In this mode, client */ +/* applications must provide their own span */ +/* callback. This lets them directly */ +/* draw or compose over an existing bitmap. */ +/* If this bit is not set, the target */ +/* pixmap's buffer _must_ be zeroed before */ +/* rendering. */ +/* */ +/* Note that for now, direct rendering is */ +/* only possible with anti-aliased glyphs. */ +/* */ +/* PVG_FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ +/* rendering mode. If set, the output will */ +/* be clipped to a box specified in the */ +/* `clip_box' field of the */ +/* @PVG_FT_Raster_Params structure. */ +/* */ +/* Note that by default, the glyph bitmap */ +/* is clipped to the target pixmap, except */ +/* in direct rendering mode where all spans */ +/* are generated if no clipping box is set. */ +/* */ +#define PVG_FT_RASTER_FLAG_DEFAULT 0x0 +#define PVG_FT_RASTER_FLAG_AA 0x1 +#define PVG_FT_RASTER_FLAG_DIRECT 0x2 +#define PVG_FT_RASTER_FLAG_CLIP 0x4 + + +/*************************************************************************/ +/* */ +/* */ +/* PVG_FT_Raster_Params */ +/* */ +/* */ +/* A structure to hold the arguments used by a raster's render */ +/* function. */ +/* */ +/* */ +/* target :: The target bitmap. */ +/* */ +/* source :: A pointer to the source glyph image (e.g., an */ +/* @PVG_FT_Outline). */ +/* */ +/* flags :: The rendering flags. */ +/* */ +/* gray_spans :: The gray span drawing callback. */ +/* */ +/* black_spans :: The black span drawing callback. UNIMPLEMENTED! */ +/* */ +/* bit_test :: The bit test callback. UNIMPLEMENTED! */ +/* */ +/* bit_set :: The bit set callback. UNIMPLEMENTED! */ +/* */ +/* user :: User-supplied data that is passed to each drawing */ +/* callback. */ +/* */ +/* clip_box :: An optional clipping box. It is only used in */ +/* direct rendering mode. Note that coordinates here */ +/* should be expressed in _integer_ pixels (and not in */ +/* 26.6 fixed-point units). */ +/* */ +/* */ +/* An anti-aliased glyph bitmap is drawn if the @PVG_FT_RASTER_FLAG_AA */ +/* bit flag is set in the `flags' field, otherwise a monochrome */ +/* bitmap is generated. */ +/* */ +/* If the @PVG_FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ +/* raster will call the `gray_spans' callback to draw gray pixel */ +/* spans, in the case of an aa glyph bitmap, it will call */ +/* `black_spans', and `bit_test' and `bit_set' in the case of a */ +/* monochrome bitmap. This allows direct composition over a */ +/* pre-existing bitmap through user-provided callbacks to perform the */ +/* span drawing/composition. */ +/* */ +/* Note that the `bit_test' and `bit_set' callbacks are required when */ +/* rendering a monochrome bitmap, as they are crucial to implement */ +/* correct drop-out control as defined in the TrueType specification. */ +/* */ +typedef struct PVG_FT_Raster_Params_ +{ + const void* source; + int flags; + PVG_FT_SpanFunc gray_spans; + void* user; + PVG_FT_BBox clip_box; + +} PVG_FT_Raster_Params; + + +void +PVG_FT_Raster_Render(const PVG_FT_Raster_Params *params); + +#endif // PLUTOVG_FT_RASTER_H diff --git a/3rdparty/software/sw_ft_stroker.c b/3rdparty/plutovg/plutovg-ft-stroker.c similarity index 57% rename from 3rdparty/software/sw_ft_stroker.c rename to 3rdparty/plutovg/plutovg-ft-stroker.c index 89ec12296..207c15d39 100644 --- a/3rdparty/software/sw_ft_stroker.c +++ b/3rdparty/plutovg/plutovg-ft-stroker.c @@ -16,11 +16,12 @@ /* */ /***************************************************************************/ -#include "sw_ft_stroker.h" +#include "plutovg-ft-stroker.h" +#include "plutovg-ft-math.h" + #include #include #include -#include "sw_ft_math.h" /*************************************************************************/ /*************************************************************************/ @@ -30,21 +31,21 @@ /*************************************************************************/ /*************************************************************************/ -#define SW_FT_SMALL_CONIC_THRESHOLD (SW_FT_ANGLE_PI / 6) -#define SW_FT_SMALL_CUBIC_THRESHOLD (SW_FT_ANGLE_PI / 8) +#define PVG_FT_SMALL_CONIC_THRESHOLD (PVG_FT_ANGLE_PI / 6) +#define PVG_FT_SMALL_CUBIC_THRESHOLD (PVG_FT_ANGLE_PI / 8) -#define SW_FT_EPSILON 2 +#define PVG_FT_EPSILON 2 -#define SW_FT_IS_SMALL(x) ((x) > -SW_FT_EPSILON && (x) < SW_FT_EPSILON) +#define PVG_FT_IS_SMALL(x) ((x) > -PVG_FT_EPSILON && (x) < PVG_FT_EPSILON) -static SW_FT_Pos ft_pos_abs(SW_FT_Pos x) +static PVG_FT_Pos ft_pos_abs(PVG_FT_Pos x) { return x >= 0 ? x : -x; } -static void ft_conic_split(SW_FT_Vector* base) +static void ft_conic_split(PVG_FT_Vector* base) { - SW_FT_Pos a, b; + PVG_FT_Pos a, b; base[4].x = base[2].x; a = base[0].x + base[1].x; @@ -61,47 +62,47 @@ static void ft_conic_split(SW_FT_Vector* base) base[1].y = a >> 1; } -static SW_FT_Bool ft_conic_is_small_enough(SW_FT_Vector* base, - SW_FT_Angle* angle_in, - SW_FT_Angle* angle_out) +static PVG_FT_Bool ft_conic_is_small_enough(PVG_FT_Vector* base, + PVG_FT_Angle* angle_in, + PVG_FT_Angle* angle_out) { - SW_FT_Vector d1, d2; - SW_FT_Angle theta; - SW_FT_Int close1, close2; + PVG_FT_Vector d1, d2; + PVG_FT_Angle theta; + PVG_FT_Int close1, close2; d1.x = base[1].x - base[2].x; d1.y = base[1].y - base[2].y; d2.x = base[0].x - base[1].x; d2.y = base[0].y - base[1].y; - close1 = SW_FT_IS_SMALL(d1.x) && SW_FT_IS_SMALL(d1.y); - close2 = SW_FT_IS_SMALL(d2.x) && SW_FT_IS_SMALL(d2.y); + close1 = PVG_FT_IS_SMALL(d1.x) && PVG_FT_IS_SMALL(d1.y); + close2 = PVG_FT_IS_SMALL(d2.x) && PVG_FT_IS_SMALL(d2.y); if (close1) { if (close2) { /* basically a point; */ /* do nothing to retain original direction */ } else { - *angle_in = *angle_out = SW_FT_Atan2(d2.x, d2.y); + *angle_in = *angle_out = PVG_FT_Atan2(d2.x, d2.y); } } else /* !close1 */ { if (close2) { - *angle_in = *angle_out = SW_FT_Atan2(d1.x, d1.y); + *angle_in = *angle_out = PVG_FT_Atan2(d1.x, d1.y); } else { - *angle_in = SW_FT_Atan2(d1.x, d1.y); - *angle_out = SW_FT_Atan2(d2.x, d2.y); + *angle_in = PVG_FT_Atan2(d1.x, d1.y); + *angle_out = PVG_FT_Atan2(d2.x, d2.y); } } - theta = ft_pos_abs(SW_FT_Angle_Diff(*angle_in, *angle_out)); + theta = ft_pos_abs(PVG_FT_Angle_Diff(*angle_in, *angle_out)); - return SW_FT_BOOL(theta < SW_FT_SMALL_CONIC_THRESHOLD); + return PVG_FT_BOOL(theta < PVG_FT_SMALL_CONIC_THRESHOLD); } -static void ft_cubic_split(SW_FT_Vector* base) +static void ft_cubic_split(PVG_FT_Vector* base) { - SW_FT_Pos a, b, c; + PVG_FT_Pos a, b, c; base[6].x = base[3].x; a = base[0].x + base[1].x; @@ -131,19 +132,19 @@ static void ft_cubic_split(SW_FT_Vector* base) /* Return the average of `angle1' and `angle2'. */ /* This gives correct result even if `angle1' and `angle2' */ /* have opposite signs. */ -static SW_FT_Angle ft_angle_mean(SW_FT_Angle angle1, SW_FT_Angle angle2) +static PVG_FT_Angle ft_angle_mean(PVG_FT_Angle angle1, PVG_FT_Angle angle2) { - return angle1 + SW_FT_Angle_Diff(angle1, angle2) / 2; + return angle1 + PVG_FT_Angle_Diff(angle1, angle2) / 2; } -static SW_FT_Bool ft_cubic_is_small_enough(SW_FT_Vector* base, - SW_FT_Angle* angle_in, - SW_FT_Angle* angle_mid, - SW_FT_Angle* angle_out) +static PVG_FT_Bool ft_cubic_is_small_enough(PVG_FT_Vector* base, + PVG_FT_Angle* angle_in, + PVG_FT_Angle* angle_mid, + PVG_FT_Angle* angle_out) { - SW_FT_Vector d1, d2, d3; - SW_FT_Angle theta1, theta2; - SW_FT_Int close1, close2, close3; + PVG_FT_Vector d1, d2, d3; + PVG_FT_Angle theta1, theta2; + PVG_FT_Int close1, close2, close3; d1.x = base[2].x - base[3].x; d1.y = base[2].y - base[3].y; @@ -152,9 +153,9 @@ static SW_FT_Bool ft_cubic_is_small_enough(SW_FT_Vector* base, d3.x = base[0].x - base[1].x; d3.y = base[0].y - base[1].y; - close1 = SW_FT_IS_SMALL(d1.x) && SW_FT_IS_SMALL(d1.y); - close2 = SW_FT_IS_SMALL(d2.x) && SW_FT_IS_SMALL(d2.y); - close3 = SW_FT_IS_SMALL(d3.x) && SW_FT_IS_SMALL(d3.y); + close1 = PVG_FT_IS_SMALL(d1.x) && PVG_FT_IS_SMALL(d1.y); + close2 = PVG_FT_IS_SMALL(d2.x) && PVG_FT_IS_SMALL(d2.y); + close3 = PVG_FT_IS_SMALL(d3.x) && PVG_FT_IS_SMALL(d3.y); if (close1) { if (close2) { @@ -163,48 +164,48 @@ static SW_FT_Bool ft_cubic_is_small_enough(SW_FT_Vector* base, /* do nothing to retain original direction */ } else /* !close3 */ { - *angle_in = *angle_mid = *angle_out = SW_FT_Atan2(d3.x, d3.y); + *angle_in = *angle_mid = *angle_out = PVG_FT_Atan2(d3.x, d3.y); } } else /* !close2 */ { if (close3) { - *angle_in = *angle_mid = *angle_out = SW_FT_Atan2(d2.x, d2.y); + *angle_in = *angle_mid = *angle_out = PVG_FT_Atan2(d2.x, d2.y); } else /* !close3 */ { - *angle_in = *angle_mid = SW_FT_Atan2(d2.x, d2.y); - *angle_out = SW_FT_Atan2(d3.x, d3.y); + *angle_in = *angle_mid = PVG_FT_Atan2(d2.x, d2.y); + *angle_out = PVG_FT_Atan2(d3.x, d3.y); } } } else /* !close1 */ { if (close2) { if (close3) { - *angle_in = *angle_mid = *angle_out = SW_FT_Atan2(d1.x, d1.y); + *angle_in = *angle_mid = *angle_out = PVG_FT_Atan2(d1.x, d1.y); } else /* !close3 */ { - *angle_in = SW_FT_Atan2(d1.x, d1.y); - *angle_out = SW_FT_Atan2(d3.x, d3.y); + *angle_in = PVG_FT_Atan2(d1.x, d1.y); + *angle_out = PVG_FT_Atan2(d3.x, d3.y); *angle_mid = ft_angle_mean(*angle_in, *angle_out); } } else /* !close2 */ { if (close3) { - *angle_in = SW_FT_Atan2(d1.x, d1.y); - *angle_mid = *angle_out = SW_FT_Atan2(d2.x, d2.y); + *angle_in = PVG_FT_Atan2(d1.x, d1.y); + *angle_mid = *angle_out = PVG_FT_Atan2(d2.x, d2.y); } else /* !close3 */ { - *angle_in = SW_FT_Atan2(d1.x, d1.y); - *angle_mid = SW_FT_Atan2(d2.x, d2.y); - *angle_out = SW_FT_Atan2(d3.x, d3.y); + *angle_in = PVG_FT_Atan2(d1.x, d1.y); + *angle_mid = PVG_FT_Atan2(d2.x, d2.y); + *angle_out = PVG_FT_Atan2(d3.x, d3.y); } } } - theta1 = ft_pos_abs(SW_FT_Angle_Diff(*angle_in, *angle_mid)); - theta2 = ft_pos_abs(SW_FT_Angle_Diff(*angle_mid, *angle_out)); + theta1 = ft_pos_abs(PVG_FT_Angle_Diff(*angle_in, *angle_mid)); + theta2 = ft_pos_abs(PVG_FT_Angle_Diff(*angle_mid, *angle_out)); - return SW_FT_BOOL(theta1 < SW_FT_SMALL_CUBIC_THRESHOLD && - theta2 < SW_FT_SMALL_CUBIC_THRESHOLD); + return PVG_FT_BOOL(theta1 < PVG_FT_SMALL_CUBIC_THRESHOLD && + theta2 < PVG_FT_SMALL_CUBIC_THRESHOLD); } /*************************************************************************/ @@ -215,35 +216,35 @@ static SW_FT_Bool ft_cubic_is_small_enough(SW_FT_Vector* base, /*************************************************************************/ /*************************************************************************/ -typedef enum SW_FT_StrokeTags_ { - SW_FT_STROKE_TAG_ON = 1, /* on-curve point */ - SW_FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ - SW_FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ - SW_FT_STROKE_TAG_END = 8 /* sub-path end */ +typedef enum PVG_FT_StrokeTags_ { + PVG_FT_STROKE_TAG_ON = 1, /* on-curve point */ + PVG_FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ + PVG_FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ + PVG_FT_STROKE_TAG_END = 8 /* sub-path end */ -} SW_FT_StrokeTags; +} PVG_FT_StrokeTags; -#define SW_FT_STROKE_TAG_BEGIN_END \ - (SW_FT_STROKE_TAG_BEGIN | SW_FT_STROKE_TAG_END) +#define PVG_FT_STROKE_TAG_BEGIN_END \ + (PVG_FT_STROKE_TAG_BEGIN | PVG_FT_STROKE_TAG_END) -typedef struct SW_FT_StrokeBorderRec_ { - SW_FT_UInt num_points; - SW_FT_UInt max_points; - SW_FT_Vector* points; - SW_FT_Byte* tags; - SW_FT_Bool movable; /* TRUE for ends of lineto borders */ - SW_FT_Int start; /* index of current sub-path start point */ - SW_FT_Bool valid; +typedef struct PVG_FT_StrokeBorderRec_ { + PVG_FT_UInt num_points; + PVG_FT_UInt max_points; + PVG_FT_Vector* points; + PVG_FT_Byte* tags; + PVG_FT_Bool movable; /* TRUE for ends of lineto borders */ + PVG_FT_Int start; /* index of current sub-path start point */ + PVG_FT_Bool valid; -} SW_FT_StrokeBorderRec, *SW_FT_StrokeBorder; +} PVG_FT_StrokeBorderRec, *PVG_FT_StrokeBorder; -SW_FT_Error SW_FT_Outline_Check(SW_FT_Outline* outline) +PVG_FT_Error PVG_FT_Outline_Check(PVG_FT_Outline* outline) { if (outline) { - SW_FT_Int n_points = outline->n_points; - SW_FT_Int n_contours = outline->n_contours; - SW_FT_Int end0, end; - SW_FT_Int n; + PVG_FT_Int n_points = outline->n_points; + PVG_FT_Int n_contours = outline->n_contours; + PVG_FT_Int end0, end; + PVG_FT_Int n; /* empty glyph? */ if (n_points == 0 && n_contours == 0) return 0; @@ -268,12 +269,12 @@ SW_FT_Error SW_FT_Outline_Check(SW_FT_Outline* outline) } Bad: - return -1; // SW_FT_THROW( Invalid_Argument ); + return -1; // PVG_FT_THROW( Invalid_Argument ); } -void SW_FT_Outline_Get_CBox(const SW_FT_Outline* outline, SW_FT_BBox* acbox) +void PVG_FT_Outline_Get_CBox(const PVG_FT_Outline* outline, PVG_FT_BBox* acbox) { - SW_FT_Pos xMin, yMin, xMax, yMax; + PVG_FT_Pos xMin, yMin, xMax, yMax; if (outline && acbox) { if (outline->n_points == 0) { @@ -282,15 +283,15 @@ void SW_FT_Outline_Get_CBox(const SW_FT_Outline* outline, SW_FT_BBox* acbox) xMax = 0; yMax = 0; } else { - SW_FT_Vector* vec = outline->points; - SW_FT_Vector* limit = vec + outline->n_points; + PVG_FT_Vector* vec = outline->points; + PVG_FT_Vector* limit = vec + outline->n_points; xMin = xMax = vec->x; yMin = yMax = vec->y; vec++; for (; vec < limit; vec++) { - SW_FT_Pos x, y; + PVG_FT_Pos x, y; x = vec->x; if (x < xMin) xMin = x; @@ -308,22 +309,22 @@ void SW_FT_Outline_Get_CBox(const SW_FT_Outline* outline, SW_FT_BBox* acbox) } } -static SW_FT_Error ft_stroke_border_grow(SW_FT_StrokeBorder border, - SW_FT_UInt new_points) +static PVG_FT_Error ft_stroke_border_grow(PVG_FT_StrokeBorder border, + PVG_FT_UInt new_points) { - SW_FT_UInt old_max = border->max_points; - SW_FT_UInt new_max = border->num_points + new_points; - SW_FT_Error error = 0; + PVG_FT_UInt old_max = border->max_points; + PVG_FT_UInt new_max = border->num_points + new_points; + PVG_FT_Error error = 0; if (new_max > old_max) { - SW_FT_UInt cur_max = old_max; + PVG_FT_UInt cur_max = old_max; while (cur_max < new_max) cur_max += (cur_max >> 1) + 16; - border->points = (SW_FT_Vector*)realloc(border->points, - cur_max * sizeof(SW_FT_Vector)); + border->points = (PVG_FT_Vector*)realloc(border->points, + cur_max * sizeof(PVG_FT_Vector)); border->tags = - (SW_FT_Byte*)realloc(border->tags, cur_max * sizeof(SW_FT_Byte)); + (PVG_FT_Byte*)realloc(border->tags, cur_max * sizeof(PVG_FT_Byte)); if (!border->points || !border->tags) goto Exit; @@ -334,11 +335,11 @@ Exit: return error; } -static void ft_stroke_border_close(SW_FT_StrokeBorder border, - SW_FT_Bool reverse) +static void ft_stroke_border_close(PVG_FT_StrokeBorder border, + PVG_FT_Bool reverse) { - SW_FT_UInt start = border->start; - SW_FT_UInt count = border->num_points; + PVG_FT_UInt start = border->start; + PVG_FT_UInt count = border->num_points; assert(border->start >= 0); @@ -350,15 +351,16 @@ static void ft_stroke_border_close(SW_FT_StrokeBorder border, /* it contains the `adjusted' starting coordinates */ border->num_points = --count; border->points[start] = border->points[count]; + border->tags[start] = border->tags[count]; if (reverse) { /* reverse the points */ { - SW_FT_Vector* vec1 = border->points + start + 1; - SW_FT_Vector* vec2 = border->points + count - 1; + PVG_FT_Vector* vec1 = border->points + start + 1; + PVG_FT_Vector* vec2 = border->points + count - 1; for (; vec1 < vec2; vec1++, vec2--) { - SW_FT_Vector tmp; + PVG_FT_Vector tmp; tmp = *vec1; *vec1 = *vec2; @@ -368,11 +370,11 @@ static void ft_stroke_border_close(SW_FT_StrokeBorder border, /* then the tags */ { - SW_FT_Byte* tag1 = border->tags + start + 1; - SW_FT_Byte* tag2 = border->tags + count - 1; + PVG_FT_Byte* tag1 = border->tags + start + 1; + PVG_FT_Byte* tag2 = border->tags + count - 1; for (; tag1 < tag2; tag1++, tag2--) { - SW_FT_Byte tmp; + PVG_FT_Byte tmp; tmp = *tag1; *tag1 = *tag2; @@ -381,18 +383,18 @@ static void ft_stroke_border_close(SW_FT_StrokeBorder border, } } - border->tags[start] |= SW_FT_STROKE_TAG_BEGIN; - border->tags[count - 1] |= SW_FT_STROKE_TAG_END; + border->tags[start] |= PVG_FT_STROKE_TAG_BEGIN; + border->tags[count - 1] |= PVG_FT_STROKE_TAG_END; } border->start = -1; border->movable = FALSE; } -static SW_FT_Error ft_stroke_border_lineto(SW_FT_StrokeBorder border, - SW_FT_Vector* to, SW_FT_Bool movable) +static PVG_FT_Error ft_stroke_border_lineto(PVG_FT_StrokeBorder border, + PVG_FT_Vector* to, PVG_FT_Bool movable) { - SW_FT_Error error = 0; + PVG_FT_Error error = 0; assert(border->start >= 0); @@ -402,18 +404,18 @@ static SW_FT_Error ft_stroke_border_lineto(SW_FT_StrokeBorder border, } else { /* don't add zero-length lineto */ if (border->num_points > 0 && - SW_FT_IS_SMALL(border->points[border->num_points - 1].x - to->x) && - SW_FT_IS_SMALL(border->points[border->num_points - 1].y - to->y)) + PVG_FT_IS_SMALL(border->points[border->num_points - 1].x - to->x) && + PVG_FT_IS_SMALL(border->points[border->num_points - 1].y - to->y)) return error; /* add one point */ error = ft_stroke_border_grow(border, 1); if (!error) { - SW_FT_Vector* vec = border->points + border->num_points; - SW_FT_Byte* tag = border->tags + border->num_points; + PVG_FT_Vector* vec = border->points + border->num_points; + PVG_FT_Byte* tag = border->tags + border->num_points; vec[0] = *to; - tag[0] = SW_FT_STROKE_TAG_ON; + tag[0] = PVG_FT_STROKE_TAG_ON; border->num_points += 1; } @@ -422,24 +424,24 @@ static SW_FT_Error ft_stroke_border_lineto(SW_FT_StrokeBorder border, return error; } -static SW_FT_Error ft_stroke_border_conicto(SW_FT_StrokeBorder border, - SW_FT_Vector* control, - SW_FT_Vector* to) +static PVG_FT_Error ft_stroke_border_conicto(PVG_FT_StrokeBorder border, + PVG_FT_Vector* control, + PVG_FT_Vector* to) { - SW_FT_Error error; + PVG_FT_Error error; assert(border->start >= 0); error = ft_stroke_border_grow(border, 2); if (!error) { - SW_FT_Vector* vec = border->points + border->num_points; - SW_FT_Byte* tag = border->tags + border->num_points; + PVG_FT_Vector* vec = border->points + border->num_points; + PVG_FT_Byte* tag = border->tags + border->num_points; vec[0] = *control; vec[1] = *to; tag[0] = 0; - tag[1] = SW_FT_STROKE_TAG_ON; + tag[1] = PVG_FT_STROKE_TAG_ON; border->num_points += 2; } @@ -449,27 +451,27 @@ static SW_FT_Error ft_stroke_border_conicto(SW_FT_StrokeBorder border, return error; } -static SW_FT_Error ft_stroke_border_cubicto(SW_FT_StrokeBorder border, - SW_FT_Vector* control1, - SW_FT_Vector* control2, - SW_FT_Vector* to) +static PVG_FT_Error ft_stroke_border_cubicto(PVG_FT_StrokeBorder border, + PVG_FT_Vector* control1, + PVG_FT_Vector* control2, + PVG_FT_Vector* to) { - SW_FT_Error error; + PVG_FT_Error error; assert(border->start >= 0); error = ft_stroke_border_grow(border, 3); if (!error) { - SW_FT_Vector* vec = border->points + border->num_points; - SW_FT_Byte* tag = border->tags + border->num_points; + PVG_FT_Vector* vec = border->points + border->num_points; + PVG_FT_Byte* tag = border->tags + border->num_points; vec[0] = *control1; vec[1] = *control2; vec[2] = *to; - tag[0] = SW_FT_STROKE_TAG_CUBIC; - tag[1] = SW_FT_STROKE_TAG_CUBIC; - tag[2] = SW_FT_STROKE_TAG_ON; + tag[0] = PVG_FT_STROKE_TAG_CUBIC; + tag[1] = PVG_FT_STROKE_TAG_CUBIC; + tag[2] = PVG_FT_STROKE_TAG_ON; border->num_points += 3; } @@ -479,35 +481,35 @@ static SW_FT_Error ft_stroke_border_cubicto(SW_FT_StrokeBorder border, return error; } -#define SW_FT_ARC_CUBIC_ANGLE (SW_FT_ANGLE_PI / 2) +#define PVG_FT_ARC_CUBIC_ANGLE (PVG_FT_ANGLE_PI / 2) -static SW_FT_Error -ft_stroke_border_arcto( SW_FT_StrokeBorder border, - SW_FT_Vector* center, - SW_FT_Fixed radius, - SW_FT_Angle angle_start, - SW_FT_Angle angle_diff ) +static PVG_FT_Error +ft_stroke_border_arcto( PVG_FT_StrokeBorder border, + PVG_FT_Vector* center, + PVG_FT_Fixed radius, + PVG_FT_Angle angle_start, + PVG_FT_Angle angle_diff ) { - SW_FT_Fixed coef; - SW_FT_Vector a0, a1, a2, a3; - SW_FT_Int i, arcs = 1; - SW_FT_Error error = 0; + PVG_FT_Fixed coef; + PVG_FT_Vector a0, a1, a2, a3; + PVG_FT_Int i, arcs = 1; + PVG_FT_Error error = 0; /* number of cubic arcs to draw */ - while ( angle_diff > SW_FT_ARC_CUBIC_ANGLE * arcs || - -angle_diff > SW_FT_ARC_CUBIC_ANGLE * arcs ) + while ( angle_diff > PVG_FT_ARC_CUBIC_ANGLE * arcs || + -angle_diff > PVG_FT_ARC_CUBIC_ANGLE * arcs ) arcs++; /* control tangents */ - coef = SW_FT_Tan( angle_diff / ( 4 * arcs ) ); + coef = PVG_FT_Tan( angle_diff / ( 4 * arcs ) ); coef += coef / 3; /* compute start and first control point */ - SW_FT_Vector_From_Polar( &a0, radius, angle_start ); - a1.x = SW_FT_MulFix( -a0.y, coef ); - a1.y = SW_FT_MulFix( a0.x, coef ); + PVG_FT_Vector_From_Polar( &a0, radius, angle_start ); + a1.x = PVG_FT_MulFix( -a0.y, coef ); + a1.y = PVG_FT_MulFix( a0.x, coef ); a0.x += center->x; a0.y += center->y; @@ -517,10 +519,10 @@ ft_stroke_border_arcto( SW_FT_StrokeBorder border, for ( i = 1; i <= arcs; i++ ) { /* compute end and second control point */ - SW_FT_Vector_From_Polar( &a3, radius, + PVG_FT_Vector_From_Polar( &a3, radius, angle_start + i * angle_diff / arcs ); - a2.x = SW_FT_MulFix( a3.y, coef ); - a2.y = SW_FT_MulFix( -a3.x, coef ); + a2.x = PVG_FT_MulFix( a3.y, coef ); + a2.y = PVG_FT_MulFix( -a3.x, coef ); a3.x += center->x; a3.y += center->y; @@ -540,8 +542,8 @@ ft_stroke_border_arcto( SW_FT_StrokeBorder border, return error; } -static SW_FT_Error ft_stroke_border_moveto(SW_FT_StrokeBorder border, - SW_FT_Vector* to) +static PVG_FT_Error ft_stroke_border_moveto(PVG_FT_StrokeBorder border, + PVG_FT_Vector* to) { /* close current open path if any ? */ if (border->start >= 0) ft_stroke_border_close(border, FALSE); @@ -552,7 +554,7 @@ static SW_FT_Error ft_stroke_border_moveto(SW_FT_StrokeBorder border, return ft_stroke_border_lineto(border, to, FALSE); } -static void ft_stroke_border_init(SW_FT_StrokeBorder border) +static void ft_stroke_border_init(PVG_FT_StrokeBorder border) { border->points = NULL; border->tags = NULL; @@ -563,14 +565,14 @@ static void ft_stroke_border_init(SW_FT_StrokeBorder border) border->valid = FALSE; } -static void ft_stroke_border_reset(SW_FT_StrokeBorder border) +static void ft_stroke_border_reset(PVG_FT_StrokeBorder border) { border->num_points = 0; border->start = -1; border->valid = FALSE; } -static void ft_stroke_border_done(SW_FT_StrokeBorder border) +static void ft_stroke_border_done(PVG_FT_StrokeBorder border) { free(border->points); free(border->tags); @@ -581,28 +583,28 @@ static void ft_stroke_border_done(SW_FT_StrokeBorder border) border->valid = FALSE; } -static SW_FT_Error ft_stroke_border_get_counts(SW_FT_StrokeBorder border, - SW_FT_UInt* anum_points, - SW_FT_UInt* anum_contours) +static PVG_FT_Error ft_stroke_border_get_counts(PVG_FT_StrokeBorder border, + PVG_FT_UInt* anum_points, + PVG_FT_UInt* anum_contours) { - SW_FT_Error error = 0; - SW_FT_UInt num_points = 0; - SW_FT_UInt num_contours = 0; + PVG_FT_Error error = 0; + PVG_FT_UInt num_points = 0; + PVG_FT_UInt num_contours = 0; - SW_FT_UInt count = border->num_points; - SW_FT_Vector* point = border->points; - SW_FT_Byte* tags = border->tags; - SW_FT_Int in_contour = 0; + PVG_FT_UInt count = border->num_points; + PVG_FT_Vector* point = border->points; + PVG_FT_Byte* tags = border->tags; + PVG_FT_Int in_contour = 0; for (; count > 0; count--, num_points++, point++, tags++) { - if (tags[0] & SW_FT_STROKE_TAG_BEGIN) { + if (tags[0] & PVG_FT_STROKE_TAG_BEGIN) { if (in_contour != 0) goto Fail; in_contour = 1; } else if (in_contour == 0) goto Fail; - if (tags[0] & SW_FT_STROKE_TAG_END) { + if (tags[0] & PVG_FT_STROKE_TAG_END) { in_contour = 0; num_contours++; } @@ -623,38 +625,38 @@ Fail: goto Exit; } -static void ft_stroke_border_export(SW_FT_StrokeBorder border, - SW_FT_Outline* outline) +static void ft_stroke_border_export(PVG_FT_StrokeBorder border, + PVG_FT_Outline* outline) { /* copy point locations */ memcpy(outline->points + outline->n_points, border->points, - border->num_points * sizeof(SW_FT_Vector)); + border->num_points * sizeof(PVG_FT_Vector)); /* copy tags */ { - SW_FT_UInt count = border->num_points; - SW_FT_Byte* read = border->tags; - SW_FT_Byte* write = (SW_FT_Byte*)outline->tags + outline->n_points; + PVG_FT_UInt count = border->num_points; + PVG_FT_Byte* read = border->tags; + PVG_FT_Byte* write = (PVG_FT_Byte*)outline->tags + outline->n_points; for (; count > 0; count--, read++, write++) { - if (*read & SW_FT_STROKE_TAG_ON) - *write = SW_FT_CURVE_TAG_ON; - else if (*read & SW_FT_STROKE_TAG_CUBIC) - *write = SW_FT_CURVE_TAG_CUBIC; + if (*read & PVG_FT_STROKE_TAG_ON) + *write = PVG_FT_CURVE_TAG_ON; + else if (*read & PVG_FT_STROKE_TAG_CUBIC) + *write = PVG_FT_CURVE_TAG_CUBIC; else - *write = SW_FT_CURVE_TAG_CONIC; + *write = PVG_FT_CURVE_TAG_CONIC; } } /* copy contours */ { - SW_FT_UInt count = border->num_points; - SW_FT_Byte* tags = border->tags; - SW_FT_Int* write = outline->contours + outline->n_contours; - SW_FT_Int idx = (SW_FT_Int)outline->n_points; + PVG_FT_UInt count = border->num_points; + PVG_FT_Byte* tags = border->tags; + PVG_FT_Int* write = outline->contours + outline->n_contours; + PVG_FT_Int idx = (PVG_FT_Int)outline->n_points; for (; count > 0; count--, tags++, idx++) { - if (*tags & SW_FT_STROKE_TAG_END) { + if (*tags & PVG_FT_STROKE_TAG_END) { *write++ = idx; outline->n_contours++; } @@ -663,7 +665,7 @@ static void ft_stroke_border_export(SW_FT_StrokeBorder border, outline->n_points = (int)(outline->n_points + border->num_points); - assert(SW_FT_Outline_Check(outline) == 0); + assert(PVG_FT_Outline_Check(outline) == 0); } /*************************************************************************/ @@ -674,37 +676,37 @@ static void ft_stroke_border_export(SW_FT_StrokeBorder border, /*************************************************************************/ /*************************************************************************/ -#define SW_FT_SIDE_TO_ROTATE(s) (SW_FT_ANGLE_PI2 - (s)*SW_FT_ANGLE_PI) +#define PVG_FT_SIDE_TO_ROTATE(s) (PVG_FT_ANGLE_PI2 - (s)*PVG_FT_ANGLE_PI) -typedef struct SW_FT_StrokerRec_ { - SW_FT_Angle angle_in; /* direction into curr join */ - SW_FT_Angle angle_out; /* direction out of join */ - SW_FT_Vector center; /* current position */ - SW_FT_Fixed line_length; /* length of last lineto */ - SW_FT_Bool first_point; /* is this the start? */ - SW_FT_Bool subpath_open; /* is the subpath open? */ - SW_FT_Angle subpath_angle; /* subpath start direction */ - SW_FT_Vector subpath_start; /* subpath start position */ - SW_FT_Fixed subpath_line_length; /* subpath start lineto len */ - SW_FT_Bool handle_wide_strokes; /* use wide strokes logic? */ +typedef struct PVG_FT_StrokerRec_ { + PVG_FT_Angle angle_in; /* direction into curr join */ + PVG_FT_Angle angle_out; /* direction out of join */ + PVG_FT_Vector center; /* current position */ + PVG_FT_Fixed line_length; /* length of last lineto */ + PVG_FT_Bool first_point; /* is this the start? */ + PVG_FT_Bool subpath_open; /* is the subpath open? */ + PVG_FT_Angle subpath_angle; /* subpath start direction */ + PVG_FT_Vector subpath_start; /* subpath start position */ + PVG_FT_Fixed subpath_line_length; /* subpath start lineto len */ + PVG_FT_Bool handle_wide_strokes; /* use wide strokes logic? */ - SW_FT_Stroker_LineCap line_cap; - SW_FT_Stroker_LineJoin line_join; - SW_FT_Stroker_LineJoin line_join_saved; - SW_FT_Fixed miter_limit; - SW_FT_Fixed radius; + PVG_FT_Stroker_LineCap line_cap; + PVG_FT_Stroker_LineJoin line_join; + PVG_FT_Stroker_LineJoin line_join_saved; + PVG_FT_Fixed miter_limit; + PVG_FT_Fixed radius; - SW_FT_StrokeBorderRec borders[2]; -} SW_FT_StrokerRec; + PVG_FT_StrokeBorderRec borders[2]; +} PVG_FT_StrokerRec; /* documentation is in ftstroke.h */ -SW_FT_Error SW_FT_Stroker_New(SW_FT_Stroker* astroker) +PVG_FT_Error PVG_FT_Stroker_New(PVG_FT_Stroker* astroker) { - SW_FT_Error error = 0; /* assigned in SW_FT_NEW */ - SW_FT_Stroker stroker = NULL; + PVG_FT_Error error = 0; /* assigned in PVG_FT_NEW */ + PVG_FT_Stroker stroker = NULL; - stroker = (SW_FT_StrokerRec*)calloc(1, sizeof(SW_FT_StrokerRec)); + stroker = (PVG_FT_StrokerRec*)calloc(1, sizeof(PVG_FT_StrokerRec)); if (stroker) { ft_stroke_border_init(&stroker->borders[0]); ft_stroke_border_init(&stroker->borders[1]); @@ -715,7 +717,7 @@ SW_FT_Error SW_FT_Stroker_New(SW_FT_Stroker* astroker) return error; } -void SW_FT_Stroker_Rewind(SW_FT_Stroker stroker) +void PVG_FT_Stroker_Rewind(PVG_FT_Stroker stroker) { if (stroker) { ft_stroke_border_reset(&stroker->borders[0]); @@ -725,10 +727,10 @@ void SW_FT_Stroker_Rewind(SW_FT_Stroker stroker) /* documentation is in ftstroke.h */ -void SW_FT_Stroker_Set(SW_FT_Stroker stroker, SW_FT_Fixed radius, - SW_FT_Stroker_LineCap line_cap, - SW_FT_Stroker_LineJoin line_join, - SW_FT_Fixed miter_limit) +void PVG_FT_Stroker_Set(PVG_FT_Stroker stroker, PVG_FT_Fixed radius, + PVG_FT_Stroker_LineCap line_cap, + PVG_FT_Stroker_LineJoin line_join, + PVG_FT_Fixed miter_limit) { stroker->radius = radius; stroker->line_cap = line_cap; @@ -742,12 +744,12 @@ void SW_FT_Stroker_Set(SW_FT_Stroker stroker, SW_FT_Fixed radius, /* line join style can be temporarily changed when stroking curves */ stroker->line_join_saved = line_join; - SW_FT_Stroker_Rewind(stroker); + PVG_FT_Stroker_Rewind(stroker); } /* documentation is in ftstroke.h */ -void SW_FT_Stroker_Done(SW_FT_Stroker stroker) +void PVG_FT_Stroker_Done(PVG_FT_Stroker stroker) { if (stroker) { ft_stroke_border_done(&stroker->borders[0]); @@ -758,17 +760,17 @@ void SW_FT_Stroker_Done(SW_FT_Stroker stroker) } /* create a circular arc at a corner or cap */ -static SW_FT_Error ft_stroker_arcto(SW_FT_Stroker stroker, SW_FT_Int side) +static PVG_FT_Error ft_stroker_arcto(PVG_FT_Stroker stroker, PVG_FT_Int side) { - SW_FT_Angle total, rotate; - SW_FT_Fixed radius = stroker->radius; - SW_FT_Error error = 0; - SW_FT_StrokeBorder border = stroker->borders + side; + PVG_FT_Angle total, rotate; + PVG_FT_Fixed radius = stroker->radius; + PVG_FT_Error error = 0; + PVG_FT_StrokeBorder border = stroker->borders + side; - rotate = SW_FT_SIDE_TO_ROTATE(side); + rotate = PVG_FT_SIDE_TO_ROTATE(side); - total = SW_FT_Angle_Diff(stroker->angle_in, stroker->angle_out); - if (total == SW_FT_ANGLE_PI) total = -rotate * 2; + total = PVG_FT_Angle_Diff(stroker->angle_in, stroker->angle_out); + if (total == PVG_FT_ANGLE_PI) total = -rotate * 2; error = ft_stroke_border_arcto(border, &stroker->center, radius, stroker->angle_in + rotate, total); @@ -777,39 +779,39 @@ static SW_FT_Error ft_stroker_arcto(SW_FT_Stroker stroker, SW_FT_Int side) } /* add a cap at the end of an opened path */ -static SW_FT_Error -ft_stroker_cap(SW_FT_Stroker stroker, - SW_FT_Angle angle, - SW_FT_Int side) +static PVG_FT_Error +ft_stroker_cap(PVG_FT_Stroker stroker, + PVG_FT_Angle angle, + PVG_FT_Int side) { - SW_FT_Error error = 0; + PVG_FT_Error error = 0; - if (stroker->line_cap == SW_FT_STROKER_LINECAP_ROUND) + if (stroker->line_cap == PVG_FT_STROKER_LINECAP_ROUND) { /* add a round cap */ stroker->angle_in = angle; - stroker->angle_out = angle + SW_FT_ANGLE_PI; + stroker->angle_out = angle + PVG_FT_ANGLE_PI; error = ft_stroker_arcto(stroker, side); } else { /* add a square or butt cap */ - SW_FT_Vector middle, delta; - SW_FT_Fixed radius = stroker->radius; - SW_FT_StrokeBorder border = stroker->borders + side; + PVG_FT_Vector middle, delta; + PVG_FT_Fixed radius = stroker->radius; + PVG_FT_StrokeBorder border = stroker->borders + side; /* compute middle point and first angle point */ - SW_FT_Vector_From_Polar( &middle, radius, angle ); + PVG_FT_Vector_From_Polar( &middle, radius, angle ); delta.x = side ? middle.y : -middle.y; delta.y = side ? -middle.x : middle.x; - if ( stroker->line_cap == SW_FT_STROKER_LINECAP_SQUARE ) + if ( stroker->line_cap == PVG_FT_STROKER_LINECAP_SQUARE ) { middle.x += stroker->center.x; middle.y += stroker->center.y; } - else /* SW_FT_STROKER_LINECAP_BUTT */ + else /* PVG_FT_STROKER_LINECAP_BUTT */ { middle.x = stroker->center.x; middle.y = stroker->center.y; @@ -834,19 +836,20 @@ Exit: } /* process an inside corner, i.e. compute intersection */ -static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, - SW_FT_Fixed line_length) +static PVG_FT_Error ft_stroker_inside(PVG_FT_Stroker stroker, PVG_FT_Int side, + PVG_FT_Fixed line_length) { - SW_FT_StrokeBorder border = stroker->borders + side; - SW_FT_Angle phi, theta, rotate; - SW_FT_Fixed length; - SW_FT_Vector sigma, delta; - SW_FT_Error error = 0; - SW_FT_Bool intersect; /* use intersection of lines? */ + PVG_FT_StrokeBorder border = stroker->borders + side; + PVG_FT_Angle phi, theta, rotate; + PVG_FT_Fixed length; + PVG_FT_Vector sigma = {0, 0}; + PVG_FT_Vector delta; + PVG_FT_Error error = 0; + PVG_FT_Bool intersect; /* use intersection of lines? */ - rotate = SW_FT_SIDE_TO_ROTATE(side); + rotate = PVG_FT_SIDE_TO_ROTATE(side); - theta = SW_FT_Angle_Diff(stroker->angle_in, stroker->angle_out) / 2; + theta = PVG_FT_Angle_Diff(stroker->angle_in, stroker->angle_out) / 2; /* Only intersect borders if between two lineto's and both */ /* lines are long enough (line_length is zero for curves). */ @@ -855,20 +858,20 @@ static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, intersect = FALSE; else { /* compute minimum required length of lines */ - SW_FT_Fixed min_length; + PVG_FT_Fixed min_length; - SW_FT_Vector_Unit( &sigma, theta ); + PVG_FT_Vector_Unit( &sigma, theta ); min_length = - ft_pos_abs( SW_FT_MulDiv( stroker->radius, sigma.y, sigma.x ) ); + ft_pos_abs( PVG_FT_MulDiv( stroker->radius, sigma.y, sigma.x ) ); - intersect = SW_FT_BOOL( min_length && + intersect = PVG_FT_BOOL( min_length && stroker->line_length >= min_length && line_length >= min_length ); } if (!intersect) { - SW_FT_Vector_From_Polar(&delta, stroker->radius, + PVG_FT_Vector_From_Polar(&delta, stroker->radius, stroker->angle_out + rotate); delta.x += stroker->center.x; delta.y += stroker->center.y; @@ -878,9 +881,9 @@ static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, /* compute median angle */ phi = stroker->angle_in + theta + rotate; - length = SW_FT_DivFix( stroker->radius, sigma.x ); + length = PVG_FT_DivFix( stroker->radius, sigma.x ); - SW_FT_Vector_From_Polar( &delta, length, phi ); + PVG_FT_Vector_From_Polar( &delta, length, phi ); delta.x += stroker->center.x; delta.y += stroker->center.y; } @@ -891,46 +894,46 @@ static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, } /* process an outside corner, i.e. compute bevel/miter/round */ -static SW_FT_Error -ft_stroker_outside( SW_FT_Stroker stroker, - SW_FT_Int side, - SW_FT_Fixed line_length ) +static PVG_FT_Error +ft_stroker_outside( PVG_FT_Stroker stroker, + PVG_FT_Int side, + PVG_FT_Fixed line_length ) { - SW_FT_StrokeBorder border = stroker->borders + side; - SW_FT_Error error; - SW_FT_Angle rotate; + PVG_FT_StrokeBorder border = stroker->borders + side; + PVG_FT_Error error; + PVG_FT_Angle rotate; - if ( stroker->line_join == SW_FT_STROKER_LINEJOIN_ROUND ) + if ( stroker->line_join == PVG_FT_STROKER_LINEJOIN_ROUND ) error = ft_stroker_arcto( stroker, side ); else { /* this is a mitered (pointed) or beveled (truncated) corner */ - SW_FT_Fixed radius = stroker->radius; - SW_FT_Vector sigma; - SW_FT_Angle theta = 0, phi = 0; - SW_FT_Bool bevel, fixed_bevel; + PVG_FT_Fixed radius = stroker->radius; + PVG_FT_Vector sigma = {0, 0}; + PVG_FT_Angle theta = 0, phi = 0; + PVG_FT_Bool bevel, fixed_bevel; - rotate = SW_FT_SIDE_TO_ROTATE( side ); + rotate = PVG_FT_SIDE_TO_ROTATE( side ); bevel = - SW_FT_BOOL( stroker->line_join == SW_FT_STROKER_LINEJOIN_BEVEL ); + PVG_FT_BOOL( stroker->line_join == PVG_FT_STROKER_LINEJOIN_BEVEL ); fixed_bevel = - SW_FT_BOOL( stroker->line_join != SW_FT_STROKER_LINEJOIN_MITER_VARIABLE ); + PVG_FT_BOOL( stroker->line_join != PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE ); /* check miter limit first */ if ( !bevel ) { - theta = SW_FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; + theta = PVG_FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; - if ( theta == SW_FT_ANGLE_PI2 ) + if ( theta == PVG_FT_ANGLE_PI2 ) theta = -rotate; phi = stroker->angle_in + theta + rotate; - SW_FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta ); + PVG_FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta ); /* is miter limit exceeded? */ if ( sigma.x < 0x10000L ) @@ -947,11 +950,11 @@ ft_stroker_outside( SW_FT_Stroker stroker, if ( fixed_bevel ) { /* the outer corners are simply joined together */ - SW_FT_Vector delta; + PVG_FT_Vector delta; /* add bevel */ - SW_FT_Vector_From_Polar( &delta, + PVG_FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate ); delta.x += stroker->center.x; @@ -963,18 +966,18 @@ ft_stroker_outside( SW_FT_Stroker stroker, else /* variable bevel or clipped miter */ { /* the miter is truncated */ - SW_FT_Vector middle, delta; - SW_FT_Fixed coef; + PVG_FT_Vector middle, delta; + PVG_FT_Fixed coef; /* compute middle point and first angle point */ - SW_FT_Vector_From_Polar( &middle, - SW_FT_MulFix( radius, stroker->miter_limit ), + PVG_FT_Vector_From_Polar( &middle, + PVG_FT_MulFix( radius, stroker->miter_limit ), phi ); - coef = SW_FT_DivFix( 0x10000L - sigma.x, sigma.y ); - delta.x = SW_FT_MulFix( middle.y, coef ); - delta.y = SW_FT_MulFix( -middle.x, coef ); + coef = PVG_FT_DivFix( 0x10000L - sigma.x, sigma.y ); + delta.x = PVG_FT_MulFix( middle.y, coef ); + delta.y = PVG_FT_MulFix( -middle.x, coef ); middle.x += stroker->center.x; middle.y += stroker->center.y; @@ -997,7 +1000,7 @@ ft_stroker_outside( SW_FT_Stroker stroker, /* (line_length is zero for curves) */ if ( line_length == 0 ) { - SW_FT_Vector_From_Polar( &delta, + PVG_FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate ); @@ -1010,13 +1013,13 @@ ft_stroker_outside( SW_FT_Stroker stroker, } else /* this is a miter (intersection) */ { - SW_FT_Fixed length; - SW_FT_Vector delta; + PVG_FT_Fixed length; + PVG_FT_Vector delta; - length = SW_FT_MulDiv( stroker->radius, stroker->miter_limit, sigma.x ); + length = PVG_FT_MulDiv( stroker->radius, stroker->miter_limit, sigma.x ); - SW_FT_Vector_From_Polar( &delta, length, phi ); + PVG_FT_Vector_From_Polar( &delta, length, phi ); delta.x += stroker->center.x; delta.y += stroker->center.y; @@ -1028,7 +1031,7 @@ ft_stroker_outside( SW_FT_Stroker stroker, /* (line_length is zero for curves) */ if ( line_length == 0 ) { - SW_FT_Vector_From_Polar( &delta, + PVG_FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate ); delta.x += stroker->center.x; @@ -1043,14 +1046,14 @@ ft_stroker_outside( SW_FT_Stroker stroker, return error; } -static SW_FT_Error ft_stroker_process_corner(SW_FT_Stroker stroker, - SW_FT_Fixed line_length) +static PVG_FT_Error ft_stroker_process_corner(PVG_FT_Stroker stroker, + PVG_FT_Fixed line_length) { - SW_FT_Error error = 0; - SW_FT_Angle turn; - SW_FT_Int inside_side; + PVG_FT_Error error = 0; + PVG_FT_Angle turn; + PVG_FT_Int inside_side; - turn = SW_FT_Angle_Diff(stroker->angle_in, stroker->angle_out); + turn = PVG_FT_Angle_Diff(stroker->angle_in, stroker->angle_out); /* no specific corner processing is required if the turn is 0 */ if (turn == 0) goto Exit; @@ -1074,17 +1077,17 @@ Exit: /* add two points to the left and right borders corresponding to the */ /* start of the subpath */ -static SW_FT_Error ft_stroker_subpath_start(SW_FT_Stroker stroker, - SW_FT_Angle start_angle, - SW_FT_Fixed line_length) +static PVG_FT_Error ft_stroker_subpath_start(PVG_FT_Stroker stroker, + PVG_FT_Angle start_angle, + PVG_FT_Fixed line_length) { - SW_FT_Vector delta; - SW_FT_Vector point; - SW_FT_Error error; - SW_FT_StrokeBorder border; + PVG_FT_Vector delta; + PVG_FT_Vector point; + PVG_FT_Error error; + PVG_FT_StrokeBorder border; - SW_FT_Vector_From_Polar(&delta, stroker->radius, - start_angle + SW_FT_ANGLE_PI2); + PVG_FT_Vector_From_Polar(&delta, stroker->radius, + start_angle + PVG_FT_ANGLE_PI2); point.x = stroker->center.x + delta.x; point.y = stroker->center.y + delta.y; @@ -1111,14 +1114,14 @@ Exit: /* documentation is in ftstroke.h */ -SW_FT_Error SW_FT_Stroker_LineTo(SW_FT_Stroker stroker, SW_FT_Vector* to) +PVG_FT_Error PVG_FT_Stroker_LineTo(PVG_FT_Stroker stroker, PVG_FT_Vector* to) { - SW_FT_Error error = 0; - SW_FT_StrokeBorder border; - SW_FT_Vector delta; - SW_FT_Angle angle; - SW_FT_Int side; - SW_FT_Fixed line_length; + PVG_FT_Error error = 0; + PVG_FT_StrokeBorder border; + PVG_FT_Vector delta; + PVG_FT_Angle angle; + PVG_FT_Int side; + PVG_FT_Fixed line_length; delta.x = to->x - stroker->center.x; delta.y = to->y - stroker->center.y; @@ -1127,10 +1130,10 @@ SW_FT_Error SW_FT_Stroker_LineTo(SW_FT_Stroker stroker, SW_FT_Vector* to) if (delta.x == 0 && delta.y == 0) goto Exit; /* compute length of line */ - line_length = SW_FT_Vector_Length(&delta); + line_length = PVG_FT_Vector_Length(&delta); - angle = SW_FT_Atan2(delta.x, delta.y); - SW_FT_Vector_From_Polar(&delta, stroker->radius, angle + SW_FT_ANGLE_PI2); + angle = PVG_FT_Atan2(delta.x, delta.y); + PVG_FT_Vector_From_Polar(&delta, stroker->radius, angle + PVG_FT_ANGLE_PI2); /* process corner if necessary */ if (stroker->first_point) { @@ -1148,7 +1151,7 @@ SW_FT_Error SW_FT_Stroker_LineTo(SW_FT_Stroker stroker, SW_FT_Vector* to) /* now add a line segment to both the `inside' and `outside' paths */ for (border = stroker->borders, side = 1; side >= 0; side--, border++) { - SW_FT_Vector point; + PVG_FT_Vector point; point.x = to->x + delta.x; point.y = to->y + delta.y; @@ -1171,21 +1174,21 @@ Exit: /* documentation is in ftstroke.h */ -SW_FT_Error SW_FT_Stroker_ConicTo(SW_FT_Stroker stroker, SW_FT_Vector* control, - SW_FT_Vector* to) +PVG_FT_Error PVG_FT_Stroker_ConicTo(PVG_FT_Stroker stroker, PVG_FT_Vector* control, + PVG_FT_Vector* to) { - SW_FT_Error error = 0; - SW_FT_Vector bez_stack[34]; - SW_FT_Vector* arc; - SW_FT_Vector* limit = bez_stack + 30; - SW_FT_Bool first_arc = TRUE; + PVG_FT_Error error = 0; + PVG_FT_Vector bez_stack[34]; + PVG_FT_Vector* arc; + PVG_FT_Vector* limit = bez_stack + 30; + PVG_FT_Bool first_arc = TRUE; /* if all control points are coincident, this is a no-op; */ /* avoid creating a spurious corner */ - if (SW_FT_IS_SMALL(stroker->center.x - control->x) && - SW_FT_IS_SMALL(stroker->center.y - control->y) && - SW_FT_IS_SMALL(control->x - to->x) && - SW_FT_IS_SMALL(control->y - to->y)) { + if (PVG_FT_IS_SMALL(stroker->center.x - control->x) && + PVG_FT_IS_SMALL(stroker->center.y - control->y) && + PVG_FT_IS_SMALL(control->x - to->x) && + PVG_FT_IS_SMALL(control->y - to->y)) { stroker->center = *to; goto Exit; } @@ -1196,7 +1199,7 @@ SW_FT_Error SW_FT_Stroker_ConicTo(SW_FT_Stroker stroker, SW_FT_Vector* control, arc[2] = stroker->center; while (arc >= bez_stack) { - SW_FT_Angle angle_in, angle_out; + PVG_FT_Angle angle_in, angle_out; /* initialize with current direction */ angle_in = angle_out = stroker->angle_in; @@ -1220,13 +1223,13 @@ SW_FT_Error SW_FT_Stroker_ConicTo(SW_FT_Stroker stroker, SW_FT_Vector* control, stroker->angle_out = angle_in; error = ft_stroker_process_corner(stroker, 0); } - } else if (ft_pos_abs(SW_FT_Angle_Diff(stroker->angle_in, angle_in)) > - SW_FT_SMALL_CONIC_THRESHOLD / 4) { + } else if (ft_pos_abs(PVG_FT_Angle_Diff(stroker->angle_in, angle_in)) > + PVG_FT_SMALL_CONIC_THRESHOLD / 4) { /* if the deviation from one arc to the next is too great, */ /* add a round corner */ stroker->center = arc[2]; stroker->angle_out = angle_in; - stroker->line_join = SW_FT_STROKER_LINEJOIN_ROUND; + stroker->line_join = PVG_FT_STROKER_LINEJOIN_ROUND; error = ft_stroker_process_corner(stroker, 0); @@ -1239,70 +1242,70 @@ SW_FT_Error SW_FT_Stroker_ConicTo(SW_FT_Stroker stroker, SW_FT_Vector* control, /* the arc's angle is small enough; we can add it directly to each */ /* border */ { - SW_FT_Vector ctrl, end; - SW_FT_Angle theta, phi, rotate, alpha0 = 0; - SW_FT_Fixed length; - SW_FT_StrokeBorder border; - SW_FT_Int side; + PVG_FT_Vector ctrl, end; + PVG_FT_Angle theta, phi, rotate, alpha0 = 0; + PVG_FT_Fixed length; + PVG_FT_StrokeBorder border; + PVG_FT_Int side; - theta = SW_FT_Angle_Diff(angle_in, angle_out) / 2; + theta = PVG_FT_Angle_Diff(angle_in, angle_out) / 2; phi = angle_in + theta; - length = SW_FT_DivFix(stroker->radius, SW_FT_Cos(theta)); + length = PVG_FT_DivFix(stroker->radius, PVG_FT_Cos(theta)); /* compute direction of original arc */ if (stroker->handle_wide_strokes) - alpha0 = SW_FT_Atan2(arc[0].x - arc[2].x, arc[0].y - arc[2].y); + alpha0 = PVG_FT_Atan2(arc[0].x - arc[2].x, arc[0].y - arc[2].y); for (border = stroker->borders, side = 0; side <= 1; side++, border++) { - rotate = SW_FT_SIDE_TO_ROTATE(side); + rotate = PVG_FT_SIDE_TO_ROTATE(side); /* compute control point */ - SW_FT_Vector_From_Polar(&ctrl, length, phi + rotate); + PVG_FT_Vector_From_Polar(&ctrl, length, phi + rotate); ctrl.x += arc[1].x; ctrl.y += arc[1].y; /* compute end point */ - SW_FT_Vector_From_Polar(&end, stroker->radius, + PVG_FT_Vector_From_Polar(&end, stroker->radius, angle_out + rotate); end.x += arc[0].x; end.y += arc[0].y; if (stroker->handle_wide_strokes) { - SW_FT_Vector start; - SW_FT_Angle alpha1; + PVG_FT_Vector start; + PVG_FT_Angle alpha1; /* determine whether the border radius is greater than the */ /* radius of curvature of the original arc */ start = border->points[border->num_points - 1]; - alpha1 = SW_FT_Atan2(end.x - start.x, end.y - start.y); + alpha1 = PVG_FT_Atan2(end.x - start.x, end.y - start.y); /* is the direction of the border arc opposite to */ /* that of the original arc? */ - if (ft_pos_abs(SW_FT_Angle_Diff(alpha0, alpha1)) > - SW_FT_ANGLE_PI / 2) { - SW_FT_Angle beta, gamma; - SW_FT_Vector bvec, delta; - SW_FT_Fixed blen, sinA, sinB, alen; + if (ft_pos_abs(PVG_FT_Angle_Diff(alpha0, alpha1)) > + PVG_FT_ANGLE_PI / 2) { + PVG_FT_Angle beta, gamma; + PVG_FT_Vector bvec, delta; + PVG_FT_Fixed blen, sinA, sinB, alen; /* use the sine rule to find the intersection point */ beta = - SW_FT_Atan2(arc[2].x - start.x, arc[2].y - start.y); - gamma = SW_FT_Atan2(arc[0].x - end.x, arc[0].y - end.y); + PVG_FT_Atan2(arc[2].x - start.x, arc[2].y - start.y); + gamma = PVG_FT_Atan2(arc[0].x - end.x, arc[0].y - end.y); bvec.x = end.x - start.x; bvec.y = end.y - start.y; - blen = SW_FT_Vector_Length(&bvec); + blen = PVG_FT_Vector_Length(&bvec); - sinA = ft_pos_abs(SW_FT_Sin(alpha1 - gamma)); - sinB = ft_pos_abs(SW_FT_Sin(beta - gamma)); + sinA = ft_pos_abs(PVG_FT_Sin(alpha1 - gamma)); + sinB = ft_pos_abs(PVG_FT_Sin(beta - gamma)); - alen = SW_FT_MulDiv(blen, sinA, sinB); + alen = PVG_FT_MulDiv(blen, sinA, sinB); - SW_FT_Vector_From_Polar(&delta, alen, beta); + PVG_FT_Vector_From_Polar(&delta, alen, beta); delta.x += start.x; delta.y += start.y; @@ -1336,6 +1339,7 @@ SW_FT_Error SW_FT_Stroker_ConicTo(SW_FT_Stroker stroker, SW_FT_Vector* control, } stroker->center = *to; + stroker->line_length = 0; Exit: return error; @@ -1343,23 +1347,23 @@ Exit: /* documentation is in ftstroke.h */ -SW_FT_Error SW_FT_Stroker_CubicTo(SW_FT_Stroker stroker, SW_FT_Vector* control1, - SW_FT_Vector* control2, SW_FT_Vector* to) +PVG_FT_Error PVG_FT_Stroker_CubicTo(PVG_FT_Stroker stroker, PVG_FT_Vector* control1, + PVG_FT_Vector* control2, PVG_FT_Vector* to) { - SW_FT_Error error = 0; - SW_FT_Vector bez_stack[37]; - SW_FT_Vector* arc; - SW_FT_Vector* limit = bez_stack + 32; - SW_FT_Bool first_arc = TRUE; + PVG_FT_Error error = 0; + PVG_FT_Vector bez_stack[37]; + PVG_FT_Vector* arc; + PVG_FT_Vector* limit = bez_stack + 32; + PVG_FT_Bool first_arc = TRUE; /* if all control points are coincident, this is a no-op; */ /* avoid creating a spurious corner */ - if (SW_FT_IS_SMALL(stroker->center.x - control1->x) && - SW_FT_IS_SMALL(stroker->center.y - control1->y) && - SW_FT_IS_SMALL(control1->x - control2->x) && - SW_FT_IS_SMALL(control1->y - control2->y) && - SW_FT_IS_SMALL(control2->x - to->x) && - SW_FT_IS_SMALL(control2->y - to->y)) { + if (PVG_FT_IS_SMALL(stroker->center.x - control1->x) && + PVG_FT_IS_SMALL(stroker->center.y - control1->y) && + PVG_FT_IS_SMALL(control1->x - control2->x) && + PVG_FT_IS_SMALL(control1->y - control2->y) && + PVG_FT_IS_SMALL(control2->x - to->x) && + PVG_FT_IS_SMALL(control2->y - to->y)) { stroker->center = *to; goto Exit; } @@ -1371,7 +1375,7 @@ SW_FT_Error SW_FT_Stroker_CubicTo(SW_FT_Stroker stroker, SW_FT_Vector* control1, arc[3] = stroker->center; while (arc >= bez_stack) { - SW_FT_Angle angle_in, angle_mid, angle_out; + PVG_FT_Angle angle_in, angle_mid, angle_out; /* initialize with current direction */ angle_in = angle_out = angle_mid = stroker->angle_in; @@ -1395,13 +1399,13 @@ SW_FT_Error SW_FT_Stroker_CubicTo(SW_FT_Stroker stroker, SW_FT_Vector* control1, stroker->angle_out = angle_in; error = ft_stroker_process_corner(stroker, 0); } - } else if (ft_pos_abs(SW_FT_Angle_Diff(stroker->angle_in, angle_in)) > - SW_FT_SMALL_CUBIC_THRESHOLD / 4) { + } else if (ft_pos_abs(PVG_FT_Angle_Diff(stroker->angle_in, angle_in)) > + PVG_FT_SMALL_CUBIC_THRESHOLD / 4) { /* if the deviation from one arc to the next is too great, */ /* add a round corner */ stroker->center = arc[3]; stroker->angle_out = angle_in; - stroker->line_join = SW_FT_STROKER_LINEJOIN_ROUND; + stroker->line_join = PVG_FT_STROKER_LINEJOIN_ROUND; error = ft_stroker_process_corner(stroker, 0); @@ -1414,77 +1418,77 @@ SW_FT_Error SW_FT_Stroker_CubicTo(SW_FT_Stroker stroker, SW_FT_Vector* control1, /* the arc's angle is small enough; we can add it directly to each */ /* border */ { - SW_FT_Vector ctrl1, ctrl2, end; - SW_FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0; - SW_FT_Fixed length1, length2; - SW_FT_StrokeBorder border; - SW_FT_Int side; + PVG_FT_Vector ctrl1, ctrl2, end; + PVG_FT_Angle theta1, phi1, theta2, phi2, rotate, alpha0 = 0; + PVG_FT_Fixed length1, length2; + PVG_FT_StrokeBorder border; + PVG_FT_Int side; - theta1 = SW_FT_Angle_Diff(angle_in, angle_mid) / 2; - theta2 = SW_FT_Angle_Diff(angle_mid, angle_out) / 2; + theta1 = PVG_FT_Angle_Diff(angle_in, angle_mid) / 2; + theta2 = PVG_FT_Angle_Diff(angle_mid, angle_out) / 2; phi1 = ft_angle_mean(angle_in, angle_mid); phi2 = ft_angle_mean(angle_mid, angle_out); - length1 = SW_FT_DivFix(stroker->radius, SW_FT_Cos(theta1)); - length2 = SW_FT_DivFix(stroker->radius, SW_FT_Cos(theta2)); + length1 = PVG_FT_DivFix(stroker->radius, PVG_FT_Cos(theta1)); + length2 = PVG_FT_DivFix(stroker->radius, PVG_FT_Cos(theta2)); /* compute direction of original arc */ if (stroker->handle_wide_strokes) - alpha0 = SW_FT_Atan2(arc[0].x - arc[3].x, arc[0].y - arc[3].y); + alpha0 = PVG_FT_Atan2(arc[0].x - arc[3].x, arc[0].y - arc[3].y); for (border = stroker->borders, side = 0; side <= 1; side++, border++) { - rotate = SW_FT_SIDE_TO_ROTATE(side); + rotate = PVG_FT_SIDE_TO_ROTATE(side); /* compute control points */ - SW_FT_Vector_From_Polar(&ctrl1, length1, phi1 + rotate); + PVG_FT_Vector_From_Polar(&ctrl1, length1, phi1 + rotate); ctrl1.x += arc[2].x; ctrl1.y += arc[2].y; - SW_FT_Vector_From_Polar(&ctrl2, length2, phi2 + rotate); + PVG_FT_Vector_From_Polar(&ctrl2, length2, phi2 + rotate); ctrl2.x += arc[1].x; ctrl2.y += arc[1].y; /* compute end point */ - SW_FT_Vector_From_Polar(&end, stroker->radius, + PVG_FT_Vector_From_Polar(&end, stroker->radius, angle_out + rotate); end.x += arc[0].x; end.y += arc[0].y; if (stroker->handle_wide_strokes) { - SW_FT_Vector start; - SW_FT_Angle alpha1; + PVG_FT_Vector start; + PVG_FT_Angle alpha1; /* determine whether the border radius is greater than the */ /* radius of curvature of the original arc */ start = border->points[border->num_points - 1]; - alpha1 = SW_FT_Atan2(end.x - start.x, end.y - start.y); + alpha1 = PVG_FT_Atan2(end.x - start.x, end.y - start.y); /* is the direction of the border arc opposite to */ /* that of the original arc? */ - if (ft_pos_abs(SW_FT_Angle_Diff(alpha0, alpha1)) > - SW_FT_ANGLE_PI / 2) { - SW_FT_Angle beta, gamma; - SW_FT_Vector bvec, delta; - SW_FT_Fixed blen, sinA, sinB, alen; + if (ft_pos_abs(PVG_FT_Angle_Diff(alpha0, alpha1)) > + PVG_FT_ANGLE_PI / 2) { + PVG_FT_Angle beta, gamma; + PVG_FT_Vector bvec, delta; + PVG_FT_Fixed blen, sinA, sinB, alen; /* use the sine rule to find the intersection point */ beta = - SW_FT_Atan2(arc[3].x - start.x, arc[3].y - start.y); - gamma = SW_FT_Atan2(arc[0].x - end.x, arc[0].y - end.y); + PVG_FT_Atan2(arc[3].x - start.x, arc[3].y - start.y); + gamma = PVG_FT_Atan2(arc[0].x - end.x, arc[0].y - end.y); bvec.x = end.x - start.x; bvec.y = end.y - start.y; - blen = SW_FT_Vector_Length(&bvec); + blen = PVG_FT_Vector_Length(&bvec); - sinA = ft_pos_abs(SW_FT_Sin(alpha1 - gamma)); - sinB = ft_pos_abs(SW_FT_Sin(beta - gamma)); + sinA = ft_pos_abs(PVG_FT_Sin(alpha1 - gamma)); + sinB = ft_pos_abs(PVG_FT_Sin(beta - gamma)); - alen = SW_FT_MulDiv(blen, sinA, sinB); + alen = PVG_FT_MulDiv(blen, sinA, sinB); - SW_FT_Vector_From_Polar(&delta, alen, beta); + PVG_FT_Vector_From_Polar(&delta, alen, beta); delta.x += start.x; delta.y += start.y; @@ -1519,6 +1523,7 @@ SW_FT_Error SW_FT_Stroker_CubicTo(SW_FT_Stroker stroker, SW_FT_Vector* control1, } stroker->center = *to; + stroker->line_length = 0; Exit: return error; @@ -1526,12 +1531,12 @@ Exit: /* documentation is in ftstroke.h */ -SW_FT_Error SW_FT_Stroker_BeginSubPath(SW_FT_Stroker stroker, SW_FT_Vector* to, - SW_FT_Bool open) +PVG_FT_Error PVG_FT_Stroker_BeginSubPath(PVG_FT_Stroker stroker, PVG_FT_Vector* to, + PVG_FT_Bool open) { /* We cannot process the first point, because there is not enough */ /* information regarding its corner/cap. The latter will be processed */ - /* in the `SW_FT_Stroker_EndSubPath' routine. */ + /* in the `PVG_FT_Stroker_EndSubPath' routine. */ /* */ stroker->first_point = TRUE; stroker->center = *to; @@ -1543,9 +1548,9 @@ SW_FT_Error SW_FT_Stroker_BeginSubPath(SW_FT_Stroker stroker, SW_FT_Vector* to, /* be created, because round & miter joins and round & square caps */ /* cover the negative sector created with wide strokes. */ stroker->handle_wide_strokes = - SW_FT_BOOL(stroker->line_join != SW_FT_STROKER_LINEJOIN_ROUND || + PVG_FT_BOOL(stroker->line_join != PVG_FT_STROKER_LINEJOIN_ROUND || (stroker->subpath_open && - stroker->line_cap == SW_FT_STROKER_LINECAP_BUTT)); + stroker->line_cap == PVG_FT_STROKER_LINECAP_BUTT)); /* record the subpath start point for each border */ stroker->subpath_start = *to; @@ -1555,41 +1560,41 @@ SW_FT_Error SW_FT_Stroker_BeginSubPath(SW_FT_Stroker stroker, SW_FT_Vector* to, return 0; } -static SW_FT_Error ft_stroker_add_reverse_left(SW_FT_Stroker stroker, - SW_FT_Bool open) +static PVG_FT_Error ft_stroker_add_reverse_left(PVG_FT_Stroker stroker, + PVG_FT_Bool open) { - SW_FT_StrokeBorder right = stroker->borders + 0; - SW_FT_StrokeBorder left = stroker->borders + 1; - SW_FT_Int new_points; - SW_FT_Error error = 0; + PVG_FT_StrokeBorder right = stroker->borders + 0; + PVG_FT_StrokeBorder left = stroker->borders + 1; + PVG_FT_Int new_points; + PVG_FT_Error error = 0; assert(left->start >= 0); new_points = left->num_points - left->start; if (new_points > 0) { - error = ft_stroke_border_grow(right, (SW_FT_UInt)new_points); + error = ft_stroke_border_grow(right, (PVG_FT_UInt)new_points); if (error) goto Exit; { - SW_FT_Vector* dst_point = right->points + right->num_points; - SW_FT_Byte* dst_tag = right->tags + right->num_points; - SW_FT_Vector* src_point = left->points + left->num_points - 1; - SW_FT_Byte* src_tag = left->tags + left->num_points - 1; + PVG_FT_Vector* dst_point = right->points + right->num_points; + PVG_FT_Byte* dst_tag = right->tags + right->num_points; + PVG_FT_Vector* src_point = left->points + left->num_points - 1; + PVG_FT_Byte* src_tag = left->tags + left->num_points - 1; while (src_point >= left->points + left->start) { *dst_point = *src_point; *dst_tag = *src_tag; if (open) - dst_tag[0] &= ~SW_FT_STROKE_TAG_BEGIN_END; + dst_tag[0] &= ~PVG_FT_STROKE_TAG_BEGIN_END; else { - SW_FT_Byte ttag = - (SW_FT_Byte)(dst_tag[0] & SW_FT_STROKE_TAG_BEGIN_END); + PVG_FT_Byte ttag = + (PVG_FT_Byte)(dst_tag[0] & PVG_FT_STROKE_TAG_BEGIN_END); /* switch begin/end tags if necessary */ - if (ttag == SW_FT_STROKE_TAG_BEGIN || - ttag == SW_FT_STROKE_TAG_END) - dst_tag[0] ^= SW_FT_STROKE_TAG_BEGIN_END; + if (ttag == PVG_FT_STROKE_TAG_BEGIN || + ttag == PVG_FT_STROKE_TAG_END) + dst_tag[0] ^= PVG_FT_STROKE_TAG_BEGIN_END; } src_point--; @@ -1613,12 +1618,12 @@ Exit: /* documentation is in ftstroke.h */ /* there's a lot of magic in this function! */ -SW_FT_Error SW_FT_Stroker_EndSubPath(SW_FT_Stroker stroker) +PVG_FT_Error PVG_FT_Stroker_EndSubPath(PVG_FT_Stroker stroker) { - SW_FT_Error error = 0; + PVG_FT_Error error = 0; if (stroker->subpath_open) { - SW_FT_StrokeBorder right = stroker->borders; + PVG_FT_StrokeBorder right = stroker->borders; /* All right, this is an opened path, we need to add a cap between */ /* right & left, add the reverse of left, then add a final cap */ @@ -1633,26 +1638,26 @@ SW_FT_Error SW_FT_Stroker_EndSubPath(SW_FT_Stroker stroker) /* now add the final cap */ stroker->center = stroker->subpath_start; error = - ft_stroker_cap(stroker, stroker->subpath_angle + SW_FT_ANGLE_PI, 0); + ft_stroker_cap(stroker, stroker->subpath_angle + PVG_FT_ANGLE_PI, 0); if (error) goto Exit; /* Now end the right subpath accordingly. The left one is */ /* rewind and doesn't need further processing. */ ft_stroke_border_close(right, FALSE); } else { - SW_FT_Angle turn; - SW_FT_Int inside_side; + PVG_FT_Angle turn; + PVG_FT_Int inside_side; /* close the path if needed */ if (stroker->center.x != stroker->subpath_start.x || stroker->center.y != stroker->subpath_start.y) { - error = SW_FT_Stroker_LineTo(stroker, &stroker->subpath_start); + error = PVG_FT_Stroker_LineTo(stroker, &stroker->subpath_start); if (error) goto Exit; } /* process the corner */ stroker->angle_out = stroker->subpath_angle; - turn = SW_FT_Angle_Diff(stroker->angle_in, stroker->angle_out); + turn = PVG_FT_Angle_Diff(stroker->angle_in, stroker->angle_out); /* no specific corner processing is required if the turn is 0 */ if (turn != 0) { @@ -1683,16 +1688,16 @@ Exit: /* documentation is in ftstroke.h */ -SW_FT_Error SW_FT_Stroker_GetBorderCounts(SW_FT_Stroker stroker, - SW_FT_StrokerBorder border, - SW_FT_UInt* anum_points, - SW_FT_UInt* anum_contours) +PVG_FT_Error PVG_FT_Stroker_GetBorderCounts(PVG_FT_Stroker stroker, + PVG_FT_StrokerBorder border, + PVG_FT_UInt* anum_points, + PVG_FT_UInt* anum_contours) { - SW_FT_UInt num_points = 0, num_contours = 0; - SW_FT_Error error; + PVG_FT_UInt num_points = 0, num_contours = 0; + PVG_FT_Error error; if (!stroker || border > 1) { - error = -1; // SW_FT_THROW( Invalid_Argument ); + error = -1; // PVG_FT_THROW( Invalid_Argument ); goto Exit; } @@ -1708,13 +1713,13 @@ Exit: /* documentation is in ftstroke.h */ -SW_FT_Error SW_FT_Stroker_GetCounts(SW_FT_Stroker stroker, - SW_FT_UInt* anum_points, - SW_FT_UInt* anum_contours) +PVG_FT_Error PVG_FT_Stroker_GetCounts(PVG_FT_Stroker stroker, + PVG_FT_UInt* anum_points, + PVG_FT_UInt* anum_contours) { - SW_FT_UInt count1, count2, num_points = 0; - SW_FT_UInt count3, count4, num_contours = 0; - SW_FT_Error error; + PVG_FT_UInt count1, count2, num_points = 0; + PVG_FT_UInt count3, count4, num_contours = 0; + PVG_FT_Error error; error = ft_stroke_border_get_counts(stroker->borders + 0, &count1, &count2); if (error) goto Exit; @@ -1733,13 +1738,13 @@ Exit: /* documentation is in ftstroke.h */ -void SW_FT_Stroker_ExportBorder(SW_FT_Stroker stroker, - SW_FT_StrokerBorder border, - SW_FT_Outline* outline) +void PVG_FT_Stroker_ExportBorder(PVG_FT_Stroker stroker, + PVG_FT_StrokerBorder border, + PVG_FT_Outline* outline) { - if (border == SW_FT_STROKER_BORDER_LEFT || - border == SW_FT_STROKER_BORDER_RIGHT) { - SW_FT_StrokeBorder sborder = &stroker->borders[border]; + if (border == PVG_FT_STROKER_BORDER_LEFT || + border == PVG_FT_STROKER_BORDER_RIGHT) { + PVG_FT_StrokeBorder sborder = &stroker->borders[border]; if (sborder->valid) ft_stroke_border_export(sborder, outline); } @@ -1747,43 +1752,43 @@ void SW_FT_Stroker_ExportBorder(SW_FT_Stroker stroker, /* documentation is in ftstroke.h */ -void SW_FT_Stroker_Export(SW_FT_Stroker stroker, SW_FT_Outline* outline) +void PVG_FT_Stroker_Export(PVG_FT_Stroker stroker, PVG_FT_Outline* outline) { - SW_FT_Stroker_ExportBorder(stroker, SW_FT_STROKER_BORDER_LEFT, outline); - SW_FT_Stroker_ExportBorder(stroker, SW_FT_STROKER_BORDER_RIGHT, outline); + PVG_FT_Stroker_ExportBorder(stroker, PVG_FT_STROKER_BORDER_LEFT, outline); + PVG_FT_Stroker_ExportBorder(stroker, PVG_FT_STROKER_BORDER_RIGHT, outline); } /* documentation is in ftstroke.h */ /* - * The following is very similar to SW_FT_Outline_Decompose, except + * The following is very similar to PVG_FT_Outline_Decompose, except * that we do support opened paths, and do not scale the outline. */ -SW_FT_Error SW_FT_Stroker_ParseOutline(SW_FT_Stroker stroker, - const SW_FT_Outline* outline) +PVG_FT_Error PVG_FT_Stroker_ParseOutline(PVG_FT_Stroker stroker, + const PVG_FT_Outline* outline) { - SW_FT_Vector v_last; - SW_FT_Vector v_control; - SW_FT_Vector v_start; + PVG_FT_Vector v_last; + PVG_FT_Vector v_control; + PVG_FT_Vector v_start; - SW_FT_Vector* point; - SW_FT_Vector* limit; + PVG_FT_Vector* point; + PVG_FT_Vector* limit; char* tags; - SW_FT_Error error; + PVG_FT_Error error; - SW_FT_Int n; /* index of contour in outline */ - SW_FT_UInt first; /* index of first point in contour */ - SW_FT_Int tag; /* current point's state */ + PVG_FT_Int n; /* index of contour in outline */ + PVG_FT_UInt first; /* index of first point in contour */ + PVG_FT_Int tag; /* current point's state */ - if (!outline || !stroker) return -1; // SW_FT_THROW( Invalid_Argument ); + if (!outline || !stroker) return -1; // PVG_FT_THROW( Invalid_Argument ); - SW_FT_Stroker_Rewind(stroker); + PVG_FT_Stroker_Rewind(stroker); first = 0; for (n = 0; n < outline->n_contours; n++) { - SW_FT_UInt last; /* index of last point in contour */ + PVG_FT_UInt last; /* index of last point in contour */ last = outline->contours[n]; limit = outline->points + last; @@ -1801,15 +1806,15 @@ SW_FT_Error SW_FT_Stroker_ParseOutline(SW_FT_Stroker stroker, point = outline->points + first; tags = outline->tags + first; - tag = SW_FT_CURVE_TAG(tags[0]); + tag = PVG_FT_CURVE_TAG(tags[0]); /* A contour cannot start with a cubic control point! */ - if (tag == SW_FT_CURVE_TAG_CUBIC) goto Invalid_Outline; + if (tag == PVG_FT_CURVE_TAG_CUBIC) goto Invalid_Outline; /* check first point to determine origin */ - if (tag == SW_FT_CURVE_TAG_CONIC) { + if (tag == PVG_FT_CURVE_TAG_CONIC) { /* First point is conic control. Yes, this happens. */ - if (SW_FT_CURVE_TAG(outline->tags[last]) == SW_FT_CURVE_TAG_ON) { + if (PVG_FT_CURVE_TAG(outline->tags[last]) == PVG_FT_CURVE_TAG_ON) { /* start at last point if it is on the curve */ v_start = v_last; limit--; @@ -1823,71 +1828,71 @@ SW_FT_Error SW_FT_Stroker_ParseOutline(SW_FT_Stroker stroker, tags--; } - error = SW_FT_Stroker_BeginSubPath(stroker, &v_start, outline->contours_flag[n]); + error = PVG_FT_Stroker_BeginSubPath(stroker, &v_start, outline->contours_flag[n]); if (error) goto Exit; while (point < limit) { point++; tags++; - tag = SW_FT_CURVE_TAG(tags[0]); + tag = PVG_FT_CURVE_TAG(tags[0]); switch (tag) { - case SW_FT_CURVE_TAG_ON: /* emit a single line_to */ + case PVG_FT_CURVE_TAG_ON: /* emit a single line_to */ { - SW_FT_Vector vec; + PVG_FT_Vector vec; vec.x = point->x; vec.y = point->y; - error = SW_FT_Stroker_LineTo(stroker, &vec); + error = PVG_FT_Stroker_LineTo(stroker, &vec); if (error) goto Exit; continue; } - case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ + case PVG_FT_CURVE_TAG_CONIC: /* consume conic arcs */ v_control.x = point->x; v_control.y = point->y; Do_Conic: if (point < limit) { - SW_FT_Vector vec; - SW_FT_Vector v_middle; + PVG_FT_Vector vec; + PVG_FT_Vector v_middle; point++; tags++; - tag = SW_FT_CURVE_TAG(tags[0]); + tag = PVG_FT_CURVE_TAG(tags[0]); vec = point[0]; - if (tag == SW_FT_CURVE_TAG_ON) { + if (tag == PVG_FT_CURVE_TAG_ON) { error = - SW_FT_Stroker_ConicTo(stroker, &v_control, &vec); + PVG_FT_Stroker_ConicTo(stroker, &v_control, &vec); if (error) goto Exit; continue; } - if (tag != SW_FT_CURVE_TAG_CONIC) goto Invalid_Outline; + if (tag != PVG_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 = - SW_FT_Stroker_ConicTo(stroker, &v_control, &v_middle); + PVG_FT_Stroker_ConicTo(stroker, &v_control, &v_middle); if (error) goto Exit; v_control = vec; goto Do_Conic; } - error = SW_FT_Stroker_ConicTo(stroker, &v_control, &v_start); + error = PVG_FT_Stroker_ConicTo(stroker, &v_control, &v_start); goto Close; - default: /* SW_FT_CURVE_TAG_CUBIC */ + default: /* PVG_FT_CURVE_TAG_CUBIC */ { - SW_FT_Vector vec1, vec2; + PVG_FT_Vector vec1, vec2; if (point + 1 > limit || - SW_FT_CURVE_TAG(tags[1]) != SW_FT_CURVE_TAG_CUBIC) + PVG_FT_CURVE_TAG(tags[1]) != PVG_FT_CURVE_TAG_CUBIC) goto Invalid_Outline; point += 2; @@ -1897,16 +1902,16 @@ SW_FT_Error SW_FT_Stroker_ParseOutline(SW_FT_Stroker stroker, vec2 = point[-1]; if (point <= limit) { - SW_FT_Vector vec; + PVG_FT_Vector vec; vec = point[0]; - error = SW_FT_Stroker_CubicTo(stroker, &vec1, &vec2, &vec); + error = PVG_FT_Stroker_CubicTo(stroker, &vec1, &vec2, &vec); if (error) goto Exit; continue; } - error = SW_FT_Stroker_CubicTo(stroker, &vec1, &vec2, &v_start); + error = PVG_FT_Stroker_CubicTo(stroker, &vec1, &vec2, &v_start); goto Close; } } @@ -1921,7 +1926,7 @@ SW_FT_Error SW_FT_Stroker_ParseOutline(SW_FT_Stroker stroker, if (error) goto Exit; } - error = SW_FT_Stroker_EndSubPath(stroker); + error = PVG_FT_Stroker_EndSubPath(stroker); if (error) goto Exit; first = last + 1; @@ -1933,7 +1938,7 @@ Exit: return error; Invalid_Outline: - return -2; // SW_FT_THROW( Invalid_Outline ); + return -2; // PVG_FT_THROW( Invalid_Outline ); } /* END */ diff --git a/3rdparty/plutovg/plutovg-ft-stroker.h b/3rdparty/plutovg/plutovg-ft-stroker.h new file mode 100644 index 000000000..09e1c50df --- /dev/null +++ b/3rdparty/plutovg/plutovg-ft-stroker.h @@ -0,0 +1,320 @@ +/***************************************************************************/ +/* */ +/* ftstroke.h */ +/* */ +/* FreeType path stroker (specification). */ +/* */ +/* Copyright 2002-2006, 2008, 2009, 2011-2012 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef PLUTOVG_FT_STROKER_H +#define PLUTOVG_FT_STROKER_H + +#include "plutovg-ft-raster.h" + +/************************************************************** + * + * @type: + * PVG_FT_Stroker + * + * @description: + * Opaque handler to a path stroker object. + */ +typedef struct PVG_FT_StrokerRec_* PVG_FT_Stroker; + + +/************************************************************** + * + * @enum: + * PVG_FT_Stroker_LineJoin + * + * @description: + * These values determine how two joining lines are rendered + * in a stroker. + * + * @values: + * PVG_FT_STROKER_LINEJOIN_ROUND :: + * Used to render rounded line joins. Circular arcs are used + * to join two lines smoothly. + * + * PVG_FT_STROKER_LINEJOIN_BEVEL :: + * Used to render beveled line joins. The outer corner of + * the joined lines is filled by enclosing the triangular + * region of the corner with a straight line between the + * outer corners of each stroke. + * + * PVG_FT_STROKER_LINEJOIN_MITER_FIXED :: + * Used to render mitered line joins, with fixed bevels if the + * miter limit is exceeded. The outer edges of the strokes + * for the two segments are extended until they meet at an + * angle. If the segments meet at too sharp an angle (such + * that the miter would extend from the intersection of the + * segments a distance greater than the product of the miter + * limit value and the border radius), then a bevel join (see + * above) is used instead. This prevents long spikes being + * created. PVG_FT_STROKER_LINEJOIN_MITER_FIXED generates a miter + * line join as used in PostScript and PDF. + * + * PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE :: + * PVG_FT_STROKER_LINEJOIN_MITER :: + * Used to render mitered line joins, with variable bevels if + * the miter limit is exceeded. The intersection of the + * strokes is clipped at a line perpendicular to the bisector + * of the angle between the strokes, at the distance from the + * intersection of the segments equal to the product of the + * miter limit value and the border radius. This prevents + * long spikes being created. + * PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE generates a mitered line + * join as used in XPS. PVG_FT_STROKER_LINEJOIN_MITER is an alias + * for PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE, retained for + * backwards compatibility. + */ +typedef enum PVG_FT_Stroker_LineJoin_ +{ + PVG_FT_STROKER_LINEJOIN_ROUND = 0, + PVG_FT_STROKER_LINEJOIN_BEVEL = 1, + PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE = 2, + PVG_FT_STROKER_LINEJOIN_MITER = PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE, + PVG_FT_STROKER_LINEJOIN_MITER_FIXED = 3 + +} PVG_FT_Stroker_LineJoin; + + +/************************************************************** + * + * @enum: + * PVG_FT_Stroker_LineCap + * + * @description: + * These values determine how the end of opened sub-paths are + * rendered in a stroke. + * + * @values: + * PVG_FT_STROKER_LINECAP_BUTT :: + * The end of lines is rendered as a full stop on the last + * point itself. + * + * PVG_FT_STROKER_LINECAP_ROUND :: + * The end of lines is rendered as a half-circle around the + * last point. + * + * PVG_FT_STROKER_LINECAP_SQUARE :: + * The end of lines is rendered as a square around the + * last point. + */ +typedef enum PVG_FT_Stroker_LineCap_ +{ + PVG_FT_STROKER_LINECAP_BUTT = 0, + PVG_FT_STROKER_LINECAP_ROUND, + PVG_FT_STROKER_LINECAP_SQUARE + +} PVG_FT_Stroker_LineCap; + + +/************************************************************** + * + * @enum: + * PVG_FT_StrokerBorder + * + * @description: + * These values are used to select a given stroke border + * in @PVG_FT_Stroker_GetBorderCounts and @PVG_FT_Stroker_ExportBorder. + * + * @values: + * PVG_FT_STROKER_BORDER_LEFT :: + * Select the left border, relative to the drawing direction. + * + * PVG_FT_STROKER_BORDER_RIGHT :: + * Select the right border, relative to the drawing direction. + * + * @note: + * Applications are generally interested in the `inside' and `outside' + * borders. However, there is no direct mapping between these and the + * `left' and `right' ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats. + * + * You can however use @PVG_FT_Outline_GetInsideBorder and + * @PVG_FT_Outline_GetOutsideBorder to get these. + */ +typedef enum PVG_FT_StrokerBorder_ +{ + PVG_FT_STROKER_BORDER_LEFT = 0, + PVG_FT_STROKER_BORDER_RIGHT + +} PVG_FT_StrokerBorder; + + +/************************************************************** + * + * @function: + * PVG_FT_Stroker_New + * + * @description: + * Create a new stroker object. + * + * @input: + * library :: + * FreeType library handle. + * + * @output: + * astroker :: + * A new stroker object handle. NULL in case of error. + * + * @return: + * FreeType error code. 0~means success. + */ +PVG_FT_Error +PVG_FT_Stroker_New( PVG_FT_Stroker *astroker ); + + +/************************************************************** + * + * @function: + * PVG_FT_Stroker_Set + * + * @description: + * Reset a stroker object's attributes. + * + * @input: + * stroker :: + * The target stroker handle. + * + * radius :: + * The border radius. + * + * line_cap :: + * The line cap style. + * + * line_join :: + * The line join style. + * + * miter_limit :: + * The miter limit for the PVG_FT_STROKER_LINEJOIN_MITER_FIXED and + * PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE line join styles, + * expressed as 16.16 fixed-point value. + * + * @note: + * The radius is expressed in the same units as the outline + * coordinates. + */ +void +PVG_FT_Stroker_Set( PVG_FT_Stroker stroker, + PVG_FT_Fixed radius, + PVG_FT_Stroker_LineCap line_cap, + PVG_FT_Stroker_LineJoin line_join, + PVG_FT_Fixed miter_limit ); + +/************************************************************** + * + * @function: + * PVG_FT_Stroker_ParseOutline + * + * @description: + * A convenience function used to parse a whole outline with + * the stroker. The resulting outline(s) can be retrieved + * later by functions like @PVG_FT_Stroker_GetCounts and @PVG_FT_Stroker_Export. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The source outline. + * + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * If `opened' is~0 (the default), the outline is treated as a closed + * path, and the stroker generates two distinct `border' outlines. + * + * + * This function calls @PVG_FT_Stroker_Rewind automatically. + */ +PVG_FT_Error +PVG_FT_Stroker_ParseOutline( PVG_FT_Stroker stroker, + const PVG_FT_Outline* outline); + + +/************************************************************** + * + * @function: + * PVG_FT_Stroker_GetCounts + * + * @description: + * Call this function once you have finished parsing your paths + * with the stroker. It returns the number of points and + * contours necessary to export all points/borders from the stroked + * outline/path. + * + * @input: + * stroker :: + * The target stroker handle. + * + * @output: + * anum_points :: + * The number of points. + * + * anum_contours :: + * The number of contours. + * + * @return: + * FreeType error code. 0~means success. + */ +PVG_FT_Error +PVG_FT_Stroker_GetCounts( PVG_FT_Stroker stroker, + PVG_FT_UInt *anum_points, + PVG_FT_UInt *anum_contours ); + + +/************************************************************** + * + * @function: + * PVG_FT_Stroker_Export + * + * @description: + * Call this function after @PVG_FT_Stroker_GetBorderCounts to + * export all borders to your own @PVG_FT_Outline structure. + * + * Note that this function appends the border points and + * contours to your outline, but does not try to resize its + * arrays. + * + * @input: + * stroker :: + * The target stroker handle. + * + * outline :: + * The target outline handle. + */ +void +PVG_FT_Stroker_Export( PVG_FT_Stroker stroker, + PVG_FT_Outline* outline ); + + +/************************************************************** + * + * @function: + * PVG_FT_Stroker_Done + * + * @description: + * Destroy a stroker object. + * + * @input: + * stroker :: + * A stroker handle. Can be NULL. + */ +void +PVG_FT_Stroker_Done( PVG_FT_Stroker stroker ); + + +#endif // PLUTOVG_FT_STROKER_H diff --git a/3rdparty/software/sw_ft_types.h b/3rdparty/plutovg/plutovg-ft-types.h similarity index 73% rename from 3rdparty/software/sw_ft_types.h rename to 3rdparty/plutovg/plutovg-ft-types.h index 828103aea..61b77787a 100644 --- a/3rdparty/software/sw_ft_types.h +++ b/3rdparty/plutovg/plutovg-ft-types.h @@ -1,152 +1,166 @@ -#ifndef SW_FT_TYPES_H -#define SW_FT_TYPES_H +/**************************************************************************** + * + * fttypes.h + * + * FreeType simple types definitions (specification only). + * + * Copyright (C) 1996-2020 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef PLUTOVG_FT_TYPES_H +#define PLUTOVG_FT_TYPES_H /*************************************************************************/ /* */ /* */ -/* SW_FT_Fixed */ +/* PVG_FT_Fixed */ /* */ /* */ /* This type is used to store 16.16 fixed-point values, like scaling */ /* values or matrix coefficients. */ /* */ -typedef signed long SW_FT_Fixed; +typedef signed long PVG_FT_Fixed; /*************************************************************************/ /* */ /* */ -/* SW_FT_Int */ +/* PVG_FT_Int */ /* */ /* */ /* A typedef for the int type. */ /* */ -typedef signed int SW_FT_Int; +typedef signed int PVG_FT_Int; /*************************************************************************/ /* */ /* */ -/* SW_FT_UInt */ +/* PVG_FT_UInt */ /* */ /* */ /* A typedef for the unsigned int type. */ /* */ -typedef unsigned int SW_FT_UInt; +typedef unsigned int PVG_FT_UInt; /*************************************************************************/ /* */ /* */ -/* SW_FT_Long */ +/* PVG_FT_Long */ /* */ /* */ /* A typedef for signed long. */ /* */ -typedef signed long SW_FT_Long; +typedef signed long PVG_FT_Long; /*************************************************************************/ /* */ /* */ -/* SW_FT_ULong */ +/* PVG_FT_ULong */ /* */ /* */ /* A typedef for unsigned long. */ /* */ -typedef unsigned long SW_FT_ULong; +typedef unsigned long PVG_FT_ULong; /*************************************************************************/ /* */ /* */ -/* SW_FT_Short */ +/* PVG_FT_Short */ /* */ /* */ /* A typedef for signed short. */ /* */ -typedef signed short SW_FT_Short; +typedef signed short PVG_FT_Short; /*************************************************************************/ /* */ /* */ -/* SW_FT_Byte */ +/* PVG_FT_Byte */ /* */ /* */ /* A simple typedef for the _unsigned_ char type. */ /* */ -typedef unsigned char SW_FT_Byte; +typedef unsigned char PVG_FT_Byte; /*************************************************************************/ /* */ /* */ -/* SW_FT_Bool */ +/* PVG_FT_Bool */ /* */ /* */ /* A typedef of unsigned char, used for simple booleans. As usual, */ /* values 1 and~0 represent true and false, respectively. */ /* */ -typedef unsigned char SW_FT_Bool; +typedef unsigned char PVG_FT_Bool; /*************************************************************************/ /* */ /* */ -/* SW_FT_Error */ +/* PVG_FT_Error */ /* */ /* */ /* The FreeType error code type. A value of~0 is always interpreted */ /* as a successful operation. */ /* */ -typedef int SW_FT_Error; +typedef int PVG_FT_Error; /*************************************************************************/ /* */ /* */ -/* SW_FT_Pos */ +/* PVG_FT_Pos */ /* */ /* */ -/* The type SW_FT_Pos is used to store vectorial coordinates. Depending */ +/* The type PVG_FT_Pos is used to store vectorial coordinates. Depending */ /* on the context, these can represent distances in integer font */ /* units, or 16.16, or 26.6 fixed-point pixel coordinates. */ /* */ -typedef signed long SW_FT_Pos; +typedef signed long PVG_FT_Pos; /*************************************************************************/ /* */ /* */ -/* SW_FT_Vector */ +/* PVG_FT_Vector */ /* */ /* */ /* A simple structure used to store a 2D vector; coordinates are of */ -/* the SW_FT_Pos type. */ +/* the PVG_FT_Pos type. */ /* */ /* */ /* x :: The horizontal coordinate. */ /* y :: The vertical coordinate. */ /* */ -typedef struct SW_FT_Vector_ +typedef struct PVG_FT_Vector_ { - SW_FT_Pos x; - SW_FT_Pos y; + PVG_FT_Pos x; + PVG_FT_Pos y; -} SW_FT_Vector; +} PVG_FT_Vector; -typedef long long int SW_FT_Int64; -typedef unsigned long long int SW_FT_UInt64; +typedef long long int PVG_FT_Int64; +typedef unsigned long long int PVG_FT_UInt64; -typedef signed int SW_FT_Int32; -typedef unsigned int SW_FT_UInt32; +typedef signed int PVG_FT_Int32; +typedef unsigned int PVG_FT_UInt32; - -#define SW_FT_BOOL( x ) ( (SW_FT_Bool)( x ) ) - -#define SW_FT_SIZEOF_LONG 4 +#define PVG_FT_BOOL( x ) ( (PVG_FT_Bool)( x ) ) #ifndef TRUE #define TRUE 1 @@ -156,5 +170,4 @@ typedef unsigned int SW_FT_UInt32; #define FALSE 0 #endif - -#endif // SW_FT_TYPES_H +#endif // PLUTOVG_FT_TYPES_H diff --git a/3rdparty/plutovg/plutovg-private.h b/3rdparty/plutovg/plutovg-private.h index b1025383c..c31a4bf73 100644 --- a/3rdparty/plutovg/plutovg-private.h +++ b/3rdparty/plutovg/plutovg-private.h @@ -66,9 +66,9 @@ struct plutovg_paint { }; typedef struct { - short x; - short y; - unsigned short len; + int x; + int len; + int y; unsigned char coverage; } plutovg_span_t; diff --git a/3rdparty/plutovg/plutovg-rle.c b/3rdparty/plutovg/plutovg-rle.c index be51ca227..69345fc61 100644 --- a/3rdparty/plutovg/plutovg-rle.c +++ b/3rdparty/plutovg/plutovg-rle.c @@ -1,26 +1,24 @@ #include "plutovg-private.h" -#include "sw_ft_raster.h" -#include "sw_ft_stroker.h" -#include "sw_ft_types.h" -#include "sw_ft_math.h" +#include "plutovg-ft-raster.h" +#include "plutovg-ft-stroker.h" #include #include -static SW_FT_Outline* sw_ft_outline_create(int points, int contours) +static PVG_FT_Outline* ft_outline_create(size_t points, size_t contours) { - SW_FT_Outline* ft = malloc(sizeof(SW_FT_Outline)); - ft->points = malloc((size_t)(points + contours) * sizeof(SW_FT_Vector)); - ft->tags = malloc((size_t)(points + contours) * sizeof(char)); - ft->contours = malloc((size_t)contours * sizeof(int)); - ft->contours_flag = malloc((size_t)contours * sizeof(char)); + PVG_FT_Outline* ft = malloc(sizeof(PVG_FT_Outline)); + ft->points = malloc((points + contours) * sizeof(PVG_FT_Vector)); + ft->tags = malloc((points + contours) * sizeof(char)); + ft->contours = malloc(contours * sizeof(int)); + ft->contours_flag = malloc(contours * sizeof(char)); ft->n_points = ft->n_contours = 0; ft->flags = 0x0; return ft; } -static void sw_ft_outline_destroy(SW_FT_Outline* ft) +static void ft_outline_destroy(PVG_FT_Outline* ft) { free(ft->points); free(ft->tags); @@ -29,14 +27,13 @@ static void sw_ft_outline_destroy(SW_FT_Outline* ft) free(ft); } -#define FT_COORD(x) (SW_FT_Pos)((x) * 64) -static void sw_ft_outline_move_to(SW_FT_Outline* ft, double x, double y) +#define FT_COORD(x) (PVG_FT_Pos)((x) * 64) +static void ft_outline_move_to(PVG_FT_Outline* ft, double x, double y) { ft->points[ft->n_points].x = FT_COORD(x); ft->points[ft->n_points].y = FT_COORD(y); - ft->tags[ft->n_points] = SW_FT_CURVE_TAG_ON; - if(ft->n_points) - { + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; + if(ft->n_points) { ft->contours[ft->n_contours] = ft->n_points - 1; ft->n_contours++; } @@ -45,33 +42,33 @@ static void sw_ft_outline_move_to(SW_FT_Outline* ft, double x, double y) ft->n_points++; } -static void sw_ft_outline_line_to(SW_FT_Outline* ft, double x, double y) +static void ft_outline_line_to(PVG_FT_Outline* ft, double x, double y) { ft->points[ft->n_points].x = FT_COORD(x); ft->points[ft->n_points].y = FT_COORD(y); - ft->tags[ft->n_points] = SW_FT_CURVE_TAG_ON; + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; ft->n_points++; } -static void sw_ft_outline_cubic_to(SW_FT_Outline* ft, double x1, double y1, double x2, double y2, double x3, double y3) +static void ft_outline_cubic_to(PVG_FT_Outline* ft, double x1, double y1, double x2, double y2, double x3, double y3) { ft->points[ft->n_points].x = FT_COORD(x1); ft->points[ft->n_points].y = FT_COORD(y1); - ft->tags[ft->n_points] = SW_FT_CURVE_TAG_CUBIC; + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC; ft->n_points++; ft->points[ft->n_points].x = FT_COORD(x2); ft->points[ft->n_points].y = FT_COORD(y2); - ft->tags[ft->n_points] = SW_FT_CURVE_TAG_CUBIC; + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC; ft->n_points++; ft->points[ft->n_points].x = FT_COORD(x3); ft->points[ft->n_points].y = FT_COORD(y3); - ft->tags[ft->n_points] = SW_FT_CURVE_TAG_ON; + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; ft->n_points++; } -static void sw_ft_outline_close(SW_FT_Outline* ft) +static void ft_outline_close(PVG_FT_Outline* ft) { ft->contours_flag[ft->n_contours] = 0; int index = ft->n_contours ? ft->contours[ft->n_contours - 1] + 1 : 0; @@ -80,66 +77,63 @@ static void sw_ft_outline_close(SW_FT_Outline* ft) ft->points[ft->n_points].x = ft->points[index].x; ft->points[ft->n_points].y = ft->points[index].y; - ft->tags[ft->n_points] = SW_FT_CURVE_TAG_ON; + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; ft->n_points++; } -static void sw_ft_outline_end(SW_FT_Outline* ft) +static void ft_outline_end(PVG_FT_Outline* ft) { - if(ft->n_points) - { + if(ft->n_points) { ft->contours[ft->n_contours] = ft->n_points - 1; ft->n_contours++; } } -static SW_FT_Outline* sw_ft_outline_convert(const plutovg_path_t* path, const plutovg_matrix_t* matrix) +static PVG_FT_Outline* ft_outline_convert(const plutovg_path_t* path, const plutovg_matrix_t* matrix) { - SW_FT_Outline* outline = sw_ft_outline_create(path->points.size, path->contours); + PVG_FT_Outline* outline = ft_outline_create(path->points.size, path->contours); plutovg_path_element_t* elements = path->elements.data; plutovg_point_t* points = path->points.data; plutovg_point_t p[3]; - for(int i = 0;i < path->elements.size;i++) - { - switch(elements[i]) - { + for(int i = 0;i < path->elements.size;i++) { + switch(elements[i]) { case plutovg_path_element_move_to: plutovg_matrix_map_point(matrix, &points[0], &p[0]); - sw_ft_outline_move_to(outline, p[0].x, p[0].y); + ft_outline_move_to(outline, p[0].x, p[0].y); points += 1; break; case plutovg_path_element_line_to: plutovg_matrix_map_point(matrix, &points[0], &p[0]); - sw_ft_outline_line_to(outline, p[0].x, p[0].y); + ft_outline_line_to(outline, p[0].x, p[0].y); points += 1; break; case plutovg_path_element_cubic_to: plutovg_matrix_map_point(matrix, &points[0], &p[0]); plutovg_matrix_map_point(matrix, &points[1], &p[1]); plutovg_matrix_map_point(matrix, &points[2], &p[2]); - sw_ft_outline_cubic_to(outline, p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y); + ft_outline_cubic_to(outline, p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y); points += 3; break; case plutovg_path_element_close: - sw_ft_outline_close(outline); + ft_outline_close(outline); points += 1; break; } } - sw_ft_outline_end(outline); + ft_outline_end(outline); return outline; } -static SW_FT_Outline* sw_ft_outline_convert_dash(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_dash_t* dash) +static PVG_FT_Outline* ft_outline_convert_dash(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_dash_t* dash) { plutovg_path_t* dashed = plutovg_dash_path(dash, path); - SW_FT_Outline* outline = sw_ft_outline_convert(dashed, matrix); + PVG_FT_Outline* outline = ft_outline_convert(dashed, matrix); plutovg_path_destroy(dashed); return outline; } -static void generation_callback(int count, const SW_FT_Span* spans, void* user) +static void generation_callback(int count, const PVG_FT_Span* spans, void* user) { plutovg_rle_t* rle = user; plutovg_array_ensure(rle->spans, count); @@ -148,15 +142,6 @@ static void generation_callback(int count, const SW_FT_Span* spans, void* user) rle->spans.size += count; } -static void bbox_callback(int x, int y, int w, int h, void* user) -{ - plutovg_rle_t* rle = user; - rle->x = x; - rle->y = y; - rle->w = w; - rle->h = h; -} - plutovg_rle_t* plutovg_rle_create(void) { plutovg_rle_t* rle = malloc(sizeof(plutovg_rle_t)); @@ -180,28 +165,28 @@ void plutovg_rle_destroy(plutovg_rle_t* rle) #define SQRT2 1.41421356237309504880 void plutovg_rle_rasterize(plutovg_rle_t* rle, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_rect_t* clip, const plutovg_stroke_data_t* stroke, plutovg_fill_rule_t winding) { - SW_FT_Raster_Params params; - params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA; + PVG_FT_Raster_Params params; + params.flags = PVG_FT_RASTER_FLAG_DIRECT | PVG_FT_RASTER_FLAG_AA; params.gray_spans = generation_callback; - params.bbox_cb = bbox_callback; params.user = rle; - - if(clip) - { - params.flags |= SW_FT_RASTER_FLAG_CLIP; - params.clip_box.xMin = (SW_FT_Pos)clip->x; - params.clip_box.yMin = (SW_FT_Pos)clip->y; - params.clip_box.xMax = (SW_FT_Pos)(clip->x + clip->w); - params.clip_box.yMax = (SW_FT_Pos)(clip->y + clip->h); + if(clip) { + params.flags |= PVG_FT_RASTER_FLAG_CLIP; + params.clip_box.xMin = (PVG_FT_Pos)clip->x; + params.clip_box.yMin = (PVG_FT_Pos)clip->y; + params.clip_box.xMax = (PVG_FT_Pos)(clip->x + clip->w); + params.clip_box.yMax = (PVG_FT_Pos)(clip->y + clip->h); } - if(stroke) - { - SW_FT_Outline* outline = stroke->dash ? sw_ft_outline_convert_dash(path, matrix, stroke->dash) : sw_ft_outline_convert(path, matrix); - SW_FT_Stroker_LineCap ftCap; - SW_FT_Stroker_LineJoin ftJoin; - SW_FT_Fixed ftWidth; - SW_FT_Fixed ftMiterLimit; + if(stroke) { + PVG_FT_Outline* outline; + if(stroke->dash == NULL) + outline = ft_outline_convert(path, matrix); + else + outline = ft_outline_convert_dash(path, matrix, stroke->dash); + PVG_FT_Stroker_LineCap ftCap; + PVG_FT_Stroker_LineJoin ftJoin; + PVG_FT_Fixed ftWidth; + PVG_FT_Fixed ftMiterLimit; plutovg_point_t p1 = {0, 0}; plutovg_point_t p2 = {SQRT2, SQRT2}; @@ -215,62 +200,90 @@ void plutovg_rle_rasterize(plutovg_rle_t* rle, const plutovg_path_t* path, const double scale = sqrt(p3.x*p3.x + p3.y*p3.y) / 2.0; - ftWidth = (SW_FT_Fixed)(stroke->width * scale * 0.5 * (1 << 6)); - ftMiterLimit = (SW_FT_Fixed)(stroke->miterlimit * (1 << 16)); + ftWidth = (PVG_FT_Fixed)(stroke->width * scale * 0.5 * (1 << 6)); + ftMiterLimit = (PVG_FT_Fixed)(stroke->miterlimit * (1 << 16)); - switch(stroke->cap) - { + switch(stroke->cap) { case plutovg_line_cap_square: - ftCap = SW_FT_STROKER_LINECAP_SQUARE; + ftCap = PVG_FT_STROKER_LINECAP_SQUARE; break; case plutovg_line_cap_round: - ftCap = SW_FT_STROKER_LINECAP_ROUND; + ftCap = PVG_FT_STROKER_LINECAP_ROUND; break; default: - ftCap = SW_FT_STROKER_LINECAP_BUTT; + ftCap = PVG_FT_STROKER_LINECAP_BUTT; break; } - switch(stroke->join) - { + switch(stroke->join) { case plutovg_line_join_bevel: - ftJoin = SW_FT_STROKER_LINEJOIN_BEVEL; + ftJoin = PVG_FT_STROKER_LINEJOIN_BEVEL; break; case plutovg_line_join_round: - ftJoin = SW_FT_STROKER_LINEJOIN_ROUND; + ftJoin = PVG_FT_STROKER_LINEJOIN_ROUND; break; default: - ftJoin = SW_FT_STROKER_LINEJOIN_MITER_FIXED; + ftJoin = PVG_FT_STROKER_LINEJOIN_MITER_FIXED; break; } - SW_FT_Stroker stroker; - SW_FT_Stroker_New(&stroker); - SW_FT_Stroker_Set(stroker, ftWidth, ftCap, ftJoin, ftMiterLimit); - SW_FT_Stroker_ParseOutline(stroker, outline); + PVG_FT_Stroker stroker; + PVG_FT_Stroker_New(&stroker); + PVG_FT_Stroker_Set(stroker, ftWidth, ftCap, ftJoin, ftMiterLimit); + PVG_FT_Stroker_ParseOutline(stroker, outline); - SW_FT_UInt points; - SW_FT_UInt contours; - SW_FT_Stroker_GetCounts(stroker, &points, &contours); + PVG_FT_UInt points; + PVG_FT_UInt contours; + PVG_FT_Stroker_GetCounts(stroker, &points, &contours); - SW_FT_Outline* strokeOutline = sw_ft_outline_create((int)points, (int)contours); - SW_FT_Stroker_Export(stroker, strokeOutline); - SW_FT_Stroker_Done(stroker); + PVG_FT_Outline* strokeOutline = ft_outline_create(points, contours); + PVG_FT_Stroker_Export(stroker, strokeOutline); + PVG_FT_Stroker_Done(stroker); - strokeOutline->flags = SW_FT_OUTLINE_NONE; + strokeOutline->flags = PVG_FT_OUTLINE_NONE; params.source = strokeOutline; - sw_ft_grays_raster.raster_render(NULL, ¶ms); - sw_ft_outline_destroy(outline); - sw_ft_outline_destroy(strokeOutline); - } - else - { - SW_FT_Outline* outline = sw_ft_outline_convert(path, matrix); - outline->flags = winding == plutovg_fill_rule_even_odd ? SW_FT_OUTLINE_EVEN_ODD_FILL : SW_FT_OUTLINE_NONE; + PVG_FT_Raster_Render(¶ms); + ft_outline_destroy(outline); + ft_outline_destroy(strokeOutline); + } else { + PVG_FT_Outline* outline = ft_outline_convert(path, matrix); + switch(winding) { + case plutovg_fill_rule_even_odd: + outline->flags = PVG_FT_OUTLINE_EVEN_ODD_FILL; + break; + default: + outline->flags = PVG_FT_OUTLINE_NONE; + break; + } + params.source = outline; - sw_ft_grays_raster.raster_render(NULL, ¶ms); - sw_ft_outline_destroy(outline); + PVG_FT_Raster_Render(¶ms); + ft_outline_destroy(outline); } + + if(rle->spans.size == 0) { + rle->x = 0; + rle->y = 0; + rle->w = 0; + rle->h = 0; + return; + } + + plutovg_span_t* spans = rle->spans.data; + int x1 = INT_MAX; + int y1 = spans[0].y; + int x2 = 0; + int y2 = spans[rle->spans.size - 1].y; + for(int i = 0;i < rle->spans.size;i++) + { + if(spans[i].x < x1) x1 = spans[i].x; + if(spans[i].x + spans[i].len > x2) x2 = spans[i].x + spans[i].len; + } + + rle->x = x1; + rle->y = y1; + rle->w = x2 - x1; + rle->h = y2 - y1 + 1; } #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/3rdparty/software/CMakeLists.txt b/3rdparty/software/CMakeLists.txt deleted file mode 100755 index feb06bfc7..000000000 --- a/3rdparty/software/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -target_sources(lunasvg -PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/sw_ft_math.c" - "${CMAKE_CURRENT_LIST_DIR}/sw_ft_raster.c" - "${CMAKE_CURRENT_LIST_DIR}/sw_ft_stroker.c" -) - -target_include_directories(lunasvg -PRIVATE - "${CMAKE_CURRENT_LIST_DIR}" -) diff --git a/3rdparty/software/sw_ft_math.h b/3rdparty/software/sw_ft_math.h deleted file mode 100644 index 95a5c4257..000000000 --- a/3rdparty/software/sw_ft_math.h +++ /dev/null @@ -1,438 +0,0 @@ -#ifndef SW_FT_MATH_H -#define SW_FT_MATH_H - -/***************************************************************************/ -/* */ -/* fttrigon.h */ -/* */ -/* FreeType trigonometric functions (specification). */ -/* */ -/* Copyright 2001, 2003, 2005, 2007, 2013 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - -#include "sw_ft_types.h" - - -/*************************************************************************/ -/* */ -/* The min and max functions missing in C. As usual, be careful not to */ -/* write things like SW_FT_MIN( a++, b++ ) to avoid side effects. */ -/* */ -#define SW_FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) ) -#define SW_FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) ) - -#define SW_FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) - -/* - * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min' - * algorithm. We use alpha = 1, beta = 3/8, giving us results with a - * largest error less than 7% compared to the exact value. - */ -#define SW_FT_HYPOT( x, y ) \ - ( x = SW_FT_ABS( x ), \ - y = SW_FT_ABS( y ), \ - x > y ? x + ( 3 * y >> 3 ) \ - : y + ( 3 * x >> 3 ) ) - -/*************************************************************************/ -/* */ -/* */ -/* SW_FT_MulFix */ -/* */ -/* */ -/* A very simple function used to perform the computation */ -/* `(a*b)/0x10000' with maximum accuracy. Most of the time this is */ -/* used to multiply a given value by a 16.16 fixed-point factor. */ -/* */ -/* */ -/* a :: The first multiplier. */ -/* b :: The second multiplier. Use a 16.16 factor here whenever */ -/* possible (see note below). */ -/* */ -/* */ -/* The result of `(a*b)/0x10000'. */ -/* */ -/* */ -/* This function has been optimized for the case where the absolute */ -/* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */ -/* As this happens mainly when scaling from notional units to */ -/* fractional pixels in FreeType, it resulted in noticeable speed */ -/* improvements between versions 2.x and 1.x. */ -/* */ -/* As a conclusion, always try to place a 16.16 factor as the */ -/* _second_ argument of this function; this can make a great */ -/* difference. */ -/* */ -SW_FT_Long -SW_FT_MulFix( SW_FT_Long a, - SW_FT_Long b ); - -/*************************************************************************/ -/* */ -/* */ -/* SW_FT_MulDiv */ -/* */ -/* */ -/* A very simple function used to perform the computation `(a*b)/c' */ -/* with maximum accuracy (it uses a 64-bit intermediate integer */ -/* whenever necessary). */ -/* */ -/* This function isn't necessarily as fast as some processor specific */ -/* operations, but is at least completely portable. */ -/* */ -/* */ -/* a :: The first multiplier. */ -/* b :: The second multiplier. */ -/* c :: The divisor. */ -/* */ -/* */ -/* The result of `(a*b)/c'. This function never traps when trying to */ -/* divide by zero; it simply returns `MaxInt' or `MinInt' depending */ -/* on the signs of `a' and `b'. */ -/* */ -SW_FT_Long -SW_FT_MulDiv( SW_FT_Long a, - SW_FT_Long b, - SW_FT_Long c ); - -/*************************************************************************/ -/* */ -/* */ -/* SW_FT_DivFix */ -/* */ -/* */ -/* A very simple function used to perform the computation */ -/* `(a*0x10000)/b' with maximum accuracy. Most of the time, this is */ -/* used to divide a given value by a 16.16 fixed-point factor. */ -/* */ -/* */ -/* a :: The numerator. */ -/* b :: The denominator. Use a 16.16 factor here. */ -/* */ -/* */ -/* The result of `(a*0x10000)/b'. */ -/* */ -SW_FT_Long -SW_FT_DivFix( SW_FT_Long a, - SW_FT_Long b ); - - - - /*************************************************************************/ - /* */ - /*
*/ - /* computations */ - /* */ - /*************************************************************************/ - - - /************************************************************************* - * - * @type: - * SW_FT_Angle - * - * @description: - * This type is used to model angle values in FreeType. Note that the - * angle is a 16.16 fixed-point value expressed in degrees. - * - */ - typedef SW_FT_Fixed SW_FT_Angle; - - - /************************************************************************* - * - * @macro: - * SW_FT_ANGLE_PI - * - * @description: - * The angle pi expressed in @SW_FT_Angle units. - * - */ -#define SW_FT_ANGLE_PI ( 180L << 16 ) - - - /************************************************************************* - * - * @macro: - * SW_FT_ANGLE_2PI - * - * @description: - * The angle 2*pi expressed in @SW_FT_Angle units. - * - */ -#define SW_FT_ANGLE_2PI ( SW_FT_ANGLE_PI * 2 ) - - - /************************************************************************* - * - * @macro: - * SW_FT_ANGLE_PI2 - * - * @description: - * The angle pi/2 expressed in @SW_FT_Angle units. - * - */ -#define SW_FT_ANGLE_PI2 ( SW_FT_ANGLE_PI / 2 ) - - - /************************************************************************* - * - * @macro: - * SW_FT_ANGLE_PI4 - * - * @description: - * The angle pi/4 expressed in @SW_FT_Angle units. - * - */ -#define SW_FT_ANGLE_PI4 ( SW_FT_ANGLE_PI / 4 ) - - - /************************************************************************* - * - * @function: - * SW_FT_Sin - * - * @description: - * Return the sinus of a given angle in fixed-point format. - * - * @input: - * angle :: - * The input angle. - * - * @return: - * The sinus value. - * - * @note: - * If you need both the sinus and cosinus for a given angle, use the - * function @SW_FT_Vector_Unit. - * - */ - SW_FT_Fixed - SW_FT_Sin( SW_FT_Angle angle ); - - - /************************************************************************* - * - * @function: - * SW_FT_Cos - * - * @description: - * Return the cosinus of a given angle in fixed-point format. - * - * @input: - * angle :: - * The input angle. - * - * @return: - * The cosinus value. - * - * @note: - * If you need both the sinus and cosinus for a given angle, use the - * function @SW_FT_Vector_Unit. - * - */ - SW_FT_Fixed - SW_FT_Cos( SW_FT_Angle angle ); - - - /************************************************************************* - * - * @function: - * SW_FT_Tan - * - * @description: - * Return the tangent of a given angle in fixed-point format. - * - * @input: - * angle :: - * The input angle. - * - * @return: - * The tangent value. - * - */ - SW_FT_Fixed - SW_FT_Tan( SW_FT_Angle angle ); - - - /************************************************************************* - * - * @function: - * SW_FT_Atan2 - * - * @description: - * Return the arc-tangent corresponding to a given vector (x,y) in - * the 2d plane. - * - * @input: - * x :: - * The horizontal vector coordinate. - * - * y :: - * The vertical vector coordinate. - * - * @return: - * The arc-tangent value (i.e. angle). - * - */ - SW_FT_Angle - SW_FT_Atan2( SW_FT_Fixed x, - SW_FT_Fixed y ); - - - /************************************************************************* - * - * @function: - * SW_FT_Angle_Diff - * - * @description: - * Return the difference between two angles. The result is always - * constrained to the ]-PI..PI] interval. - * - * @input: - * angle1 :: - * First angle. - * - * angle2 :: - * Second angle. - * - * @return: - * Constrained value of `value2-value1'. - * - */ - SW_FT_Angle - SW_FT_Angle_Diff( SW_FT_Angle angle1, - SW_FT_Angle angle2 ); - - - /************************************************************************* - * - * @function: - * SW_FT_Vector_Unit - * - * @description: - * Return the unit vector corresponding to a given angle. After the - * call, the value of `vec.x' will be `sin(angle)', and the value of - * `vec.y' will be `cos(angle)'. - * - * This function is useful to retrieve both the sinus and cosinus of a - * given angle quickly. - * - * @output: - * vec :: - * The address of target vector. - * - * @input: - * angle :: - * The input angle. - * - */ - void - SW_FT_Vector_Unit( SW_FT_Vector* vec, - SW_FT_Angle angle ); - - - /************************************************************************* - * - * @function: - * SW_FT_Vector_Rotate - * - * @description: - * Rotate a vector by a given angle. - * - * @inout: - * vec :: - * The address of target vector. - * - * @input: - * angle :: - * The input angle. - * - */ - void - SW_FT_Vector_Rotate( SW_FT_Vector* vec, - SW_FT_Angle angle ); - - - /************************************************************************* - * - * @function: - * SW_FT_Vector_Length - * - * @description: - * Return the length of a given vector. - * - * @input: - * vec :: - * The address of target vector. - * - * @return: - * The vector length, expressed in the same units that the original - * vector coordinates. - * - */ - SW_FT_Fixed - SW_FT_Vector_Length( SW_FT_Vector* vec ); - - - /************************************************************************* - * - * @function: - * SW_FT_Vector_Polarize - * - * @description: - * Compute both the length and angle of a given vector. - * - * @input: - * vec :: - * The address of source vector. - * - * @output: - * length :: - * The vector length. - * - * angle :: - * The vector angle. - * - */ - void - SW_FT_Vector_Polarize( SW_FT_Vector* vec, - SW_FT_Fixed *length, - SW_FT_Angle *angle ); - - - /************************************************************************* - * - * @function: - * SW_FT_Vector_From_Polar - * - * @description: - * Compute vector coordinates from a length and angle. - * - * @output: - * vec :: - * The address of source vector. - * - * @input: - * length :: - * The vector length. - * - * angle :: - * The vector angle. - * - */ - void - SW_FT_Vector_From_Polar( SW_FT_Vector* vec, - SW_FT_Fixed length, - SW_FT_Angle angle ); - - -#endif // SW_FT_MATH_H diff --git a/3rdparty/software/sw_ft_raster.c b/3rdparty/software/sw_ft_raster.c deleted file mode 100644 index b38d799d6..000000000 --- a/3rdparty/software/sw_ft_raster.c +++ /dev/null @@ -1,1423 +0,0 @@ -/***************************************************************************/ -/* */ -/* ftgrays.c */ -/* */ -/* A new `perfect' anti-aliasing renderer (body). */ -/* */ -/* Copyright 2000-2003, 2005-2014 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - -/*************************************************************************/ -/* */ -/* 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_ */ -/* coverage of the outline on each pixel cell. */ -/* */ -/* It is based on ideas that I initially found in Raph Levien's */ -/* excellent LibArt graphics library (see http://www.levien.com/libart */ -/* for more information, though the web pages do not tell anything */ -/* about the renderer; you'll have to dive into the source code to */ -/* understand how it works). */ -/* */ -/* Note, however, that this is a _very_ different implementation */ -/* compared to Raph's. Coverage information is stored in a very */ -/* different way, and I don't use sorted vector paths. Also, it doesn't */ -/* use floating point values. */ -/* */ -/* This renderer has the following advantages: */ -/* */ -/* - It doesn't need an intermediate bitmap. Instead, one can supply a */ -/* callback function that will be called by the renderer to draw gray */ -/* spans on any target surface. You can thus do direct composition on */ -/* any kind of bitmap, provided that you give the renderer the right */ -/* callback. */ -/* */ -/* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */ -/* each pixel cell. */ -/* */ -/* - It performs a single pass on the outline (the `standard' FT2 */ -/* renderer makes two passes). */ -/* */ -/* - It can easily be modified to render to _any_ number of gray levels */ -/* cheaply. */ -/* */ -/* - For small (< 20) pixel sizes, it is faster than the standard */ -/* renderer. */ -/* */ -/*************************************************************************/ - -#include "sw_ft_raster.h" -#include "sw_ft_math.h" - -/* Auxiliary macros for token concatenation. */ -#define SW_FT_ERR_XCAT(x, y) x##y -#define SW_FT_ERR_CAT(x, y) SW_FT_ERR_XCAT(x, y) - -#define SW_FT_BEGIN_STMNT do { -#define SW_FT_END_STMNT \ - } \ - 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 -#define SW_FT_CHAR_BIT CHAR_BIT - -#define ft_memset memset - -#define ft_setjmp setjmp -#define ft_longjmp longjmp -#define ft_jmp_buf jmp_buf - -typedef ptrdiff_t SW_FT_PtrDist; - -#define ErrRaster_Invalid_Mode -2 -#define ErrRaster_Invalid_Outline -1 -#define ErrRaster_Invalid_Argument -3 -#define ErrRaster_Memory_Overflow -4 - -#define SW_FT_BEGIN_HEADER -#define SW_FT_END_HEADER - -/* This macro is used to indicate that a function parameter is unused. */ -/* Its purpose is simply to reduce compiler warnings. Note also that */ -/* simply defining it as `(void)x' doesn't avoid warnings with certain */ -/* ANSI compilers (e.g. LCC). */ -#define SW_FT_UNUSED(x) (x) = (x) - -#define SW_FT_THROW(e) SW_FT_ERR_CAT(ErrRaster_, e) - -/* The size in bytes of the render pool used by the scan-line converter */ -/* to do all of its work. */ -#define SW_FT_RENDER_POOL_SIZE 16384L - -typedef int (*SW_FT_Outline_MoveToFunc)(const SW_FT_Vector* to, void* user); - -#define SW_FT_Outline_MoveTo_Func SW_FT_Outline_MoveToFunc - -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); - -#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); - -#define SW_FT_Outline_CubicTo_Func SW_FT_Outline_CubicToFunc - -typedef struct SW_FT_Outline_Funcs_ { - SW_FT_Outline_MoveToFunc move_to; - 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_}; - -#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_}; - -#ifndef SW_FT_MEM_SET -#define SW_FT_MEM_SET(d, s, c) ft_memset(d, s, c) -#endif - -#ifndef SW_FT_MEM_ZERO -#define SW_FT_MEM_ZERO(dest, count) SW_FT_MEM_SET(dest, 0, count) -#endif - -/* as usual, for the speed hungry :-) */ - -#undef RAS_ARG -#undef RAS_ARG_ -#undef RAS_VAR -#undef RAS_VAR_ - -#ifndef SW_FT_STATIC_RASTER - -#define RAS_ARG gray_PWorker worker -#define RAS_ARG_ gray_PWorker worker, - -#define RAS_VAR worker -#define RAS_VAR_ worker, - -#else /* SW_FT_STATIC_RASTER */ - -#define RAS_ARG /* empty */ -#define RAS_ARG_ /* empty */ -#define RAS_VAR /* empty */ -#define RAS_VAR_ /* empty */ - -#endif /* SW_FT_STATIC_RASTER */ - -/* must be at least 6 bits! */ -#define PIXEL_BITS 8 - -#undef FLOOR -#undef CEILING -#undef TRUNC -#undef SCALED - -#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 FLOOR(x) ((x) & -ONE_PIXEL) -#define CEILING(x) (((x) + ONE_PIXEL - 1) & -ONE_PIXEL) -#define ROUND(x) (((x) + ONE_PIXEL / 2) & -ONE_PIXEL) - -#if PIXEL_BITS >= 6 -#define UPSCALE(x) ((x) << (PIXEL_BITS - 6)) -#define DOWNSCALE(x) ((x) >> (PIXEL_BITS - 6)) -#else -#define UPSCALE(x) ((x) >> (6 - PIXEL_BITS)) -#define DOWNSCALE(x) ((x) << (6 - PIXEL_BITS)) -#endif - -/* Compute `dividend / divisor' and return both its quotient and */ -/* 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 - -#ifdef __arm__ -/* Work around a bug specific to GCC which make the compiler fail to */ -/* optimize a division and modulo operation on the same parameters */ -/* into a single call to `__aeabi_idivmod'. See */ -/* */ -/* 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 -#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)) - -/*************************************************************************/ -/* */ -/* TYPE DEFINITIONS */ -/* */ - -/* don't change the following types to SW_FT_Int or SW_FT_Pos, since we might */ -/* need to define them to "float" or "double" when experimenting with */ -/* new algorithms */ - -typedef long TCoord; /* integer scanline/pixel coordinate */ -typedef long TPos; /* sub-pixel coordinate */ - -/* determine the type used to store cell areas. This normally takes at */ -/* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */ -/* `long' instead of `int', otherwise bad things happen */ - -#if PIXEL_BITS <= 7 - -typedef int TArea; - -#else /* PIXEL_BITS >= 8 */ - -/* approximately determine the size of integers using an ANSI-C header */ -#if SW_FT_UINT_MAX == 0xFFFFU -typedef long TArea; -#else -typedef int TArea; -#endif - -#endif /* PIXEL_BITS >= 8 */ - -/* maximum number of gray spans in a call to the span callback */ -#define SW_FT_MAX_GRAY_SPANS 256 - -typedef struct TCell_* PCell; - -typedef struct TCell_ { - TPos x; /* same with gray_TWorker.ex */ - TCoord cover; /* same with gray_TWorker.cover */ - TArea area; - PCell next; - -} TCell; - -#if defined(_MSC_VER) /* Visual C++ (and Intel C++) */ -/* We disable the warning `structure was padded due to */ -/* __declspec(align())' in order to compile cleanly with */ -/* the maximum level of warnings. */ -#pragma warning(push) -#pragma warning(disable : 4324) -#endif /* _MSC_VER */ - -typedef struct gray_TWorker_ { - 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) -#pragma warning(pop) -#endif - -#ifndef SW_FT_STATIC_RASTER -#define ras (*worker) -#else -static gray_TWorker ras; -#endif - -typedef struct gray_TRaster_ { - void* memory; - -} gray_TRaster, *gray_PRaster; - -/*************************************************************************/ -/* */ -/* Initialize the cells table. */ -/* */ -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; - ras.num_cells = 0; - ras.area = 0; - ras.cover = 0; - ras.invalid = 1; - - ras.bound_left = INT_MAX; - ras.bound_top = INT_MAX; - ras.bound_right = INT_MIN; - ras.bound_bottom = INT_MIN; -} - -/*************************************************************************/ -/* */ -/* Compute the outline bounding box. */ -/* */ -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; - ras.max_ex = (ras.max_ex + 63) >> 6; - ras.max_ey = (ras.max_ey + 63) >> 6; -} - -/*************************************************************************/ -/* */ -/* Record the current cell in the table. */ -/* */ -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; -} - -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; - } -} - -/*************************************************************************/ -/* */ -/* Set the current cell to a new position. */ -/* */ -static void gray_set_cell(RAS_ARG_ TCoord ex, TCoord ey) -{ - /* Move the cell pointer to a new position. We set the `invalid' */ - /* flag to indicate that the cell isn't part of those we're interested */ - /* in during the render phase. This means that: */ - /* */ - /* . the new vertical position must be within min_ey..max_ey-1. */ - /* . the new horizontal position must be strictly less than max_ex */ - /* */ - /* 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); -} - -/*************************************************************************/ -/* */ -/* Start a new contour at a given cell. */ -/* */ -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); -} - -/*************************************************************************/ -/* */ -/* Render a straight line across multiple cells in any direction. */ -/* */ -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); - - /* perform vertical clipping */ - if ((ey1 >= ras.max_ey && ey2 >= ras.max_ey) || - (ey1 < ras.min_ey && ey2 < ras.min_ey)) - goto End; - - 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 */ - { - 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 */ - { - 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 */ - { - fx2 = 0; - fy2 = (TPos)SW_FT_UDIV(-prod, -dx); - prod -= dy * ONE_PIXEL; - 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 */ - { - prod -= dx * ONE_PIXEL; - fx2 = (TPos)SW_FT_UDIV(-prod, dy); - fy2 = ONE_PIXEL; - 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 */ - { - prod += dy * ONE_PIXEL; - fx2 = ONE_PIXEL; - 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 */ - { - fx2 = (TPos)SW_FT_UDIV(prod, -dy); - fy2 = 0; - prod += dx * ONE_PIXEL; - 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); - } - - fx2 = to_x - SUBPIXELS(ex2); - fy2 = to_y - SUBPIXELS(ey2); - - ras.cover += (fy2 - fy1); - ras.area += (fy2 - fy1) * (fx1 + fx2); - -End: - ras.x = to_x; - ras.y = to_y; -} - -static void gray_split_conic(SW_FT_Vector* base) -{ - 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; - - 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; -} - -static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, - const SW_FT_Vector* to) -{ - TPos dx, dy; - TPos min, max, y; - 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); - arc[1].x = UPSCALE(control->x); - arc[1].y = UPSCALE(control->y); - 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) { - gray_split_conic(arc); - arc += 2; - top++; - 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; - - - 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; - - 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; -} - - -static void -gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, - const SW_FT_Vector* control2, - const SW_FT_Vector* to) -{ - SW_FT_Vector* arc = ras.bez_stack; - - arc[0].x = UPSCALE( to->x ); - arc[0].y = UPSCALE( to->y ); - arc[1].x = UPSCALE( control2->x ); - arc[1].y = UPSCALE( control2->y ); - arc[2].x = UPSCALE( control1->x ); - 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 */ - if ( ( TRUNC( arc[0].y ) >= ras.max_ey && - TRUNC( arc[1].y ) >= ras.max_ey && - TRUNC( arc[2].y ) >= ras.max_ey && - TRUNC( arc[3].y ) >= ras.max_ey ) || - ( TRUNC( arc[0].y ) < ras.min_ey && - TRUNC( arc[1].y ) < ras.min_ey && - TRUNC( arc[2].y ) < ras.min_ey && - TRUNC( arc[3].y ) < ras.min_ey ) ) - { - ras.x = arc[0].x; - ras.y = arc[0].y; - return; - } - - for (;;) - { - /* with each split, control points quickly converge towards */ - /* chord trisection points and the vanishing distances below */ - /* indicate when the segment is flat enough to draw */ - if ( SW_FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 || - SW_FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 || - SW_FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 || - SW_FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 ) - goto Split; - - gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); - - if ( arc == ras.bez_stack ) - return; - - arc -= 3; - continue; - - Split: - gray_split_cubic( arc ); - arc += 3; - } -} - -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; -} - -static int gray_line_to(const SW_FT_Vector* to, gray_PWorker worker) -{ - gray_render_line(RAS_VAR_ UPSCALE(to->x), UPSCALE(to->y)); - return 0; -} - -static int gray_conic_to(const SW_FT_Vector* control, const SW_FT_Vector* to, - gray_PWorker worker) -{ - gray_render_conic(RAS_VAR_ control, to); - return 0; -} - -static int gray_cubic_to(const SW_FT_Vector* control1, - const SW_FT_Vector* control2, const SW_FT_Vector* to, - gray_PWorker worker) -{ - gray_render_cubic(RAS_VAR_ control1, control2, to); - return 0; -} - -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 */ - /* */ - /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */ - /* */ - 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) - coverage = 255; - } else { - /* 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; - if (count > 0 && span->y == y && (int)span->x + span->len == (int)x && - span->coverage == coverage) { - 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++) - fprintf(stderr, "[%d , %d..%d] : %d ", span->y, span->x, - 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++; - } -} - -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); -} - -/*************************************************************************/ -/* */ -/* The following function should only compile in stand-alone mode, */ -/* i.e., when building this component without the rest of FreeType. */ -/* */ -/*************************************************************************/ - -/*************************************************************************/ -/* */ -/* */ -/* SW_FT_Outline_Decompose */ -/* */ -/* */ -/* Walk over an outline's structure to decompose it into individual */ -/* segments and Bézier arcs. This function is also able to emit */ -/* `move to' and `close to' operations to indicate the start and end */ -/* of new contours in the outline. */ -/* */ -/* */ -/* outline :: A pointer to the source target. */ -/* */ -/* func_interface :: A table of `emitters', i.e., function pointers */ -/* called during decomposition to indicate path */ -/* operations. */ -/* */ -/* */ -/* user :: A typeless pointer which is passed to each */ -/* emitter during the decomposition. It can be */ -/* used to store the state during the */ -/* decomposition. */ -/* */ -/* */ -/* Error code. 0 means success. */ -/* */ -static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, - const SW_FT_Outline_Funcs* func_interface, - void* user) -{ -#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); - - 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. */ - if (SW_FT_CURVE_TAG(outline->tags[last]) == SW_FT_CURVE_TAG_ON) { - /* start at last point if it is on the curve */ - v_start = v_last; - limit--; - } else { - /* if both first and last points are conic, */ - /* start at their middle and record its position */ - /* for closure */ - v_start.x = (v_start.x + v_last.x) / 2; - v_start.y = (v_start.y + v_last.y) / 2; - } - 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) { - 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; - } - - 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, - (SW_FT_Outline_MoveTo_Func)gray_move_to, - (SW_FT_Outline_LineTo_Func)gray_line_to, - (SW_FT_Outline_ConicTo_Func)gray_conic_to, - (SW_FT_Outline_CubicTo_Func)gray_cubic_to, 0, 0) - -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; -} - -static int gray_convert_glyph(RAS_ARG) -{ - gray_TBand bands[40]; - gray_TBand* volatile band; - 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; - band[0].max = top; - band++; - } - } - - if (ras.band_shoot > 8 && ras.band_size > 16) - ras.band_size = ras.band_size / 2; - - return 0; -} - -static int gray_raster_render(gray_PRaster raster, - const SW_FT_Raster_Params* params) -{ - 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 { - ras.clip_box.xMin = -32768L; - ras.clip_box.yMin = -32768L; - 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, - ras.bound_bottom - ras.bound_top + 1, params->user); - return 1; -} - -/**** RASTER OBJECT CREATION: In stand-alone mode, we simply use *****/ -/**** a static object. *****/ - -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; -} - -static void gray_raster_done(SW_FT_Raster raster) -{ - /* nothing */ - SW_FT_UNUSED(raster); -} - -static void gray_raster_reset(SW_FT_Raster raster, char* pool_base, - long pool_size) -{ - SW_FT_UNUSED(raster); - SW_FT_UNUSED(pool_base); - SW_FT_UNUSED(pool_size); -} - -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, - (SW_FT_Raster_Done_Func)gray_raster_done) - -/* END */ diff --git a/3rdparty/software/sw_ft_raster.h b/3rdparty/software/sw_ft_raster.h deleted file mode 100644 index 85a69bc32..000000000 --- a/3rdparty/software/sw_ft_raster.h +++ /dev/null @@ -1,607 +0,0 @@ -#ifndef SW_FT_IMG_H -#define SW_FT_IMG_H -/***************************************************************************/ -/* */ -/* ftimage.h */ -/* */ -/* FreeType glyph image formats and default raster interface */ -/* (specification). */ -/* */ -/* Copyright 1996-2010, 2013 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - /*************************************************************************/ - /* */ - /* Note: A `raster' is simply a scan-line converter, used to render */ - /* SW_FT_Outlines into SW_FT_Bitmaps. */ - /* */ - /*************************************************************************/ - -#include "sw_ft_types.h" - - /*************************************************************************/ - /* */ - /* */ - /* FT_BBox */ - /* */ - /* */ - /* A structure used to hold an outline's bounding box, i.e., the */ - /* coordinates of its extrema in the horizontal and vertical */ - /* directions. */ - /* */ - /* */ - /* xMin :: The horizontal minimum (left-most). */ - /* */ - /* yMin :: The vertical minimum (bottom-most). */ - /* */ - /* xMax :: The horizontal maximum (right-most). */ - /* */ - /* yMax :: The vertical maximum (top-most). */ - /* */ - /* */ - /* The bounding box is specified with the coordinates of the lower */ - /* left and the upper right corner. In PostScript, those values are */ - /* often called (llx,lly) and (urx,ury), respectively. */ - /* */ - /* If `yMin' is negative, this value gives the glyph's descender. */ - /* Otherwise, the glyph doesn't descend below the baseline. */ - /* Similarly, if `ymax' is positive, this value gives the glyph's */ - /* ascender. */ - /* */ - /* `xMin' gives the horizontal distance from the glyph's origin to */ - /* the left edge of the glyph's bounding box. If `xMin' is negative, */ - /* the glyph extends to the left of the origin. */ - /* */ - typedef struct SW_FT_BBox_ - { - SW_FT_Pos xMin, yMin; - SW_FT_Pos xMax, yMax; - - } SW_FT_BBox; - -/*************************************************************************/ -/* */ -/* */ -/* SW_FT_Outline */ -/* */ -/* */ -/* This structure is used to describe an outline to the scan-line */ -/* converter. */ -/* */ -/* */ -/* n_contours :: The number of contours in the outline. */ -/* */ -/* n_points :: The number of points in the outline. */ -/* */ -/* points :: A pointer to an array of `n_points' @SW_FT_Vector */ -/* elements, giving the outline's point coordinates. */ -/* */ -/* tags :: A pointer to an array of `n_points' chars, giving */ -/* each outline point's type. */ -/* */ -/* If bit~0 is unset, the point is `off' the curve, */ -/* i.e., a Bézier control point, while it is `on' if */ -/* set. */ -/* */ -/* Bit~1 is meaningful for `off' points only. If set, */ -/* it indicates a third-order Bézier arc control point; */ -/* and a second-order control point if unset. */ -/* */ -/* If bit~2 is set, bits 5-7 contain the drop-out mode */ -/* (as defined in the OpenType specification; the value */ -/* is the same as the argument to the SCANMODE */ -/* instruction). */ -/* */ -/* Bits 3 and~4 are reserved for internal purposes. */ -/* */ -/* contours :: An array of `n_contours' shorts, giving the end */ -/* point of each contour within the outline. For */ -/* example, the first contour is defined by the points */ -/* `0' to `contours[0]', the second one is defined by */ -/* the points `contours[0]+1' to `contours[1]', etc. */ -/* */ -/* flags :: A set of bit flags used to characterize the outline */ -/* and give hints to the scan-converter and hinter on */ -/* how to convert/grid-fit it. See @SW_FT_OUTLINE_FLAGS.*/ -/* */ -typedef struct SW_FT_Outline_ -{ - int n_contours; /* number of contours in glyph */ - int n_points; /* number of points in the glyph */ - - SW_FT_Vector* points; /* the outline's points */ - char* tags; /* the points flags */ - int* contours; /* the contour end points */ - char* contours_flag; /* the contour open flags */ - - int flags; /* outline masks */ - -} SW_FT_Outline; - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_OUTLINE_FLAGS */ - /* */ - /* */ - /* A list of bit-field constants use for the flags in an outline's */ - /* `flags' field. */ - /* */ - /* */ - /* SW_FT_OUTLINE_NONE :: */ - /* Value~0 is reserved. */ - /* */ - /* SW_FT_OUTLINE_OWNER :: */ - /* If set, this flag indicates that the outline's field arrays */ - /* (i.e., `points', `flags', and `contours') are `owned' by the */ - /* outline object, and should thus be freed when it is destroyed. */ - /* */ - /* SW_FT_OUTLINE_EVEN_ODD_FILL :: */ - /* By default, outlines are filled using the non-zero winding rule. */ - /* If set to 1, the outline will be filled using the even-odd fill */ - /* rule (only works with the smooth rasterizer). */ - /* */ - /* SW_FT_OUTLINE_REVERSE_FILL :: */ - /* By default, outside contours of an outline are oriented in */ - /* clock-wise direction, as defined in the TrueType specification. */ - /* This flag is set if the outline uses the opposite direction */ - /* (typically for Type~1 fonts). This flag is ignored by the scan */ - /* converter. */ - /* */ - /* */ - /* */ - /* There exists a second mechanism to pass the drop-out mode to the */ - /* B/W rasterizer; see the `tags' field in @SW_FT_Outline. */ - /* */ - /* Please refer to the description of the `SCANTYPE' instruction in */ - /* the OpenType specification (in file `ttinst1.doc') how simple */ - /* drop-outs, smart drop-outs, and stubs are defined. */ - /* */ -#define SW_FT_OUTLINE_NONE 0x0 -#define SW_FT_OUTLINE_OWNER 0x1 -#define SW_FT_OUTLINE_EVEN_ODD_FILL 0x2 -#define SW_FT_OUTLINE_REVERSE_FILL 0x4 - - /* */ - -#define SW_FT_CURVE_TAG( flag ) ( flag & 3 ) - -#define SW_FT_CURVE_TAG_ON 1 -#define SW_FT_CURVE_TAG_CONIC 0 -#define SW_FT_CURVE_TAG_CUBIC 2 - - -#define SW_FT_Curve_Tag_On SW_FT_CURVE_TAG_ON -#define SW_FT_Curve_Tag_Conic SW_FT_CURVE_TAG_CONIC -#define SW_FT_Curve_Tag_Cubic SW_FT_CURVE_TAG_CUBIC - - /*************************************************************************/ - /* */ - /* A raster is a scan converter, in charge of rendering an outline into */ - /* a a bitmap. This section contains the public API for rasters. */ - /* */ - /* Note that in FreeType 2, all rasters are now encapsulated within */ - /* specific modules called `renderers'. See `ftrender.h' for more */ - /* details on renderers. */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Raster */ - /* */ - /* */ - /* A handle (pointer) to a raster object. Each object can be used */ - /* independently to convert an outline into a bitmap or pixmap. */ - /* */ - typedef struct SW_FT_RasterRec_* SW_FT_Raster; - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Span */ - /* */ - /* */ - /* A structure used to model a single span of gray (or black) pixels */ - /* when rendering a monochrome or anti-aliased bitmap. */ - /* */ - /* */ - /* x :: The span's horizontal start position. */ - /* */ - /* len :: The span's length in pixels. */ - /* */ - /* coverage :: The span color/coverage, ranging from 0 (background) */ - /* to 255 (foreground). Only used for anti-aliased */ - /* rendering. */ - /* */ - /* */ - /* This structure is used by the span drawing callback type named */ - /* @SW_FT_SpanFunc that takes the y~coordinate of the span as a */ - /* parameter. */ - /* */ - /* The coverage value is always between 0 and 255. If you want less */ - /* gray values, the callback function has to reduce them. */ - /* */ - typedef struct SW_FT_Span_ - { - short x; - short y; - unsigned short len; - unsigned char coverage; - - } SW_FT_Span; - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_SpanFunc */ - /* */ - /* */ - /* A function used as a call-back by the anti-aliased renderer in */ - /* order to let client applications draw themselves the gray pixel */ - /* spans on each scan line. */ - /* */ - /* */ - /* y :: The scanline's y~coordinate. */ - /* */ - /* count :: The number of spans to draw on this scanline. */ - /* */ - /* spans :: A table of `count' spans to draw on the scanline. */ - /* */ - /* user :: User-supplied data that is passed to the callback. */ - /* */ - /* */ - /* This callback allows client applications to directly render the */ - /* gray spans of the anti-aliased bitmap to any kind of surfaces. */ - /* */ - /* This can be used to write anti-aliased outlines directly to a */ - /* given background bitmap, and even perform translucency. */ - /* */ - /* Note that the `count' field cannot be greater than a fixed value */ - /* defined by the `SW_FT_MAX_GRAY_SPANS' configuration macro in */ - /* `ftoption.h'. By default, this value is set to~32, which means */ - /* that if there are more than 32~spans on a given scanline, the */ - /* callback is called several times with the same `y' parameter in */ - /* order to draw all callbacks. */ - /* */ - /* Otherwise, the callback is only called once per scan-line, and */ - /* only for those scanlines that do have `gray' pixels on them. */ - /* */ - typedef void - (*SW_FT_SpanFunc)( int count, - const SW_FT_Span* spans, - void* user ); - - typedef void - (*SW_FT_BboxFunc)( int x, int y, int w, int h, - void* user); - -#define SW_FT_Raster_Span_Func SW_FT_SpanFunc - - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_RASTER_FLAG_XXX */ - /* */ - /* */ - /* A list of bit flag constants as used in the `flags' field of a */ - /* @SW_FT_Raster_Params structure. */ - /* */ - /* */ - /* SW_FT_RASTER_FLAG_DEFAULT :: This value is 0. */ - /* */ - /* SW_FT_RASTER_FLAG_AA :: This flag is set to indicate that an */ - /* anti-aliased glyph image should be */ - /* generated. Otherwise, it will be */ - /* monochrome (1-bit). */ - /* */ - /* SW_FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */ - /* rendering. In this mode, client */ - /* applications must provide their own span */ - /* callback. This lets them directly */ - /* draw or compose over an existing bitmap. */ - /* If this bit is not set, the target */ - /* pixmap's buffer _must_ be zeroed before */ - /* rendering. */ - /* */ - /* Note that for now, direct rendering is */ - /* only possible with anti-aliased glyphs. */ - /* */ - /* SW_FT_RASTER_FLAG_CLIP :: This flag is only used in direct */ - /* rendering mode. If set, the output will */ - /* be clipped to a box specified in the */ - /* `clip_box' field of the */ - /* @SW_FT_Raster_Params structure. */ - /* */ - /* Note that by default, the glyph bitmap */ - /* is clipped to the target pixmap, except */ - /* in direct rendering mode where all spans */ - /* are generated if no clipping box is set. */ - /* */ -#define SW_FT_RASTER_FLAG_DEFAULT 0x0 -#define SW_FT_RASTER_FLAG_AA 0x1 -#define SW_FT_RASTER_FLAG_DIRECT 0x2 -#define SW_FT_RASTER_FLAG_CLIP 0x4 - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Raster_Params */ - /* */ - /* */ - /* A structure to hold the arguments used by a raster's render */ - /* function. */ - /* */ - /* */ - /* target :: The target bitmap. */ - /* */ - /* source :: A pointer to the source glyph image (e.g., an */ - /* @SW_FT_Outline). */ - /* */ - /* flags :: The rendering flags. */ - /* */ - /* gray_spans :: The gray span drawing callback. */ - /* */ - /* black_spans :: The black span drawing callback. UNIMPLEMENTED! */ - /* */ - /* bit_test :: The bit test callback. UNIMPLEMENTED! */ - /* */ - /* bit_set :: The bit set callback. UNIMPLEMENTED! */ - /* */ - /* user :: User-supplied data that is passed to each drawing */ - /* callback. */ - /* */ - /* clip_box :: An optional clipping box. It is only used in */ - /* direct rendering mode. Note that coordinates here */ - /* should be expressed in _integer_ pixels (and not in */ - /* 26.6 fixed-point units). */ - /* */ - /* */ - /* An anti-aliased glyph bitmap is drawn if the @SW_FT_RASTER_FLAG_AA */ - /* bit flag is set in the `flags' field, otherwise a monochrome */ - /* bitmap is generated. */ - /* */ - /* If the @SW_FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */ - /* raster will call the `gray_spans' callback to draw gray pixel */ - /* spans, in the case of an aa glyph bitmap, it will call */ - /* `black_spans', and `bit_test' and `bit_set' in the case of a */ - /* monochrome bitmap. This allows direct composition over a */ - /* pre-existing bitmap through user-provided callbacks to perform the */ - /* span drawing/composition. */ - /* */ - /* Note that the `bit_test' and `bit_set' callbacks are required when */ - /* rendering a monochrome bitmap, as they are crucial to implement */ - /* correct drop-out control as defined in the TrueType specification. */ - /* */ - typedef struct SW_FT_Raster_Params_ - { - const void* source; - int flags; - SW_FT_SpanFunc gray_spans; - SW_FT_BboxFunc bbox_cb; - void* user; - SW_FT_BBox clip_box; - - } SW_FT_Raster_Params; - - -/*************************************************************************/ -/* */ -/* */ -/* SW_FT_Outline_Check */ -/* */ -/* */ -/* Check the contents of an outline descriptor. */ -/* */ -/* */ -/* outline :: A handle to a source outline. */ -/* */ -/* */ -/* FreeType error code. 0~means success. */ -/* */ -SW_FT_Error -SW_FT_Outline_Check( SW_FT_Outline* outline ); - - -/*************************************************************************/ -/* */ -/* */ -/* SW_FT_Outline_Get_CBox */ -/* */ -/* */ -/* Return an outline's `control box'. The control box encloses all */ -/* the outline's points, including Bézier control points. Though it */ -/* coincides with the exact bounding box for most glyphs, it can be */ -/* slightly larger in some situations (like when rotating an outline */ -/* that contains Bézier outside arcs). */ -/* */ -/* Computing the control box is very fast, while getting the bounding */ -/* box can take much more time as it needs to walk over all segments */ -/* and arcs in the outline. To get the latter, you can use the */ -/* `ftbbox' component, which is dedicated to this single task. */ -/* */ -/* */ -/* outline :: A pointer to the source outline descriptor. */ -/* */ -/* */ -/* acbox :: The outline's control box. */ -/* */ -/* */ -/* See @SW_FT_Glyph_Get_CBox for a discussion of tricky fonts. */ -/* */ -void -SW_FT_Outline_Get_CBox( const SW_FT_Outline* outline, - SW_FT_BBox *acbox ); - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Raster_NewFunc */ - /* */ - /* */ - /* A function used to create a new raster object. */ - /* */ - /* */ - /* memory :: A handle to the memory allocator. */ - /* */ - /* */ - /* raster :: A handle to the new raster object. */ - /* */ - /* */ - /* Error code. 0~means success. */ - /* */ - /* */ - /* The `memory' parameter is a typeless pointer in order to avoid */ - /* un-wanted dependencies on the rest of the FreeType code. In */ - /* practice, it is an @SW_FT_Memory object, i.e., a handle to the */ - /* standard FreeType memory allocator. However, this field can be */ - /* completely ignored by a given raster implementation. */ - /* */ - typedef int - (*SW_FT_Raster_NewFunc)( SW_FT_Raster* raster ); - -#define SW_FT_Raster_New_Func SW_FT_Raster_NewFunc - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Raster_DoneFunc */ - /* */ - /* */ - /* A function used to destroy a given raster object. */ - /* */ - /* */ - /* raster :: A handle to the raster object. */ - /* */ - typedef void - (*SW_FT_Raster_DoneFunc)( SW_FT_Raster raster ); - -#define SW_FT_Raster_Done_Func SW_FT_Raster_DoneFunc - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Raster_ResetFunc */ - /* */ - /* */ - /* FreeType provides an area of memory called the `render pool', */ - /* available to all registered rasters. This pool can be freely used */ - /* during a given scan-conversion but is shared by all rasters. Its */ - /* content is thus transient. */ - /* */ - /* This function is called each time the render pool changes, or just */ - /* after a new raster object is created. */ - /* */ - /* */ - /* raster :: A handle to the new raster object. */ - /* */ - /* pool_base :: The address in memory of the render pool. */ - /* */ - /* pool_size :: The size in bytes of the render pool. */ - /* */ - /* */ - /* Rasters can ignore the render pool and rely on dynamic memory */ - /* allocation if they want to (a handle to the memory allocator is */ - /* passed to the raster constructor). However, this is not */ - /* recommended for efficiency purposes. */ - /* */ - typedef void - (*SW_FT_Raster_ResetFunc)( SW_FT_Raster raster, - unsigned char* pool_base, - unsigned long pool_size ); - -#define SW_FT_Raster_Reset_Func SW_FT_Raster_ResetFunc - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Raster_RenderFunc */ - /* */ - /* */ - /* Invoke a given raster to scan-convert a given glyph image into a */ - /* target bitmap. */ - /* */ - /* */ - /* raster :: A handle to the raster object. */ - /* */ - /* params :: A pointer to an @SW_FT_Raster_Params structure used to */ - /* store the rendering parameters. */ - /* */ - /* */ - /* Error code. 0~means success. */ - /* */ - /* */ - /* The exact format of the source image depends on the raster's glyph */ - /* format defined in its @SW_FT_Raster_Funcs structure. It can be an */ - /* @SW_FT_Outline or anything else in order to support a large array of */ - /* glyph formats. */ - /* */ - /* Note also that the render function can fail and return a */ - /* `SW_FT_Err_Unimplemented_Feature' error code if the raster used does */ - /* not support direct composition. */ - /* */ - /* XXX: For now, the standard raster doesn't support direct */ - /* composition but this should change for the final release (see */ - /* the files `demos/src/ftgrays.c' and `demos/src/ftgrays2.c' */ - /* for examples of distinct implementations that support direct */ - /* composition). */ - /* */ - typedef int - (*SW_FT_Raster_RenderFunc)( SW_FT_Raster raster, - const SW_FT_Raster_Params* params ); - -#define SW_FT_Raster_Render_Func SW_FT_Raster_RenderFunc - - - /*************************************************************************/ - /* */ - /* */ - /* SW_FT_Raster_Funcs */ - /* */ - /* */ - /* A structure used to describe a given raster class to the library. */ - /* */ - /* */ - /* glyph_format :: The supported glyph format for this raster. */ - /* */ - /* raster_new :: The raster constructor. */ - /* */ - /* raster_reset :: Used to reset the render pool within the raster. */ - /* */ - /* raster_render :: A function to render a glyph into a given bitmap. */ - /* */ - /* raster_done :: The raster destructor. */ - /* */ - typedef struct SW_FT_Raster_Funcs_ - { - SW_FT_Raster_NewFunc raster_new; - SW_FT_Raster_ResetFunc raster_reset; - SW_FT_Raster_RenderFunc raster_render; - SW_FT_Raster_DoneFunc raster_done; - - } SW_FT_Raster_Funcs; - - -extern const SW_FT_Raster_Funcs sw_ft_grays_raster; - -#endif // SW_FT_IMG_H diff --git a/3rdparty/software/sw_ft_stroker.h b/3rdparty/software/sw_ft_stroker.h deleted file mode 100644 index 95036c5ee..000000000 --- a/3rdparty/software/sw_ft_stroker.h +++ /dev/null @@ -1,319 +0,0 @@ -#ifndef SW_FT_STROKER_H -#define SW_FT_STROKER_H -/***************************************************************************/ -/* */ -/* ftstroke.h */ -/* */ -/* FreeType path stroker (specification). */ -/* */ -/* Copyright 2002-2006, 2008, 2009, 2011-2012 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - -#include "sw_ft_raster.h" - - /************************************************************** - * - * @type: - * SW_FT_Stroker - * - * @description: - * Opaque handler to a path stroker object. - */ - typedef struct SW_FT_StrokerRec_* SW_FT_Stroker; - - - /************************************************************** - * - * @enum: - * SW_FT_Stroker_LineJoin - * - * @description: - * These values determine how two joining lines are rendered - * in a stroker. - * - * @values: - * SW_FT_STROKER_LINEJOIN_ROUND :: - * Used to render rounded line joins. Circular arcs are used - * to join two lines smoothly. - * - * SW_FT_STROKER_LINEJOIN_BEVEL :: - * Used to render beveled line joins. The outer corner of - * the joined lines is filled by enclosing the triangular - * region of the corner with a straight line between the - * outer corners of each stroke. - * - * SW_FT_STROKER_LINEJOIN_MITER_FIXED :: - * Used to render mitered line joins, with fixed bevels if the - * miter limit is exceeded. The outer edges of the strokes - * for the two segments are extended until they meet at an - * angle. If the segments meet at too sharp an angle (such - * that the miter would extend from the intersection of the - * segments a distance greater than the product of the miter - * limit value and the border radius), then a bevel join (see - * above) is used instead. This prevents long spikes being - * created. SW_FT_STROKER_LINEJOIN_MITER_FIXED generates a miter - * line join as used in PostScript and PDF. - * - * SW_FT_STROKER_LINEJOIN_MITER_VARIABLE :: - * SW_FT_STROKER_LINEJOIN_MITER :: - * Used to render mitered line joins, with variable bevels if - * the miter limit is exceeded. The intersection of the - * strokes is clipped at a line perpendicular to the bisector - * of the angle between the strokes, at the distance from the - * intersection of the segments equal to the product of the - * miter limit value and the border radius. This prevents - * long spikes being created. - * SW_FT_STROKER_LINEJOIN_MITER_VARIABLE generates a mitered line - * join as used in XPS. SW_FT_STROKER_LINEJOIN_MITER is an alias - * for SW_FT_STROKER_LINEJOIN_MITER_VARIABLE, retained for - * backwards compatibility. - */ - typedef enum SW_FT_Stroker_LineJoin_ - { - SW_FT_STROKER_LINEJOIN_ROUND = 0, - SW_FT_STROKER_LINEJOIN_BEVEL = 1, - SW_FT_STROKER_LINEJOIN_MITER_VARIABLE = 2, - SW_FT_STROKER_LINEJOIN_MITER = SW_FT_STROKER_LINEJOIN_MITER_VARIABLE, - SW_FT_STROKER_LINEJOIN_MITER_FIXED = 3 - - } SW_FT_Stroker_LineJoin; - - - /************************************************************** - * - * @enum: - * SW_FT_Stroker_LineCap - * - * @description: - * These values determine how the end of opened sub-paths are - * rendered in a stroke. - * - * @values: - * SW_FT_STROKER_LINECAP_BUTT :: - * The end of lines is rendered as a full stop on the last - * point itself. - * - * SW_FT_STROKER_LINECAP_ROUND :: - * The end of lines is rendered as a half-circle around the - * last point. - * - * SW_FT_STROKER_LINECAP_SQUARE :: - * The end of lines is rendered as a square around the - * last point. - */ - typedef enum SW_FT_Stroker_LineCap_ - { - SW_FT_STROKER_LINECAP_BUTT = 0, - SW_FT_STROKER_LINECAP_ROUND, - SW_FT_STROKER_LINECAP_SQUARE - - } SW_FT_Stroker_LineCap; - - - /************************************************************** - * - * @enum: - * SW_FT_StrokerBorder - * - * @description: - * These values are used to select a given stroke border - * in @SW_FT_Stroker_GetBorderCounts and @SW_FT_Stroker_ExportBorder. - * - * @values: - * SW_FT_STROKER_BORDER_LEFT :: - * Select the left border, relative to the drawing direction. - * - * SW_FT_STROKER_BORDER_RIGHT :: - * Select the right border, relative to the drawing direction. - * - * @note: - * Applications are generally interested in the `inside' and `outside' - * borders. However, there is no direct mapping between these and the - * `left' and `right' ones, since this really depends on the glyph's - * drawing orientation, which varies between font formats. - * - * You can however use @SW_FT_Outline_GetInsideBorder and - * @SW_FT_Outline_GetOutsideBorder to get these. - */ - typedef enum SW_FT_StrokerBorder_ - { - SW_FT_STROKER_BORDER_LEFT = 0, - SW_FT_STROKER_BORDER_RIGHT - - } SW_FT_StrokerBorder; - - - /************************************************************** - * - * @function: - * SW_FT_Stroker_New - * - * @description: - * Create a new stroker object. - * - * @input: - * library :: - * FreeType library handle. - * - * @output: - * astroker :: - * A new stroker object handle. NULL in case of error. - * - * @return: - * FreeType error code. 0~means success. - */ - SW_FT_Error - SW_FT_Stroker_New( SW_FT_Stroker *astroker ); - - - /************************************************************** - * - * @function: - * SW_FT_Stroker_Set - * - * @description: - * Reset a stroker object's attributes. - * - * @input: - * stroker :: - * The target stroker handle. - * - * radius :: - * The border radius. - * - * line_cap :: - * The line cap style. - * - * line_join :: - * The line join style. - * - * miter_limit :: - * The miter limit for the SW_FT_STROKER_LINEJOIN_MITER_FIXED and - * SW_FT_STROKER_LINEJOIN_MITER_VARIABLE line join styles, - * expressed as 16.16 fixed-point value. - * - * @note: - * The radius is expressed in the same units as the outline - * coordinates. - */ - void - SW_FT_Stroker_Set( SW_FT_Stroker stroker, - SW_FT_Fixed radius, - SW_FT_Stroker_LineCap line_cap, - SW_FT_Stroker_LineJoin line_join, - SW_FT_Fixed miter_limit ); - - /************************************************************** - * - * @function: - * SW_FT_Stroker_ParseOutline - * - * @description: - * A convenience function used to parse a whole outline with - * the stroker. The resulting outline(s) can be retrieved - * later by functions like @SW_FT_Stroker_GetCounts and @SW_FT_Stroker_Export. - * - * @input: - * stroker :: - * The target stroker handle. - * - * outline :: - * The source outline. - * - * - * @return: - * FreeType error code. 0~means success. - * - * @note: - * If `opened' is~0 (the default), the outline is treated as a closed - * path, and the stroker generates two distinct `border' outlines. - * - * - * This function calls @SW_FT_Stroker_Rewind automatically. - */ - SW_FT_Error - SW_FT_Stroker_ParseOutline( SW_FT_Stroker stroker, - const SW_FT_Outline* outline); - - - /************************************************************** - * - * @function: - * SW_FT_Stroker_GetCounts - * - * @description: - * Call this function once you have finished parsing your paths - * with the stroker. It returns the number of points and - * contours necessary to export all points/borders from the stroked - * outline/path. - * - * @input: - * stroker :: - * The target stroker handle. - * - * @output: - * anum_points :: - * The number of points. - * - * anum_contours :: - * The number of contours. - * - * @return: - * FreeType error code. 0~means success. - */ - SW_FT_Error - SW_FT_Stroker_GetCounts( SW_FT_Stroker stroker, - SW_FT_UInt *anum_points, - SW_FT_UInt *anum_contours ); - - - /************************************************************** - * - * @function: - * SW_FT_Stroker_Export - * - * @description: - * Call this function after @SW_FT_Stroker_GetBorderCounts to - * export all borders to your own @SW_FT_Outline structure. - * - * Note that this function appends the border points and - * contours to your outline, but does not try to resize its - * arrays. - * - * @input: - * stroker :: - * The target stroker handle. - * - * outline :: - * The target outline handle. - */ - void - SW_FT_Stroker_Export( SW_FT_Stroker stroker, - SW_FT_Outline* outline ); - - - /************************************************************** - * - * @function: - * SW_FT_Stroker_Done - * - * @description: - * Destroy a stroker object. - * - * @input: - * stroker :: - * A stroker handle. Can be NULL. - */ - void - SW_FT_Stroker_Done( SW_FT_Stroker stroker ); - - -#endif // SW_FT_STROKER_H diff --git a/CMakeLists.txt b/CMakeLists.txt index b9bf46a88..926e6d5f8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.3) -project(lunasvg VERSION 2.3.2 LANGUAGES CXX C) +project(lunasvg VERSION 2.3.4 LANGUAGES CXX C) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_C_STANDARD 11) option(BUILD_SHARED_LIBS "Builds as shared library" OFF) @@ -12,7 +12,6 @@ add_library(lunasvg) add_subdirectory(include) add_subdirectory(source) -add_subdirectory(3rdparty/software) add_subdirectory(3rdparty/plutovg) if(BUILD_SHARED_LIBS) diff --git a/README.md b/README.md index 54ae0432f..de7e53145 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Releases](https://img.shields.io/badge/Version-2.3.2-orange.svg)](https://github.com/sammycage/lunasvg/releases) +[![Releases](https://img.shields.io/badge/Version-2.3.4-orange.svg)](https://github.com/sammycage/lunasvg/releases) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/sammycage/lunasvg/blob/master/LICENSE) [![Build Status](https://github.com/sammycage/lunasvg/actions/workflows/ci.yml/badge.svg)](https://github.com/sammycage/lunasvg/actions) diff --git a/source/canvas.cpp b/source/canvas.cpp index 6311ffc17..32db99abe 100644 --- a/source/canvas.cpp +++ b/source/canvas.cpp @@ -9,7 +9,7 @@ static plutovg_fill_rule_t to_plutovg_fill_rule(WindRule winding); static plutovg_operator_t to_plutovg_operator(BlendMode mode); static plutovg_line_cap_t to_plutovg_line_cap(LineCap cap); static plutovg_line_join_t to_plutovg_line_join(LineJoin join); -static plutovg_spread_method_t to_plutovg_spread_methood(SpreadMethod spread); +static plutovg_spread_method_t to_plutovg_spread_method(SpreadMethod spread); static void to_plutovg_stops(plutovg_gradient_t* gradient, const GradientStops& stops); static void to_plutovg_path(plutovg_t* pluto, const Path& path); @@ -59,7 +59,7 @@ Canvas::~Canvas() void Canvas::setColor(const Color& color) { - plutovg_set_source_rgba(pluto, color.r, color.g, color.b, color.a); + plutovg_set_source_rgba(pluto, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0); } void Canvas::setLinearGradient(double x1, double y1, double x2, double y2, const GradientStops& stops, SpreadMethod spread, const Transform& transform) @@ -67,7 +67,7 @@ void Canvas::setLinearGradient(double x1, double y1, double x2, double y2, const auto gradient = plutovg_gradient_create_linear(x1, y1, x2, y2); auto matrix = to_plutovg_matrix(transform); to_plutovg_stops(gradient, stops); - plutovg_gradient_set_spread(gradient, to_plutovg_spread_methood(spread)); + plutovg_gradient_set_spread(gradient, to_plutovg_spread_method(spread)); plutovg_gradient_set_matrix(gradient, &matrix); plutovg_set_source_gradient(pluto, gradient); plutovg_gradient_destroy(gradient); @@ -78,7 +78,7 @@ void Canvas::setRadialGradient(double cx, double cy, double r, double fx, double auto gradient = plutovg_gradient_create_radial(cx, cy, r, fx, fy, 0); auto matrix = to_plutovg_matrix(transform); to_plutovg_stops(gradient, stops); - plutovg_gradient_set_spread(gradient, to_plutovg_spread_methood(spread)); + plutovg_gradient_set_spread(gradient, to_plutovg_spread_method(spread)); plutovg_gradient_set_matrix(gradient, &matrix); plutovg_set_source_gradient(pluto, gradient); plutovg_gradient_destroy(gradient); @@ -227,7 +227,7 @@ plutovg_line_join_t to_plutovg_line_join(LineJoin join) return join == LineJoin::Miter ? plutovg_line_join_miter : join == LineJoin::Round ? plutovg_line_join_round : plutovg_line_join_bevel; } -static plutovg_spread_method_t to_plutovg_spread_methood(SpreadMethod spread) +static plutovg_spread_method_t to_plutovg_spread_method(SpreadMethod spread) { return spread == SpreadMethod::Pad ? plutovg_spread_method_pad : spread == SpreadMethod::Reflect ? plutovg_spread_method_reflect : plutovg_spread_method_repeat; } @@ -238,7 +238,7 @@ static void to_plutovg_stops(plutovg_gradient_t* gradient, const GradientStops& { auto offset = std::get<0>(stop); auto& color = std::get<1>(stop); - plutovg_gradient_add_stop_rgba(gradient, offset, color.r, color.g, color.b, color.a); + plutovg_gradient_add_stop_rgba(gradient, offset, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0); } } diff --git a/source/clippathelement.cpp b/source/clippathelement.cpp index 9472b5ce5..25ea70097 100644 --- a/source/clippathelement.cpp +++ b/source/clippathelement.cpp @@ -5,13 +5,13 @@ namespace lunasvg { ClipPathElement::ClipPathElement() - : GraphicsElement(ElementId::ClipPath) + : GraphicsElement(ElementID::ClipPath) { } Units ClipPathElement::clipPathUnits() const { - auto& value = get(PropertyId::ClipPathUnits); + auto& value = get(PropertyID::ClipPathUnits); return Parser::parseUnits(value, Units::UserSpaceOnUse); } diff --git a/source/defselement.cpp b/source/defselement.cpp index b39ddeac9..9402561d0 100644 --- a/source/defselement.cpp +++ b/source/defselement.cpp @@ -3,7 +3,7 @@ namespace lunasvg { DefsElement::DefsElement() - : GraphicsElement(ElementId::Defs) + : GraphicsElement(ElementID::Defs) { } diff --git a/source/element.cpp b/source/element.cpp index a3d3a319a..518556fdb 100644 --- a/source/element.cpp +++ b/source/element.cpp @@ -4,7 +4,7 @@ namespace lunasvg { -void PropertyList::set(PropertyId id, const std::string& value, int specificity) +void PropertyList::set(PropertyID id, const std::string& value, int specificity) { auto property = get(id); if(property == nullptr) @@ -21,7 +21,7 @@ void PropertyList::set(PropertyId id, const std::string& value, int specificity) property->value = value; } -Property* PropertyList::get(PropertyId id) const +Property* PropertyList::get(PropertyID id) const { auto data = m_properties.data(); auto end = data + m_properties.size(); @@ -59,19 +59,19 @@ std::unique_ptr TextNode::clone() const return std::move(node); } -Element::Element(ElementId id) +Element::Element(ElementID id) : id(id) { } -void Element::set(PropertyId id, const std::string& value, int specificity) +void Element::set(PropertyID id, const std::string& value, int specificity) { properties.set(id, value, specificity); } static const std::string EmptyString; -const std::string& Element::get(PropertyId id) const +const std::string& Element::get(PropertyID id) const { auto property = properties.get(id); if(property == nullptr) @@ -82,7 +82,7 @@ const std::string& Element::get(PropertyId id) const static const std::string InheritString{"inherit"}; -const std::string& Element::find(PropertyId id) const +const std::string& Element::find(PropertyID id) const { auto element = this; do { @@ -95,12 +95,12 @@ const std::string& Element::find(PropertyId id) const return EmptyString; } -bool Element::has(PropertyId id) const +bool Element::has(PropertyID id) const { return properties.get(id); } -Element* Element::previousSibling() const +Element* Element::previousElement() const { if(parent == nullptr) return nullptr; @@ -122,7 +122,7 @@ Element* Element::previousSibling() const return nullptr; } -Element* Element::nextSibling() const +Element* Element::nextElement() const { if(parent == nullptr) return nullptr; @@ -162,15 +162,15 @@ Rect Element::currentViewport() const if(parent == nullptr) { auto element = static_cast(this); - if(element->has(PropertyId::ViewBox)) + if(element->has(PropertyID::ViewBox)) return element->viewBox(); return Rect{0, 0, 300, 150}; } - if(parent->id == ElementId::Svg) + if(parent->id == ElementID::Svg) { auto element = static_cast(parent); - if(element->has(PropertyId::ViewBox)) + if(element->has(PropertyID::ViewBox)) return element->viewBox(); LengthContext lengthContext(element); diff --git a/source/element.h b/source/element.h index f94f92774..e6c668975 100644 --- a/source/element.h +++ b/source/element.h @@ -8,7 +8,7 @@ namespace lunasvg { -enum class ElementId +enum class ElementID { Unknown = 0, Star, @@ -35,7 +35,7 @@ enum class ElementId Use }; -enum class PropertyId +enum class PropertyID { Unknown = 0, Class, @@ -108,7 +108,7 @@ enum class PropertyId struct Property { - PropertyId id; + PropertyID id; std::string value; int specificity; }; @@ -118,10 +118,11 @@ class PropertyList public: PropertyList() = default; - void set(PropertyId id, const std::string& value, int specificity); - Property* get(PropertyId id) const; + void set(PropertyID id, const std::string& value, int specificity); + Property* get(PropertyID id) const; void add(const Property& property); void add(const PropertyList& properties); + void clear() { m_properties.clear(); } private: std::vector m_properties; @@ -164,15 +165,15 @@ using NodeList = std::list>; class Element : public Node { public: - Element(ElementId id); + Element(ElementID id); - void set(PropertyId id, const std::string& value, int specificity); - const std::string& get(PropertyId id) const; - const std::string& find(PropertyId id) const; - bool has(PropertyId id) const; + void set(PropertyID id, const std::string& value, int specificity); + const std::string& get(PropertyID id) const; + const std::string& find(PropertyID id) const; + bool has(PropertyID id) const; - Element* previousSibling() const; - Element* nextSibling() const; + Element* previousElement() const; + Element* nextElement() const; Node* addChild(std::unique_ptr child); void layoutChildren(LayoutContext* context, LayoutContainer* current) const; Rect currentViewport() const; @@ -208,7 +209,7 @@ public: } public: - ElementId id; + ElementID id; NodeList children; PropertyList properties; }; diff --git a/source/gelement.cpp b/source/gelement.cpp index b0f5c84a7..2dc805b94 100644 --- a/source/gelement.cpp +++ b/source/gelement.cpp @@ -4,7 +4,7 @@ namespace lunasvg { GElement::GElement() - : GraphicsElement(ElementId::G) + : GraphicsElement(ElementID::G) { } diff --git a/source/geometryelement.cpp b/source/geometryelement.cpp index c93b6d52b..6f848ac72 100644 --- a/source/geometryelement.cpp +++ b/source/geometryelement.cpp @@ -6,7 +6,7 @@ namespace lunasvg { -GeometryElement::GeometryElement(ElementId id) +GeometryElement::GeometryElement(ElementID id) : GraphicsElement(id) { } @@ -35,13 +35,13 @@ void GeometryElement::layout(LayoutContext* context, LayoutContainer* current) c } PathElement::PathElement() - : GeometryElement(ElementId::Path) + : GeometryElement(ElementID::Path) { } Path PathElement::d() const { - auto& value = get(PropertyId::D); + auto& value = get(PropertyID::D); return Parser::parsePath(value); } @@ -55,19 +55,19 @@ std::unique_ptr PathElement::clone() const return cloneElement(); } -PolyElement::PolyElement(ElementId id) +PolyElement::PolyElement(ElementID id) : GeometryElement(id) { } PointList PolyElement::points() const { - auto& value = get(PropertyId::Points); + auto& value = get(PropertyID::Points); return Parser::parsePointList(value); } PolygonElement::PolygonElement() - : PolyElement(ElementId::Polygon) + : PolyElement(ElementID::Polygon) { } @@ -92,7 +92,7 @@ std::unique_ptr PolygonElement::clone() const } PolylineElement::PolylineElement() - : PolyElement(ElementId::Polyline) + : PolyElement(ElementID::Polyline) { } @@ -116,25 +116,25 @@ std::unique_ptr PolylineElement::clone() const } CircleElement::CircleElement() - : GeometryElement(ElementId::Circle) + : GeometryElement(ElementID::Circle) { } Length CircleElement::cx() const { - auto& value = get(PropertyId::Cx); + auto& value = get(PropertyID::Cx); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length CircleElement::cy() const { - auto& value = get(PropertyId::Cy); + auto& value = get(PropertyID::Cy); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length CircleElement::r() const { - auto& value = get(PropertyId::R); + auto& value = get(PropertyID::R); return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero); } @@ -160,31 +160,31 @@ std::unique_ptr CircleElement::clone() const } EllipseElement::EllipseElement() - : GeometryElement(ElementId::Ellipse) + : GeometryElement(ElementID::Ellipse) { } Length EllipseElement::cx() const { - auto& value = get(PropertyId::Cx); + auto& value = get(PropertyID::Cx); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length EllipseElement::cy() const { - auto& value = get(PropertyId::Cy); + auto& value = get(PropertyID::Cy); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length EllipseElement::rx() const { - auto& value = get(PropertyId::Rx); + auto& value = get(PropertyID::Rx); return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero); } Length EllipseElement::ry() const { - auto& value = get(PropertyId::Ry); + auto& value = get(PropertyID::Ry); return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero); } @@ -212,31 +212,31 @@ std::unique_ptr EllipseElement::clone() const } LineElement::LineElement() - : GeometryElement(ElementId::Line) + : GeometryElement(ElementID::Line) { } Length LineElement::x1() const { - auto& value = get(PropertyId::X1); + auto& value = get(PropertyID::X1); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length LineElement::y1() const { - auto& value = get(PropertyId::Y1); + auto& value = get(PropertyID::Y1); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length LineElement::x2() const { - auto& value = get(PropertyId::X2); + auto& value = get(PropertyID::X2); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length LineElement::y2() const { - auto& value = get(PropertyId::Y2); + auto& value = get(PropertyID::Y2); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } @@ -260,43 +260,43 @@ std::unique_ptr LineElement::clone() const } RectElement::RectElement() - : GeometryElement(ElementId::Rect) + : GeometryElement(ElementID::Rect) { } Length RectElement::x() const { - auto& value = get(PropertyId::X); + auto& value = get(PropertyID::X); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length RectElement::y() const { - auto& value = get(PropertyId::Y); + auto& value = get(PropertyID::Y); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length RectElement::rx() const { - auto& value = get(PropertyId::Rx); + auto& value = get(PropertyID::Rx); return Parser::parseLength(value, ForbidNegativeLengths, Length::Unknown); } Length RectElement::ry() const { - auto& value = get(PropertyId::Ry); + auto& value = get(PropertyID::Ry); return Parser::parseLength(value, ForbidNegativeLengths, Length::Unknown); } Length RectElement::width() const { - auto& value = get(PropertyId::Width); + auto& value = get(PropertyID::Width); return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero); } Length RectElement::height() const { - auto& value = get(PropertyId::Height); + auto& value = get(PropertyID::Height); return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero); } diff --git a/source/geometryelement.h b/source/geometryelement.h index 8d302ee39..e2f0bb462 100644 --- a/source/geometryelement.h +++ b/source/geometryelement.h @@ -10,7 +10,7 @@ class LayoutShape; class GeometryElement : public GraphicsElement { public: - GeometryElement(ElementId id); + GeometryElement(ElementID id); bool isGeometry() const { return true; } virtual void layout(LayoutContext* context, LayoutContainer* current) const; @@ -31,7 +31,7 @@ public: class PolyElement : public GeometryElement { public: - PolyElement(ElementId id); + PolyElement(ElementID id); PointList points() const; }; diff --git a/source/graphicselement.cpp b/source/graphicselement.cpp index 60c28f955..9df1a00c3 100644 --- a/source/graphicselement.cpp +++ b/source/graphicselement.cpp @@ -3,14 +3,14 @@ namespace lunasvg { -GraphicsElement::GraphicsElement(ElementId id) +GraphicsElement::GraphicsElement(ElementID id) : StyledElement(id) { } Transform GraphicsElement::transform() const { - auto& value = get(PropertyId::Transform); + auto& value = get(PropertyID::Transform); return Parser::parseTransform(value); } diff --git a/source/graphicselement.h b/source/graphicselement.h index 4da8ce8ab..1c156a04c 100644 --- a/source/graphicselement.h +++ b/source/graphicselement.h @@ -8,7 +8,7 @@ namespace lunasvg { class GraphicsElement : public StyledElement { public: - GraphicsElement(ElementId id); + GraphicsElement(ElementID id); Transform transform() const; }; diff --git a/source/layoutcontext.cpp b/source/layoutcontext.cpp index 5b92c8779..24f4d0f1e 100644 --- a/source/layoutcontext.cpp +++ b/source/layoutcontext.cpp @@ -479,14 +479,14 @@ void RenderState::endGroup(RenderState& state, const BlendInfo& info) state.canvas->blend(canvas.get(), BlendMode::Src_Over, m_mode == RenderMode::Display ? info.opacity : 1.0); } -LayoutContext::LayoutContext(const ParseDocument* document, LayoutSymbol* root) - : m_document(document), m_root(root) +LayoutContext::LayoutContext(const TreeBuilder* builder, LayoutSymbol* root) + : m_builder(builder), m_root(root) { } Element* LayoutContext::getElementById(const std::string& id) const { - return m_document->getElementById(id); + return m_builder->getElementById(id); } LayoutObject* LayoutContext::getResourcesById(const std::string& id) const @@ -517,7 +517,7 @@ LayoutMask* LayoutContext::getMasker(const std::string& id) return static_cast(ref); auto element = getElementById(id); - if(element == nullptr || element->id != ElementId::Mask) + if(element == nullptr || element->id != ElementID::Mask) return nullptr; auto masker = static_cast(element)->getMasker(this); @@ -534,7 +534,7 @@ LayoutClipPath* LayoutContext::getClipper(const std::string& id) return static_cast(ref); auto element = getElementById(id); - if(element == nullptr || element->id != ElementId::ClipPath) + if(element == nullptr || element->id != ElementID::ClipPath) return nullptr; auto clipper = static_cast(element)->getClipper(this); @@ -551,7 +551,7 @@ LayoutMarker* LayoutContext::getMarker(const std::string& id) return static_cast(ref); auto element = getElementById(id); - if(element == nullptr || element->id != ElementId::Marker) + if(element == nullptr || element->id != ElementID::Marker) return nullptr; auto marker = static_cast(element)->getMarker(this); diff --git a/source/layoutcontext.h b/source/layoutcontext.h index 13c3d3c5a..e81be5ad6 100644 --- a/source/layoutcontext.h +++ b/source/layoutcontext.h @@ -346,14 +346,14 @@ private: RenderMode m_mode; }; -class ParseDocument; +class TreeBuilder; class StyledElement; class GeometryElement; class LayoutContext { public: - LayoutContext(const ParseDocument* document, LayoutSymbol* root); + LayoutContext(const TreeBuilder* builder, LayoutSymbol* root); Element* getElementById(const std::string& id) const; LayoutObject* getResourcesById(const std::string& id) const; @@ -373,7 +373,7 @@ public: bool hasReference(const Element* element) const; private: - const ParseDocument* m_document; + const TreeBuilder* m_builder; LayoutSymbol* m_root; std::map m_resourcesCache; std::set m_references; diff --git a/source/lunasvg.cpp b/source/lunasvg.cpp index 2a75aa3c7..a77cfefb9 100644 --- a/source/lunasvg.cpp +++ b/source/lunasvg.cpp @@ -292,11 +292,11 @@ std::unique_ptr Document::loadFromData(const std::string& string) std::unique_ptr Document::loadFromData(const char* data, std::size_t size) { - ParseDocument parser; - if(!parser.parse(data, size)) + TreeBuilder builder; + if(!builder.parse(data, size)) return nullptr; - auto root = parser.layout(); + auto root = builder.build(); if(!root || root->children.empty()) return nullptr; diff --git a/source/markerelement.cpp b/source/markerelement.cpp index 262d7b201..5a61aff69 100644 --- a/source/markerelement.cpp +++ b/source/markerelement.cpp @@ -5,55 +5,55 @@ namespace lunasvg { MarkerElement::MarkerElement() - : StyledElement(ElementId::Marker) + : StyledElement(ElementID::Marker) { } Length MarkerElement::refX() const { - auto& value = get(PropertyId::RefX); + auto& value = get(PropertyID::RefX); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length MarkerElement::refY() const { - auto& value = get(PropertyId::RefY); + auto& value = get(PropertyID::RefY); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length MarkerElement::markerWidth() const { - auto& value = get(PropertyId::MarkerWidth); + auto& value = get(PropertyID::MarkerWidth); return Parser::parseLength(value, ForbidNegativeLengths, Length::ThreePercent); } Length MarkerElement::markerHeight() const { - auto& value = get(PropertyId::MarkerHeight); + auto& value = get(PropertyID::MarkerHeight); return Parser::parseLength(value, ForbidNegativeLengths, Length::ThreePercent); } Angle MarkerElement::orient() const { - auto& value = get(PropertyId::Orient); + auto& value = get(PropertyID::Orient); return Parser::parseAngle(value); } MarkerUnits MarkerElement::markerUnits() const { - auto& value = get(PropertyId::MarkerUnits); + auto& value = get(PropertyID::MarkerUnits); return Parser::parseMarkerUnits(value); } Rect MarkerElement::viewBox() const { - auto& value = get(PropertyId::ViewBox); + auto& value = get(PropertyID::ViewBox); return Parser::parseViewBox(value); } PreserveAspectRatio MarkerElement::preserveAspectRatio() const { - auto& value = get(PropertyId::PreserveAspectRatio); + auto& value = get(PropertyID::PreserveAspectRatio); return Parser::parsePreserveAspectRatio(value); } diff --git a/source/maskelement.cpp b/source/maskelement.cpp index da0a7fbe6..0503657e1 100644 --- a/source/maskelement.cpp +++ b/source/maskelement.cpp @@ -5,43 +5,43 @@ namespace lunasvg { MaskElement::MaskElement() - : StyledElement(ElementId::Mask) + : StyledElement(ElementID::Mask) { } Length MaskElement::x() const { - auto& value = get(PropertyId::X); + auto& value = get(PropertyID::X); return Parser::parseLength(value, AllowNegativeLengths, Length::MinusTenPercent); } Length MaskElement::y() const { - auto& value = get(PropertyId::Y); + auto& value = get(PropertyID::Y); return Parser::parseLength(value, AllowNegativeLengths, Length::MinusTenPercent); } Length MaskElement::width() const { - auto& value = get(PropertyId::Width); + auto& value = get(PropertyID::Width); return Parser::parseLength(value, ForbidNegativeLengths, Length::OneTwentyPercent); } Length MaskElement::height() const { - auto& value = get(PropertyId::Height); + auto& value = get(PropertyID::Height); return Parser::parseLength(value, ForbidNegativeLengths, Length::OneTwentyPercent); } Units MaskElement::maskUnits() const { - auto& value = get(PropertyId::MaskUnits); + auto& value = get(PropertyID::MaskUnits); return Parser::parseUnits(value, Units::ObjectBoundingBox); } Units MaskElement::maskContentUnits() const { - auto& value = get(PropertyId::MaskContentUnits); + auto& value = get(PropertyID::MaskContentUnits); return Parser::parseUnits(value, Units::UserSpaceOnUse); } diff --git a/source/paintelement.cpp b/source/paintelement.cpp index 0e0776e72..7cc77a6f3 100644 --- a/source/paintelement.cpp +++ b/source/paintelement.cpp @@ -7,37 +7,37 @@ namespace lunasvg { -PaintElement::PaintElement(ElementId id) +PaintElement::PaintElement(ElementID id) : StyledElement(id) { } -GradientElement::GradientElement(ElementId id) +GradientElement::GradientElement(ElementID id) : PaintElement(id) { } Transform GradientElement::gradientTransform() const { - auto& value = get(PropertyId::GradientTransform); + auto& value = get(PropertyID::GradientTransform); return Parser::parseTransform(value); } SpreadMethod GradientElement::spreadMethod() const { - auto& value = get(PropertyId::SpreadMethod); + auto& value = get(PropertyID::SpreadMethod); return Parser::parseSpreadMethod(value); } Units GradientElement::gradientUnits() const { - auto& value = get(PropertyId::GradientUnits); + auto& value = get(PropertyID::GradientUnits); return Parser::parseUnits(value, Units::ObjectBoundingBox); } std::string GradientElement::href() const { - auto& value = get(PropertyId::Href); + auto& value = get(PropertyID::Href); return Parser::parseHref(value); } @@ -50,7 +50,7 @@ GradientStops GradientElement::buildGradientStops() const if(child->isText()) continue; auto element = static_cast(child.get()); - if(element->id != ElementId::Stop) + if(element->id != ElementID::Stop) continue; auto stop = static_cast(element); auto offset = std::max(prevOffset, stop->offset()); @@ -62,31 +62,31 @@ GradientStops GradientElement::buildGradientStops() const } LinearGradientElement::LinearGradientElement() - : GradientElement(ElementId::LinearGradient) + : GradientElement(ElementID::LinearGradient) { } Length LinearGradientElement::x1() const { - auto& value = get(PropertyId::X1); + auto& value = get(PropertyID::X1); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length LinearGradientElement::y1() const { - auto& value = get(PropertyId::Y1); + auto& value = get(PropertyID::Y1); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length LinearGradientElement::x2() const { - auto& value = get(PropertyId::X2); + auto& value = get(PropertyID::X2); return Parser::parseLength(value, AllowNegativeLengths, Length::HundredPercent); } Length LinearGradientElement::y2() const { - auto& value = get(PropertyId::Y2); + auto& value = get(PropertyID::Y2); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } @@ -98,30 +98,30 @@ std::unique_ptr LinearGradientElement::getPainter(LayoutContext* c while(true) { - if(!attributes.hasGradientTransform() && current->has(PropertyId::GradientTransform)) + if(!attributes.hasGradientTransform() && current->has(PropertyID::GradientTransform)) attributes.setGradientTransform(current->gradientTransform()); - if(!attributes.hasSpreadMethod() && current->has(PropertyId::SpreadMethod)) + if(!attributes.hasSpreadMethod() && current->has(PropertyID::SpreadMethod)) attributes.setSpreadMethod(current->spreadMethod()); - if(!attributes.hasGradientUnits() && current->has(PropertyId::GradientUnits)) + if(!attributes.hasGradientUnits() && current->has(PropertyID::GradientUnits)) attributes.setGradientUnits(current->gradientUnits()); if(!attributes.hasGradientStops()) attributes.setGradientStops(current->buildGradientStops()); - if(current->id == ElementId::LinearGradient) + if(current->id == ElementID::LinearGradient) { auto element = static_cast(current); - if(!attributes.hasX1() && element->has(PropertyId::X1)) + if(!attributes.hasX1() && element->has(PropertyID::X1)) attributes.setX1(element->x1()); - if(!attributes.hasY1() && element->has(PropertyId::Y1)) + if(!attributes.hasY1() && element->has(PropertyID::Y1)) attributes.setY1(element->y1()); - if(!attributes.hasX2() && element->has(PropertyId::X2)) + if(!attributes.hasX2() && element->has(PropertyID::X2)) attributes.setX2(element->x2()); - if(!attributes.hasY2() && element->has(PropertyId::Y2)) + if(!attributes.hasY2() && element->has(PropertyID::Y2)) attributes.setY2(element->y2()); } auto ref = context->getElementById(current->href()); - if(!ref || !(ref->id == ElementId::LinearGradient || ref->id == ElementId::RadialGradient)) + if(!ref || !(ref->id == ElementID::LinearGradient || ref->id == ElementID::RadialGradient)) break; processedGradients.insert(current); @@ -164,37 +164,37 @@ std::unique_ptr LinearGradientElement::clone() const } RadialGradientElement::RadialGradientElement() - : GradientElement(ElementId::RadialGradient) + : GradientElement(ElementID::RadialGradient) { } Length RadialGradientElement::cx() const { - auto& value = get(PropertyId::Cx); + auto& value = get(PropertyID::Cx); return Parser::parseLength(value, AllowNegativeLengths, Length::FiftyPercent); } Length RadialGradientElement::cy() const { - auto& value = get(PropertyId::Cy); + auto& value = get(PropertyID::Cy); return Parser::parseLength(value, AllowNegativeLengths, Length::FiftyPercent); } Length RadialGradientElement::r() const { - auto& value = get(PropertyId::R); + auto& value = get(PropertyID::R); return Parser::parseLength(value, ForbidNegativeLengths, Length::FiftyPercent); } Length RadialGradientElement::fx() const { - auto& value = get(PropertyId::Fx); + auto& value = get(PropertyID::Fx); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length RadialGradientElement::fy() const { - auto& value = get(PropertyId::Fy); + auto& value = get(PropertyID::Fy); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } @@ -206,32 +206,32 @@ std::unique_ptr RadialGradientElement::getPainter(LayoutContext* c while(true) { - if(!attributes.hasGradientTransform() && current->has(PropertyId::GradientTransform)) + if(!attributes.hasGradientTransform() && current->has(PropertyID::GradientTransform)) attributes.setGradientTransform(current->gradientTransform()); - if(!attributes.hasSpreadMethod() && current->has(PropertyId::SpreadMethod)) + if(!attributes.hasSpreadMethod() && current->has(PropertyID::SpreadMethod)) attributes.setSpreadMethod(current->spreadMethod()); - if(!attributes.hasGradientUnits() && current->has(PropertyId::GradientUnits)) + if(!attributes.hasGradientUnits() && current->has(PropertyID::GradientUnits)) attributes.setGradientUnits(current->gradientUnits()); if(!attributes.hasGradientStops()) attributes.setGradientStops(current->buildGradientStops()); - if(current->id == ElementId::RadialGradient) + if(current->id == ElementID::RadialGradient) { auto element = static_cast(current); - if(!attributes.hasCx() && element->has(PropertyId::Cx)) + if(!attributes.hasCx() && element->has(PropertyID::Cx)) attributes.setCx(element->cx()); - if(!attributes.hasCy() && element->has(PropertyId::Cy)) + if(!attributes.hasCy() && element->has(PropertyID::Cy)) attributes.setCy(element->cy()); - if(!attributes.hasR() && element->has(PropertyId::R)) + if(!attributes.hasR() && element->has(PropertyID::R)) attributes.setR(element->r()); - if(!attributes.hasFx() && element->has(PropertyId::Fx)) + if(!attributes.hasFx() && element->has(PropertyID::Fx)) attributes.setFx(element->fx()); - if(!attributes.hasFy() && element->has(PropertyId::Fy)) + if(!attributes.hasFy() && element->has(PropertyID::Fy)) attributes.setFy(element->fy()); } auto ref = context->getElementById(current->href()); - if(!ref || !(ref->id == ElementId::LinearGradient || ref->id == ElementId::RadialGradient)) + if(!ref || !(ref->id == ElementID::LinearGradient || ref->id == ElementID::RadialGradient)) break; processedGradients.insert(current); @@ -278,67 +278,67 @@ std::unique_ptr RadialGradientElement::clone() const } PatternElement::PatternElement() - : PaintElement(ElementId::Pattern) + : PaintElement(ElementID::Pattern) { } Length PatternElement::x() const { - auto& value = get(PropertyId::X); + auto& value = get(PropertyID::X); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length PatternElement::y() const { - auto& value = get(PropertyId::Y); + auto& value = get(PropertyID::Y); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length PatternElement::width() const { - auto& value = get(PropertyId::Width); + auto& value = get(PropertyID::Width); return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero); } Length PatternElement::height() const { - auto& value = get(PropertyId::Height); + auto& value = get(PropertyID::Height); return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero); } Transform PatternElement::patternTransform() const { - auto& value = get(PropertyId::PatternTransform); + auto& value = get(PropertyID::PatternTransform); return Parser::parseTransform(value); } Units PatternElement::patternUnits() const { - auto& value = get(PropertyId::PatternUnits); + auto& value = get(PropertyID::PatternUnits); return Parser::parseUnits(value, Units::ObjectBoundingBox); } Units PatternElement::patternContentUnits() const { - auto& value = get(PropertyId::PatternContentUnits); + auto& value = get(PropertyID::PatternContentUnits); return Parser::parseUnits(value, Units::UserSpaceOnUse); } Rect PatternElement::viewBox() const { - auto& value = get(PropertyId::ViewBox); + auto& value = get(PropertyID::ViewBox); return Parser::parseViewBox(value); } PreserveAspectRatio PatternElement::preserveAspectRatio() const { - auto& value = get(PropertyId::PreserveAspectRatio); + auto& value = get(PropertyID::PreserveAspectRatio); return Parser::parsePreserveAspectRatio(value); } std::string PatternElement::href() const { - auto& value = get(PropertyId::Href); + auto& value = get(PropertyID::Href); return Parser::parseHref(value); } @@ -353,29 +353,29 @@ std::unique_ptr PatternElement::getPainter(LayoutContext* context) while(true) { - if(!attributes.hasX() && current->has(PropertyId::X)) + if(!attributes.hasX() && current->has(PropertyID::X)) attributes.setX(current->x()); - if(!attributes.hasY() && current->has(PropertyId::Y)) + if(!attributes.hasY() && current->has(PropertyID::Y)) attributes.setY(current->y()); - if(!attributes.hasWidth() && current->has(PropertyId::Width)) + if(!attributes.hasWidth() && current->has(PropertyID::Width)) attributes.setWidth(current->width()); - if(!attributes.hasHeight() && current->has(PropertyId::Height)) + if(!attributes.hasHeight() && current->has(PropertyID::Height)) attributes.setHeight(current->height()); - if(!attributes.hasPatternTransform() && current->has(PropertyId::PatternTransform)) + if(!attributes.hasPatternTransform() && current->has(PropertyID::PatternTransform)) attributes.setPatternTransform(current->patternTransform()); - if(!attributes.hasPatternUnits() && current->has(PropertyId::PatternUnits)) + if(!attributes.hasPatternUnits() && current->has(PropertyID::PatternUnits)) attributes.setPatternUnits(current->patternUnits()); - if(!attributes.hasPatternContentUnits() && current->has(PropertyId::PatternContentUnits)) + if(!attributes.hasPatternContentUnits() && current->has(PropertyID::PatternContentUnits)) attributes.setPatternContentUnits(current->patternContentUnits()); - if(!attributes.hasViewBox() && current->has(PropertyId::ViewBox)) + if(!attributes.hasViewBox() && current->has(PropertyID::ViewBox)) attributes.setViewBox(current->viewBox()); - if(!attributes.hasPreserveAspectRatio() && current->has(PropertyId::PreserveAspectRatio)) + if(!attributes.hasPreserveAspectRatio() && current->has(PropertyID::PreserveAspectRatio)) attributes.setPreserveAspectRatio(current->preserveAspectRatio()); if(!attributes.hasPatternContentElement() && current->children.size()) attributes.setPatternContentElement(current); auto ref = context->getElementById(current->href()); - if(!ref || ref->id != ElementId::Pattern) + if(!ref || ref->id != ElementID::Pattern) break; processedPatterns.insert(current); @@ -413,7 +413,7 @@ std::unique_ptr PatternElement::clone() const } SolidColorElement::SolidColorElement() - : PaintElement(ElementId::SolidColor) + : PaintElement(ElementID::SolidColor) { } @@ -421,7 +421,7 @@ std::unique_ptr SolidColorElement::getPainter(LayoutContext*) cons { auto solid = std::make_unique(); solid->color = solid_color(); - solid->color.a = solid_opacity(); + solid->color.combine(solid_opacity()); return std::move(solid); } diff --git a/source/paintelement.h b/source/paintelement.h index 70c86cd9f..b2d152a63 100644 --- a/source/paintelement.h +++ b/source/paintelement.h @@ -11,7 +11,7 @@ class LayoutObject; class PaintElement : public StyledElement { public: - PaintElement(ElementId id); + PaintElement(ElementID id); bool isPaint() const { return true; } virtual std::unique_ptr getPainter(LayoutContext* context) const = 0; @@ -20,7 +20,7 @@ public: class GradientElement : public PaintElement { public: - GradientElement(ElementId id); + GradientElement(ElementID id); Transform gradientTransform() const; SpreadMethod spreadMethod() const; diff --git a/source/parser.cpp b/source/parser.cpp index e3b20f67c..5e4dee02b 100644 --- a/source/parser.cpp +++ b/source/parser.cpp @@ -690,16 +690,12 @@ Color Parser::parseColor(const std::string& string, const StyledElement* element value |= value << 4; } - auto r = (value&0xff0000)>>16; - auto g = (value&0x00ff00)>>8; - auto b = (value&0x0000ff)>>0; - - return Color{r / 255.0, g / 255.0, b / 255.0}; + return Color(value | 0xFF000000); } if(Utils::skipDesc(ptr, end, "rgb(")) { - double r, g, b; + int r, g, b; if(!Utils::skipWs(ptr, end) || !parseColorComponent(ptr, end, r) || !Utils::skipWsComma(ptr, end) @@ -710,7 +706,7 @@ Color Parser::parseColor(const std::string& string, const StyledElement* element || !Utils::skipDesc(ptr, end, ')')) return defaultValue; - return Color{r / 255.0, g / 255.0, b / 255.0}; + return Color(r, g, b, 255); } if(Utils::skipDesc(ptr, end, "none")) @@ -722,13 +718,7 @@ Color Parser::parseColor(const std::string& string, const StyledElement* element auto it = colormap.find(string); if(it == colormap.end()) return defaultValue; - - auto value = it->second; - auto r = (value&0xff0000)>>16; - auto g = (value&0x00ff00)>>8; - auto b = (value&0x0000ff)>>0; - - return Color{r / 255.0, g / 255.0, b / 255.0}; + return Color(it->second | 0xFF000000); } Paint Parser::parsePaint(const std::string& string, const StyledElement* element, const Color& defaultValue) @@ -907,15 +897,17 @@ bool Parser::parseArcFlag(const char*& ptr, const char* end, bool& flag) return true; } -bool Parser::parseColorComponent(const char*& ptr, const char* end, double& value) +bool Parser::parseColorComponent(const char*& ptr, const char* end, int& component) { + double value = 0; if(!Utils::parseNumber(ptr, end, value)) return false; if(Utils::skipDesc(ptr, end, '%')) value *= 2.55; - value = (value < 0.0) ? 0.0 : (value > 255.0) ? 255.0 : std::round(value); + value = std::clamp(value, 0.0, 255.0); + component = static_cast(std::round(value)); return true; } @@ -1024,122 +1016,122 @@ bool Parser::parseTransform(const char*& ptr, const char* end, TransformType& ty return true; } -static const std::map elementmap = { - {"circle", ElementId::Circle}, - {"clipPath", ElementId::ClipPath}, - {"defs", ElementId::Defs}, - {"ellipse", ElementId::Ellipse}, - {"g", ElementId::G}, - {"line", ElementId::Line}, - {"linearGradient", ElementId::LinearGradient}, - {"marker", ElementId::Marker}, - {"mask", ElementId::Mask}, - {"path", ElementId::Path}, - {"pattern", ElementId::Pattern}, - {"polygon", ElementId::Polygon}, - {"polyline", ElementId::Polyline}, - {"radialGradient", ElementId::RadialGradient}, - {"rect", ElementId::Rect}, - {"stop", ElementId::Stop}, - {"style", ElementId::Style}, - {"solidColor", ElementId::SolidColor}, - {"svg", ElementId::Svg}, - {"symbol", ElementId::Symbol}, - {"use", ElementId::Use} +static const std::map elementmap = { + {"circle", ElementID::Circle}, + {"clipPath", ElementID::ClipPath}, + {"defs", ElementID::Defs}, + {"ellipse", ElementID::Ellipse}, + {"g", ElementID::G}, + {"line", ElementID::Line}, + {"linearGradient", ElementID::LinearGradient}, + {"marker", ElementID::Marker}, + {"mask", ElementID::Mask}, + {"path", ElementID::Path}, + {"pattern", ElementID::Pattern}, + {"polygon", ElementID::Polygon}, + {"polyline", ElementID::Polyline}, + {"radialGradient", ElementID::RadialGradient}, + {"rect", ElementID::Rect}, + {"stop", ElementID::Stop}, + {"style", ElementID::Style}, + {"solidColor", ElementID::SolidColor}, + {"svg", ElementID::Svg}, + {"symbol", ElementID::Symbol}, + {"use", ElementID::Use} }; -static const std::map propertymap = { - {"class", PropertyId::Class}, - {"clipPathUnits", PropertyId::ClipPathUnits}, - {"cx", PropertyId::Cx}, - {"cy", PropertyId::Cy}, - {"d", PropertyId::D}, - {"fx", PropertyId::Fx}, - {"fy", PropertyId::Fy}, - {"gradientTransform", PropertyId::GradientTransform}, - {"gradientUnits", PropertyId::GradientUnits}, - {"height", PropertyId::Height}, - {"href", PropertyId::Href}, - {"id", PropertyId::Id}, - {"markerHeight", PropertyId::MarkerHeight}, - {"markerUnits", PropertyId::MarkerUnits}, - {"markerWidth", PropertyId::MarkerWidth}, - {"maskContentUnits", PropertyId::MaskContentUnits}, - {"maskUnits", PropertyId::MaskUnits}, - {"offset", PropertyId::Offset}, - {"orient", PropertyId::Orient}, - {"patternContentUnits", PropertyId::PatternContentUnits}, - {"patternTransform", PropertyId::PatternTransform}, - {"patternUnits", PropertyId::PatternUnits}, - {"points", PropertyId::Points}, - {"preserveAspectRatio", PropertyId::PreserveAspectRatio}, - {"r", PropertyId::R}, - {"refX", PropertyId::RefX}, - {"refY", PropertyId::RefY}, - {"rx", PropertyId::Rx}, - {"ry", PropertyId::Ry}, - {"spreadMethod", PropertyId::SpreadMethod}, - {"style", PropertyId::Style}, - {"transform", PropertyId::Transform}, - {"viewBox", PropertyId::ViewBox}, - {"width", PropertyId::Width}, - {"x", PropertyId::X}, - {"x1", PropertyId::X1}, - {"x2", PropertyId::X2}, - {"xlink:href", PropertyId::Href}, - {"y", PropertyId::Y}, - {"y1", PropertyId::Y1}, - {"y2", PropertyId::Y2} +static const std::map propertymap = { + {"class", PropertyID::Class}, + {"clipPathUnits", PropertyID::ClipPathUnits}, + {"cx", PropertyID::Cx}, + {"cy", PropertyID::Cy}, + {"d", PropertyID::D}, + {"fx", PropertyID::Fx}, + {"fy", PropertyID::Fy}, + {"gradientTransform", PropertyID::GradientTransform}, + {"gradientUnits", PropertyID::GradientUnits}, + {"height", PropertyID::Height}, + {"href", PropertyID::Href}, + {"id", PropertyID::Id}, + {"markerHeight", PropertyID::MarkerHeight}, + {"markerUnits", PropertyID::MarkerUnits}, + {"markerWidth", PropertyID::MarkerWidth}, + {"maskContentUnits", PropertyID::MaskContentUnits}, + {"maskUnits", PropertyID::MaskUnits}, + {"offset", PropertyID::Offset}, + {"orient", PropertyID::Orient}, + {"patternContentUnits", PropertyID::PatternContentUnits}, + {"patternTransform", PropertyID::PatternTransform}, + {"patternUnits", PropertyID::PatternUnits}, + {"points", PropertyID::Points}, + {"preserveAspectRatio", PropertyID::PreserveAspectRatio}, + {"r", PropertyID::R}, + {"refX", PropertyID::RefX}, + {"refY", PropertyID::RefY}, + {"rx", PropertyID::Rx}, + {"ry", PropertyID::Ry}, + {"spreadMethod", PropertyID::SpreadMethod}, + {"style", PropertyID::Style}, + {"transform", PropertyID::Transform}, + {"viewBox", PropertyID::ViewBox}, + {"width", PropertyID::Width}, + {"x", PropertyID::X}, + {"x1", PropertyID::X1}, + {"x2", PropertyID::X2}, + {"xlink:href", PropertyID::Href}, + {"y", PropertyID::Y}, + {"y1", PropertyID::Y1}, + {"y2", PropertyID::Y2} }; -static const std::map csspropertymap = { - {"clip-path", PropertyId::Clip_Path}, - {"clip-rule", PropertyId::Clip_Rule}, - {"color", PropertyId::Color}, - {"display", PropertyId::Display}, - {"fill", PropertyId::Fill}, - {"fill-opacity", PropertyId::Fill_Opacity}, - {"fill-rule", PropertyId::Fill_Rule}, - {"marker-end", PropertyId::Marker_End}, - {"marker-mid", PropertyId::Marker_Mid}, - {"marker-start", PropertyId::Marker_Start}, - {"mask", PropertyId::Mask}, - {"opacity", PropertyId::Opacity}, - {"overflow", PropertyId::Overflow}, - {"solid-color", PropertyId::Solid_Color}, - {"solid-opacity", PropertyId::Solid_Opacity}, - {"stop-color", PropertyId::Stop_Color}, - {"stop-opacity", PropertyId::Stop_Opacity}, - {"stroke", PropertyId::Stroke}, - {"stroke-dasharray", PropertyId::Stroke_Dasharray}, - {"stroke-dashoffset", PropertyId::Stroke_Dashoffset}, - {"stroke-linecap", PropertyId::Stroke_Linecap}, - {"stroke-linejoin", PropertyId::Stroke_Linejoin}, - {"stroke-miterlimit", PropertyId::Stroke_Miterlimit}, - {"stroke-opacity", PropertyId::Stroke_Opacity}, - {"stroke-width", PropertyId::Stroke_Width}, - {"visibility", PropertyId::Visibility} +static const std::map csspropertymap = { + {"clip-path", PropertyID::Clip_Path}, + {"clip-rule", PropertyID::Clip_Rule}, + {"color", PropertyID::Color}, + {"display", PropertyID::Display}, + {"fill", PropertyID::Fill}, + {"fill-opacity", PropertyID::Fill_Opacity}, + {"fill-rule", PropertyID::Fill_Rule}, + {"marker-end", PropertyID::Marker_End}, + {"marker-mid", PropertyID::Marker_Mid}, + {"marker-start", PropertyID::Marker_Start}, + {"mask", PropertyID::Mask}, + {"opacity", PropertyID::Opacity}, + {"overflow", PropertyID::Overflow}, + {"solid-color", PropertyID::Solid_Color}, + {"solid-opacity", PropertyID::Solid_Opacity}, + {"stop-color", PropertyID::Stop_Color}, + {"stop-opacity", PropertyID::Stop_Opacity}, + {"stroke", PropertyID::Stroke}, + {"stroke-dasharray", PropertyID::Stroke_Dasharray}, + {"stroke-dashoffset", PropertyID::Stroke_Dashoffset}, + {"stroke-linecap", PropertyID::Stroke_Linecap}, + {"stroke-linejoin", PropertyID::Stroke_Linejoin}, + {"stroke-miterlimit", PropertyID::Stroke_Miterlimit}, + {"stroke-opacity", PropertyID::Stroke_Opacity}, + {"stroke-width", PropertyID::Stroke_Width}, + {"visibility", PropertyID::Visibility} }; -static inline ElementId elementId(const std::string& name) +static inline ElementID elementId(const std::string& name) { auto it = elementmap.find(name); if(it == elementmap.end()) - return ElementId::Unknown; + return ElementID::Unknown; return it->second; } -static inline PropertyId cssPropertyId(const std::string& name) +static inline PropertyID cssPropertyId(const std::string& name) { auto it = csspropertymap.find(name); if(it == csspropertymap.end()) - return PropertyId::Unknown; + return PropertyID::Unknown; return it->second; } -static inline PropertyId propertyId(const std::string& name) +static inline PropertyID propertyId(const std::string& name) { auto it = propertymap.find(name); if(it == propertymap.end()) @@ -1148,331 +1140,17 @@ static inline PropertyId propertyId(const std::string& name) return it->second; } -#define IS_STARTNAMECHAR(c) (IS_ALPHA(c) || (c) == '_' || (c) == ':') -#define IS_NAMECHAR(c) (IS_STARTNAMECHAR(c) || IS_NUM(c) || (c) == '-' || (c) == '.') -static inline bool readIdentifier(const char*& ptr, const char* end, std::string& value) +bool RuleData::match(const Element* element) const { - if(ptr >= end || !IS_STARTNAMECHAR(*ptr)) + if(m_selector.empty()) return false; - auto start = ptr; - ++ptr; - while(ptr < end && IS_NAMECHAR(*ptr)) - ++ptr; + if(m_selector.size() == 1) + return matchSimpleSelector(m_selector.front(), element); - value.assign(start, ptr); - return true; -} - -#define IS_CSS_STARTNAMECHAR(c) (IS_ALPHA(c) || (c) == '_' || (c) == '-') -#define IS_CSS_NAMECHAR(c) (IS_CSS_STARTNAMECHAR(c) || IS_NUM(c)) -static inline bool readCSSIdentifier(const char*& ptr, const char* end, std::string& value) -{ - if(ptr >= end || !IS_CSS_STARTNAMECHAR(*ptr)) - return false; - - auto start = ptr; - ++ptr; - while(ptr < end && IS_CSS_NAMECHAR(*ptr)) - ++ptr; - - value.assign(start, ptr); - return true; -} - -bool CSSParser::parseMore(const std::string& value) -{ - auto ptr = value.data(); - auto end = ptr + value.size(); - - while(ptr < end) - { - Utils::skipWs(ptr, end); - if(Utils::skipDesc(ptr, end, '@')) - { - if(!parseAtRule(ptr, end)) - return false; - continue; - } - - Rule rule; - if(!parseRule(ptr, end, rule)) - return false; - m_rules.push_back(rule); - } - - return true; -} - -bool CSSParser::parseAtRule(const char*& ptr, const char* end) const -{ - int depth = 0; - while(ptr < end) - { - auto ch = *ptr; - ++ptr; - if(ch == ';' && depth == 0) - break; - if(ch == '{') ++depth; - else if(ch == '}' && depth > 0) - { - if(depth == 1) - break; - --depth; - } - } - - return true; -} - -bool CSSParser::parseRule(const char*& ptr, const char* end, Rule& rule) const -{ - if(!parseSelectors(ptr, end, rule.selectors)) - return false; - - if(!parseDeclarations(ptr, end, rule.declarations)) - return false; - - return true; -} - -bool CSSParser::parseSelectors(const char*& ptr, const char* end, SelectorList& selectors) const -{ - Selector selector; - if(!parseSelector(ptr, end, selector)) - return false; - selectors.push_back(selector); - - while(Utils::skipDesc(ptr, end, ',')) - { - Utils::skipWs(ptr, end); - Selector selector; - if(!parseSelector(ptr, end, selector)) - return false; - selectors.push_back(selector); - } - - return true; -} - -bool CSSParser::parseDeclarations(const char*& ptr, const char* end, PropertyList& declarations) const -{ - if(!Utils::skipDesc(ptr, end, '{')) - return false; - - std::string name; - std::string value; - Utils::skipWs(ptr, end); - do { - if(!readCSSIdentifier(ptr, end, name)) - return false; - Utils::skipWs(ptr, end); - if(!Utils::skipDesc(ptr, end, ':')) - return false; - Utils::skipWs(ptr, end); - auto start = ptr; - while(ptr < end && !(*ptr == '!' || *ptr == ';' || *ptr == '}')) - ++ptr; - value.assign(start, Utils::rtrim(start, ptr)); - int specificity = 0x10; - if(Utils::skipDesc(ptr, end, '!')) - { - if(!Utils::skipDesc(ptr, end, "important")) - return false; - specificity = 0x1000; - } - - auto id = cssPropertyId(name); - if(id != PropertyId::Unknown) - declarations.set(id, value, specificity); - Utils::skipWsDelimiter(ptr, end, ';'); - } while(ptr < end && *ptr != '}'); - - return Utils::skipDesc(ptr, end, '}'); -} - -#define IS_SELECTOR_STARTNAMECHAR(c) (IS_CSS_STARTNAMECHAR(c) || (c) == '*' || (c) == '#' || (c) == '.' || (c) == '[' || (c) == ':') -bool CSSParser::parseSelector(const char*& ptr, const char* end, Selector& selector) const -{ - do { - SimpleSelector simpleSelector; - if(!parseSimpleSelector(ptr, end, simpleSelector)) - return false; - - selector.specificity += (simpleSelector.id == ElementId::Star) ? 0x0 : 0x1; - for(auto& attributeSelector : simpleSelector.attributeSelectors) - selector.specificity += (attributeSelector.id == PropertyId::Id) ? 0x10000 : 0x100; - - selector.simpleSelectors.push_back(simpleSelector); - Utils::skipWs(ptr, end); - } while(ptr < end && IS_SELECTOR_STARTNAMECHAR(*ptr)); - - return true; -} - -bool CSSParser::parseSimpleSelector(const char*& ptr, const char* end, SimpleSelector& simpleSelector) const -{ - std::string name; - if(Utils::skipDesc(ptr, end, '*')) - simpleSelector.id = ElementId::Star; - else if(readCSSIdentifier(ptr, end, name)) - simpleSelector.id = elementId(name); - - while(ptr < end) - { - if(Utils::skipDesc(ptr, end, '#')) - { - AttributeSelector a; - a.id = PropertyId::Id; - a.matchType = AttributeSelector::MatchType::Equal; - if(!readCSSIdentifier(ptr, end, a.value)) - return false; - simpleSelector.attributeSelectors.push_back(a); - continue; - } - - if(Utils::skipDesc(ptr, end, '.')) - { - AttributeSelector a; - a.id = PropertyId::Class; - a.matchType = AttributeSelector::MatchType::Includes; - if(!readCSSIdentifier(ptr, end, a.value)) - return false; - simpleSelector.attributeSelectors.push_back(a); - continue; - } - - if(Utils::skipDesc(ptr, end, '[')) - { - Utils::skipWs(ptr, end); - if(!readCSSIdentifier(ptr, end, name)) - return false; - AttributeSelector a; - a.id = propertyId(name); - if(Utils::skipDesc(ptr, end, '=')) - a.matchType = AttributeSelector::MatchType::Equal; - else if(Utils::skipDesc(ptr, end, "~=")) - a.matchType = AttributeSelector::MatchType::Includes; - else if(Utils::skipDesc(ptr, end, "|=")) - a.matchType = AttributeSelector::MatchType::DashMatch; - else if(Utils::skipDesc(ptr, end, "^=")) - a.matchType = AttributeSelector::MatchType::StartsWith; - else if(Utils::skipDesc(ptr, end, "$=")) - a.matchType = AttributeSelector::MatchType::EndsWith; - else if(Utils::skipDesc(ptr, end, "*=")) - a.matchType = AttributeSelector::MatchType::Contains; - if(a.matchType != AttributeSelector::MatchType::None) - { - Utils::skipWs(ptr, end); - if(!readCSSIdentifier(ptr, end, a.value)) - { - if(ptr >= end || !(*ptr == '\"' || *ptr == '\'')) - return false; - - auto quote = *ptr; - ++ptr; - if(!Utils::readUntil(ptr, end, quote, a.value)) - return false; - ++ptr; - } - } - - Utils::skipWs(ptr, end); - if(!Utils::skipDesc(ptr, end, ']')) - return false; - simpleSelector.attributeSelectors.push_back(a); - continue; - } - - if(Utils::skipDesc(ptr, end, ':')) - { - if(!readCSSIdentifier(ptr, end, name)) - return false; - PseudoClass pseudo; - if(name.compare("empty") == 0) - pseudo.type = PseudoClass::Type::Empty; - else if(name.compare("root") == 0) - pseudo.type = PseudoClass::Type::Root; - else if(name.compare("not") == 0) - pseudo.type = PseudoClass::Type::Not; - else if(name.compare("first-child") == 0) - pseudo.type = PseudoClass::Type::FirstChild; - else if(name.compare("last-child") == 0) - pseudo.type = PseudoClass::Type::LastChild; - else if(name.compare("only-child") == 0) - pseudo.type = PseudoClass::Type::OnlyChild; - else if(name.compare("first-of-type") == 0) - pseudo.type = PseudoClass::Type::FirstOfType; - else if(name.compare("last-of-type") == 0) - pseudo.type = PseudoClass::Type::LastOfType; - else if(name.compare("only-of-type") == 0) - pseudo.type = PseudoClass::Type::OnlyOfType; - if(pseudo.type == PseudoClass::Type::Not) - { - if(!Utils::skipDesc(ptr, end, '(')) - return false; - - Utils::skipWs(ptr, end); - if(!parseSelectors(ptr, end, pseudo.notSelectors)) - return false; - - Utils::skipWs(ptr, end); - if(!Utils::skipDesc(ptr, end, ')')) - return false; - } - - simpleSelector.pseudoClasses.push_back(pseudo); - continue; - } - - break; - } - - Utils::skipWs(ptr, end); - if(Utils::skipDesc(ptr, end, '>')) - simpleSelector.combinator = SimpleSelector::Combinator::Child; - else if(Utils::skipDesc(ptr, end, '+')) - simpleSelector.combinator = SimpleSelector::Combinator::DirectAdjacent; - else if(Utils::skipDesc(ptr, end, '~')) - simpleSelector.combinator = SimpleSelector::Combinator::InDirectAdjacent; - - return true; -} - -RuleMatchContext::RuleMatchContext(const std::vector& rules) -{ - for(auto& rule : rules) - for(auto& selector : rule.selectors) - m_selectors.emplace(selector.specificity, std::make_pair(&selector, &rule.declarations)); -} - -std::vector RuleMatchContext::match(const Element* element) const -{ - std::vector declarations; - auto it = m_selectors.begin(); - auto end = m_selectors.end(); - for(;it != end;++it) - { - auto& value = it->second; - if(!selectorMatch(std::get<0>(value), element)) - continue; - declarations.push_back(std::get<1>(value)); - } - - return declarations; -} - -bool RuleMatchContext::selectorMatch(const Selector* selector, const Element* element) const -{ - if(selector->simpleSelectors.empty()) - return false; - - if(selector->simpleSelectors.size() == 1) - return simpleSelectorMatch(selector->simpleSelectors.front(), element); - - auto it = selector->simpleSelectors.rbegin(); - auto end = selector->simpleSelectors.rend(); - if(!simpleSelectorMatch(*it, element)) + auto it = m_selector.rbegin(); + auto end = m_selector.rend(); + if(!matchSimpleSelector(*it, element)) return false; ++it; @@ -1485,14 +1163,14 @@ bool RuleMatchContext::selectorMatch(const Selector* selector, const Element* el break; case SimpleSelector::Combinator::DirectAdjacent: case SimpleSelector::Combinator::InDirectAdjacent: - element = element->previousSibling(); + element = element->previousElement(); break; } if(element == nullptr) return false; - auto match = simpleSelectorMatch(*it, element); + auto match = matchSimpleSelector(*it, element); if(!match && (it->combinator != SimpleSelector::Combinator::Descendant && it->combinator != SimpleSelector::Combinator::InDirectAdjacent)) return false; @@ -1503,23 +1181,23 @@ bool RuleMatchContext::selectorMatch(const Selector* selector, const Element* el return true; } -bool RuleMatchContext::simpleSelectorMatch(const SimpleSelector& selector, const Element* element) const +bool RuleData::matchSimpleSelector(const SimpleSelector& selector, const Element* element) const { - if(selector.id != ElementId::Star && selector.id != element->id) + if(selector.id != ElementID::Star && selector.id != element->id) return false; - for(auto& attributeSelector : selector.attributeSelectors) - if(!attributeSelectorMatch(attributeSelector, element)) + for(auto& sel : selector.attributeSelectors) + if(!matchAttributeSelector(sel, element)) return false; - for(auto& pseudoClass : selector.pseudoClasses) - if(!pseudoClassMatch(pseudoClass, element)) + for(auto& sel : selector.pseudoClassSelectors) + if(!matchPseudoClassSelector(sel, element)) return false; return true; } -bool RuleMatchContext::attributeSelectorMatch(const AttributeSelector& selector, const Element* element) const +bool RuleData::matchAttributeSelector(const AttributeSelector& selector, const Element* element) const { auto& value = element->get(selector.id); if(value.empty()) @@ -1583,52 +1261,70 @@ bool RuleMatchContext::attributeSelectorMatch(const AttributeSelector& selector, return false; } -bool RuleMatchContext::pseudoClassMatch(const PseudoClass& pseudo, const Element* element) const +bool RuleData::matchPseudoClassSelector(const PseudoClassSelector& selector, const Element* element) const { - if(pseudo.type == PseudoClass::Type::Empty) + if(selector.type == PseudoClassSelector::Type::Empty) return element->children.empty(); - if(pseudo.type == PseudoClass::Type::Root) + if(selector.type == PseudoClassSelector::Type::Root) return element->parent == nullptr; - if(pseudo.type == PseudoClass::Type::Not) + if(selector.type == PseudoClassSelector::Type::Is) { - for(auto& selector : pseudo.notSelectors) - if(selectorMatch(&selector, element)) - return false; - return true; - } - - if(pseudo.type == PseudoClass::Type::FirstChild) - return !element->previousSibling(); - - if(pseudo.type == PseudoClass::Type::LastChild) - return !element->nextSibling(); - - if(pseudo.type == PseudoClass::Type::OnlyChild) - return !(element->previousSibling() || element->nextSibling()); - - if(pseudo.type == PseudoClass::Type::FirstOfType) - { - auto sibling = element->previousSibling(); - while(sibling) - { - if(sibling->id == element->id) - return false; - sibling = element->previousSibling(); + for(auto& selector : selector.subSelectors) { + for(auto& sel : selector) { + if(!matchSimpleSelector(sel, element)) { + return false; + } + } } return true; } - if(pseudo.type == PseudoClass::Type::LastOfType) + if(selector.type == PseudoClassSelector::Type::Not) { - auto sibling = element->nextSibling(); + for(auto& selector : selector.subSelectors) { + for(auto& sel : selector) { + if(matchSimpleSelector(sel, element)) { + return false; + } + } + } + + return true; + } + + if(selector.type == PseudoClassSelector::Type::FirstChild) + return !element->previousElement(); + + if(selector.type == PseudoClassSelector::Type::LastChild) + return !element->nextElement(); + + if(selector.type == PseudoClassSelector::Type::OnlyChild) + return !(element->previousElement() || element->nextElement()); + + if(selector.type == PseudoClassSelector::Type::FirstOfType) + { + auto sibling = element->previousElement(); while(sibling) { if(sibling->id == element->id) return false; - sibling = element->nextSibling(); + sibling = element->previousElement(); + } + + return true; + } + + if(selector.type == PseudoClassSelector::Type::LastOfType) + { + auto sibling = element->nextElement(); + while(sibling) + { + if(sibling->id == element->id) + return false; + sibling = element->nextElement(); } return true; @@ -1637,50 +1333,372 @@ bool RuleMatchContext::pseudoClassMatch(const PseudoClass& pseudo, const Element return false; } -static inline std::unique_ptr createElement(ElementId id) +void StyleSheet::parse(const std::string& content) +{ + CSSParser::parseSheet(this, content); +} + +void StyleSheet::add(const Rule& rule) +{ + for(auto& selector : rule.selectors) { + uint32_t specificity = 0; + for(auto& simpleSelector : selector) { + specificity += (simpleSelector.id == ElementID::Star) ? 0x0 : 0x1; + for(auto& attributeSelector : simpleSelector.attributeSelectors) { + specificity += (attributeSelector.id == PropertyID::Id) ? 0x10000 : 0x100; + } + } + + m_rules.emplace(selector, rule.declarations, specificity, m_position); + } + + m_position += 1; +} + +std::vector StyleSheet::match(const Element *element) const +{ + std::vector declarations; + for(auto& rule : m_rules) { + if(!rule.match(element)) + continue; + declarations.push_back(&rule.properties()); + } + + return declarations; +} + +#define IS_STARTNAMECHAR(c) (IS_ALPHA(c) || (c) == '_' || (c) == ':') +#define IS_NAMECHAR(c) (IS_STARTNAMECHAR(c) || IS_NUM(c) || (c) == '-' || (c) == '.') +static inline bool readIdentifier(const char*& ptr, const char* end, std::string& value) +{ + if(ptr >= end || !IS_STARTNAMECHAR(*ptr)) + return false; + + auto start = ptr; + ++ptr; + while(ptr < end && IS_NAMECHAR(*ptr)) + ++ptr; + + value.assign(start, ptr); + return true; +} + +#define IS_CSS_STARTNAMECHAR(c) (IS_ALPHA(c) || (c) == '_' || (c) == '-') +#define IS_CSS_NAMECHAR(c) (IS_CSS_STARTNAMECHAR(c) || IS_NUM(c)) +static inline bool readCSSIdentifier(const char*& ptr, const char* end, std::string& value) +{ + if(ptr >= end || !IS_CSS_STARTNAMECHAR(*ptr)) + return false; + + auto start = ptr; + ++ptr; + while(ptr < end && IS_CSS_NAMECHAR(*ptr)) + ++ptr; + + value.assign(start, ptr); + return true; +} + +bool CSSParser::parseSheet(StyleSheet* sheet, const std::string& value) +{ + auto ptr = value.data(); + auto end = ptr + value.size(); + + Rule rule; + while(ptr < end) + { + Utils::skipWs(ptr, end); + if(Utils::skipDesc(ptr, end, '@')) + { + if(!parseAtRule(ptr, end)) + return false; + continue; + } + + if(!parseRule(ptr, end, rule)) + return false; + sheet->add(rule); + } + + return true; +} + +bool CSSParser::parseAtRule(const char*& ptr, const char* end) +{ + int depth = 0; + while(ptr < end) + { + auto ch = *ptr; + ++ptr; + if(ch == ';' && depth == 0) + break; + if(ch == '{') ++depth; + else if(ch == '}' && depth > 0) + { + if(depth == 1) + break; + --depth; + } + } + + return true; +} + +bool CSSParser::parseRule(const char*& ptr, const char* end, Rule& rule) +{ + if(!parseSelectors(ptr, end, rule.selectors)) + return false; + + if(!parseDeclarations(ptr, end, rule.declarations)) + return false; + + return true; +} + +bool CSSParser::parseSelectors(const char*& ptr, const char* end, SelectorList& selectors) +{ + selectors.clear(); + Selector selector; + if(!parseSelector(ptr, end, selector)) + return false; + selectors.push_back(selector); + + while(Utils::skipDesc(ptr, end, ',')) + { + Utils::skipWs(ptr, end); + Selector selector; + if(!parseSelector(ptr, end, selector)) + return false; + selectors.push_back(selector); + } + + return true; +} + +bool CSSParser::parseDeclarations(const char*& ptr, const char* end, PropertyList& declarations) +{ + declarations.clear(); + if(!Utils::skipDesc(ptr, end, '{')) + return false; + + std::string name; + std::string value; + Utils::skipWs(ptr, end); + do { + if(!readCSSIdentifier(ptr, end, name)) + return false; + Utils::skipWs(ptr, end); + if(!Utils::skipDesc(ptr, end, ':')) + return false; + Utils::skipWs(ptr, end); + auto start = ptr; + while(ptr < end && !(*ptr == '!' || *ptr == ';' || *ptr == '}')) + ++ptr; + value.assign(start, Utils::rtrim(start, ptr)); + int specificity = 0x10; + if(Utils::skipDesc(ptr, end, '!')) + { + if(!Utils::skipDesc(ptr, end, "important")) + return false; + specificity = 0x1000; + } + + auto id = cssPropertyId(name); + if(id != PropertyID::Unknown) + declarations.set(id, value, specificity); + Utils::skipWsDelimiter(ptr, end, ';'); + } while(ptr < end && *ptr != '}'); + + return Utils::skipDesc(ptr, end, '}'); +} + +#define IS_SELECTOR_STARTNAMECHAR(c) (IS_CSS_STARTNAMECHAR(c) || (c) == '*' || (c) == '#' || (c) == '.' || (c) == '[' || (c) == ':') +bool CSSParser::parseSelector(const char*& ptr, const char* end, Selector& selector) +{ + do { + SimpleSelector simpleSelector; + if(!parseSimpleSelector(ptr, end, simpleSelector)) + return false; + selector.push_back(simpleSelector); + Utils::skipWs(ptr, end); + } while(ptr < end && IS_SELECTOR_STARTNAMECHAR(*ptr)); + + return true; +} + +bool CSSParser::parseSimpleSelector(const char*& ptr, const char* end, SimpleSelector& simpleSelector) +{ + std::string name; + if(Utils::skipDesc(ptr, end, '*')) + simpleSelector.id = ElementID::Star; + else if(readCSSIdentifier(ptr, end, name)) + simpleSelector.id = elementId(name); + + while(ptr < end) + { + if(Utils::skipDesc(ptr, end, '#')) + { + AttributeSelector a; + a.id = PropertyID::Id; + a.matchType = AttributeSelector::MatchType::Equal; + if(!readCSSIdentifier(ptr, end, a.value)) + return false; + simpleSelector.attributeSelectors.push_back(a); + continue; + } + + if(Utils::skipDesc(ptr, end, '.')) + { + AttributeSelector a; + a.id = PropertyID::Class; + a.matchType = AttributeSelector::MatchType::Includes; + if(!readCSSIdentifier(ptr, end, a.value)) + return false; + simpleSelector.attributeSelectors.push_back(a); + continue; + } + + if(Utils::skipDesc(ptr, end, '[')) + { + Utils::skipWs(ptr, end); + if(!readCSSIdentifier(ptr, end, name)) + return false; + AttributeSelector a; + a.id = propertyId(name); + if(Utils::skipDesc(ptr, end, '=')) + a.matchType = AttributeSelector::MatchType::Equal; + else if(Utils::skipDesc(ptr, end, "~=")) + a.matchType = AttributeSelector::MatchType::Includes; + else if(Utils::skipDesc(ptr, end, "|=")) + a.matchType = AttributeSelector::MatchType::DashMatch; + else if(Utils::skipDesc(ptr, end, "^=")) + a.matchType = AttributeSelector::MatchType::StartsWith; + else if(Utils::skipDesc(ptr, end, "$=")) + a.matchType = AttributeSelector::MatchType::EndsWith; + else if(Utils::skipDesc(ptr, end, "*=")) + a.matchType = AttributeSelector::MatchType::Contains; + if(a.matchType != AttributeSelector::MatchType::None) + { + Utils::skipWs(ptr, end); + if(!readCSSIdentifier(ptr, end, a.value)) + { + if(ptr >= end || !(*ptr == '\"' || *ptr == '\'')) + return false; + + auto quote = *ptr; + ++ptr; + if(!Utils::readUntil(ptr, end, quote, a.value)) + return false; + ++ptr; + } + } + + Utils::skipWs(ptr, end); + if(!Utils::skipDesc(ptr, end, ']')) + return false; + simpleSelector.attributeSelectors.push_back(a); + continue; + } + + if(Utils::skipDesc(ptr, end, ':')) + { + if(!readCSSIdentifier(ptr, end, name)) + return false; + PseudoClassSelector selector; + if(name.compare("empty") == 0) + selector.type = PseudoClassSelector::Type::Empty; + else if(name.compare("root") == 0) + selector.type = PseudoClassSelector::Type::Root; + else if(name.compare("not") == 0) + selector.type = PseudoClassSelector::Type::Not; + else if(name.compare("first-child") == 0) + selector.type = PseudoClassSelector::Type::FirstChild; + else if(name.compare("last-child") == 0) + selector.type = PseudoClassSelector::Type::LastChild; + else if(name.compare("only-child") == 0) + selector.type = PseudoClassSelector::Type::OnlyChild; + else if(name.compare("first-of-type") == 0) + selector.type = PseudoClassSelector::Type::FirstOfType; + else if(name.compare("last-of-type") == 0) + selector.type = PseudoClassSelector::Type::LastOfType; + else if(name.compare("only-of-type") == 0) + selector.type = PseudoClassSelector::Type::OnlyOfType; + if(selector.type == PseudoClassSelector::Type::Is || selector.type == PseudoClassSelector::Type::Not) + { + if(!Utils::skipDesc(ptr, end, '(')) + return false; + + Utils::skipWs(ptr, end); + if(!parseSelectors(ptr, end, selector.subSelectors)) + return false; + + Utils::skipWs(ptr, end); + if(!Utils::skipDesc(ptr, end, ')')) + return false; + } + + simpleSelector.pseudoClassSelectors.push_back(selector); + continue; + } + + break; + } + + Utils::skipWs(ptr, end); + if(Utils::skipDesc(ptr, end, '>')) + simpleSelector.combinator = SimpleSelector::Combinator::Child; + else if(Utils::skipDesc(ptr, end, '+')) + simpleSelector.combinator = SimpleSelector::Combinator::DirectAdjacent; + else if(Utils::skipDesc(ptr, end, '~')) + simpleSelector.combinator = SimpleSelector::Combinator::InDirectAdjacent; + + return true; +} + +static inline std::unique_ptr createElement(ElementID id) { switch(id) { - case ElementId::Svg: + case ElementID::Svg: return std::make_unique(); - case ElementId::Path: + case ElementID::Path: return std::make_unique(); - case ElementId::G: + case ElementID::G: return std::make_unique(); - case ElementId::Rect: + case ElementID::Rect: return std::make_unique(); - case ElementId::Circle: + case ElementID::Circle: return std::make_unique(); - case ElementId::Ellipse: + case ElementID::Ellipse: return std::make_unique(); - case ElementId::Line: + case ElementID::Line: return std::make_unique(); - case ElementId::Defs: + case ElementID::Defs: return std::make_unique(); - case ElementId::Polygon: + case ElementID::Polygon: return std::make_unique(); - case ElementId::Polyline: + case ElementID::Polyline: return std::make_unique(); - case ElementId::Stop: + case ElementID::Stop: return std::make_unique(); - case ElementId::LinearGradient: + case ElementID::LinearGradient: return std::make_unique(); - case ElementId::RadialGradient: + case ElementID::RadialGradient: return std::make_unique(); - case ElementId::Symbol: + case ElementID::Symbol: return std::make_unique(); - case ElementId::Use: + case ElementID::Use: return std::make_unique(); - case ElementId::Pattern: + case ElementID::Pattern: return std::make_unique(); - case ElementId::Mask: + case ElementID::Mask: return std::make_unique(); - case ElementId::ClipPath: + case ElementID::ClipPath: return std::make_unique(); - case ElementId::SolidColor: + case ElementID::SolidColor: return std::make_unique(); - case ElementId::Marker: + case ElementID::Marker: return std::make_unique(); - case ElementId::Style: + case ElementID::Style: return std::make_unique(); default: break; @@ -1790,26 +1808,22 @@ static inline void parseStyle(const std::string& string, Element* element) ++ptr; value.assign(start, Utils::rtrim(start, ptr)); auto id = cssPropertyId(name); - if(id != PropertyId::Unknown) + if(id != PropertyID::Unknown) element->set(id, value, 0x100); Utils::skipWsDelimiter(ptr, end, ';'); } } -ParseDocument::ParseDocument() -{ -} +TreeBuilder::TreeBuilder() = default; -ParseDocument::~ParseDocument() -{ -} +TreeBuilder::~TreeBuilder() = default; -bool ParseDocument::parse(const char* data, std::size_t size) +bool TreeBuilder::parse(const char* data, std::size_t size) { auto ptr = data; auto end = ptr + size; - CSSParser cssparser; + StyleSheet styleSheet; Element* current = nullptr; std::string name; std::string value; @@ -1825,7 +1839,7 @@ bool ParseDocument::parse(const char* data, std::size_t size) }; auto handle_text = [&](const char* start, const char* end, bool in_cdata) { - if(ignoring > 0 || current == nullptr || current->id != ElementId::Style) + if(ignoring > 0 || current == nullptr || current->id != ElementID::Style) return; if(in_cdata) @@ -1834,7 +1848,7 @@ bool ParseDocument::parse(const char* data, std::size_t size) decodeText(start, end, value); remove_comments(value); - cssparser.parseMore(value); + styleSheet.parse(value); }; while(ptr < end) @@ -1940,8 +1954,8 @@ bool ParseDocument::parse(const char* data, std::size_t size) if(!readIdentifier(ptr, end, name)) return false; - auto id = ignoring == 0 ? elementId(name) : ElementId::Unknown; - if(id == ElementId::Unknown) + auto id = ignoring == 0 ? elementId(name) : ElementID::Unknown; + if(id == ElementID::Unknown) ++ignoring; Element* element = nullptr; @@ -1952,7 +1966,7 @@ bool ParseDocument::parse(const char* data, std::size_t size) if(m_rootElement == nullptr) { - if(id != ElementId::Svg) + if(id != ElementID::Svg) return false; m_rootElement = std::make_unique(); @@ -1988,18 +2002,18 @@ bool ParseDocument::parse(const char* data, std::size_t size) if(ptr >= end || *ptr != quote) return false; - auto id = element ? propertyId(name) : PropertyId::Unknown; - if(id != PropertyId::Unknown) + auto id = element ? propertyId(name) : PropertyID::Unknown; + if(id != PropertyID::Unknown) { decodeText(start, Utils::rtrim(start, ptr), value); - if(id == PropertyId::Style) + if(id == PropertyID::Style) { remove_comments(value); parseStyle(value, element); } else { - if(id == PropertyId::Id) + if(id == PropertyID::Id) m_idCache.emplace(value, element); element->set(id, value, 0x1); } @@ -2037,16 +2051,14 @@ bool ParseDocument::parse(const char* data, std::size_t size) if(!m_rootElement || ptr < end || ignoring > 0) return false; - const auto& rules = cssparser.rules(); - if(!rules.empty()) + if(!styleSheet.empty()) { - RuleMatchContext context(rules); - m_rootElement->transverse([&context](Node* node) { + m_rootElement->transverse([&styleSheet](Node* node) { if(node->isText()) return false; auto element = static_cast(node); - auto declarations = context.match(element); + auto declarations = styleSheet.match(element); for(auto& declaration : declarations) element->properties.add(*declaration); return false; @@ -2056,7 +2068,7 @@ bool ParseDocument::parse(const char* data, std::size_t size) return true; } -Element* ParseDocument::getElementById(const std::string& id) const +Element* TreeBuilder::getElementById(const std::string& id) const { auto it = m_idCache.find(id); if(it == m_idCache.end()) @@ -2065,9 +2077,9 @@ Element* ParseDocument::getElementById(const std::string& id) const return it->second; } -std::unique_ptr ParseDocument::layout() const +std::unique_ptr TreeBuilder::build() const { - return m_rootElement->layoutDocument(this); + return m_rootElement->build(this); } } // namespace lunasvg diff --git a/source/parser.h b/source/parser.h index 6ced83e16..76864d3ee 100644 --- a/source/parser.h +++ b/source/parser.h @@ -2,6 +2,7 @@ #define PARSER_H #include +#include #include "property.h" #include "element.h" @@ -58,12 +59,15 @@ private: static bool parseLength(const char*& ptr, const char* end, double& value, LengthUnits& units, LengthNegativeValuesMode mode); static bool parseNumberList(const char*& ptr, const char* end, double* values, int count); static bool parseArcFlag(const char*& ptr, const char* end, bool& flag); - static bool parseColorComponent(const char*& ptr, const char* end, double& value); + static bool parseColorComponent(const char*& ptr, const char* end, int& component); static bool parseUrlFragment(const char*& ptr, const char* end, std::string& ref); static bool parseTransform(const char*& ptr, const char* end, TransformType& type, double* values, int& count); }; -struct Selector; +struct SimpleSelector; + +using Selector = std::vector; +using SelectorList = std::vector; struct AttributeSelector { @@ -78,20 +82,19 @@ struct AttributeSelector Contains }; - PropertyId id{PropertyId::Unknown}; - std::string value; MatchType matchType{MatchType::None}; + PropertyID id{PropertyID::Unknown}; + std::string value; }; -using SelectorList = std::vector; - -struct PseudoClass +struct PseudoClassSelector { enum class Type { Unknown, Empty, Root, + Is, Not, FirstChild, LastChild, @@ -102,7 +105,9 @@ struct PseudoClass }; Type type{Type::Unknown}; - SelectorList notSelectors; + int16_t a{0}; + int16_t b{0}; + SelectorList subSelectors; }; struct SimpleSelector @@ -115,16 +120,10 @@ struct SimpleSelector InDirectAdjacent }; - ElementId id{ElementId::Star}; - std::vector attributeSelectors; - std::vector pseudoClasses; Combinator combinator{Combinator::Descendant}; -}; - -struct Selector -{ - std::vector simpleSelectors; - int specificity{0}; + ElementID id{ElementID::Star}; + std::vector attributeSelectors; + std::vector pseudoClassSelectors; }; struct Rule @@ -133,21 +132,47 @@ struct Rule PropertyList declarations; }; -class RuleMatchContext -{ +class RuleData { public: - RuleMatchContext(const std::vector& rules); + RuleData(const Selector& selector, const PropertyList& properties, uint32_t specificity, uint32_t position) + : m_selector(selector), m_properties(properties), m_specificity(specificity), m_position(position) + {} + + const Selector& selector() const { return m_selector; } + const PropertyList& properties() const { return m_properties; } + const uint32_t& specificity() const { return m_specificity; } + const uint32_t& position() const { return m_position; } + + bool match(const Element* element) const; + +private: + bool matchSimpleSelector(const SimpleSelector& selector, const Element* element) const; + bool matchAttributeSelector(const AttributeSelector& selector, const Element* element) const; + bool matchPseudoClassSelector(const PseudoClassSelector& selector, const Element* element) const; + +private: + Selector m_selector; + PropertyList m_properties; + uint32_t m_specificity; + uint32_t m_position; +}; + +inline bool operator<(const RuleData& a, const RuleData& b) { return std::tie(a.specificity(), a.position()) < std::tie(b.specificity(), b.position()); } +inline bool operator>(const RuleData& a, const RuleData& b) { return std::tie(a.specificity(), a.position()) > std::tie(b.specificity(), b.position()); } + +class StyleSheet { +public: + StyleSheet() = default; + + void parse(const std::string& content); + void add(const Rule& rule); + bool empty() const { return m_position == 0; } std::vector match(const Element* element) const; private: - bool selectorMatch(const Selector* selector, const Element* element) const; - bool simpleSelectorMatch(const SimpleSelector& selector, const Element* element) const; - bool attributeSelectorMatch(const AttributeSelector& selector, const Element* element) const; - bool pseudoClassMatch(const PseudoClass& pseudo, const Element* element) const; - -private: - std::multimap, std::less> m_selectors; + std::multiset m_rules; + uint32_t m_position{0}; }; class CSSParser @@ -155,35 +180,29 @@ class CSSParser public: CSSParser() = default; - bool parseMore(const std::string& value); - - const std::vector& rules() const { return m_rules; } + static bool parseSheet(StyleSheet* sheet, const std::string& value); private: - bool parseAtRule(const char*& ptr, const char* end) const; - bool parseRule(const char*& ptr, const char* end, Rule& rule) const; - bool parseSelectors(const char*& ptr, const char* end, SelectorList& selectors) const; - bool parseDeclarations(const char*& ptr, const char* end, PropertyList& declarations) const; - bool parseSelector(const char*& ptr, const char* end, Selector& selector) const; - bool parseSimpleSelector(const char*& ptr, const char* end, SimpleSelector& simpleSelector) const; - -private: - std::vector m_rules; + static bool parseAtRule(const char*& ptr, const char* end); + static bool parseRule(const char*& ptr, const char* end, Rule& rule); + static bool parseSelectors(const char*& ptr, const char* end, SelectorList& selectors); + static bool parseDeclarations(const char*& ptr, const char* end, PropertyList& declarations); + static bool parseSelector(const char*& ptr, const char* end, Selector& selector); + static bool parseSimpleSelector(const char*& ptr, const char* end, SimpleSelector& simpleSelector); }; class LayoutSymbol; -class ParseDocument -{ +class TreeBuilder { public: - ParseDocument(); - ~ParseDocument(); + TreeBuilder(); + ~TreeBuilder(); bool parse(const char* data, std::size_t size); SVGElement* rootElement() const { return m_rootElement.get(); } Element* getElementById(const std::string& id) const; - std::unique_ptr layout() const; + std::unique_ptr build() const; private: std::unique_ptr m_rootElement; diff --git a/source/property.cpp b/source/property.cpp index 97ddf3730..44b1414df 100644 --- a/source/property.cpp +++ b/source/property.cpp @@ -2,21 +2,26 @@ #include "styledelement.h" #include "lunasvg.h" +#include #include namespace lunasvg { -const Color Color::Black{0, 0, 0, 1}; -const Color Color::White{1, 1, 1, 1}; -const Color Color::Red{1, 0, 0, 1}; -const Color Color::Green{0, 1, 0, 1}; -const Color Color::Blue{0, 0, 1, 1}; -const Color Color::Yellow{1, 1, 0, 1}; -const Color Color::Transparent{0, 0, 0, 0}; +const Color Color::Black(0xFF000000); +const Color Color::White(0xFFFFFFFF); +const Color Color::Transparent(0x00000000); -Color::Color(double r, double g, double b, double a) - : r(r), g(g), b(b), a(a) +Color& Color::combine(double opacity) { + *this = combined(opacity); + return *this; +} + +Color Color::combined(double opacity) const +{ + auto rgb = m_value & 0x00FFFFFF; + auto a = static_cast(std::clamp(opacity * alpha(), 0.0, 255.0)); + return Color(rgb | a << 24); } Paint::Paint(const Color& color) diff --git a/source/property.h b/source/property.h index 52a07e523..619581046 100644 --- a/source/property.h +++ b/source/property.h @@ -68,23 +68,27 @@ class Color { public: Color() = default; - Color(double r, double g, double b, double a = 1); + explicit Color(uint32_t value) : m_value(value) {} + Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : m_value(a << 24 | r << 16 | g << 8 | b) {} - bool isNone() const { return a == 0.0; } + uint8_t alpha() const { return (m_value >> 24) & 0xff; } + uint8_t red() const { return (m_value >> 16) & 0xff; } + uint8_t green() const { return (m_value >> 8) & 0xff; } + uint8_t blue() const { return (m_value >> 0) & 0xff; } + + uint32_t value() const { return m_value; } + + Color& combine(double opacity); + Color combined(double opacity) const; + + bool isNone() const { return m_value == 0; } static const Color Black; static const Color White; - static const Color Red; - static const Color Green; - static const Color Blue; - static const Color Yellow; static const Color Transparent; -public: - double r{0}; - double g{0}; - double b{0}; - double a{1}; +private: + uint32_t m_value{0}; }; class Paint diff --git a/source/stopelement.cpp b/source/stopelement.cpp index 453138356..f38d771df 100644 --- a/source/stopelement.cpp +++ b/source/stopelement.cpp @@ -4,20 +4,20 @@ namespace lunasvg { StopElement::StopElement() - : StyledElement(ElementId::Stop) + : StyledElement(ElementID::Stop) { } double StopElement::offset() const { - auto& value = get(PropertyId::Offset); + auto& value = get(PropertyID::Offset); return Parser::parseNumberPercentage(value, 0.0); } Color StopElement::stopColorWithOpacity() const { auto color = stop_color(); - color.a = stop_opacity(); + color.combine(stop_opacity()); return color; } diff --git a/source/styledelement.cpp b/source/styledelement.cpp index bfb5ad8f0..fda779d87 100644 --- a/source/styledelement.cpp +++ b/source/styledelement.cpp @@ -3,164 +3,164 @@ namespace lunasvg { -StyledElement::StyledElement(ElementId id) +StyledElement::StyledElement(ElementID id) : Element(id) { } Paint StyledElement::fill() const { - auto& value = find(PropertyId::Fill); + auto& value = find(PropertyID::Fill); return Parser::parsePaint(value, this, Color::Black); } Paint StyledElement::stroke() const { - auto& value = find(PropertyId::Stroke); + auto& value = find(PropertyID::Stroke); return Parser::parsePaint(value, this, Color::Transparent); } Color StyledElement::color() const { - auto& value = find(PropertyId::Color); + auto& value = find(PropertyID::Color); return Parser::parseColor(value, this, Color::Black); } Color StyledElement::stop_color() const { - auto& value = find(PropertyId::Stop_Color); + auto& value = find(PropertyID::Stop_Color); return Parser::parseColor(value, this, Color::Black); } Color StyledElement::solid_color() const { - auto& value = find(PropertyId::Solid_Color); + auto& value = find(PropertyID::Solid_Color); return Parser::parseColor(value, this, Color::Black); } double StyledElement::opacity() const { - auto& value = get(PropertyId::Opacity); + auto& value = get(PropertyID::Opacity); return Parser::parseNumberPercentage(value, 1.0); } double StyledElement::fill_opacity() const { - auto& value = find(PropertyId::Fill_Opacity); + auto& value = find(PropertyID::Fill_Opacity); return Parser::parseNumberPercentage(value, 1.0); } double StyledElement::stroke_opacity() const { - auto& value = find(PropertyId::Stroke_Opacity); + auto& value = find(PropertyID::Stroke_Opacity); return Parser::parseNumberPercentage(value, 1.0); } double StyledElement::stop_opacity() const { - auto& value = find(PropertyId::Stop_Opacity); + auto& value = find(PropertyID::Stop_Opacity); return Parser::parseNumberPercentage(value, 1.0); } double StyledElement::solid_opacity() const { - auto& value = find(PropertyId::Solid_Opacity); + auto& value = find(PropertyID::Solid_Opacity); return Parser::parseNumberPercentage(value, 1.0); } double StyledElement::stroke_miterlimit() const { - auto& value = find(PropertyId::Stroke_Miterlimit); + auto& value = find(PropertyID::Stroke_Miterlimit); return Parser::parseNumber(value, 4.0); } Length StyledElement::stroke_width() const { - auto& value = find(PropertyId::Stroke_Width); + auto& value = find(PropertyID::Stroke_Width); return Parser::parseLength(value, ForbidNegativeLengths, Length::One); } Length StyledElement::stroke_dashoffset() const { - auto& value = find(PropertyId::Stroke_Dashoffset); + auto& value = find(PropertyID::Stroke_Dashoffset); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } LengthList StyledElement::stroke_dasharray() const { - auto& value = find(PropertyId::Stroke_Dasharray); + auto& value = find(PropertyID::Stroke_Dasharray); return Parser::parseLengthList(value, ForbidNegativeLengths); } WindRule StyledElement::fill_rule() const { - auto& value = find(PropertyId::Fill_Rule); + auto& value = find(PropertyID::Fill_Rule); return Parser::parseWindRule(value); } WindRule StyledElement::clip_rule() const { - auto& value = find(PropertyId::Clip_Rule); + auto& value = find(PropertyID::Clip_Rule); return Parser::parseWindRule(value); } LineCap StyledElement::stroke_linecap() const { - auto& value = find(PropertyId::Stroke_Linecap); + auto& value = find(PropertyID::Stroke_Linecap); return Parser::parseLineCap(value); } LineJoin StyledElement::stroke_linejoin() const { - auto& value = find(PropertyId::Stroke_Linejoin); + auto& value = find(PropertyID::Stroke_Linejoin); return Parser::parseLineJoin(value); } Display StyledElement::display() const { - auto& value = get(PropertyId::Display); + auto& value = get(PropertyID::Display); return Parser::parseDisplay(value); } Visibility StyledElement::visibility() const { - auto& value = find(PropertyId::Visibility); + auto& value = find(PropertyID::Visibility); return Parser::parseVisibility(value); } Overflow StyledElement::overflow() const { - auto& value = get(PropertyId::Overflow); + auto& value = get(PropertyID::Overflow); return Parser::parseOverflow(value, parent == nullptr ? Overflow::Visible : Overflow::Hidden); } std::string StyledElement::clip_path() const { - auto& value = get(PropertyId::Clip_Path); + auto& value = get(PropertyID::Clip_Path); return Parser::parseUrl(value); } std::string StyledElement::mask() const { - auto& value = get(PropertyId::Mask); + auto& value = get(PropertyID::Mask); return Parser::parseUrl(value); } std::string StyledElement::marker_start() const { - auto& value = find(PropertyId::Marker_Start); + auto& value = find(PropertyID::Marker_Start); return Parser::parseUrl(value); } std::string StyledElement::marker_mid() const { - auto& value = find(PropertyId::Marker_Mid); + auto& value = find(PropertyID::Marker_Mid); return Parser::parseUrl(value); } std::string StyledElement::marker_end() const { - auto& value = find(PropertyId::Marker_End); + auto& value = find(PropertyID::Marker_End); return Parser::parseUrl(value); } diff --git a/source/styledelement.h b/source/styledelement.h index 1257548ad..4d0ceb0a0 100644 --- a/source/styledelement.h +++ b/source/styledelement.h @@ -8,7 +8,7 @@ namespace lunasvg { class StyledElement : public Element { public: - StyledElement(ElementId id); + StyledElement(ElementID id); Paint fill() const; Paint stroke() const; diff --git a/source/styleelement.cpp b/source/styleelement.cpp index 800146cf5..3b1de5765 100644 --- a/source/styleelement.cpp +++ b/source/styleelement.cpp @@ -3,7 +3,7 @@ namespace lunasvg { StyleElement::StyleElement() - : Element(ElementId::Style) + : Element(ElementID::Style) { } diff --git a/source/svgelement.cpp b/source/svgelement.cpp index 1468045c8..e4b1a1d82 100644 --- a/source/svgelement.cpp +++ b/source/svgelement.cpp @@ -5,47 +5,47 @@ namespace lunasvg { SVGElement::SVGElement() - : GraphicsElement(ElementId::Svg) + : GraphicsElement(ElementID::Svg) { } Length SVGElement::x() const { - auto& value = get(PropertyId::X); + auto& value = get(PropertyID::X); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length SVGElement::y() const { - auto& value = get(PropertyId::Y); + auto& value = get(PropertyID::Y); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length SVGElement::width() const { - auto& value = get(PropertyId::Width); + auto& value = get(PropertyID::Width); return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent); } Length SVGElement::height() const { - auto& value = get(PropertyId::Height); + auto& value = get(PropertyID::Height); return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent); } Rect SVGElement::viewBox() const { - auto& value = get(PropertyId::ViewBox); + auto& value = get(PropertyID::ViewBox); return Parser::parseViewBox(value); } PreserveAspectRatio SVGElement::preserveAspectRatio() const { - auto& value = get(PropertyId::PreserveAspectRatio); + auto& value = get(PropertyID::PreserveAspectRatio); return Parser::parsePreserveAspectRatio(value); } -std::unique_ptr SVGElement::layoutDocument(const ParseDocument* document) const +std::unique_ptr SVGElement::build(const TreeBuilder* builder) const { if(isDisplayNone()) return nullptr; @@ -73,7 +73,7 @@ std::unique_ptr SVGElement::layoutDocument(const ParseDocument* do root->clip = isOverflowHidden() ? preserveAspectRatio.getClip(_w, _h, viewBox) : Rect::Invalid; root->opacity = opacity(); - LayoutContext context(document, root.get()); + LayoutContext context(builder, root.get()); root->masker = context.getMasker(mask()); root->clipper = context.getClipper(clip_path()); layoutChildren(&context, root.get()); diff --git a/source/svgelement.h b/source/svgelement.h index b6e62343e..789a7cad4 100644 --- a/source/svgelement.h +++ b/source/svgelement.h @@ -5,7 +5,7 @@ namespace lunasvg { -class ParseDocument; +class TreeBuilder; class LayoutSymbol; class SVGElement : public GraphicsElement @@ -20,7 +20,7 @@ public: Rect viewBox() const; PreserveAspectRatio preserveAspectRatio() const; - std::unique_ptr layoutDocument(const ParseDocument* document) const; + std::unique_ptr build(const TreeBuilder* builder) const; void layout(LayoutContext* context, LayoutContainer* current) const; std::unique_ptr clone() const; diff --git a/source/symbolelement.cpp b/source/symbolelement.cpp index 10d451cb7..03673d8a9 100644 --- a/source/symbolelement.cpp +++ b/source/symbolelement.cpp @@ -4,43 +4,43 @@ namespace lunasvg { SymbolElement::SymbolElement() - : StyledElement(ElementId::Symbol) + : StyledElement(ElementID::Symbol) { } Length SymbolElement::x() const { - auto& value = get(PropertyId::X); + auto& value = get(PropertyID::X); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length SymbolElement::y() const { - auto& value = get(PropertyId::Y); + auto& value = get(PropertyID::Y); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length SymbolElement::width() const { - auto& value = get(PropertyId::Width); + auto& value = get(PropertyID::Width); return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent); } Length SymbolElement::height() const { - auto& value = get(PropertyId::Height); + auto& value = get(PropertyID::Height); return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent); } Rect SymbolElement::viewBox() const { - auto& value = get(PropertyId::ViewBox); + auto& value = get(PropertyID::ViewBox); return Parser::parseViewBox(value); } PreserveAspectRatio SymbolElement::preserveAspectRatio() const { - auto& value = get(PropertyId::PreserveAspectRatio); + auto& value = get(PropertyID::PreserveAspectRatio); return Parser::parsePreserveAspectRatio(value); } diff --git a/source/useelement.cpp b/source/useelement.cpp index f67383303..ced0ec004 100644 --- a/source/useelement.cpp +++ b/source/useelement.cpp @@ -8,47 +8,47 @@ namespace lunasvg { UseElement::UseElement() - : GraphicsElement(ElementId::Use) + : GraphicsElement(ElementID::Use) { } Length UseElement::x() const { - auto& value = get(PropertyId::X); + auto& value = get(PropertyID::X); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length UseElement::y() const { - auto& value = get(PropertyId::Y); + auto& value = get(PropertyID::Y); return Parser::parseLength(value, AllowNegativeLengths, Length::Zero); } Length UseElement::width() const { - auto& value = get(PropertyId::Width); + auto& value = get(PropertyID::Width); return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent); } Length UseElement::height() const { - auto& value = get(PropertyId::Height); + auto& value = get(PropertyID::Height); return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent); } std::string UseElement::href() const { - auto& value = get(PropertyId::Href); + auto& value = get(PropertyID::Href); return Parser::parseHref(value); } void UseElement::transferWidthAndHeight(Element* element) const { - auto& width = get(PropertyId::Width); - auto& height = get(PropertyId::Height); + auto& width = get(PropertyID::Width); + auto& height = get(PropertyID::Height); - element->set(PropertyId::Width, width, 0x0); - element->set(PropertyId::Height, height, 0x0); + element->set(PropertyID::Width, width, 0x0); + element->set(PropertyID::Height, height, 0x0); } void UseElement::layout(LayoutContext* context, LayoutContainer* current) const @@ -69,15 +69,15 @@ void UseElement::layout(LayoutContext* context, LayoutContainer* current) const auto _x = lengthContext.valueForLength(x(), LengthMode::Width); auto _y = lengthContext.valueForLength(y(), LengthMode::Height); - auto transform = get(PropertyId::Transform); + auto transform = get(PropertyID::Transform); transform += "translate("; transform += std::to_string(_x); transform += ' '; transform += std::to_string(_y); transform += ')'; - group->set(PropertyId::Transform, transform, 0x10); + group->set(PropertyID::Transform, transform, 0x10); - if(ref->id == ElementId::Svg || ref->id == ElementId::Symbol) + if(ref->id == ElementID::Svg || ref->id == ElementID::Symbol) { auto element = ref->cloneElement(); transferWidthAndHeight(element.get());