diff --git a/.clang-format b/.clang-format index 0bcc6c1..886cad8 100644 --- a/.clang-format +++ b/.clang-format @@ -1,10 +1,67 @@ -BasedOnStyle: LLVM -IndentWidth: 8 -UseTab: Always -BreakBeforeBraces: Linux +# SPDX-License-Identifier: GPL-2.0 +# +# clang-format configuration file. Intended for clang-format >= 11. +# +# For more information, see: +# +# Documentation/process/clang-format.rst +# https://clang.llvm.org/docs/ClangFormat.html +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false -AlignConsecutiveMacros: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false -IndentCaseLabels: false \ No newline at end of file +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +IndentWidth: 8 +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +UseTab: Always +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false \ No newline at end of file diff --git a/include/nanosvg.h b/include/nanosvg.h index d16f0ea..d8d5b10 100644 --- a/include/nanosvg.h +++ b/include/nanosvg.h @@ -22,7 +22,8 @@ * * Arc calculation code based on canvg (https://code.google.com/p/canvg/) * - * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + * Bounding box calculation based on + * http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html * */ @@ -35,24 +36,27 @@ extern "C" { #endif #endif -// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. +// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of +// cubic bezier shapes. // -// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. +// The library suits well for anything from rendering scalable icons in your editor application to +// prototyping a game. // -// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! +// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create +// a pull request! // // The shapes in the SVG images are transformed by the viewBox and converted to specified units. // That is, you should get the same looking data as your designed in your favorite app. // -// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose -// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. +// NanoSVG can return the paths in few different units. For example if you want to render an image, +// you may choose to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you +// may want to use millimeters. // // The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. // DPI (dots-per-inch) controls how the unit conversion is done. // // If you don't know or care about the units stuff, "px" and 96 should get you going. - /* Example Usage: // Load SVG NSVGimage* image; @@ -80,32 +84,15 @@ enum NSVGpaintType { NSVG_PAINT_RADIAL_GRADIENT = 3 }; -enum NSVGspreadType { - NSVG_SPREAD_PAD = 0, - NSVG_SPREAD_REFLECT = 1, - NSVG_SPREAD_REPEAT = 2 -}; +enum NSVGspreadType { NSVG_SPREAD_PAD = 0, NSVG_SPREAD_REFLECT = 1, NSVG_SPREAD_REPEAT = 2 }; -enum NSVGlineJoin { - NSVG_JOIN_MITER = 0, - NSVG_JOIN_ROUND = 1, - NSVG_JOIN_BEVEL = 2 -}; +enum NSVGlineJoin { NSVG_JOIN_MITER = 0, NSVG_JOIN_ROUND = 1, NSVG_JOIN_BEVEL = 2 }; -enum NSVGlineCap { - NSVG_CAP_BUTT = 0, - NSVG_CAP_ROUND = 1, - NSVG_CAP_SQUARE = 2 -}; +enum NSVGlineCap { NSVG_CAP_BUTT = 0, NSVG_CAP_ROUND = 1, NSVG_CAP_SQUARE = 2 }; -enum NSVGfillRule { - NSVG_FILLRULE_NONZERO = 0, - NSVG_FILLRULE_EVENODD = 1 -}; +enum NSVGfillRule { NSVG_FILLRULE_NONZERO = 0, NSVG_FILLRULE_EVENODD = 1 }; -enum NSVGflags { - NSVG_FLAGS_VISIBLE = 0x01 -}; +enum NSVGflags { NSVG_FLAGS_VISIBLE = 0x01 }; typedef struct NSVGgradientStop { unsigned int color; @@ -124,65 +111,62 @@ typedef struct NSVGpaint { char type; union { unsigned int color; - NSVGgradient* gradient; + NSVGgradient *gradient; }; } NSVGpaint; -typedef struct NSVGpath -{ - float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... - int npts; // Total number of bezier points. - char closed; // Flag indicating if shapes should be treated as closed. - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - struct NSVGpath* next; // Pointer to next path, or NULL if last element. +typedef struct NSVGpath { + float *pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath *next; // Pointer to next path, or NULL if last element. } NSVGpath; -typedef struct NSVGshape -{ - char id[64]; // Optional 'id' attr of the shape or its group - NSVGpaint fill; // Fill paint - NSVGpaint stroke; // Stroke paint - float opacity; // Opacity of the shape. - float strokeWidth; // Stroke width (scaled). - float strokeDashOffset; // Stroke dash offset (scaled). - float strokeDashArray[8]; // Stroke dash array (scaled). - char strokeDashCount; // Number of dash values in dash array. - char strokeLineJoin; // Stroke join type. - char strokeLineCap; // Stroke cap type. - float miterLimit; // Miter limit - char fillRule; // Fill rule, see NSVGfillRule. - unsigned char flags; // Logical or of NSVG_FLAGS_* flags - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - char unicode[NSVG_MAX_UNICODE_LEN]; // Unicode character code. - int horizAdvX; // Horizontal distance to advance after rendering glyph. - NSVGpath* paths; // Linked list of paths in the image. - struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +typedef struct NSVGshape { + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + char unicode[NSVG_MAX_UNICODE_LEN]; // Unicode character code. + int horizAdvX; // Horizontal distance to advance after rendering glyph. + NSVGpath *paths; // Linked list of paths in the image. + struct NSVGshape *next; // Pointer to next shape, or NULL if last element. } NSVGshape; - -typedef struct NSVGimage -{ - float width; // Width of the image. - float height; // Height of the image. + +typedef struct NSVGimage { + float width; // Width of the image. + float height; // Height of the image. int fontAscent; int fontDescent; int defaultHorizAdv; - NSVGshape* shapes; // Linked list of shapes in the image. + NSVGshape *shapes; // Linked list of shapes in the image. } NSVGimage; // Parses SVG file from a file, returns SVG image as paths. -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi); // Parses SVG file from a null terminated string, returns SVG image as paths. // Important note: changes the string. -NSVGimage* nsvgParse(char* input, const char* units, float dpi); +NSVGimage *nsvgParse(char *input, const char *units, float dpi); // Duplicates a path. -NSVGpath* nsvgDuplicatePath(NSVGpath* p); +NSVGpath *nsvgDuplicatePath(NSVGpath *p); // Deletes an image. -void nsvgDelete(NSVGimage* image); +void nsvgDelete(NSVGimage *image); -NSVGshape** nsvgGetTextShapes(const NSVGimage* image, const char* text, int textLen); +NSVGshape **nsvgGetTextShapes(const NSVGimage *image, const char *text, int textLen); #ifndef NANOSVG_CPLUSPLUS #ifdef __cplusplus @@ -194,12 +178,13 @@ NSVGshape** nsvgGetTextShapes(const NSVGimage* image, const char* text, int text #ifdef NANOSVG_IMPLEMENTATION -#include -#include #include +#include +#include #define NSVG_PI (3.14159265358979323846264338327f) -#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. +#define NSVG_KAPPA90 \ + (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. #define NSVG_ALIGN_MIN 0 #define NSVG_ALIGN_MID 1 @@ -208,21 +193,23 @@ NSVGshape** nsvgGetTextShapes(const NSVGimage* image, const char* text, int text #define NSVG_ALIGN_MEET 1 #define NSVG_ALIGN_SLICE 2 -#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_NOTUSED(v) \ + do { \ + (void)(1 ? (void)0 : ((void)(v))); \ + } while (0) #define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) #ifdef _MSC_VER - #pragma warning (disable: 4996) // Switch off security warnings - #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings - #ifdef __cplusplus - #define NSVG_INLINE inline - #else - #define NSVG_INLINE - #endif +#pragma warning(disable : 4996) // Switch off security warnings +#pragma warning(disable : 4100) // Switch off unreferenced formal parameter warnings +#ifdef __cplusplus +#define NSVG_INLINE inline #else - #define NSVG_INLINE inline +#define NSVG_INLINE +#endif +#else +#define NSVG_INLINE inline #endif - static int nsvg__isspace(char c) { @@ -234,9 +221,14 @@ static int nsvg__isdigit(char c) return c >= '0' && c <= '9'; } -static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } -static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } - +static NSVG_INLINE float nsvg__minf(float a, float b) +{ + return a < b ? a : b; +} +static NSVG_INLINE float nsvg__maxf(float a, float b) +{ + return a > b ? a : b; +} // Simple XML parser @@ -244,32 +236,32 @@ static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } #define NSVG_XML_CONTENT 2 #define NSVG_XML_MAX_ATTRIBS 256 -static void nsvg__parseContent(char* s, - void (*contentCb)(void* ud, const char* s), - void* ud) +static void nsvg__parseContent(char *s, void (*contentCb)(void *ud, const char *s), void *ud) { // Trim start white spaces - while (*s && nsvg__isspace(*s)) s++; - if (!*s) return; + while (*s && nsvg__isspace(*s)) + s++; + if (!*s) + return; if (contentCb) (*contentCb)(ud, s); } -static void nsvg__parseElement(char* s, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void* ud) +static void nsvg__parseElement(char *s, + void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), void *ud) { - const char* attr[NSVG_XML_MAX_ATTRIBS]; + const char *attr[NSVG_XML_MAX_ATTRIBS]; int nattr = 0; - char* name; + char *name; int start = 0; int end = 0; char quote; // Skip white space after the '<' - while (*s && nsvg__isspace(*s)) s++; + while (*s && nsvg__isspace(*s)) + s++; // Check if the tag is end tag if (*s == '/') { @@ -285,34 +277,47 @@ static void nsvg__parseElement(char* s, // Get tag name name = s; - while (*s && !nsvg__isspace(*s)) s++; - if (*s) { *s++ = '\0'; } + while (*s && !nsvg__isspace(*s)) + s++; + if (*s) { + *s++ = '\0'; + } // Get attribs - while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { - char* name = NULL; - char* value = NULL; + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS - 3) { + char *name = NULL; + char *value = NULL; // Skip white space before the attrib name - while (*s && nsvg__isspace(*s)) s++; - if (!*s) break; + while (*s && nsvg__isspace(*s)) + s++; + if (!*s) + break; if (*s == '/') { end = 1; break; } name = s; // Find end of the attrib name. - while (*s && !nsvg__isspace(*s) && *s != '=') s++; - if (*s) { *s++ = '\0'; } + while (*s && !nsvg__isspace(*s) && *s != '=') + s++; + if (*s) { + *s++ = '\0'; + } // Skip until the beginning of the value. - while (*s && *s != '\"' && *s != '\'') s++; - if (!*s) break; + while (*s && *s != '\"' && *s != '\'') + s++; + if (!*s) + break; quote = *s; s++; // Store value and find the end of it. value = s; - while (*s && *s != quote) s++; - if (*s) { *s++ = '\0'; } + while (*s && *s != quote) + s++; + if (*s) { + *s++ = '\0'; + } // Store only well formed attributes if (name && value) { @@ -332,14 +337,12 @@ static void nsvg__parseElement(char* s, (*endelCb)(ud, name); } -int nsvg__parseXML(char* input, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void (*contentCb)(void* ud, const char* s), - void* ud) +int nsvg__parseXML(char *input, void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), + void (*contentCb)(void *ud, const char *s), void *ud) { - char* s = input; - char* mark = s; + char *s = input; + char *mark = s; int state = NSVG_XML_CONTENT; while (*s) { if (*s == '<' && state == NSVG_XML_CONTENT) { @@ -362,15 +365,11 @@ int nsvg__parseXML(char* input, return 1; } - /* Simple SVG parser. */ #define NSVG_MAX_ATTR 128 -enum NSVGgradientUnits { - NSVG_USER_SPACE = 0, - NSVG_OBJECT_SPACE = 1 -}; +enum NSVGgradientUnits { NSVG_USER_SPACE = 0, NSVG_OBJECT_SPACE = 1 }; #define NSVG_MAX_DASHES 8 @@ -400,8 +399,7 @@ typedef struct NSVGradialData { NSVGcoordinate cx, cy, r, fx, fy; } NSVGradialData; -typedef struct NSVGgradientData -{ +typedef struct NSVGgradientData { char id[64]; char ref[64]; char type; @@ -413,12 +411,11 @@ typedef struct NSVGgradientData char units; float xform[6]; int nstops; - NSVGgradientStop* stops; - struct NSVGgradientData* next; + NSVGgradientStop *stops; + struct NSVGgradientData *next; } NSVGgradientData; -typedef struct NSVGattrib -{ +typedef struct NSVGattrib { char id[64]; float xform[6]; unsigned int fillColor; @@ -445,17 +442,16 @@ typedef struct NSVGattrib char visible; } NSVGattrib; -typedef struct NSVGparser -{ +typedef struct NSVGparser { NSVGattrib attr[NSVG_MAX_ATTR]; int attrHead; - float* pts; + float *pts; int npts; int cpts; - NSVGpath* plist; - NSVGimage* image; - NSVGgradientData* gradients; - NSVGshape* shapesTail; + NSVGpath *plist; + NSVGimage *image; + NSVGgradientData *gradients; + NSVGshape *shapesTail; float viewMinx, viewMiny, viewWidth, viewHeight; int alignX, alignY, alignType; float dpi; @@ -465,50 +461,68 @@ typedef struct NSVGparser const char *horizAdvFlag; } NSVGparser; -static void nsvg__xformIdentity(float* t) +static void nsvg__xformIdentity(float *t) { - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetTranslation(float* t, float tx, float ty) +static void nsvg__xformSetTranslation(float *t, float tx, float ty) { - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = tx; t[5] = ty; + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = tx; + t[5] = ty; } -static void nsvg__xformSetScale(float* t, float sx, float sy) +static void nsvg__xformSetScale(float *t, float sx, float sy) { - t[0] = sx; t[1] = 0.0f; - t[2] = 0.0f; t[3] = sy; - t[4] = 0.0f; t[5] = 0.0f; + t[0] = sx; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = sy; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetSkewX(float* t, float a) +static void nsvg__xformSetSkewX(float *t, float a) { - t[0] = 1.0f; t[1] = 0.0f; - t[2] = tanf(a); t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = tanf(a); + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetSkewY(float* t, float a) +static void nsvg__xformSetSkewY(float *t, float a) { - t[0] = 1.0f; t[1] = tanf(a); - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; + t[0] = 1.0f; + t[1] = tanf(a); + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetRotation(float* t, float a) +static void nsvg__xformSetRotation(float *t, float a) { float cs = cosf(a), sn = sinf(a); - t[0] = cs; t[1] = sn; - t[2] = -sn; t[3] = cs; - t[4] = 0.0f; t[5] = 0.0f; + t[0] = cs; + t[1] = sn; + t[2] = -sn; + t[3] = cs; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformMultiply(float* t, float* s) +static void nsvg__xformMultiply(float *t, float *s) { float t0 = t[0] * s[0] + t[1] * s[2]; float t2 = t[2] * s[0] + t[3] * s[2]; @@ -521,7 +535,7 @@ static void nsvg__xformMultiply(float* t, float* s) t[4] = t4; } -static void nsvg__xformInverse(float* inv, float* t) +static void nsvg__xformInverse(float *inv, float *t) { double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; if (det > -1e-6 && det < 1e-6) { @@ -537,48 +551,47 @@ static void nsvg__xformInverse(float* inv, float* t) inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); } -static void nsvg__xformPremultiply(float* t, float* s) +static void nsvg__xformPremultiply(float *t, float *s) { float s2[6]; - memcpy(s2, s, sizeof(float)*6); + memcpy(s2, s, sizeof(float) * 6); nsvg__xformMultiply(s2, t); - memcpy(t, s2, sizeof(float)*6); + memcpy(t, s2, sizeof(float) * 6); } -static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) +static void nsvg__xformPoint(float *dx, float *dy, float x, float y, float *t) { - *dx = x*t[0] + y*t[2] + t[4]; - *dy = x*t[1] + y*t[3] + t[5]; + *dx = x * t[0] + y * t[2] + t[4]; + *dy = x * t[1] + y * t[3] + t[5]; } -static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) +static void nsvg__xformVec(float *dx, float *dy, float x, float y, float *t) { - *dx = x*t[0] + y*t[2]; - *dy = x*t[1] + y*t[3]; + *dx = x * t[0] + y * t[2]; + *dy = x * t[1] + y * t[3]; } #define NSVG_EPSILON (1e-12) -static int nsvg__ptInBounds(float* pt, float* bounds) +static int nsvg__ptInBounds(float *pt, float *bounds) { return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; } - static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) { - double it = 1.0-t; - return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; + double it = 1.0 - t; + return it * it * it * p0 + 3.0 * it * it * t * p1 + 3.0 * it * t * t * p2 + t * t * t * p3; } -static void nsvg__curveBounds(float* bounds, float* curve) +static void nsvg__curveBounds(float *bounds, float *curve) { int i, j, count; double roots[2], a, b, c, b2ac, t, v; - float* v0 = &curve[0]; - float* v1 = &curve[2]; - float* v2 = &curve[4]; - float* v3 = &curve[6]; + float *v0 = &curve[0]; + float *v1 = &curve[2]; + float *v2 = &curve[4]; + float *v3 = &curve[6]; // Start the bounding box by end points bounds[0] = nsvg__minf(v0[0], v3[0]); @@ -600,44 +613,46 @@ static void nsvg__curveBounds(float* bounds, float* curve) if (fabs(a) < NSVG_EPSILON) { if (fabs(b) > NSVG_EPSILON) { t = -c / b; - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) roots[count++] = t; } } else { - b2ac = b*b - 4.0*c*a; + b2ac = b * b - 4.0 * c * a; if (b2ac > NSVG_EPSILON) { t = (-b + sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) roots[count++] = t; t = (-b - sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) roots[count++] = t; } } for (j = 0; j < count; j++) { v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); - bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); - bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); + bounds[0 + i] = nsvg__minf(bounds[0 + i], (float)v); + bounds[2 + i] = nsvg__maxf(bounds[2 + i], (float)v); } } } -static NSVGparser* nsvg__createParser() +static NSVGparser *nsvg__createParser() { - NSVGparser* p; - p = (NSVGparser*)malloc(sizeof(NSVGparser)); - if (p == NULL) goto error; + NSVGparser *p; + p = (NSVGparser *)malloc(sizeof(NSVGparser)); + if (p == NULL) + goto error; memset(p, 0, sizeof(NSVGparser)); - p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); - if (p->image == NULL) goto error; + p->image = (NSVGimage *)malloc(sizeof(NSVGimage)); + if (p->image == NULL) + goto error; memset(p->image, 0, sizeof(NSVGimage)); // Init style nsvg__xformIdentity(p->attr[0].xform); memset(p->attr[0].id, 0, sizeof p->attr[0].id); - p->attr[0].fillColor = NSVG_RGB(0,0,0); - p->attr[0].strokeColor = NSVG_RGB(0,0,0); + p->attr[0].fillColor = NSVG_RGB(0, 0, 0); + p->attr[0].strokeColor = NSVG_RGB(0, 0, 0); p->attr[0].opacity = 1; p->attr[0].fillOpacity = 1; p->attr[0].strokeOpacity = 1; @@ -654,13 +669,14 @@ static NSVGparser* nsvg__createParser() error: if (p) { - if (p->image) free(p->image); + if (p->image) + free(p->image); free(p); } return NULL; } -static void nsvg__deletePaths(NSVGpath* path) +static void nsvg__deletePaths(NSVGpath *path) { while (path) { NSVGpath *next = path->next; @@ -671,15 +687,15 @@ static void nsvg__deletePaths(NSVGpath* path) } } -static void nsvg__deletePaint(NSVGpaint* paint) +static void nsvg__deletePaint(NSVGpaint *paint) { if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) free(paint->gradient); } -static void nsvg__deleteGradientData(NSVGgradientData* grad) +static void nsvg__deleteGradientData(NSVGgradientData *grad) { - NSVGgradientData* next; + NSVGgradientData *next; while (grad != NULL) { next = grad->next; free(grad->stops); @@ -688,7 +704,7 @@ static void nsvg__deleteGradientData(NSVGgradientData* grad) } } -static void nsvg__deleteParser(NSVGparser* p) +static void nsvg__deleteParser(NSVGparser *p) { if (p != NULL) { nsvg__deletePaths(p->plist); @@ -699,48 +715,50 @@ static void nsvg__deleteParser(NSVGparser* p) } } -static void nsvg__resetPath(NSVGparser* p) +static void nsvg__resetPath(NSVGparser *p) { p->npts = 0; } -static void nsvg__addPoint(NSVGparser* p, float x, float y) +static void nsvg__addPoint(NSVGparser *p, float x, float y) { - if (p->npts+1 > p->cpts) { - p->cpts = p->cpts ? p->cpts*2 : 8; - p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); - if (!p->pts) return; + if (p->npts + 1 > p->cpts) { + p->cpts = p->cpts ? p->cpts * 2 : 8; + p->pts = (float *)realloc(p->pts, p->cpts * 2 * sizeof(float)); + if (!p->pts) + return; } - p->pts[p->npts*2+0] = x; - p->pts[p->npts*2+1] = y; + p->pts[p->npts * 2 + 0] = x; + p->pts[p->npts * 2 + 1] = y; p->npts++; } -static void nsvg__moveTo(NSVGparser* p, float x, float y) +static void nsvg__moveTo(NSVGparser *p, float x, float y) { if (p->npts > 0) { - p->pts[(p->npts-1)*2+0] = x; - p->pts[(p->npts-1)*2+1] = y; + p->pts[(p->npts - 1) * 2 + 0] = x; + p->pts[(p->npts - 1) * 2 + 1] = y; } else { nsvg__addPoint(p, x, y); } } -static void nsvg__lineTo(NSVGparser* p, float x, float y) +static void nsvg__lineTo(NSVGparser *p, float x, float y) { - float px,py, dx,dy; + float px, py, dx, dy; if (p->npts > 0) { - px = p->pts[(p->npts-1)*2+0]; - py = p->pts[(p->npts-1)*2+1]; + px = p->pts[(p->npts - 1) * 2 + 0]; + py = p->pts[(p->npts - 1) * 2 + 1]; dx = x - px; dy = y - py; - nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); - nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); + nsvg__addPoint(p, px + dx / 3.0f, py + dy / 3.0f); + nsvg__addPoint(p, x - dx / 3.0f, y - dy / 3.0f); nsvg__addPoint(p, x, y); } } -static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) +static void nsvg__cubicBezTo(NSVGparser *p, float cpx1, float cpy1, float cpx2, float cpy2, float x, + float y) { if (p->npts > 0) { nsvg__addPoint(p, cpx1, cpy1); @@ -749,73 +767,84 @@ static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, } } -static NSVGattrib* nsvg__getAttr(NSVGparser* p) +static NSVGattrib *nsvg__getAttr(NSVGparser *p) { return &p->attr[p->attrHead]; } -static void nsvg__pushAttr(NSVGparser* p) +static void nsvg__pushAttr(NSVGparser *p) { - if (p->attrHead < NSVG_MAX_ATTR-1) { + if (p->attrHead < NSVG_MAX_ATTR - 1) { p->attrHead++; - memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead - 1], sizeof(NSVGattrib)); } } -static void nsvg__popAttr(NSVGparser* p) +static void nsvg__popAttr(NSVGparser *p) { if (p->attrHead > 0) p->attrHead--; } -static float nsvg__actualOrigX(NSVGparser* p) +static float nsvg__actualOrigX(NSVGparser *p) { return p->viewMinx; } -static float nsvg__actualOrigY(NSVGparser* p) +static float nsvg__actualOrigY(NSVGparser *p) { return p->viewMiny; } -static float nsvg__actualWidth(NSVGparser* p) +static float nsvg__actualWidth(NSVGparser *p) { return p->viewWidth; } -static float nsvg__actualHeight(NSVGparser* p) +static float nsvg__actualHeight(NSVGparser *p) { return p->viewHeight; } -static float nsvg__actualLength(NSVGparser* p) +static float nsvg__actualLength(NSVGparser *p) { float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); - return sqrtf(w*w + h*h) / sqrtf(2.0f); + return sqrtf(w * w + h * h) / sqrtf(2.0f); } -static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) +static float nsvg__convertToPixels(NSVGparser *p, NSVGcoordinate c, float orig, float length) { - NSVGattrib* attr = nsvg__getAttr(p); + NSVGattrib *attr = nsvg__getAttr(p); switch (c.units) { - case NSVG_UNITS_USER: return c.value; - case NSVG_UNITS_PX: return c.value; - case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; - case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; - case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; - case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; - case NSVG_UNITS_IN: return c.value * p->dpi; - case NSVG_UNITS_EM: return c.value * attr->fontSize; - case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. - case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; - default: return c.value; + case NSVG_UNITS_USER: + return c.value; + case NSVG_UNITS_PX: + return c.value; + case NSVG_UNITS_PT: + return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: + return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: + return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: + return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: + return c.value * p->dpi; + case NSVG_UNITS_EM: + return c.value * attr->fontSize; + case NSVG_UNITS_EX: + return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: + return orig + c.value / 100.0f * length; + default: + return c.value; } return c.value; } -static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) +static NSVGgradientData *nsvg__findGradientData(NSVGparser *p, const char *id) { - NSVGgradientData* grad = p->gradients; + NSVGgradientData *grad = p->gradients; if (id == NULL || *id == '\0') return NULL; while (grad != NULL) { @@ -826,40 +855,47 @@ static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) return NULL; } -static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) +static NSVGgradient *nsvg__createGradient(NSVGparser *p, const char *id, const float *localBounds, + char *paintType) { - NSVGattrib* attr = nsvg__getAttr(p); - NSVGgradientData* data = NULL; - NSVGgradientData* ref = NULL; - NSVGgradientStop* stops = NULL; - NSVGgradient* grad; + NSVGattrib *attr = nsvg__getAttr(p); + NSVGgradientData *data = NULL; + NSVGgradientData *ref = NULL; + NSVGgradientStop *stops = NULL; + NSVGgradient *grad; float ox, oy, sw, sh, sl; int nstops = 0; int refIter; data = nsvg__findGradientData(p, id); - if (data == NULL) return NULL; + if (data == NULL) + return NULL; // TODO: use ref to fill in all unset values too. ref = data; refIter = 0; while (ref != NULL) { - NSVGgradientData* nextRef = NULL; + NSVGgradientData *nextRef = NULL; if (stops == NULL && ref->stops != NULL) { stops = ref->stops; nstops = ref->nstops; break; } nextRef = nsvg__findGradientData(p, ref->ref); - if (nextRef == ref) break; // prevent infite loops on malformed data + if (nextRef == ref) + break; // prevent infite loops on malformed data ref = nextRef; refIter++; - if (refIter > 32) break; // prevent infite loops on malformed data + if (refIter > 32) + break; // prevent infite loops on malformed data } - if (stops == NULL) return NULL; + if (stops == NULL) + return NULL; - grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); - if (grad == NULL) return NULL; + grad = (NSVGgradient *)malloc(sizeof(NSVGgradient) + + sizeof(NSVGgradientStop) * (nstops - 1)); + if (grad == NULL) + return NULL; // The shape width and height. if (data->units == NSVG_OBJECT_SPACE) { @@ -873,7 +909,7 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f sw = nsvg__actualWidth(p); sh = nsvg__actualHeight(p); } - sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); + sl = sqrtf(sw * sw + sh * sh) / sqrtf(2.0f); if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { float x1, y1, x2, y2, dx, dy; @@ -884,9 +920,12 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f // Calculate transform aligned to the line dx = x2 - x1; dy = y2 - y1; - grad->xform[0] = dy; grad->xform[1] = -dx; - grad->xform[2] = dx; grad->xform[3] = dy; - grad->xform[4] = x1; grad->xform[5] = y1; + grad->xform[0] = dy; + grad->xform[1] = -dx; + grad->xform[2] = dx; + grad->xform[3] = dy; + grad->xform[4] = x1; + grad->xform[5] = y1; } else { float cx, cy, fx, fy, r; cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); @@ -895,9 +934,12 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); r = nsvg__convertToPixels(p, data->radial.r, 0, sl); // Calculate transform aligned to the circle - grad->xform[0] = r; grad->xform[1] = 0; - grad->xform[2] = 0; grad->xform[3] = r; - grad->xform[4] = cx; grad->xform[5] = cy; + grad->xform[0] = r; + grad->xform[1] = 0; + grad->xform[2] = 0; + grad->xform[3] = r; + grad->xform[4] = cx; + grad->xform[5] = cy; grad->fx = fx / r; grad->fy = fy / r; } @@ -906,7 +948,7 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f nsvg__xformMultiply(grad->xform, attr->xform); grad->spread = data->spread; - memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); + memcpy(grad->stops, stops, nstops * sizeof(NSVGgradientStop)); grad->nstops = nstops; *paintType = data->type; @@ -914,24 +956,27 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f return grad; } -static float nsvg__getAverageScale(float* t) +static float nsvg__getAverageScale(float *t) { - float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); - float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); + float sx = sqrtf(t[0] * t[0] + t[2] * t[2]); + float sy = sqrtf(t[1] * t[1] + t[3] * t[3]); return (sx + sy) * 0.5f; } -static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) +static void nsvg__getLocalBounds(float *bounds, NSVGshape *shape, float *xform) { - NSVGpath* path; - float curve[4*2], curveBounds[4]; + NSVGpath *path; + float curve[4 * 2], curveBounds[4]; int i, first = 1; for (path = shape->paths; path != NULL; path = path->next) { nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); - for (i = 0; i < path->npts-1; i += 3) { - nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); - nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); - nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); + for (i = 0; i < path->npts - 1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i + 1) * 2], + path->pts[(i + 1) * 2 + 1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i + 2) * 2], + path->pts[(i + 2) * 2 + 1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i + 3) * 2], + path->pts[(i + 3) * 2 + 1], xform); nsvg__curveBounds(curveBounds, curve); if (first) { bounds[0] = curveBounds[0]; @@ -951,20 +996,21 @@ static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) } } -static void nsvg__addShape(NSVGparser* p) +static void nsvg__addShape(NSVGparser *p) { - NSVGattrib* attr = nsvg__getAttr(p); + NSVGattrib *attr = nsvg__getAttr(p); float scale = 1.0f; - NSVGshape* shape; + NSVGshape *shape; char *end; - NSVGpath* path; + NSVGpath *path; int i; if (p->plist == NULL) return; - shape = (NSVGshape*)malloc(sizeof(NSVGshape)); - if (shape == NULL) goto error; + shape = (NSVGshape *)malloc(sizeof(NSVGshape)); + if (shape == NULL) + goto error; memset(shape, 0, sizeof(NSVGshape)); memcpy(shape->id, attr->id, sizeof shape->id); @@ -1015,12 +1061,13 @@ static void nsvg__addShape(NSVGparser* p) } else if (attr->hasFill == 1) { shape->fill.type = NSVG_PAINT_COLOR; shape->fill.color = attr->fillColor; - shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; + shape->fill.color |= (unsigned int)(attr->fillOpacity * 255) << 24; } else if (attr->hasFill == 2) { float inv[6], localBounds[4]; nsvg__xformInverse(inv, attr->xform); nsvg__getLocalBounds(localBounds, shape, inv); - shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); + shape->fill.gradient = + nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); if (shape->fill.gradient == NULL) { shape->fill.type = NSVG_PAINT_NONE; } @@ -1032,12 +1079,13 @@ static void nsvg__addShape(NSVGparser* p) } else if (attr->hasStroke == 1) { shape->stroke.type = NSVG_PAINT_COLOR; shape->stroke.color = attr->strokeColor; - shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity * 255) << 24; } else if (attr->hasStroke == 2) { float inv[6], localBounds[4]; nsvg__xformInverse(inv, attr->xform); nsvg__getLocalBounds(localBounds, shape, inv); - shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); + shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, + &shape->stroke.type); if (shape->stroke.gradient == NULL) shape->stroke.type = NSVG_PAINT_NONE; } @@ -1055,15 +1103,16 @@ static void nsvg__addShape(NSVGparser* p) return; error: - if (shape) free(shape); + if (shape) + free(shape); } -static void nsvg__addPath(NSVGparser* p, char closed) +static void nsvg__addPath(NSVGparser *p, char closed) { - NSVGattrib* attr = nsvg__getAttr(p); - NSVGpath* path = NULL; + NSVGattrib *attr = nsvg__getAttr(p); + NSVGpath *path = NULL; float bounds[4]; - float* curve; + float *curve; int i; if (p->npts < 4) @@ -1076,22 +1125,25 @@ static void nsvg__addPath(NSVGparser* p, char closed) if ((p->npts % 3) != 1) return; - path = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (path == NULL) goto error; + path = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (path == NULL) + goto error; memset(path, 0, sizeof(NSVGpath)); - path->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (path->pts == NULL) goto error; + path->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (path->pts == NULL) + goto error; path->closed = closed; path->npts = p->npts; // Transform path. for (i = 0; i < p->npts; ++i) - nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); + nsvg__xformPoint(&path->pts[i * 2], &path->pts[i * 2 + 1], p->pts[i * 2], + p->pts[i * 2 + 1], attr->xform); // Find bounds - for (i = 0; i < path->npts-1; i += 3) { - curve = &path->pts[i*2]; + for (i = 0; i < path->npts - 1; i += 3) { + curve = &path->pts[i * 2]; nsvg__curveBounds(bounds, curve); if (i == 0) { path->bounds[0] = bounds[0]; @@ -1113,16 +1165,17 @@ static void nsvg__addPath(NSVGparser* p, char closed) error: if (path != NULL) { - if (path->pts != NULL) free(path->pts); + if (path->pts != NULL) + free(path->pts); free(path); } } // We roll our own string to float because the std library one uses locale and messes things up. -static double nsvg__atof(const char* s) +static double nsvg__atof(const char *s) { - char* cur = (char*)s; - char* end = NULL; + char *cur = (char *)s; + char *end = NULL; double res = 0.0, sign = 1.0; long long intPart = 0, fracPart = 0; char hasIntPart = 0, hasFracPart = 0; @@ -1177,42 +1230,48 @@ static double nsvg__atof(const char* s) return res * sign; } - -static const char* nsvg__parseNumber(const char* s, char* it, const int size) +static const char *nsvg__parseNumber(const char *s, char *it, const int size) { - const int last = size-1; + const int last = size - 1; int i = 0; // sign if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; + if (i < last) + it[i++] = *s; s++; } // integer part while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; + if (i < last) + it[i++] = *s; s++; } if (*s == '.') { // decimal point - if (i < last) it[i++] = *s; + if (i < last) + it[i++] = *s; s++; // fraction part while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; + if (i < last) + it[i++] = *s; s++; } } // exponent if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { - if (i < last) it[i++] = *s; + if (i < last) + it[i++] = *s; s++; if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; + if (i < last) + it[i++] = *s; s++; } while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; + if (i < last) + it[i++] = *s; s++; } } @@ -1221,12 +1280,14 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size) return s; } -static const char* nsvg__getNextPathItem(const char* s, char* it) +static const char *nsvg__getNextPathItem(const char *s, char *it) { it[0] = '\0'; // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; - if (!*s) return s; + while (*s && (nsvg__isspace(*s) || *s == ',')) + s++; + if (!*s) + return s; if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { s = nsvg__parseNumber(s, it, 64); } else { @@ -1239,40 +1300,40 @@ static const char* nsvg__getNextPathItem(const char* s, char* it) return s; } -static unsigned int nsvg__parseColorHex(const char* str) +static unsigned int nsvg__parseColorHex(const char *str) { - unsigned int r=0, g=0, b=0; - if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex + unsigned int r = 0, g = 0, b = 0; + if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3) // 2 digit hex return NSVG_RGB(r, g, b); - if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa - return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), .. + if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3) // 1 digit hex, e.g. #abc -> 0xccbbaa + return NSVG_RGB(r * 17, g * 17, b * 17); // same effect as (r<<4|r), (g<<4|g), .. return NSVG_RGB(128, 128, 128); } -static unsigned int nsvg__parseColorRGB(const char* str) +static unsigned int nsvg__parseColorRGB(const char *str) { - unsigned int r=0, g=0, b=0; - if (sscanf(str, "rgb(%u, %u, %u)", &r, &g, &b) == 3) // decimal integers + unsigned int r = 0, g = 0, b = 0; + if (sscanf(str, "rgb(%u, %u, %u)", &r, &g, &b) == 3) // decimal integers return NSVG_RGB(r, g, b); - if (sscanf(str, "rgb(%u%%, %u%%, %u%%)", &r, &g, &b) == 3) // decimal integer percentage - return NSVG_RGB(r*255/100, g*255/100, b*255/100); + if (sscanf(str, "rgb(%u%%, %u%%, %u%%)", &r, &g, &b) == 3) // decimal integer percentage + return NSVG_RGB(r * 255 / 100, g * 255 / 100, b * 255 / 100); return NSVG_RGB(128, 128, 128); } typedef struct NSVGNamedColor { - const char* name; + const char *name; unsigned int color; } NSVGNamedColor; NSVGNamedColor nsvg__colors[] = { { "red", NSVG_RGB(255, 0, 0) }, - { "green", NSVG_RGB( 0, 128, 0) }, - { "blue", NSVG_RGB( 0, 0, 255) }, + { "green", NSVG_RGB(0, 128, 0) }, + { "blue", NSVG_RGB(0, 0, 255) }, { "yellow", NSVG_RGB(255, 255, 0) }, - { "cyan", NSVG_RGB( 0, 255, 255) }, + { "cyan", NSVG_RGB(0, 255, 255) }, { "magenta", NSVG_RGB(255, 0, 255) }, - { "black", NSVG_RGB( 0, 0, 0) }, + { "black", NSVG_RGB(0, 0, 0) }, { "grey", NSVG_RGB(128, 128, 128) }, { "gray", NSVG_RGB(128, 128, 128) }, { "white", NSVG_RGB(255, 255, 255) }, @@ -1280,7 +1341,7 @@ NSVGNamedColor nsvg__colors[] = { #ifdef NANOSVG_ALL_COLOR_KEYWORDS { "aliceblue", NSVG_RGB(240, 248, 255) }, { "antiquewhite", NSVG_RGB(250, 235, 215) }, - { "aqua", NSVG_RGB( 0, 255, 255) }, + { "aqua", NSVG_RGB(0, 255, 255) }, { "aquamarine", NSVG_RGB(127, 255, 212) }, { "azure", NSVG_RGB(240, 255, 255) }, { "beige", NSVG_RGB(245, 245, 220) }, @@ -1289,40 +1350,40 @@ NSVGNamedColor nsvg__colors[] = { { "blueviolet", NSVG_RGB(138, 43, 226) }, { "brown", NSVG_RGB(165, 42, 42) }, { "burlywood", NSVG_RGB(222, 184, 135) }, - { "cadetblue", NSVG_RGB( 95, 158, 160) }, + { "cadetblue", NSVG_RGB(95, 158, 160) }, { "chartreuse", NSVG_RGB(127, 255, 0) }, { "chocolate", NSVG_RGB(210, 105, 30) }, { "coral", NSVG_RGB(255, 127, 80) }, { "cornflowerblue", NSVG_RGB(100, 149, 237) }, { "cornsilk", NSVG_RGB(255, 248, 220) }, { "crimson", NSVG_RGB(220, 20, 60) }, - { "darkblue", NSVG_RGB( 0, 0, 139) }, - { "darkcyan", NSVG_RGB( 0, 139, 139) }, + { "darkblue", NSVG_RGB(0, 0, 139) }, + { "darkcyan", NSVG_RGB(0, 139, 139) }, { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, { "darkgray", NSVG_RGB(169, 169, 169) }, - { "darkgreen", NSVG_RGB( 0, 100, 0) }, + { "darkgreen", NSVG_RGB(0, 100, 0) }, { "darkgrey", NSVG_RGB(169, 169, 169) }, { "darkkhaki", NSVG_RGB(189, 183, 107) }, { "darkmagenta", NSVG_RGB(139, 0, 139) }, - { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, + { "darkolivegreen", NSVG_RGB(85, 107, 47) }, { "darkorange", NSVG_RGB(255, 140, 0) }, { "darkorchid", NSVG_RGB(153, 50, 204) }, { "darkred", NSVG_RGB(139, 0, 0) }, { "darksalmon", NSVG_RGB(233, 150, 122) }, { "darkseagreen", NSVG_RGB(143, 188, 143) }, - { "darkslateblue", NSVG_RGB( 72, 61, 139) }, - { "darkslategray", NSVG_RGB( 47, 79, 79) }, - { "darkslategrey", NSVG_RGB( 47, 79, 79) }, - { "darkturquoise", NSVG_RGB( 0, 206, 209) }, + { "darkslateblue", NSVG_RGB(72, 61, 139) }, + { "darkslategray", NSVG_RGB(47, 79, 79) }, + { "darkslategrey", NSVG_RGB(47, 79, 79) }, + { "darkturquoise", NSVG_RGB(0, 206, 209) }, { "darkviolet", NSVG_RGB(148, 0, 211) }, { "deeppink", NSVG_RGB(255, 20, 147) }, - { "deepskyblue", NSVG_RGB( 0, 191, 255) }, + { "deepskyblue", NSVG_RGB(0, 191, 255) }, { "dimgray", NSVG_RGB(105, 105, 105) }, { "dimgrey", NSVG_RGB(105, 105, 105) }, - { "dodgerblue", NSVG_RGB( 30, 144, 255) }, + { "dodgerblue", NSVG_RGB(30, 144, 255) }, { "firebrick", NSVG_RGB(178, 34, 34) }, { "floralwhite", NSVG_RGB(255, 250, 240) }, - { "forestgreen", NSVG_RGB( 34, 139, 34) }, + { "forestgreen", NSVG_RGB(34, 139, 34) }, { "fuchsia", NSVG_RGB(255, 0, 255) }, { "gainsboro", NSVG_RGB(220, 220, 220) }, { "ghostwhite", NSVG_RGB(248, 248, 255) }, @@ -1332,7 +1393,7 @@ NSVGNamedColor nsvg__colors[] = { { "honeydew", NSVG_RGB(240, 255, 240) }, { "hotpink", NSVG_RGB(255, 105, 180) }, { "indianred", NSVG_RGB(205, 92, 92) }, - { "indigo", NSVG_RGB( 75, 0, 130) }, + { "indigo", NSVG_RGB(75, 0, 130) }, { "ivory", NSVG_RGB(255, 255, 240) }, { "khaki", NSVG_RGB(240, 230, 140) }, { "lavender", NSVG_RGB(230, 230, 250) }, @@ -1348,31 +1409,31 @@ NSVGNamedColor nsvg__colors[] = { { "lightgrey", NSVG_RGB(211, 211, 211) }, { "lightpink", NSVG_RGB(255, 182, 193) }, { "lightsalmon", NSVG_RGB(255, 160, 122) }, - { "lightseagreen", NSVG_RGB( 32, 178, 170) }, + { "lightseagreen", NSVG_RGB(32, 178, 170) }, { "lightskyblue", NSVG_RGB(135, 206, 250) }, { "lightslategray", NSVG_RGB(119, 136, 153) }, { "lightslategrey", NSVG_RGB(119, 136, 153) }, { "lightsteelblue", NSVG_RGB(176, 196, 222) }, { "lightyellow", NSVG_RGB(255, 255, 224) }, - { "lime", NSVG_RGB( 0, 255, 0) }, - { "limegreen", NSVG_RGB( 50, 205, 50) }, + { "lime", NSVG_RGB(0, 255, 0) }, + { "limegreen", NSVG_RGB(50, 205, 50) }, { "linen", NSVG_RGB(250, 240, 230) }, { "maroon", NSVG_RGB(128, 0, 0) }, { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, - { "mediumblue", NSVG_RGB( 0, 0, 205) }, + { "mediumblue", NSVG_RGB(0, 0, 205) }, { "mediumorchid", NSVG_RGB(186, 85, 211) }, { "mediumpurple", NSVG_RGB(147, 112, 219) }, - { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, + { "mediumseagreen", NSVG_RGB(60, 179, 113) }, { "mediumslateblue", NSVG_RGB(123, 104, 238) }, - { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, - { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, + { "mediumspringgreen", NSVG_RGB(0, 250, 154) }, + { "mediumturquoise", NSVG_RGB(72, 209, 204) }, { "mediumvioletred", NSVG_RGB(199, 21, 133) }, - { "midnightblue", NSVG_RGB( 25, 25, 112) }, + { "midnightblue", NSVG_RGB(25, 25, 112) }, { "mintcream", NSVG_RGB(245, 255, 250) }, { "mistyrose", NSVG_RGB(255, 228, 225) }, { "moccasin", NSVG_RGB(255, 228, 181) }, { "navajowhite", NSVG_RGB(255, 222, 173) }, - { "navy", NSVG_RGB( 0, 0, 128) }, + { "navy", NSVG_RGB(0, 0, 128) }, { "oldlace", NSVG_RGB(253, 245, 230) }, { "olive", NSVG_RGB(128, 128, 0) }, { "olivedrab", NSVG_RGB(107, 142, 35) }, @@ -1391,11 +1452,11 @@ NSVGNamedColor nsvg__colors[] = { { "powderblue", NSVG_RGB(176, 224, 230) }, { "purple", NSVG_RGB(128, 0, 128) }, { "rosybrown", NSVG_RGB(188, 143, 143) }, - { "royalblue", NSVG_RGB( 65, 105, 225) }, + { "royalblue", NSVG_RGB(65, 105, 225) }, { "saddlebrown", NSVG_RGB(139, 69, 19) }, { "salmon", NSVG_RGB(250, 128, 114) }, { "sandybrown", NSVG_RGB(244, 164, 96) }, - { "seagreen", NSVG_RGB( 46, 139, 87) }, + { "seagreen", NSVG_RGB(46, 139, 87) }, { "seashell", NSVG_RGB(255, 245, 238) }, { "sienna", NSVG_RGB(160, 82, 45) }, { "silver", NSVG_RGB(192, 192, 192) }, @@ -1404,13 +1465,13 @@ NSVGNamedColor nsvg__colors[] = { { "slategray", NSVG_RGB(112, 128, 144) }, { "slategrey", NSVG_RGB(112, 128, 144) }, { "snow", NSVG_RGB(255, 250, 250) }, - { "springgreen", NSVG_RGB( 0, 255, 127) }, - { "steelblue", NSVG_RGB( 70, 130, 180) }, + { "springgreen", NSVG_RGB(0, 255, 127) }, + { "steelblue", NSVG_RGB(70, 130, 180) }, { "tan", NSVG_RGB(210, 180, 140) }, - { "teal", NSVG_RGB( 0, 128, 128) }, + { "teal", NSVG_RGB(0, 128, 128) }, { "thistle", NSVG_RGB(216, 191, 216) }, { "tomato", NSVG_RGB(255, 99, 71) }, - { "turquoise", NSVG_RGB( 64, 224, 208) }, + { "turquoise", NSVG_RGB(64, 224, 208) }, { "violet", NSVG_RGB(238, 130, 238) }, { "wheat", NSVG_RGB(245, 222, 179) }, { "whitesmoke", NSVG_RGB(245, 245, 245) }, @@ -1418,7 +1479,7 @@ NSVGNamedColor nsvg__colors[] = { #endif }; -static unsigned int nsvg__parseColorName(const char* str) +static unsigned int nsvg__parseColorName(const char *str) { int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); @@ -1431,10 +1492,11 @@ static unsigned int nsvg__parseColorName(const char* str) return NSVG_RGB(128, 128, 128); } -static unsigned int nsvg__parseColor(const char* str) +static unsigned int nsvg__parseColor(const char *str) { size_t len = 0; - while(*str == ' ') ++str; + while (*str == ' ') + ++str; len = strlen(str); if (len >= 1 && *str == '#') return nsvg__parseColorHex(str); @@ -1443,22 +1505,25 @@ static unsigned int nsvg__parseColor(const char* str) return nsvg__parseColorName(str); } -static float nsvg__parseOpacity(const char* str) +static float nsvg__parseOpacity(const char *str) { float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; - if (val > 1.0f) val = 1.0f; + if (val < 0.0f) + val = 0.0f; + if (val > 1.0f) + val = 1.0f; return val; } -static float nsvg__parseMiterLimit(const char* str) +static float nsvg__parseMiterLimit(const char *str) { float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; + if (val < 0.0f) + val = 0.0f; return val; } -static int nsvg__parseUnits(const char* units) +static int nsvg__parseUnits(const char *units) { if (units[0] == 'p' && units[1] == 'x') return NSVG_UNITS_PX; @@ -1481,7 +1546,7 @@ static int nsvg__parseUnits(const char* units) return NSVG_UNITS_USER; } -static int nsvg__isCoordinate(const char* s) +static int nsvg__isCoordinate(const char *s) { // optional sign if (*s == '-' || *s == '+') @@ -1490,9 +1555,9 @@ static int nsvg__isCoordinate(const char* s) return (nsvg__isdigit(*s) || *s == '.'); } -static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) +static NSVGcoordinate nsvg__parseCoordinateRaw(const char *str) { - NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + NSVGcoordinate coord = { 0, NSVG_UNITS_USER }; char buf[64]; coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); coord.value = nsvg__atof(buf); @@ -1501,35 +1566,38 @@ static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) static NSVGcoordinate nsvg__coord(float v, int units) { - NSVGcoordinate coord = {v, units}; + NSVGcoordinate coord = { v, units }; return coord; } -static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) +static float nsvg__parseCoordinate(NSVGparser *p, const char *str, float orig, float length) { NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); return nsvg__convertToPixels(p, coord, orig, length); } -static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) +static int nsvg__parseTransformArgs(const char *str, float *args, int maxNa, int *na) { - const char* end; - const char* ptr; + const char *end; + const char *ptr; char it[64]; *na = 0; ptr = str; - while (*ptr && *ptr != '(') ++ptr; + while (*ptr && *ptr != '(') + ++ptr; if (*ptr == 0) return 1; end = ptr; - while (*end && *end != ')') ++end; + while (*end && *end != ')') + ++end; if (*end == 0) return 1; while (ptr < end) { if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { - if (*na >= maxNa) return 0; + if (*na >= maxNa) + return 0; ptr = nsvg__parseNumber(ptr, it, 64); args[(*na)++] = (float)nsvg__atof(it); } else { @@ -1539,65 +1607,67 @@ static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int return (int)(end - str); } - -static int nsvg__parseMatrix(float* xform, const char* str) +static int nsvg__parseMatrix(float *xform, const char *str) { float t[6]; int na = 0; int len = nsvg__parseTransformArgs(str, t, 6, &na); - if (na != 6) return len; - memcpy(xform, t, sizeof(float)*6); + if (na != 6) + return len; + memcpy(xform, t, sizeof(float) * 6); return len; } -static int nsvg__parseTranslate(float* xform, const char* str) +static int nsvg__parseTranslate(float *xform, const char *str) { float args[2]; float t[6]; int na = 0; int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = 0.0; + if (na == 1) + args[1] = 0.0; nsvg__xformSetTranslation(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); + memcpy(xform, t, sizeof(float) * 6); return len; } -static int nsvg__parseScale(float* xform, const char* str) +static int nsvg__parseScale(float *xform, const char *str) { float args[2]; int na = 0; float t[6]; int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = args[0]; + if (na == 1) + args[1] = args[0]; nsvg__xformSetScale(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); + memcpy(xform, t, sizeof(float) * 6); return len; } -static int nsvg__parseSkewX(float* xform, const char* str) +static int nsvg__parseSkewX(float *xform, const char *str) { float args[1]; int na = 0; float t[6]; int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); + nsvg__xformSetSkewX(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); return len; } -static int nsvg__parseSkewY(float* xform, const char* str) +static int nsvg__parseSkewY(float *xform, const char *str) { float args[1]; int na = 0; float t[6]; int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); + nsvg__xformSetSkewY(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); return len; } -static int nsvg__parseRotate(float* xform, const char* str) +static int nsvg__parseRotate(float *xform, const char *str) { float args[3]; int na = 0; @@ -1613,7 +1683,7 @@ static int nsvg__parseRotate(float* xform, const char* str) nsvg__xformMultiply(m, t); } - nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); + nsvg__xformSetRotation(t, args[0] / 180.0f * NSVG_PI); nsvg__xformMultiply(m, t); if (na > 1) { @@ -1621,18 +1691,17 @@ static int nsvg__parseRotate(float* xform, const char* str) nsvg__xformMultiply(m, t); } - memcpy(xform, m, sizeof(float)*6); + memcpy(xform, m, sizeof(float) * 6); return len; } -static void nsvg__parseTransform(float* xform, const char* str) +static void nsvg__parseTransform(float *xform, const char *str) { float t[6]; int len; nsvg__xformIdentity(xform); - while (*str) - { + while (*str) { if (strncmp(str, "matrix", 6) == 0) len = nsvg__parseMatrix(t, str); else if (strncmp(str, "translate", 9) == 0) @@ -1645,7 +1714,7 @@ static void nsvg__parseTransform(float* xform, const char* str) len = nsvg__parseSkewX(t, str); else if (strncmp(str, "skewY", 5) == 0) len = nsvg__parseSkewY(t, str); - else{ + else { ++str; continue; } @@ -1660,7 +1729,7 @@ static void nsvg__parseTransform(float* xform, const char* str) } } -static void nsvg__parseUrl(char* id, const char* str) +static void nsvg__parseUrl(char *id, const char *str) { int i = 0; str += 4; // "url("; @@ -1673,7 +1742,7 @@ static void nsvg__parseUrl(char* id, const char* str) id[i] = '\0'; } -static char nsvg__parseLineCap(const char* str) +static char nsvg__parseLineCap(const char *str) { if (strcmp(str, "butt") == 0) return NSVG_CAP_BUTT; @@ -1685,7 +1754,7 @@ static char nsvg__parseLineCap(const char* str) return NSVG_CAP_BUTT; } -static char nsvg__parseLineJoin(const char* str) +static char nsvg__parseLineJoin(const char *str) { if (strcmp(str, "miter") == 0) return NSVG_JOIN_MITER; @@ -1697,7 +1766,7 @@ static char nsvg__parseLineJoin(const char* str) return NSVG_JOIN_MITER; } -static char nsvg__parseFillRule(const char* str) +static char nsvg__parseFillRule(const char *str) { if (strcmp(str, "nonzero") == 0) return NSVG_FILLRULE_NONZERO; @@ -1707,12 +1776,13 @@ static char nsvg__parseFillRule(const char* str) return NSVG_FILLRULE_NONZERO; } -static const char* nsvg__getNextDashItem(const char* s, char* it) +static const char *nsvg__getNextDashItem(const char *s, char *it) { int n = 0; it[0] = '\0'; // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + while (*s && (nsvg__isspace(*s) || *s == ',')) + s++; // Advance until whitespace, comma or end. while (*s && (!nsvg__isspace(*s) && *s != ',')) { if (n < 63) @@ -1723,7 +1793,7 @@ static const char* nsvg__getNextDashItem(const char* s, char* it) return s; } -static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) +static int nsvg__parseStrokeDashArray(NSVGparser *p, const char *str, float *strokeDashArray) { char item[64]; int count = 0, i; @@ -1736,9 +1806,11 @@ static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* str // Parse dashes while (*str) { str = nsvg__getNextDashItem(str, item); - if (!*item) break; + if (!*item) + break; if (count < NSVG_MAX_DASHES) - strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + strokeDashArray[count++] = + fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); } for (i = 0; i < count; i++) @@ -1749,13 +1821,14 @@ static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* str return count; } -static void nsvg__parseStyle(NSVGparser* p, const char* str); +static void nsvg__parseStyle(NSVGparser *p, const char *str); -static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) +static int nsvg__parseAttr(NSVGparser *p, const char *name, const char *value) { float xform[6]; - NSVGattrib* attr = nsvg__getAttr(p); - if (!attr) return 0; + NSVGattrib *attr = nsvg__getAttr(p); + if (!attr) + return 0; if (strcmp(name, "style") == 0) { nsvg__parseStyle(p, value); @@ -1793,7 +1866,8 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) } else if (strcmp(name, "stroke-dasharray") == 0) { attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); } else if (strcmp(name, "stroke-dashoffset") == 0) { - attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + attr->strokeDashOffset = + nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); } else if (strcmp(name, "stroke-opacity") == 0) { attr->strokeOpacity = nsvg__parseOpacity(value); } else if (strcmp(name, "stroke-linecap") == 0) { @@ -1824,78 +1898,88 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) return 1; } -static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) +static int nsvg__parseNameValue(NSVGparser *p, const char *start, const char *end) { - const char* str; - const char* val; + const char *str; + const char *val; char name[512]; char value[512]; int n; str = start; - while (str < end && *str != ':') ++str; + while (str < end && *str != ':') + ++str; val = str; // Right Trim - while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; + while (str > start && (*str == ':' || nsvg__isspace(*str))) + --str; ++str; n = (int)(str - start); - if (n > 511) n = 511; - if (n) memcpy(name, start, n); + if (n > 511) + n = 511; + if (n) + memcpy(name, start, n); name[n] = 0; - while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; + while (val < end && (*val == ':' || nsvg__isspace(*val))) + ++val; n = (int)(end - val); - if (n > 511) n = 511; - if (n) memcpy(value, val, n); + if (n > 511) + n = 511; + if (n) + memcpy(value, val, n); value[n] = 0; return nsvg__parseAttr(p, name, value); } -static void nsvg__parseStyle(NSVGparser* p, const char* str) +static void nsvg__parseStyle(NSVGparser *p, const char *str) { - const char* start; - const char* end; + const char *start; + const char *end; while (*str) { // Left Trim - while(*str && nsvg__isspace(*str)) ++str; + while (*str && nsvg__isspace(*str)) + ++str; start = str; - while(*str && *str != ';') ++str; + while (*str && *str != ';') + ++str; end = str; // Right Trim - while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; + while (end > start && (*end == ';' || nsvg__isspace(*end))) + --end; ++end; nsvg__parseNameValue(p, start, end); - if (*str) ++str; + if (*str) + ++str; } } -static void nsvg__parseAttribs(NSVGparser* p, const char** attr) +static void nsvg__parseAttribs(NSVGparser *p, const char **attr) { int i; char *end; - for (i = 0; attr[i]; i += 2) - { + for (i = 0; attr[i]; i += 2) { if (strcmp(attr[i], "style") == 0) { nsvg__parseStyle(p, attr[i + 1]); } else if (strcmp(attr[i], "horiz-adv-x") == 0) { - p->image->defaultHorizAdv = strtol(attr[i+1], &end, 10); - if (end == attr[i+1]) + p->image->defaultHorizAdv = strtol(attr[i + 1], &end, 10); + if (end == attr[i + 1]) p->image->defaultHorizAdv = 0; } else if (strcmp(attr[i], "ascent") == 0) { - p->image->fontAscent = strtol(attr[i+1], &end, 10); - if (end == attr[i+1]) + p->image->fontAscent = strtol(attr[i + 1], &end, 10); + if (end == attr[i + 1]) p->image->fontAscent = 0; } else if (strcmp(attr[i], "descent") == 0) { - p->image->fontDescent = strtol(attr[i+1], &end, 10); - if (end == attr[i+1]) + p->image->fontDescent = strtol(attr[i + 1], &end, 10); + if (end == attr[i + 1]) p->image->fontDescent = 0; } else { nsvg__parseAttr(p, attr[i], attr[i + 1]); @@ -1906,37 +1990,37 @@ static void nsvg__parseAttribs(NSVGparser* p, const char** attr) static int nsvg__getArgsPerElement(char cmd) { switch (cmd) { - case 'v': - case 'V': - case 'h': - case 'H': - return 1; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - return 2; - case 'q': - case 'Q': - case 's': - case 'S': - return 4; - case 'c': - case 'C': - return 6; - case 'a': - case 'A': - return 7; - case 'z': - case 'Z': - return 0; + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + case 'z': + case 'Z': + return 0; } return -1; } -static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +static void nsvg__pathMoveTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { if (rel) { *cpx += args[0]; @@ -1948,7 +2032,7 @@ static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, nsvg__moveTo(p, *cpx, *cpy); } -static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +static void nsvg__pathLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { if (rel) { *cpx += args[0]; @@ -1960,7 +2044,7 @@ static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, nsvg__lineTo(p, *cpx, *cpy); } -static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +static void nsvg__pathHLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { if (rel) *cpx += args[0]; @@ -1969,7 +2053,7 @@ static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args nsvg__lineTo(p, *cpx, *cpy); } -static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +static void nsvg__pathVLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { if (rel) *cpy += args[0]; @@ -1978,8 +2062,8 @@ static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args nsvg__lineTo(p, *cpx, *cpy); } -static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) +static void nsvg__pathCubicBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, + float *args, int rel) { float x2, y2, cx1, cy1, cx2, cy2; @@ -1999,7 +2083,7 @@ static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, y2 = args[5]; } - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); *cpx2 = cx2; *cpy2 = cy2; @@ -2007,8 +2091,8 @@ static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, *cpy = y2; } -static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) +static void nsvg__pathCubicBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, + float *cpy2, float *args, int rel) { float x1, y1, x2, y2, cx1, cy1, cx2, cy2; @@ -2026,10 +2110,10 @@ static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, y2 = args[3]; } - cx1 = 2*x1 - *cpx2; - cy1 = 2*y1 - *cpy2; + cx1 = 2 * x1 - *cpx2; + cy1 = 2 * y1 - *cpy2; - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); *cpx2 = cx2; *cpy2 = cy2; @@ -2037,8 +2121,8 @@ static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, *cpy = y2; } -static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) +static void nsvg__pathQuadBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, + float *args, int rel) { float x1, y1, x2, y2, cx, cy; float cx1, cy1, cx2, cy2; @@ -2058,12 +2142,12 @@ static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, } // Convert to cubic bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); *cpx2 = cx; *cpy2 = cy; @@ -2071,8 +2155,8 @@ static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, *cpy = y2; } -static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) +static void nsvg__pathQuadBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, + float *cpy2, float *args, int rel) { float x1, y1, x2, y2, cx, cy; float cx1, cy1, cx2, cy2; @@ -2087,16 +2171,16 @@ static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, y2 = args[1]; } - cx = 2*x1 - *cpx2; - cy = 2*y1 - *cpy2; + cx = 2 * x1 - *cpx2; + cy = 2 * y1 - *cpy2; // Convert to cubix bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); *cpx2 = cx; *cpy2 = cy; @@ -2104,23 +2188,31 @@ static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, *cpy = y2; } -static float nsvg__sqr(float x) { return x*x; } -static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } +static float nsvg__sqr(float x) +{ + return x * x; +} +static float nsvg__vmag(float x, float y) +{ + return sqrtf(x * x + y * y); +} static float nsvg__vecrat(float ux, float uy, float vx, float vy) { - return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); + return (ux * vx + uy * vy) / (nsvg__vmag(ux, uy) * nsvg__vmag(vx, vy)); } static float nsvg__vecang(float ux, float uy, float vx, float vy) { - float r = nsvg__vecrat(ux,uy, vx,vy); - if (r < -1.0f) r = -1.0f; - if (r > 1.0f) r = 1.0f; - return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); + float r = nsvg__vecrat(ux, uy, vx, vy); + if (r < -1.0f) + r = -1.0f; + if (r > 1.0f) + r = 1.0f; + return ((ux * vy < uy * vx) ? -1.0f : 1.0f) * acosf(r); } -static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +static void nsvg__pathArcTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { // Ported from canvg (https://code.google.com/p/canvg/) float rx, ry, rotx; @@ -2133,14 +2225,14 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int i, ndivs; float hda, kappa; - rx = fabsf(args[0]); // y radius - ry = fabsf(args[1]); // x radius - rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle - fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc - fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction - x1 = *cpx; // start point + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point y1 = *cpy; - if (rel) { // end point + if (rel) { // end point x2 = *cpx + args[5]; y2 = *cpy + args[6]; } else { @@ -2150,7 +2242,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, dx = x1 - x2; dy = y1 - y2; - d = sqrtf(dx*dx + dy*dy); + d = sqrtf(dx * dx + dy * dy); if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { // The arc degenerates to a line nsvg__lineTo(p, x2, y2); @@ -2167,7 +2259,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, // 1) Compute x1', y1' x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; - d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); + d = nsvg__sqr(x1p) / nsvg__sqr(rx) + nsvg__sqr(y1p) / nsvg__sqr(ry); if (d > 1) { d = sqrtf(d); rx *= d; @@ -2175,9 +2267,11 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, } // 2) Compute cx', cy' s = 0.0f; - sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); - sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); - if (sa < 0.0f) sa = 0.0f; + sa = nsvg__sqr(rx) * nsvg__sqr(ry) - nsvg__sqr(rx) * nsvg__sqr(y1p) - + nsvg__sqr(ry) * nsvg__sqr(x1p); + sb = nsvg__sqr(rx) * nsvg__sqr(y1p) + nsvg__sqr(ry) * nsvg__sqr(x1p); + if (sa < 0.0f) + sa = 0.0f; if (sb > 0.0f) s = sqrtf(sa / sb); if (fa == fs) @@ -2186,19 +2280,19 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, cyp = s * -ry * x1p / rx; // 3) Compute cx,cy from cx',cy' - cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; - cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; + cx = (x1 + x2) / 2.0f + cosrx * cxp - sinrx * cyp; + cy = (y1 + y2) / 2.0f + sinrx * cxp + cosrx * cyp; // 4) Calculate theta1, and delta theta. ux = (x1p - cxp) / rx; uy = (y1p - cyp) / ry; vx = (-x1p - cxp) / rx; vy = (-y1p - cyp) / ry; - a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle - da = nsvg__vecang(ux,uy, vx,vy); // Delta angle + a1 = nsvg__vecang(1.0f, 0.0f, ux, uy); // Initial angle + da = nsvg__vecang(ux, uy, vx, vy); // Delta angle -// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; -// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + // if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; + // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; if (fs == 0 && da > 0) da -= 2 * NSVG_PI; @@ -2206,13 +2300,16 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, da += 2 * NSVG_PI; // Approximate the arc using cubic spline segments. - t[0] = cosrx; t[1] = sinrx; - t[2] = -sinrx; t[3] = cosrx; - t[4] = cx; t[5] = cy; + t[0] = cosrx; + t[1] = sinrx; + t[2] = -sinrx; + t[3] = cosrx; + t[4] = cx; + t[5] = cy; // Split arc into max 90 degree segments. // The loop assumes an iteration per end point (including start and end), this +1. - ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); + ndivs = (int)(fabsf(da) / (NSVG_PI * 0.5f) + 1.0f); hda = (da / (float)ndivs) / 2.0f; // Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite) if ((hda < 1e-3f) && (hda > -1e-3f)) @@ -2224,13 +2321,13 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, kappa = -kappa; for (i = 0; i <= ndivs; i++) { - a = a1 + da * ((float)i/(float)ndivs); + a = a1 + da * ((float)i / (float)ndivs); dx = cosf(a); dy = sinf(a); - nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position - nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent + nsvg__xformPoint(&x, &y, dx * rx, dy * ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy * rx * kappa, dx * ry * kappa, t); // tangent if (i > 0) - nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); + nsvg__cubicBezTo(p, px + ptanx, py + ptany, x - tanx, y - tany, x, y); px = x; py = y; ptanx = tanx; @@ -2241,16 +2338,16 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, *cpy = y2; } -static void nsvg__parsePath(NSVGparser* p, const char** attr) +static void nsvg__parsePath(NSVGparser *p, const char **attr) { - const char* s = NULL; + const char *s = NULL; char cmd = '\0'; float args[10]; int nargs; int rargs = 0; char initPoint; float cpx, cpy, cpx2, cpy2; - const char* tmp[4]; + const char *tmp[4]; char closedFlag; int i; char item[64]; @@ -2258,11 +2355,11 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr) for (i = 0; attr[i]; i += 2) { if (strcmp(attr[i], "d") == 0) { s = attr[i + 1]; - } else if (strcmp(attr[i], "unicode") == 0 - && strlen(attr[i+1]) < NSVG_MAX_UNICODE_LEN) { - strcpy(p->unicodeFlag, attr[i+1]); + } else if (strcmp(attr[i], "unicode") == 0 && + strlen(attr[i + 1]) < NSVG_MAX_UNICODE_LEN) { + strcpy(p->unicodeFlag, attr[i + 1]); } else if (strcmp(attr[i], "horiz-adv-x") == 0) { - p->horizAdvFlag = attr[i+1]; + p->horizAdvFlag = attr[i + 1]; } else { tmp[0] = attr[i]; tmp[1] = attr[i + 1]; @@ -2274,73 +2371,93 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr) if (s) { nsvg__resetPath(p); - cpx = 0; cpy = 0; - cpx2 = 0; cpy2 = 0; + cpx = 0; + cpy = 0; + cpx2 = 0; + cpy2 = 0; initPoint = 0; closedFlag = 0; nargs = 0; while (*s) { s = nsvg__getNextPathItem(s, item); - if (!*item) break; + if (!*item) + break; if (cmd != '\0' && nsvg__isCoordinate(item)) { if (nargs < 10) args[nargs++] = (float)nsvg__atof(item); if (nargs >= rargs) { switch (cmd) { - case 'm': - case 'M': - nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); - // Moveto can be followed by multiple coordinate pairs, - // which should be treated as linetos. - cmd = (cmd == 'm') ? 'l' : 'L'; - rargs = nsvg__getArgsPerElement(cmd); - cpx2 = cpx; cpy2 = cpy; - initPoint = 1; - break; - case 'l': - case 'L': - nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'H': - case 'h': - nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'V': - case 'v': - nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'C': - case 'c': - nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); - break; - case 'S': - case 's': - nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); - break; - case 'Q': - case 'q': - nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); - break; - case 'T': - case 't': - nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); - break; - case 'A': - case 'a': - nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - default: - if (nargs >= 2) { - cpx = args[nargs-2]; - cpy = args[nargs-1]; - cpx2 = cpx; cpy2 = cpy; - } - break; + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, + cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate + // pairs, which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; + cpy2 = cpy; + initPoint = 1; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, + cmd == 'l' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, + cmd == 'h' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, + cmd == 'v' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, + args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, + &cpy2, args, + cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, + args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, + &cpy2, args, + cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, + cmd == 'a' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs - 2]; + cpy = args[nargs - 1]; + cpx2 = cpx; + cpy2 = cpy; + } + break; } nargs = 0; } @@ -2355,7 +2472,8 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr) closedFlag = 0; nargs = 0; } else if (initPoint == 0) { - // Do not allow other commands until initial point has been set (moveTo called once). + // Do not allow other commands until initial point has been + // set (moveTo called once). cmd = '\0'; } if (cmd == 'Z' || cmd == 'z') { @@ -2365,7 +2483,8 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr) // Move current point to first point cpx = p->pts[0]; cpy = p->pts[1]; - cpx2 = cpx; cpy2 = cpy; + cpx2 = cpx; + cpy2 = cpy; nsvg__addPath(p, closedFlag); } // Start new subpath. @@ -2390,7 +2509,7 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr) nsvg__addShape(p); } -static void nsvg__parseRect(NSVGparser* p, const char** attr) +static void nsvg__parseRect(NSVGparser *p, const char **attr) { float x = 0.0f; float y = 0.0f; @@ -2402,41 +2521,63 @@ static void nsvg__parseRect(NSVGparser* p, const char** attr) for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); - if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + if (strcmp(attr[i], "x") == 0) + x = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), + nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) + y = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), + nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) + w = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, + nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) + h = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, + nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, + nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, + nsvg__actualHeight(p))); } } - if (rx < 0.0f && ry > 0.0f) rx = ry; - if (ry < 0.0f && rx > 0.0f) ry = rx; - if (rx < 0.0f) rx = 0.0f; - if (ry < 0.0f) ry = 0.0f; - if (rx > w/2.0f) rx = w/2.0f; - if (ry > h/2.0f) ry = h/2.0f; + if (rx < 0.0f && ry > 0.0f) + rx = ry; + if (ry < 0.0f && rx > 0.0f) + ry = rx; + if (rx < 0.0f) + rx = 0.0f; + if (ry < 0.0f) + ry = 0.0f; + if (rx > w / 2.0f) + rx = w / 2.0f; + if (ry > h / 2.0f) + ry = h / 2.0f; if (w != 0.0f && h != 0.0f) { nsvg__resetPath(p); if (rx < 0.00001f || ry < 0.0001f) { nsvg__moveTo(p, x, y); - nsvg__lineTo(p, x+w, y); - nsvg__lineTo(p, x+w, y+h); - nsvg__lineTo(p, x, y+h); + nsvg__lineTo(p, x + w, y); + nsvg__lineTo(p, x + w, y + h); + nsvg__lineTo(p, x, y + h); } else { // Rounded rectangle - nsvg__moveTo(p, x+rx, y); - nsvg__lineTo(p, x+w-rx, y); - nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); - nsvg__lineTo(p, x+w, y+h-ry); - nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); - nsvg__lineTo(p, x+rx, y+h); - nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); - nsvg__lineTo(p, x, y+ry); - nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); + nsvg__moveTo(p, x + rx, y); + nsvg__lineTo(p, x + w - rx, y); + nsvg__cubicBezTo(p, x + w - rx * (1 - NSVG_KAPPA90), y, x + w, + y + ry * (1 - NSVG_KAPPA90), x + w, y + ry); + nsvg__lineTo(p, x + w, y + h - ry); + nsvg__cubicBezTo(p, x + w, y + h - ry * (1 - NSVG_KAPPA90), + x + w - rx * (1 - NSVG_KAPPA90), y + h, x + w - rx, y + h); + nsvg__lineTo(p, x + rx, y + h); + nsvg__cubicBezTo(p, x + rx * (1 - NSVG_KAPPA90), y + h, x, + y + h - ry * (1 - NSVG_KAPPA90), x, y + h - ry); + nsvg__lineTo(p, x, y + ry); + nsvg__cubicBezTo(p, x, y + ry * (1 - NSVG_KAPPA90), + x + rx * (1 - NSVG_KAPPA90), y, x + rx, y); } nsvg__addPath(p, 1); @@ -2445,7 +2586,7 @@ static void nsvg__parseRect(NSVGparser* p, const char** attr) } } -static void nsvg__parseCircle(NSVGparser* p, const char** attr) +static void nsvg__parseCircle(NSVGparser *p, const char **attr) { float cx = 0.0f; float cy = 0.0f; @@ -2454,20 +2595,30 @@ static void nsvg__parseCircle(NSVGparser* p, const char** attr) for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), + nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), + nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) + r = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, + nsvg__actualLength(p))); } } if (r > 0.0f) { nsvg__resetPath(p); - nsvg__moveTo(p, cx+r, cy); - nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); - nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); - nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); - nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); + nsvg__moveTo(p, cx + r, cy); + nsvg__cubicBezTo(p, cx + r, cy + r * NSVG_KAPPA90, cx + r * NSVG_KAPPA90, cy + r, + cx, cy + r); + nsvg__cubicBezTo(p, cx - r * NSVG_KAPPA90, cy + r, cx - r, cy + r * NSVG_KAPPA90, + cx - r, cy); + nsvg__cubicBezTo(p, cx - r, cy - r * NSVG_KAPPA90, cx - r * NSVG_KAPPA90, cy - r, + cx, cy - r); + nsvg__cubicBezTo(p, cx + r * NSVG_KAPPA90, cy - r, cx + r, cy - r * NSVG_KAPPA90, + cx + r, cy); nsvg__addPath(p, 1); @@ -2475,7 +2626,7 @@ static void nsvg__parseCircle(NSVGparser* p, const char** attr) } } -static void nsvg__parseEllipse(NSVGparser* p, const char** attr) +static void nsvg__parseEllipse(NSVGparser *p, const char **attr) { float cx = 0.0f; float cy = 0.0f; @@ -2485,10 +2636,18 @@ static void nsvg__parseEllipse(NSVGparser* p, const char** attr) for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), + nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), + nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, + nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, + nsvg__actualHeight(p))); } } @@ -2496,11 +2655,15 @@ static void nsvg__parseEllipse(NSVGparser* p, const char** attr) nsvg__resetPath(p); - nsvg__moveTo(p, cx+rx, cy); - nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); - nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); - nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); - nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); + nsvg__moveTo(p, cx + rx, cy); + nsvg__cubicBezTo(p, cx + rx, cy + ry * NSVG_KAPPA90, cx + rx * NSVG_KAPPA90, + cy + ry, cx, cy + ry); + nsvg__cubicBezTo(p, cx - rx * NSVG_KAPPA90, cy + ry, cx - rx, + cy + ry * NSVG_KAPPA90, cx - rx, cy); + nsvg__cubicBezTo(p, cx - rx, cy - ry * NSVG_KAPPA90, cx - rx * NSVG_KAPPA90, + cy - ry, cx, cy - ry); + nsvg__cubicBezTo(p, cx + rx * NSVG_KAPPA90, cy - ry, cx + rx, + cy - ry * NSVG_KAPPA90, cx + rx, cy); nsvg__addPath(p, 1); @@ -2508,7 +2671,7 @@ static void nsvg__parseEllipse(NSVGparser* p, const char** attr) } } -static void nsvg__parseLine(NSVGparser* p, const char** attr) +static void nsvg__parseLine(NSVGparser *p, const char **attr) { float x1 = 0.0; float y1 = 0.0; @@ -2518,10 +2681,18 @@ static void nsvg__parseLine(NSVGparser* p, const char** attr) for (i = 0; attr[i]; i += 2) { if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x1") == 0) + x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), + nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) + y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), + nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) + x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), + nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) + y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), + nsvg__actualHeight(p)); } } @@ -2535,10 +2706,10 @@ static void nsvg__parseLine(NSVGparser* p, const char** attr) nsvg__addShape(p); } -static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) +static void nsvg__parsePoly(NSVGparser *p, const char **attr, int closeFlag) { int i; - const char* s; + const char *s; float args[2]; int nargs, npts = 0; char item[64]; @@ -2571,7 +2742,7 @@ static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) nsvg__addShape(p); } -static void nsvg__parseSVG(NSVGparser* p, const char** attr) +static void nsvg__parseSVG(NSVGparser *p, const char **attr) { int i; for (i = 0; attr[i]; i += 2) { @@ -2579,22 +2750,29 @@ static void nsvg__parseSVG(NSVGparser* p, const char** attr) if (strcmp(attr[i], "width") == 0) { p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); } else if (strcmp(attr[i], "height") == 0) { - p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + p->image->height = + nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); } else if (strcmp(attr[i], "viewBox") == 0) { const char *s = attr[i + 1]; char buf[64]; s = nsvg__parseNumber(s, buf, 64); p->viewMinx = nsvg__atof(buf); - while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; - if (!*s) return; + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) + s++; + if (!*s) + return; s = nsvg__parseNumber(s, buf, 64); p->viewMiny = nsvg__atof(buf); - while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; - if (!*s) return; + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) + s++; + if (!*s) + return; s = nsvg__parseNumber(s, buf, 64); p->viewWidth = nsvg__atof(buf); - while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; - if (!*s) return; + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) + s++; + if (!*s) + return; s = nsvg__parseNumber(s, buf, 64); p->viewHeight = nsvg__atof(buf); } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { @@ -2626,11 +2804,12 @@ static void nsvg__parseSVG(NSVGparser* p, const char** attr) } } -static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) +static void nsvg__parseGradient(NSVGparser *p, const char **attr, char type) { int i; - NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); - if (grad == NULL) return; + NSVGgradientData *grad = (NSVGgradientData *)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) + return; memset(grad, 0, sizeof(NSVGgradientData)); grad->units = NSVG_OBJECT_SPACE; grad->type = type; @@ -2649,11 +2828,11 @@ static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) for (i = 0; attr[i]; i += 2) { if (strcmp(attr[i], "id") == 0) { - strncpy(grad->id, attr[i+1], 63); + strncpy(grad->id, attr[i + 1], 63); grad->id[63] = '\0'; } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { if (strcmp(attr[i], "gradientUnits") == 0) { - if (strcmp(attr[i+1], "objectBoundingBox") == 0) + if (strcmp(attr[i + 1], "objectBoundingBox") == 0) grad->units = NSVG_OBJECT_SPACE; else grad->units = NSVG_USER_SPACE; @@ -2678,15 +2857,15 @@ static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) } else if (strcmp(attr[i], "y2") == 0) { grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); } else if (strcmp(attr[i], "spreadMethod") == 0) { - if (strcmp(attr[i+1], "pad") == 0) + if (strcmp(attr[i + 1], "pad") == 0) grad->spread = NSVG_SPREAD_PAD; - else if (strcmp(attr[i+1], "reflect") == 0) + else if (strcmp(attr[i + 1], "reflect") == 0) grad->spread = NSVG_SPREAD_REFLECT; - else if (strcmp(attr[i+1], "repeat") == 0) + else if (strcmp(attr[i + 1], "repeat") == 0) grad->spread = NSVG_SPREAD_REPEAT; } else if (strcmp(attr[i], "xlink:href") == 0) { - const char *href = attr[i+1]; - strncpy(grad->ref, href+1, 62); + const char *href = attr[i + 1]; + strncpy(grad->ref, href + 1, 62); grad->ref[62] = '\0'; } } @@ -2696,11 +2875,11 @@ static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) p->gradients = grad; } -static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) +static void nsvg__parseGradientStop(NSVGparser *p, const char **attr) { - NSVGattrib* curAttr = nsvg__getAttr(p); - NSVGgradientData* grad; - NSVGgradientStop* stop; + NSVGattrib *curAttr = nsvg__getAttr(p); + NSVGgradientData *grad; + NSVGgradientStop *stop; int i, idx; curAttr->stopOffset = 0; @@ -2713,34 +2892,37 @@ static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) // Add stop to the last gradient. grad = p->gradients; - if (grad == NULL) return; + if (grad == NULL) + return; grad->nstops++; - grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); - if (grad->stops == NULL) return; + grad->stops = + (NSVGgradientStop *)realloc(grad->stops, sizeof(NSVGgradientStop) * grad->nstops); + if (grad->stops == NULL) + return; // Insert - idx = grad->nstops-1; - for (i = 0; i < grad->nstops-1; i++) { + idx = grad->nstops - 1; + for (i = 0; i < grad->nstops - 1; i++) { if (curAttr->stopOffset < grad->stops[i].offset) { idx = i; break; } } - if (idx != grad->nstops-1) { - for (i = grad->nstops-1; i > idx; i--) - grad->stops[i] = grad->stops[i-1]; + if (idx != grad->nstops - 1) { + for (i = grad->nstops - 1; i > idx; i--) + grad->stops[i] = grad->stops[i - 1]; } stop = &grad->stops[idx]; stop->color = curAttr->stopColor; - stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; + stop->color |= (unsigned int)(curAttr->stopOpacity * 255) << 24; stop->offset = curAttr->stopOffset; } -static void nsvg__startElement(void* ud, const char* el, const char** attr) +static void nsvg__startElement(void *ud, const char *el, const char **attr) { - NSVGparser* p = (NSVGparser*)ud; + NSVGparser *p = (NSVGparser *)ud; if (p->defsFlag) { // Skip everything but gradients and fonts in defs @@ -2751,7 +2933,7 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr) } else if (strcmp(el, "stop") == 0) { nsvg__parseGradientStop(p, attr); } else if (strcmp(el, "glyph") == 0) { // glyphs are just special paths - if (p->pathFlag) // Do not allow nested paths. + if (p->pathFlag) // Do not allow nested paths. return; nsvg__pushAttr(p); nsvg__parsePath(p, attr); @@ -2770,7 +2952,7 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr) nsvg__pushAttr(p); nsvg__parseAttribs(p, attr); } else if (strcmp(el, "path") == 0) { - if (p->pathFlag) // Do not allow nested paths. + if (p->pathFlag) // Do not allow nested paths. return; nsvg__pushAttr(p); nsvg__parsePath(p, attr); @@ -2787,19 +2969,19 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr) nsvg__pushAttr(p); nsvg__parseEllipse(p, attr); nsvg__popAttr(p); - } else if (strcmp(el, "line") == 0) { + } else if (strcmp(el, "line") == 0) { nsvg__pushAttr(p); nsvg__parseLine(p, attr); nsvg__popAttr(p); - } else if (strcmp(el, "polyline") == 0) { + } else if (strcmp(el, "polyline") == 0) { nsvg__pushAttr(p); nsvg__parsePoly(p, attr, 0); nsvg__popAttr(p); - } else if (strcmp(el, "polygon") == 0) { + } else if (strcmp(el, "polygon") == 0) { nsvg__pushAttr(p); nsvg__parsePoly(p, attr, 1); nsvg__popAttr(p); - } else if (strcmp(el, "linearGradient") == 0) { + } else if (strcmp(el, "linearGradient") == 0) { nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); } else if (strcmp(el, "radialGradient") == 0) { nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); @@ -2812,9 +2994,9 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr) } } -static void nsvg__endElement(void* ud, const char* el) +static void nsvg__endElement(void *ud, const char *el) { - NSVGparser* p = (NSVGparser*)ud; + NSVGparser *p = (NSVGparser *)ud; if (strcmp(el, "g") == 0) { nsvg__popAttr(p); @@ -2825,16 +3007,16 @@ static void nsvg__endElement(void* ud, const char* el) } } -static void nsvg__content(void* ud, const char* s) +static void nsvg__content(void *ud, const char *s) { NSVG_NOTUSED(ud); NSVG_NOTUSED(s); // empty } -static void nsvg__imageBounds(NSVGparser* p, float* bounds) +static void nsvg__imageBounds(NSVGparser *p, float *bounds) { - NSVGshape* shape; + NSVGshape *shape; shape = p->image->shapes; if (shape == NULL) { bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; @@ -2862,23 +3044,23 @@ static float nsvg__viewAlign(float content, float container, int type) return (container - content) * 0.5f; } -static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) +static void nsvg__scaleGradient(NSVGgradient *grad, float tx, float ty, float sx, float sy) { float t[6]; nsvg__xformSetTranslation(t, tx, ty); - nsvg__xformMultiply (grad->xform, t); + nsvg__xformMultiply(grad->xform, t); nsvg__xformSetScale(t, sx, sy); - nsvg__xformMultiply (grad->xform, t); + nsvg__xformMultiply(grad->xform, t); } -static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) +static void nsvg__scaleToViewbox(NSVGparser *p, const char *units) { - NSVGshape* shape; - NSVGpath* path; + NSVGshape *shape; + NSVGpath *path; float tx, ty, sx, sy, us, bounds[4], t[6], avgs; int i; - float* pt; + float *pt; // Guess image size if not set completely. nsvg__imageBounds(p, bounds); @@ -2909,25 +3091,26 @@ static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; // Unit scaling - us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + us = 1.0f / + nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); // Fix aspect ratio if (p->alignType == NSVG_ALIGN_MEET) { // fit whole image into viewbox sx = sy = nsvg__minf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; } else if (p->alignType == NSVG_ALIGN_SLICE) { // fill whole viewbox with image sx = sy = nsvg__maxf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; } // Transform sx *= us; sy *= us; - avgs = (sx+sy) / 2.0f; + avgs = (sx + sy) / 2.0f; for (shape = p->image->shapes; shape != NULL; shape = shape->next) { shape->bounds[0] = (shape->bounds[0] + tx) * sx; shape->bounds[1] = (shape->bounds[1] + ty) * sy; @@ -2938,21 +3121,23 @@ static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) path->bounds[1] = (path->bounds[1] + ty) * sy; path->bounds[2] = (path->bounds[2] + tx) * sx; path->bounds[3] = (path->bounds[3] + ty) * sy; - for (i =0; i < path->npts; i++) { - pt = &path->pts[i*2]; + for (i = 0; i < path->npts; i++) { + pt = &path->pts[i * 2]; pt[0] = (pt[0] + tx) * sx; pt[1] = (pt[1] + ty) * sy; } } - if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); - memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || + shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx, ty, sx, sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float) * 6); nsvg__xformInverse(shape->fill.gradient->xform, t); } - if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); - memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || + shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx, ty, sx, sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float) * 6); nsvg__xformInverse(shape->stroke.gradient->xform, t); } @@ -2963,15 +3148,14 @@ static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) } } -NSVGshape** nsvgGetTextShapes(const NSVGimage* image, const char* text, int textLen) +NSVGshape **nsvgGetTextShapes(const NSVGimage *image, const char *text, int textLen) { NSVGshape *shape = NULL; NSVGshape **ret = calloc(textLen, sizeof(shape)); // array of paths, text to render int i; // make list of paths representing glyphs to render - for (i = 0; i < textLen; i++) - { + for (i = 0; i < textLen; i++) { if (text[i] == ' ' || text[i] == '\n') { ret[i] = NULL; continue; @@ -2984,17 +3168,17 @@ NSVGshape** nsvgGetTextShapes(const NSVGimage* image, const char* text, int text goto found; } } -found: + found: continue; } return ret; } -NSVGimage* nsvgParse(char* input, const char* units, float dpi) +NSVGimage *nsvgParse(char *input, const char *units, float dpi) { - NSVGparser* p; - NSVGimage* ret = 0; + NSVGparser *p; + NSVGimage *ret = 0; p = nsvg__createParser(); if (p == NULL) { @@ -3015,22 +3199,25 @@ NSVGimage* nsvgParse(char* input, const char* units, float dpi) return ret; } -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi) { - FILE* fp = NULL; + FILE *fp = NULL; size_t size; - char* data = NULL; - NSVGimage* image = NULL; + char *data = NULL; + NSVGimage *image = NULL; fp = fopen(filename, "rb"); - if (!fp) goto error; + if (!fp) + goto error; fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); - data = (char*)malloc(size+1); - if (data == NULL) goto error; - if (fread(data, 1, size, fp) != size) goto error; - data[size] = '\0'; // Must be null terminated. + data = (char *)malloc(size + 1); + if (data == NULL) + goto error; + if (fread(data, 1, size, fp) != size) + goto error; + data[size] = '\0'; // Must be null terminated. fclose(fp); image = nsvgParse(data, units, dpi); free(data); @@ -3038,46 +3225,51 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) return image; error: - if (fp) fclose(fp); - if (data) free(data); + if (fp) + fclose(fp); + if (data) + free(data); nsvgDelete(image); return NULL; } -NSVGpath* nsvgDuplicatePath(NSVGpath* p) +NSVGpath *nsvgDuplicatePath(NSVGpath *p) { - NSVGpath* res = NULL; + NSVGpath *res = NULL; - if (p == NULL) - return NULL; + if (p == NULL) + return NULL; - res = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (res == NULL) goto error; - memset(res, 0, sizeof(NSVGpath)); + res = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (res == NULL) + goto error; + memset(res, 0, sizeof(NSVGpath)); - res->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (res->pts == NULL) goto error; - memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); - res->npts = p->npts; + res->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (res->pts == NULL) + goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; - memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); - res->closed = p->closed; + res->closed = p->closed; - return res; + return res; error: - if (res != NULL) { - free(res->pts); - free(res); - } - return NULL; + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; } -void nsvgDelete(NSVGimage* image) +void nsvgDelete(NSVGimage *image) { NSVGshape *snext, *shape; - if (image == NULL) return; + if (image == NULL) + return; shape = image->shapes; while (shape != NULL) { snext = shape->next; diff --git a/include/nanosvgrast.h b/include/nanosvgrast.h index 030303a..3b7b311 100644 --- a/include/nanosvgrast.h +++ b/include/nanosvgrast.h @@ -47,7 +47,7 @@ typedef struct NSVGrasterizer NSVGrasterizer; */ // Allocated rasterizer context. -NSVGrasterizer* nsvgCreateRasterizer(); +NSVGrasterizer *nsvgCreateRasterizer(); // Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) // r - pointer to rasterizer context @@ -58,19 +58,14 @@ NSVGrasterizer* nsvgCreateRasterizer(); // w - width of the image to render // h - height of the image to render // stride - number of bytes per scaleline in the destination buffer -void nsvgRasterize(NSVGrasterizer* r, - NSVGimage* image, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride); +void nsvgRasterize(NSVGrasterizer *r, NSVGimage *image, float tx, float ty, float scale, + unsigned char *dst, int w, int h, int stride); // Deletes rasterizer context. -void nsvgDeleteRasterizer(NSVGrasterizer*); - - -void nsvgRasterizeText(NSVGrasterizer* r, - const NSVGimage* font, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride, - const char* text); +void nsvgDeleteRasterizer(NSVGrasterizer *); +void nsvgRasterizeText(NSVGrasterizer *r, const NSVGimage *font, float tx, float ty, float scale, + unsigned char *dst, int w, int h, int stride, const char *text); #ifndef NANOSVGRAST_CPLUSPLUS #ifdef __cplusplus @@ -84,16 +79,16 @@ void nsvgRasterizeText(NSVGrasterizer* r, #include -#define NSVG__SUBSAMPLES 5 -#define NSVG__FIXSHIFT 10 -#define NSVG__FIX (1 << NSVG__FIXSHIFT) -#define NSVG__FIXMASK (NSVG__FIX-1) -#define NSVG__MEMPAGE_SIZE 1024 +#define NSVG__SUBSAMPLES 5 +#define NSVG__FIXSHIFT 10 +#define NSVG__FIX (1 << NSVG__FIXSHIFT) +#define NSVG__FIXMASK (NSVG__FIX - 1) +#define NSVG__MEMPAGE_SIZE 1024 typedef struct NSVGedge { - float x0,y0, x1,y1; + float x0, y0, x1, y1; int dir; - struct NSVGedge* next; + struct NSVGedge *next; } NSVGedge; typedef struct NSVGpoint { @@ -105,7 +100,7 @@ typedef struct NSVGpoint { } NSVGpoint; typedef struct NSVGactiveEdge { - int x,dx; + int x, dx; float ey; int dir; struct NSVGactiveEdge *next; @@ -114,7 +109,7 @@ typedef struct NSVGactiveEdge { typedef struct NSVGmemPage { unsigned char mem[NSVG__MEMPAGE_SIZE]; int size; - struct NSVGmemPage* next; + struct NSVGmemPage *next; } NSVGmemPage; typedef struct NSVGcachedPaint { @@ -124,40 +119,40 @@ typedef struct NSVGcachedPaint { unsigned int colors[256]; } NSVGcachedPaint; -struct NSVGrasterizer -{ +struct NSVGrasterizer { float px, py; float tessTol; float distTol; - NSVGedge* edges; + NSVGedge *edges; int nedges; int cedges; - NSVGpoint* points; + NSVGpoint *points; int npoints; int cpoints; - NSVGpoint* points2; + NSVGpoint *points2; int npoints2; int cpoints2; - NSVGactiveEdge* freelist; - NSVGmemPage* pages; - NSVGmemPage* curpage; + NSVGactiveEdge *freelist; + NSVGmemPage *pages; + NSVGmemPage *curpage; - unsigned char* scanline; + unsigned char *scanline; int cscanline; - unsigned char* bitmap; + unsigned char *bitmap; int width, height, stride; }; -NSVGrasterizer* nsvgCreateRasterizer() +NSVGrasterizer *nsvgCreateRasterizer() { - NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer)); - if (r == NULL) goto error; + NSVGrasterizer *r = (NSVGrasterizer *)malloc(sizeof(NSVGrasterizer)); + if (r == NULL) + goto error; memset(r, 0, sizeof(NSVGrasterizer)); r->tessTol = 0.25f; @@ -170,28 +165,33 @@ error: return NULL; } -void nsvgDeleteRasterizer(NSVGrasterizer* r) +void nsvgDeleteRasterizer(NSVGrasterizer *r) { - NSVGmemPage* p; + NSVGmemPage *p; - if (r == NULL) return; + if (r == NULL) + return; p = r->pages; while (p != NULL) { - NSVGmemPage* next = p->next; + NSVGmemPage *next = p->next; free(p); p = next; } - if (r->edges) free(r->edges); - if (r->points) free(r->points); - if (r->points2) free(r->points2); - if (r->scanline) free(r->scanline); + if (r->edges) + free(r->edges); + if (r->points) + free(r->points); + if (r->points2) + free(r->points2); + if (r->scanline) + free(r->scanline); free(r); } -static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) +static NSVGmemPage *nsvg__nextPage(NSVGrasterizer *r, NSVGmemPage *cur) { NSVGmemPage *newp; @@ -201,8 +201,9 @@ static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) } // Alloc new page - newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage)); - if (newp == NULL) return NULL; + newp = (NSVGmemPage *)malloc(sizeof(NSVGmemPage)); + if (newp == NULL) + return NULL; memset(newp, 0, sizeof(NSVGmemPage)); // Add to linked list @@ -214,9 +215,9 @@ static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) return newp; } -static void nsvg__resetPool(NSVGrasterizer* r) +static void nsvg__resetPool(NSVGrasterizer *r) { - NSVGmemPage* p = r->pages; + NSVGmemPage *p = r->pages; while (p != NULL) { p->size = 0; p = p->next; @@ -224,11 +225,12 @@ static void nsvg__resetPool(NSVGrasterizer* r) r->curpage = r->pages; } -static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size) +static unsigned char *nsvg__alloc(NSVGrasterizer *r, int size) { - unsigned char* buf; - if (size > NSVG__MEMPAGE_SIZE) return NULL; - if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) { + unsigned char *buf; + if (size > NSVG__MEMPAGE_SIZE) + return NULL; + if (r->curpage == NULL || r->curpage->size + size > NSVG__MEMPAGE_SIZE) { r->curpage = nsvg__nextPage(r, r->curpage); } buf = &r->curpage->mem[r->curpage->size]; @@ -240,25 +242,26 @@ static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol) { float dx = x2 - x1; float dy = y2 - y1; - return dx*dx + dy*dy < tol*tol; + return dx * dx + dy * dy < tol * tol; } -static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) +static void nsvg__addPathPoint(NSVGrasterizer *r, float x, float y, int flags) { - NSVGpoint* pt; + NSVGpoint *pt; if (r->npoints > 0) { - pt = &r->points[r->npoints-1]; - if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { + pt = &r->points[r->npoints - 1]; + if (nsvg__ptEquals(pt->x, pt->y, x, y, r->distTol)) { pt->flags = (unsigned char)(pt->flags | flags); return; } } - if (r->npoints+1 > r->cpoints) { + if (r->npoints + 1 > r->cpoints) { r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; - r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); - if (r->points == NULL) return; + r->points = (NSVGpoint *)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) + return; } pt = &r->points[r->npoints]; @@ -268,41 +271,44 @@ static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) r->npoints++; } -static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt) +static void nsvg__appendPathPoint(NSVGrasterizer *r, NSVGpoint pt) { - if (r->npoints+1 > r->cpoints) { + if (r->npoints + 1 > r->cpoints) { r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; - r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); - if (r->points == NULL) return; + r->points = (NSVGpoint *)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) + return; } r->points[r->npoints] = pt; r->npoints++; } -static void nsvg__duplicatePoints(NSVGrasterizer* r) +static void nsvg__duplicatePoints(NSVGrasterizer *r) { if (r->npoints > r->cpoints2) { r->cpoints2 = r->npoints; - r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); - if (r->points2 == NULL) return; + r->points2 = (NSVGpoint *)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); + if (r->points2 == NULL) + return; } memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints); r->npoints2 = r->npoints; } -static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1) +static void nsvg__addEdge(NSVGrasterizer *r, float x0, float y0, float x1, float y1) { - NSVGedge* e; + NSVGedge *e; // Skip horizontal edges if (y0 == y1) return; - if (r->nedges+1 > r->cedges) { + if (r->nedges + 1 > r->cedges) { r->cedges = r->cedges > 0 ? r->cedges * 2 : 64; - r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges); - if (r->edges == NULL) return; + r->edges = (NSVGedge *)realloc(r->edges, sizeof(NSVGedge) * r->cedges); + if (r->edges == NULL) + return; } e = &r->edges[r->nedges]; @@ -323,9 +329,9 @@ static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float } } -static float nsvg__normalize(float *x, float* y) +static float nsvg__normalize(float *x, float *y) { - float d = sqrtf((*x)*(*x) + (*y)*(*y)); + float d = sqrtf((*x) * (*x) + (*y) * (*y)); if (d > 1e-6f) { float id = 1.0f / d; *x *= id; @@ -334,95 +340,99 @@ static float nsvg__normalize(float *x, float* y) return d; } -static float nsvg__absf(float x) { return x < 0 ? -x : x; } - -static void nsvg__flattenCubicBez(NSVGrasterizer* r, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4, - int level, int type) +static float nsvg__absf(float x) { - float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234; - float dx,dy,d2,d3; + return x < 0 ? -x : x; +} - if (level > 10) return; +static void nsvg__flattenCubicBez(NSVGrasterizer *r, float x1, float y1, float x2, float y2, + float x3, float y3, float x4, float y4, int level, int type) +{ + float x12, y12, x23, y23, x34, y34, x123, y123, x234, y234, x1234, y1234; + float dx, dy, d2, d3; - x12 = (x1+x2)*0.5f; - y12 = (y1+y2)*0.5f; - x23 = (x2+x3)*0.5f; - y23 = (y2+y3)*0.5f; - x34 = (x3+x4)*0.5f; - y34 = (y3+y4)*0.5f; - x123 = (x12+x23)*0.5f; - y123 = (y12+y23)*0.5f; + if (level > 10) + return; + + x12 = (x1 + x2) * 0.5f; + y12 = (y1 + y2) * 0.5f; + x23 = (x2 + x3) * 0.5f; + y23 = (y2 + y3) * 0.5f; + x34 = (x3 + x4) * 0.5f; + y34 = (y3 + y4) * 0.5f; + x123 = (x12 + x23) * 0.5f; + y123 = (y12 + y23) * 0.5f; dx = x4 - x1; dy = y4 - y1; d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx)); d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx)); - if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { + if ((d2 + d3) * (d2 + d3) < r->tessTol * (dx * dx + dy * dy)) { nsvg__addPathPoint(r, x4, y4, type); return; } - x234 = (x23+x34)*0.5f; - y234 = (y23+y34)*0.5f; - x1234 = (x123+x234)*0.5f; - y1234 = (y123+y234)*0.5f; + x234 = (x23 + x34) * 0.5f; + y234 = (y23 + y34) * 0.5f; + x1234 = (x123 + x234) * 0.5f; + y1234 = (y123 + y234) * 0.5f; - nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0); - nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); + nsvg__flattenCubicBez(r, x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1, 0); + nsvg__flattenCubicBez(r, x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1, type); } -static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) +static void nsvg__flattenShape(NSVGrasterizer *r, NSVGshape *shape, float scale) { int i, j; - NSVGpath* path; + NSVGpath *path; for (path = shape->paths; path != NULL; path = path->next) { r->npoints = 0; // Flatten path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); - for (i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0); + nsvg__addPathPoint(r, path->pts[0] * scale, path->pts[1] * scale, 0); + for (i = 0; i < path->npts - 1; i += 3) { + float *p = &path->pts[i * 2]; + nsvg__flattenCubicBez(r, p[0] * scale, p[1] * scale, p[2] * scale, + p[3] * scale, p[4] * scale, p[5] * scale, + p[6] * scale, p[7] * scale, 0, 0); } // Close path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + nsvg__addPathPoint(r, path->pts[0] * scale, path->pts[1] * scale, 0); // Build edges - for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) - nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); + for (i = 0, j = r->npoints - 1; i < r->npoints; j = i++) + nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, + r->points[i].y); } } -enum NSVGpointFlags -{ - NSVG_PT_CORNER = 0x01, - NSVG_PT_BEVEL = 0x02, - NSVG_PT_LEFT = 0x04 -}; +enum NSVGpointFlags { NSVG_PT_CORNER = 0x01, NSVG_PT_BEVEL = 0x02, NSVG_PT_LEFT = 0x04 }; -static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +static void nsvg__initClosed(NSVGpoint *left, NSVGpoint *right, NSVGpoint *p0, NSVGpoint *p1, + float lineWidth) { float w = lineWidth * 0.5f; float dx = p1->x - p0->x; float dy = p1->y - p0->y; float len = nsvg__normalize(&dx, &dy); - float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f; + float px = p0->x + dx * len * 0.5f, py = p0->y + dy * len * 0.5f; float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; + float lx = px - dlx * w, ly = py - dly * w; + float rx = px + dlx * w, ry = py + dly * w; + left->x = lx; + left->y = ly; + right->x = rx; + right->y = ry; } -static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +static void nsvg__buttCap(NSVGrasterizer *r, NSVGpoint *left, NSVGpoint *right, NSVGpoint *p, + float dx, float dy, float lineWidth, int connect) { float w = lineWidth * 0.5f; float px = p->x, py = p->y; float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; + float lx = px - dlx * w, ly = py - dly * w; + float rx = px + dlx * w, ry = py + dly * w; nsvg__addEdge(r, lx, ly, rx, ry); @@ -430,17 +440,20 @@ static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, nsvg__addEdge(r, left->x, left->y, lx, ly); nsvg__addEdge(r, rx, ry, right->x, right->y); } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; + left->x = lx; + left->y = ly; + right->x = rx; + right->y = ry; } -static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +static void nsvg__squareCap(NSVGrasterizer *r, NSVGpoint *left, NSVGpoint *right, NSVGpoint *p, + float dx, float dy, float lineWidth, int connect) { float w = lineWidth * 0.5f; - float px = p->x - dx*w, py = p->y - dy*w; + float px = p->x - dx * w, py = p->y - dy * w; float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; + float lx = px - dlx * w, ly = py - dly * w; + float rx = px + dlx * w, ry = py + dly * w; nsvg__addEdge(r, lx, ly, rx, ry); @@ -448,15 +461,18 @@ static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right nsvg__addEdge(r, left->x, left->y, lx, ly); nsvg__addEdge(r, rx, ry, right->x, right->y); } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; + left->x = lx; + left->y = ly; + right->x = rx; + right->y = ry; } #ifndef NSVG_PI #define NSVG_PI (3.14159265358979323846264338327f) #endif -static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect) +static void nsvg__roundCap(NSVGrasterizer *r, NSVGpoint *left, NSVGpoint *right, NSVGpoint *p, + float dx, float dy, float lineWidth, int ncap, int connect) { int i; float w = lineWidth * 0.5f; @@ -465,10 +481,10 @@ static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0; for (i = 0; i < ncap; i++) { - float a = (float)i/(float)(ncap-1)*NSVG_PI; + float a = (float)i / (float)(ncap - 1) * NSVG_PI; float ax = cosf(a) * w, ay = sinf(a) * w; - float x = px - dlx*ax - dx*ay; - float y = py - dly*ax - dy*ay; + float x = px - dlx * ax - dx * ay; + float y = py - dly * ax - dy * ay; if (i > 0) nsvg__addEdge(r, prevx, prevy, x, y); @@ -477,9 +493,11 @@ static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, prevy = y; if (i == 0) { - lx = x; ly = y; - } else if (i == ncap-1) { - rx = x; ry = y; + lx = x; + ly = y; + } else if (i == ncap - 1) { + rx = x; + ry = y; } } @@ -488,11 +506,14 @@ static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, nsvg__addEdge(r, rx, ry, right->x, right->y); } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; + left->x = lx; + left->y = ly; + right->x = rx; + right->y = ry; } -static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +static void nsvg__bevelJoin(NSVGrasterizer *r, NSVGpoint *left, NSVGpoint *right, NSVGpoint *p0, + NSVGpoint *p1, float lineWidth) { float w = lineWidth * 0.5f; float dlx0 = p0->dy, dly0 = -p0->dx; @@ -508,11 +529,14 @@ static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right nsvg__addEdge(r, right->x, right->y, rx0, ry0); nsvg__addEdge(r, rx0, ry0, rx1, ry1); - left->x = lx1; left->y = ly1; - right->x = rx1; right->y = ry1; + left->x = lx1; + left->y = ly1; + right->x = rx1; + right->y = ry1; } -static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +static void nsvg__miterJoin(NSVGrasterizer *r, NSVGpoint *left, NSVGpoint *right, NSVGpoint *p0, + NSVGpoint *p1, float lineWidth) { float w = lineWidth * 0.5f; float dlx0 = p0->dy, dly0 = -p0->dx; @@ -544,11 +568,14 @@ static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right nsvg__addEdge(r, right->x, right->y, rx1, ry1); } - left->x = lx1; left->y = ly1; - right->x = rx1; right->y = ry1; + left->x = lx1; + left->y = ly1; + right->x = rx1; + right->y = ry1; } -static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap) +static void nsvg__roundJoin(NSVGrasterizer *r, NSVGpoint *left, NSVGpoint *right, NSVGpoint *p0, + NSVGpoint *p1, float lineWidth, int ncap) { int i, n; float w = lineWidth * 0.5f; @@ -559,12 +586,16 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right float da = a1 - a0; float lx, ly, rx, ry; - if (da < NSVG_PI) da += NSVG_PI*2; - if (da > NSVG_PI) da -= NSVG_PI*2; + if (da < NSVG_PI) + da += NSVG_PI * 2; + if (da > NSVG_PI) + da -= NSVG_PI * 2; n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap); - if (n < 2) n = 2; - if (n > ncap) n = ncap; + if (n < 2) + n = 2; + if (n > ncap) + n = ncap; lx = left->x; ly = left->y; @@ -572,8 +603,8 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right ry = right->y; for (i = 0; i < n; i++) { - float u = (float)i/(float)(n-1); - float a = a0 + u*da; + float u = (float)i / (float)(n - 1); + float a = a0 + u * da; float ax = cosf(a) * w, ay = sinf(a) * w; float lx1 = p1->x - ax, ly1 = p1->y - ay; float rx1 = p1->x + ax, ry1 = p1->y + ay; @@ -581,15 +612,20 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right nsvg__addEdge(r, lx1, ly1, lx, ly); nsvg__addEdge(r, rx, ry, rx1, ry1); - lx = lx1; ly = ly1; - rx = rx1; ry = ry1; + lx = lx1; + ly = ly1; + rx = rx1; + ry = ry1; } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; + left->x = lx; + left->y = ly; + right->x = rx; + right->y = ry; } -static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth) +static void nsvg__straightJoin(NSVGrasterizer *r, NSVGpoint *left, NSVGpoint *right, NSVGpoint *p1, + float lineWidth) { float w = lineWidth * 0.5f; float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w); @@ -598,29 +634,35 @@ static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* ri nsvg__addEdge(r, lx, ly, left->x, left->y); nsvg__addEdge(r, right->x, right->y, rx, ry); - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; + left->x = lx; + left->y = ly; + right->x = rx; + right->y = ry; } static int nsvg__curveDivs(float r, float arc, float tol) { float da = acosf(r / (r + tol)) * 2.0f; int divs = (int)ceilf(arc / da); - if (divs < 2) divs = 2; + if (divs < 2) + divs = 2; return divs; } -static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth) +static void nsvg__expandStroke(NSVGrasterizer *r, NSVGpoint *points, int npoints, int closed, + int lineJoin, int lineCap, float lineWidth) { - int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle. - NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0}; - NSVGpoint* p0, *p1; + int ncap = nsvg__curveDivs(lineWidth * 0.5f, NSVG_PI, + r->tessTol); // Calculate divisions per half circle. + NSVGpoint left = { 0, 0, 0, 0, 0, 0, 0, 0 }, right = { 0, 0, 0, 0, 0, 0, 0, 0 }, + firstLeft = { 0, 0, 0, 0, 0, 0, 0, 0 }, firstRight = { 0, 0, 0, 0, 0, 0, 0, 0 }; + NSVGpoint *p0, *p1; int j, s, e; // Build stroke edges if (closed) { // Looping - p0 = &points[npoints-1]; + p0 = &points[npoints - 1]; p1 = &points[0]; s = 0; e = npoints; @@ -629,7 +671,7 @@ static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints p0 = &points[0]; p1 = &points[1]; s = 1; - e = npoints-1; + e = npoints - 1; } if (closed) { @@ -681,12 +723,12 @@ static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints } } -static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin) +static void nsvg__prepareStroke(NSVGrasterizer *r, float miterLimit, int lineJoin) { int i, j; - NSVGpoint* p0, *p1; + NSVGpoint *p0, *p1; - p0 = &r->points[r->npoints-1]; + p0 = &r->points[r->npoints - 1]; p1 = &r->points[0]; for (i = 0; i < r->npoints; i++) { // Calculate segment direction and length @@ -698,7 +740,7 @@ static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoi } // calculate joins - p0 = &r->points[r->npoints-1]; + p0 = &r->points[r->npoints - 1]; p1 = &r->points[0]; for (j = 0; j < r->npoints; j++) { float dlx0, dly0, dlx1, dly1, dmr2, cross; @@ -709,7 +751,7 @@ static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoi // Calculate extrusions p1->dmx = (dlx0 + dlx1) * 0.5f; p1->dmy = (dly0 + dly1) * 0.5f; - dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; + dmr2 = p1->dmx * p1->dmx + p1->dmy * p1->dmy; if (dmr2 > 0.000001f) { float s2 = 1.0f / dmr2; if (s2 > 600.0f) { @@ -729,7 +771,8 @@ static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoi // Check to see if the corner needs to be beveled. if (p1->flags & NSVG_PT_CORNER) { - if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { + if ((dmr2 * miterLimit * miterLimit) < 1.0f || + lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { p1->flags |= NSVG_PT_BEVEL; } } @@ -738,11 +781,11 @@ static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoi } } -static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) +static void nsvg__flattenShapeStroke(NSVGrasterizer *r, NSVGshape *shape, float scale) { int i, j, closed; - NSVGpath* path; - NSVGpoint* p0, *p1; + NSVGpath *path; + NSVGpoint *p0, *p1; float miterLimit = shape->miterLimit; int lineJoin = shape->strokeLineJoin; int lineCap = shape->strokeLineCap; @@ -751,10 +794,12 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float for (path = shape->paths; path != NULL; path = path->next) { // Flatten path r->npoints = 0; - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); - for (i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER); + nsvg__addPathPoint(r, path->pts[0] * scale, path->pts[1] * scale, NSVG_PT_CORNER); + for (i = 0; i < path->npts - 1; i += 3) { + float *p = &path->pts[i * 2]; + nsvg__flattenCubicBez(r, p[0] * scale, p[1] * scale, p[2] * scale, + p[3] * scale, p[4] * scale, p[5] * scale, + p[6] * scale, p[7] * scale, 0, NSVG_PT_CORNER); } if (r->npoints < 2) continue; @@ -762,11 +807,11 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float closed = path->closed; // If the first and last points are the same, remove the last, mark as closed path. - p0 = &r->points[r->npoints-1]; + p0 = &r->points[r->npoints - 1]; p1 = &r->points[0]; - if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) { + if (nsvg__ptEquals(p0->x, p0->y, p1->x, p1->y, r->distTol)) { r->npoints--; - p0 = &r->points[r->npoints-1]; + p0 = &r->points[r->npoints - 1]; closed = 1; } @@ -782,7 +827,7 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float nsvg__duplicatePoints(r); r->npoints = 0; - cur = r->points2[0]; + cur = r->points2[0]; nsvg__appendPathPoint(r, cur); // Figure out dash offset. @@ -802,10 +847,10 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float } dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; - for (j = 1; j < r->npoints2; ) { + for (j = 1; j < r->npoints2;) { float dx = r->points2[j].x - cur.x; float dy = r->points2[j].y - cur.y; - float dist = sqrtf(dx*dx + dy*dy); + float dist = sqrtf(dx * dx + dy * dy); if ((totalDist + dist) > dashLen) { // Calculate intermediate point @@ -817,11 +862,12 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float // Stroke if (r->npoints > 1 && dashState) { nsvg__prepareStroke(r, miterLimit, lineJoin); - nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + nsvg__expandStroke(r, r->points, r->npoints, 0, + lineJoin, lineCap, lineWidth); } // Advance dash pattern dashState = !dashState; - idash = (idash+1) % shape->strokeDashCount; + idash = (idash + 1) % shape->strokeDashCount; dashLen = shape->strokeDashArray[idash] * scale; // Restart cur.x = x; @@ -839,28 +885,31 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float } // Stroke any leftover path if (r->npoints > 1 && dashState) - nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, + lineWidth); } else { nsvg__prepareStroke(r, miterLimit, lineJoin); - nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth); + nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, + lineWidth); } } } static int nsvg__cmpEdge(const void *p, const void *q) { - const NSVGedge* a = (const NSVGedge*)p; - const NSVGedge* b = (const NSVGedge*)q; + const NSVGedge *a = (const NSVGedge *)p; + const NSVGedge *b = (const NSVGedge *)q; - if (a->y0 < b->y0) return -1; - if (a->y0 > b->y0) return 1; + if (a->y0 < b->y0) + return -1; + if (a->y0 > b->y0) + return 1; return 0; } - -static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) +static NSVGactiveEdge *nsvg__addActive(NSVGrasterizer *r, NSVGedge *e, float startPoint) { - NSVGactiveEdge* z; + NSVGactiveEdge *z; if (r->freelist != NULL) { // Restore from freelist. @@ -868,19 +917,20 @@ static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float sta r->freelist = z->next; } else { // Alloc new edge. - z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge)); - if (z == NULL) return NULL; + z = (NSVGactiveEdge *)nsvg__alloc(r, sizeof(NSVGactiveEdge)); + if (z == NULL) + return NULL; } float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); -// STBTT_assert(e->y0 <= start_point); + // STBTT_assert(e->y0 <= start_point); // round dx down to avoid going too far if (dxdy < 0) z->dx = (int)(-floorf(NSVG__FIX * -dxdy)); else z->dx = (int)floorf(NSVG__FIX * dxdy); z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); -// z->x -= off_x * FIX; + // z->x -= off_x * FIX; z->ey = e->y1; z->next = 0; z->dir = e->dir; @@ -888,30 +938,39 @@ static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float sta return z; } -static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z) +static void nsvg__freeActive(NSVGrasterizer *r, NSVGactiveEdge *z) { z->next = r->freelist; r->freelist = z; } -static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax) +static void nsvg__fillScanline(unsigned char *scanline, int len, int x0, int x1, int maxWeight, + int *xmin, int *xmax) { int i = x0 >> NSVG__FIXSHIFT; int j = x1 >> NSVG__FIXSHIFT; - if (i < *xmin) *xmin = i; - if (j > *xmax) *xmax = j; + if (i < *xmin) + *xmin = i; + if (j > *xmax) + *xmax = j; if (i < len && j >= 0) { if (i == j) { // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT)); + scanline[i] = (unsigned char)(scanline[i] + + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT)); } else { if (i >= 0) // add antialiasing for x0 - scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT)); + scanline[i] = (unsigned char)(scanline[i] + + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * + maxWeight) >> + NSVG__FIXSHIFT)); else i = -1; // clip if (j < len) // add antialiasing for x1 - scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT)); + scanline[j] = (unsigned char)(scanline[j] + + (((x1 & NSVG__FIXMASK) * maxWeight) >> + NSVG__FIXSHIFT)); else j = len; // clip @@ -924,7 +983,8 @@ static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, // note: this routine clips fills that extend off the edges... ideally this // wouldn't happen, but it could happen if the truetype glyph bounding boxes // are wrong, or if the user supplies a too-small bitmap -static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule) +static void nsvg__fillActiveEdges(unsigned char *scanline, int len, NSVGactiveEdge *e, + int maxWeight, int *xmin, int *xmax, char fillRule) { // non-zero winding fill int x0 = 0, w = 0; @@ -933,13 +993,17 @@ static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEd // Non-zero while (e != NULL) { if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->dir; + // if we're currently at zero, we need to record the edge start + // point + x0 = e->x; + w += e->dir; } else { - int x1 = e->x; w += e->dir; + int x1 = e->x; + w += e->dir; // if we went to zero, we need to draw if (w == 0) - nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); + nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, + xmax); } e = e->next; } @@ -947,10 +1011,13 @@ static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEd // Even-odd while (e != NULL) { if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w = 1; + // if we're currently at zero, we need to record the edge start + // point + x0 = e->x; + w = 1; } else { - int x1 = e->x; w = 0; + int x1 = e->x; + w = 0; nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); } e = e->next; @@ -958,7 +1025,10 @@ static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEd } } -static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } +static float nsvg__clampf(float a, float mn, float mx) +{ + return a < mn ? mn : (a > mx ? mx : a); +} static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { @@ -968,30 +1038,30 @@ static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) { int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); - int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8; - int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8; - int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8; - int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8; + int r = (((c0)&0xff) * (256 - iu) + (((c1)&0xff) * iu)) >> 8; + int g = (((c0 >> 8) & 0xff) * (256 - iu) + (((c1 >> 8) & 0xff) * iu)) >> 8; + int b = (((c0 >> 16) & 0xff) * (256 - iu) + (((c1 >> 16) & 0xff) * iu)) >> 8; + int a = (((c0 >> 24) & 0xff) * (256 - iu) + (((c1 >> 24) & 0xff) * iu)) >> 8; return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); } static unsigned int nsvg__applyOpacity(unsigned int c, float u) { int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); - int r = (c) & 0xff; - int g = (c>>8) & 0xff; - int b = (c>>16) & 0xff; - int a = (((c>>24) & 0xff)*iu) >> 8; + int r = (c)&0xff; + int g = (c >> 8) & 0xff; + int b = (c >> 16) & 0xff; + int a = (((c >> 24) & 0xff) * iu) >> 8; return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); } static inline int nsvg__div255(int x) { - return ((x+1) * 257) >> 16; + return ((x + 1) * 257) >> 16; } -static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, - float tx, float ty, float scale, NSVGcachedPaint* cache) +static void nsvg__scanlineSolid(unsigned char *dst, int count, unsigned char *cover, int x, int y, + float tx, float ty, float scale, NSVGcachedPaint *cache) { if (cache->type == NSVG_PAINT_COLOR) { @@ -1002,7 +1072,7 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co ca = (cache->colors[0] >> 24) & 0xff; for (i = 0; i < count; i++) { - int r,g,b; + int r, g, b; int a = nsvg__div255((int)cover[0] * ca); int ia = 255 - a; // Premultiply @@ -1028,7 +1098,7 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co // TODO: spread modes. // TODO: plenty of opportunities to optimize. float fx, fy, dx, gy; - float* t = cache->xform; + float *t = cache->xform; int i, cr, cg, cb, ca; unsigned int c; @@ -1037,10 +1107,10 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co dx = 1.0f / scale; for (i = 0; i < count; i++) { - int r,g,b,a,ia; - gy = fx*t[1] + fy*t[3] + t[5]; - c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)]; - cr = (c) & 0xff; + int r, g, b, a, ia; + gy = fx * t[1] + fy * t[3] + t[5]; + c = cache->colors[(int)nsvg__clampf(gy * 255.0f, 0, 255.0f)]; + cr = (c)&0xff; cg = (c >> 8) & 0xff; cb = (c >> 16) & 0xff; ca = (c >> 24) & 0xff; @@ -1073,7 +1143,7 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co // TODO: plenty of opportunities to optimize. // TODO: focus (fx,fy) float fx, fy, dx, gx, gy, gd; - float* t = cache->xform; + float *t = cache->xform; int i, cr, cg, cb, ca; unsigned int c; @@ -1082,12 +1152,12 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co dx = 1.0f / scale; for (i = 0; i < count; i++) { - int r,g,b,a,ia; - gx = fx*t[0] + fy*t[2] + t[4]; - gy = fx*t[1] + fy*t[3] + t[5]; - gd = sqrtf(gx*gx + gy*gy); - c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)]; - cr = (c) & 0xff; + int r, g, b, a, ia; + gx = fx * t[0] + fy * t[2] + t[4]; + gy = fx * t[1] + fy * t[3] + t[5]; + gd = sqrtf(gx * gx + gy * gy); + c = cache->colors[(int)nsvg__clampf(gd * 255.0f, 0, 255.0f)]; + cr = (c)&0xff; cg = (c >> 8) & 0xff; cb = (c >> 16) & 0xff; ca = (c >> 24) & 0xff; @@ -1118,12 +1188,13 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co } } -static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) +static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, + NSVGcachedPaint *cache, char fillRule) { NSVGactiveEdge *active = NULL; int y, s; int e = 0; - int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline + int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline int xmin, xmax; for (y = 0; y < r->height; y++) { @@ -1132,7 +1203,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl xmax = 0; for (s = 0; s < NSVG__SUBSAMPLES; ++s) { // find center of pixel for this scanline - float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f; + float scany = (float)(y * NSVG__SUBSAMPLES + s) + 0.5f; NSVGactiveEdge **step = &active; // update all active edges; @@ -1141,7 +1212,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl NSVGactiveEdge *z = *step; if (z->ey <= scany) { *step = z->next; // delete from list -// NSVG__assert(z->valid); + // NSVG__assert(z->valid); nsvg__freeActive(r, z); } else { z->x += z->dx; // advance to position for current scanline @@ -1155,8 +1226,8 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl step = &active; while (*step && (*step)->next) { if ((*step)->x > (*step)->next->x) { - NSVGactiveEdge* t = *step; - NSVGactiveEdge* q = t->next; + NSVGactiveEdge *t = *step; + NSVGactiveEdge *q = t->next; t->next = q->next; q->next = t; *step = q; @@ -1164,14 +1235,17 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl } step = &(*step)->next; } - if (!changed) break; + if (!changed) + break; } - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + // insert all edges that start before the center of this scanline -- omit + // ones that also end on this scanline while (e < r->nedges && r->edges[e].y0 <= scany) { if (r->edges[e].y1 > scany) { - NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany); - if (z == NULL) break; + NSVGactiveEdge *z = nsvg__addActive(r, &r->edges[e], scany); + if (z == NULL) + break; // find insertion point if (active == NULL) { active = z; @@ -1181,7 +1255,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl active = z; } else { // find thing to insert AFTER - NSVGactiveEdge* p = active; + NSVGactiveEdge *p = active; while (p->next && p->next->x < z->x) p = p->next; // at this point, p->next->x is NOT < z->x @@ -1194,31 +1268,34 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl // now process all active edges in non-zero fashion if (active != NULL) - nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule); + nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, + &xmin, &xmax, fillRule); } // Blit - if (xmin < 0) xmin = 0; - if (xmax > r->width-1) xmax = r->width-1; + if (xmin < 0) + xmin = 0; + if (xmax > r->width - 1) + xmax = r->width - 1; if (xmin <= xmax) { - nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); + nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin * 4, xmax - xmin + 1, + &r->scanline[xmin], xmin, y, tx, ty, scale, cache); } } - } -static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride) +static void nsvg__unpremultiplyAlpha(unsigned char *image, int w, int h, int stride) { - int x,y; + int x, y; // Unpremultiply for (y = 0; y < h; y++) { - unsigned char *row = &image[y*stride]; + unsigned char *row = &image[y * stride]; for (x = 0; x < w; x++) { int r = row[0], g = row[1], b = row[2], a = row[3]; if (a != 0) { - row[0] = (unsigned char)(r*255/a); - row[1] = (unsigned char)(g*255/a); - row[2] = (unsigned char)(b*255/a); + row[0] = (unsigned char)(r * 255 / a); + row[1] = (unsigned char)(g * 255 / a); + row[2] = (unsigned char)(b * 255 / a); } row += 4; } @@ -1226,38 +1303,38 @@ static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int str // Defringe for (y = 0; y < h; y++) { - unsigned char *row = &image[y*stride]; + unsigned char *row = &image[y * stride]; for (x = 0; x < w; x++) { int r = 0, g = 0, b = 0, a = row[3], n = 0; if (a == 0) { - if (x-1 > 0 && row[-1] != 0) { + if (x - 1 > 0 && row[-1] != 0) { r += row[-4]; g += row[-3]; b += row[-2]; n++; } - if (x+1 < w && row[7] != 0) { + if (x + 1 < w && row[7] != 0) { r += row[4]; g += row[5]; b += row[6]; n++; } - if (y-1 > 0 && row[-stride+3] != 0) { + if (y - 1 > 0 && row[-stride + 3] != 0) { r += row[-stride]; - g += row[-stride+1]; - b += row[-stride+2]; + g += row[-stride + 1]; + b += row[-stride + 2]; n++; } - if (y+1 < h && row[stride+3] != 0) { + if (y + 1 < h && row[stride + 3] != 0) { r += row[stride]; - g += row[stride+1]; - b += row[stride+2]; + g += row[stride + 1]; + b += row[stride + 2]; n++; } if (n > 0) { - row[0] = (unsigned char)(r/n); - row[1] = (unsigned char)(g/n); - row[2] = (unsigned char)(b/n); + row[0] = (unsigned char)(r / n); + row[1] = (unsigned char)(g / n); + row[2] = (unsigned char)(b / n); } } row += 4; @@ -1265,11 +1342,10 @@ static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int str } } - -static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity) +static void nsvg__initPaint(NSVGcachedPaint *cache, NSVGpaint *paint, float opacity) { int i, j; - NSVGgradient* grad; + NSVGgradient *grad; cache->type = paint->type; @@ -1281,12 +1357,13 @@ static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opac grad = paint->gradient; cache->spread = grad->spread; - memcpy(cache->xform, grad->xform, sizeof(float)*6); + memcpy(cache->xform, grad->xform, sizeof(float) * 6); if (grad->nstops == 0) { for (i = 0; i < 256; i++) cache->colors[i] = 0; - } if (grad->nstops == 1) { + } + if (grad->nstops == 1) { for (i = 0; i < 256; i++) cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); } else { @@ -1296,26 +1373,27 @@ static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opac ca = nsvg__applyOpacity(grad->stops[0].color, opacity); ua = nsvg__clampf(grad->stops[0].offset, 0, 1); - ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); + ub = nsvg__clampf(grad->stops[grad->nstops - 1].offset, ua, 1); ia = (int)(ua * 255.0f); ib = (int)(ub * 255.0f); for (i = 0; i < ia; i++) { cache->colors[i] = ca; } - for (i = 0; i < grad->nstops-1; i++) { + for (i = 0; i < grad->nstops - 1; i++) { ca = nsvg__applyOpacity(grad->stops[i].color, opacity); - cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); + cb = nsvg__applyOpacity(grad->stops[i + 1].color, opacity); ua = nsvg__clampf(grad->stops[i].offset, 0, 1); - ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); + ub = nsvg__clampf(grad->stops[i + 1].offset, 0, 1); ia = (int)(ua * 255.0f); ib = (int)(ub * 255.0f); count = ib - ia; - if (count <= 0) continue; + if (count <= 0) + continue; u = 0; du = 1.0f / (float)count; for (j = 0; j < count; j++) { - cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u); + cache->colors[ia + j] = nsvg__lerpRGBA(ca, cb, u); u += du; } } @@ -1323,7 +1401,6 @@ static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opac for (i = ib; i < 256; i++) cache->colors[i] = cb; } - } /* @@ -1350,17 +1427,21 @@ static void dumpEdges(NSVGrasterizer* r, const char* name) ymax = nsvg__maxf(ymax, e->y1); } - fprintf(fp, "", xmin, ymin, (xmax - xmin), (ymax - ymin)); + fprintf(fp, "", xmin, +ymin, (xmax - xmin), (ymax - ymin)); for (i = 0; i < r->nedges; i++) { e = &r->edges[i]; - fprintf(fp ,"", e->x0,e->y0, e->x1,e->y1); + fprintf(fp ,"", e->x0,e->y0, e->x1,e->y1); } for (i = 0; i < r->npoints; i++) { if (i+1 < r->npoints) - fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); - fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); + fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); + fprintf(fp ,"", +r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); } fprintf(fp, ""); @@ -1368,10 +1449,8 @@ static void dumpEdges(NSVGrasterizer* r, const char* name) } */ -void nsvgRasterizeText(NSVGrasterizer* r, - const NSVGimage* font, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride, - const char* text) +void nsvgRasterizeText(NSVGrasterizer *r, const NSVGimage *font, float tx, float ty, float scale, + unsigned char *dst, int w, int h, int stride, const char *text) { NSVGshape *shape = NULL; NSVGedge *e = NULL; @@ -1393,14 +1472,14 @@ void nsvgRasterizeText(NSVGrasterizer* r, if (w > r->cscanline) { r->cscanline = w; - r->scanline = (unsigned char*)realloc(r->scanline, w); + r->scanline = (unsigned char *)realloc(r->scanline, w); if (r->scanline == NULL) { return; } } for (i = 0; i < h; i++) { - memset(&dst[i*stride], 0, w*4); + memset(&dst[i * stride], 0, w * 4); } for (i = 0; i < textLen; i++) { @@ -1442,10 +1521,11 @@ void nsvgRasterizeText(NSVGrasterizer* r, // Rasterize edges qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + // now, traverse the scanlines and find the intersections on each scanline, + // use non-zero rule nsvg__initPaint(&cache, &shape->fill, shape->opacity); - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); + nsvg__rasterizeSortedEdges(r, tx, ty, scale, &cache, shape->fillRule); } if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { nsvg__resetPool(r); @@ -1454,7 +1534,7 @@ void nsvgRasterizeText(NSVGrasterizer* r, nsvg__flattenShapeStroke(r, shape, scale); -// dumpEdges(r, "edge.svg"); + // dumpEdges(r, "edge.svg"); // Scale and translate edges for (j = 0; j < r->nedges; j++) { @@ -1468,10 +1548,11 @@ void nsvgRasterizeText(NSVGrasterizer* r, // Rasterize edges qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + // now, traverse the scanlines and find the intersections on each scanline, + // use non-zero rule nsvg__initPaint(&cache, &shape->stroke, shape->opacity); - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); + nsvg__rasterizeSortedEdges(r, tx, ty, scale, &cache, NSVG_FILLRULE_NONZERO); } tx += shape->horizAdvX * scale; } @@ -1486,9 +1567,8 @@ void nsvgRasterizeText(NSVGrasterizer* r, r->stride = 0; } -void nsvgRasterize(NSVGrasterizer* r, - NSVGimage* image, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride) +void nsvgRasterize(NSVGrasterizer *r, NSVGimage *image, float tx, float ty, float scale, + unsigned char *dst, int w, int h, int stride) { NSVGshape *shape = NULL; NSVGedge *e = NULL; @@ -1502,12 +1582,13 @@ void nsvgRasterize(NSVGrasterizer* r, if (w > r->cscanline) { r->cscanline = w; - r->scanline = (unsigned char*)realloc(r->scanline, w); - if (r->scanline == NULL) return; + r->scanline = (unsigned char *)realloc(r->scanline, w); + if (r->scanline == NULL) + return; } for (i = 0; i < h; i++) - memset(&dst[i*stride], 0, w*4); + memset(&dst[i * stride], 0, w * 4); for (shape = image->shapes; shape != NULL; shape = shape->next) { if (!(shape->flags & NSVG_FLAGS_VISIBLE)) @@ -1532,10 +1613,11 @@ void nsvgRasterize(NSVGrasterizer* r, // Rasterize edges qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + // now, traverse the scanlines and find the intersections on each scanline, + // use non-zero rule nsvg__initPaint(&cache, &shape->fill, shape->opacity); - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); + nsvg__rasterizeSortedEdges(r, tx, ty, scale, &cache, shape->fillRule); } if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { nsvg__resetPool(r); @@ -1544,7 +1626,7 @@ void nsvgRasterize(NSVGrasterizer* r, nsvg__flattenShapeStroke(r, shape, scale); -// dumpEdges(r, "edge.svg"); + // dumpEdges(r, "edge.svg"); // Scale and translate edges for (i = 0; i < r->nedges; i++) { @@ -1558,10 +1640,11 @@ void nsvgRasterize(NSVGrasterizer* r, // Rasterize edges qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + // now, traverse the scanlines and find the intersections on each scanline, + // use non-zero rule nsvg__initPaint(&cache, &shape->stroke, shape->opacity); - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); + nsvg__rasterizeSortedEdges(r, tx, ty, scale, &cache, NSVG_FILLRULE_NONZERO); } } diff --git a/include/pbsplash.h b/include/pbsplash.h index a136a66..c122f0b 100644 --- a/include/pbsplash.h +++ b/include/pbsplash.h @@ -3,13 +3,30 @@ #define MM_TO_PX(dpi, mm) (dpi / 25.4) * (mm) +#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof(a[0]))) +#define INT_ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define MIN(x, y) \ + ({ \ + __typeof__(x) _x = (x); \ + __typeof__(y) _y = (y); \ + _x <= _y ? _x : _y; \ + }) + +#define MAX(x, y) \ + ({ \ + __typeof__(x) _x = (x); \ + __typeof__(y) _y = (y); \ + _x > _y ? _x : _y; \ + }) + struct col { - union { - unsigned int rgba; - struct { - unsigned char r, g, b, a; - }; - }; + union { + unsigned int rgba; + struct { + unsigned char r, g, b, a; + }; + }; }; void animate_frame(int frame, int w, int y_off, long dpi); diff --git a/include/tfblib.h b/include/tfblib.h new file mode 100644 index 0000000..278a5af --- /dev/null +++ b/include/tfblib.h @@ -0,0 +1,571 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file tfblib.h + * @brief Tfblib's main header file + */ + +#pragma once +#define _TFBLIB_H_ + +#include +#include +#include + +#include "pbsplash.h" + +/// Convenience macro used to shorten the signatures. Undefined at the end. +#define u8 uint8_t + +/// Convenience macro used to shorten the signatures. Undefined at the end. +#define u32 uint32_t + +/* + * ---------------------------------------------------------------------------- + * + * Initialization/setup functions and definitions + * + * ---------------------------------------------------------------------------- + */ + +/** + * \addtogroup flags Flags + * @{ + */ + +/** + * Do NOT put TTY in graphics mode. + * + * Passing this flag to tfb_acquire_fb() will + * allow to use the framebuffer and to see stdout on TTY as well. That usually + * is undesirable because the text written to TTY will overwrite the graphics. + */ +#define TFB_FL_NO_TTY_KD_GRAPHICS (1 << 0) + +/** + * Do NOT write directly onto the framebuffer. + * + * Passing this flag to tfb_acquire_fb() will make it allocate a regular memory + * buffer where all the writes (while drawing) will be directed to. The changes + * will appear on-screen only after manually called tfb_flush_rect() or + * tfb_flush_rect(). This flag is useful for applications needing to clean and + * redraw the whole screen (or part of it) very often (e.g. games) in order to + * avoid the annoying flicker effect. + */ +#define TFB_FL_USE_DOUBLE_BUFFER (1 << 1) + +/** @} */ + +/** + * Opens and maps the framebuffer device in the current address space + * + * A successful call to tfb_acquire_fb() is mandatory before calling any drawing + * functions, including the tfb_clear_* and tfb_flush_* functions. + * + * @param[in] flags One or more among: #TFB_FL_NO_TTY_KD_GRAPHICS, + * #TFB_FL_USE_DOUBLE_BUFFER. + * + * @param[in] fb_device The framebuffer device file. Can be NULL. + * Defaults to /dev/fb0. + * + * @param[in] tty_device The tty device file to use for setting tty in + * graphics mode. Can be NULL. Defaults to /dev/tty. + * + * @return #TFB_SUCCESS in case of success or one of the + * following errors: + * #TFB_ERR_OPEN_FB, + * #TFB_ERR_IOCTL_FB, + * #TFB_ERR_UNSUPPORTED_VIDEO_MODE, + * #TFB_ERR_TTY_GRAPHIC_MODE, + * #TFB_ERR_MMAP_FB, + * #TFB_ERR_OUT_OF_MEMORY. + * + * \note This function does not affect the kb mode. tfb_set_kb_raw_mode() can + * be called before or after tfb_acquire_fb(). + */ +int tfb_acquire_fb(u32 flags, const char *fb_device, const char *tty_device); + +/** + * Release the framebuffer device + * + * \note The function **must** be called before exiting, otherwise the TTY + * will remain in graphics mode and be unusable. + * + * \note This function does not affect the kb mode. If tfb_set_kb_raw_mode() + * has been used, tfb_restore_kb_mode() must be called to restore the + * kb mode to its original value. + */ +void tfb_release_fb(void); + +/** + * Limit the drawing to a window at (x, y) having size (w, h) + * + * In case the application does not want to use the whole screen, it can call + * this function to get the coordinate system shifted by (+x, +y) and everything + * outside of it just cut off. Using windows smaller than then screen could + * improve application's performance. + * + * @param[in] x X coordinate of the window, in pixels + * @param[in] y Y coordinate of the window, in pixels + * @param[in] w Width of the window, in pixels + * @param[in] h Height of the window, in pixels + * + * @return #TFB_SUCCESS in case of success or #TFB_ERR_INVALID_WINDOW. + */ +int tfb_set_window(u32 x, u32 y, u32 w, u32 h); + +/** + * Limit the drawing to a window having size (w, h) at the center of the screen + * + * tfb_set_center_window_size() is a wrapper of tfb_set_window() which just + * calculates the (x, y) coordinates of the window in order it to be at the + * center of the screen. + * + * @param[in] w Width of the window, in pixels + * @param[in] h Height of the window, in pixels + * + * @return #TFB_SUCCESS in case of success or #TFB_ERR_INVALID_WINDOW. + */ +int tfb_set_center_window_size(u32 w, u32 h); + +/* + * ---------------------------------------------------------------------------- + * + * Text-related functions and definitions + * + * ---------------------------------------------------------------------------- + */ + +/** + * \addtogroup flags Flags + * @{ + */ + +/** + * When passed to the 'w' param of tfb_set_font_by_size(), means that any font + * width is acceptable. + */ +#define TFB_FONT_ANY_WIDTH 0 + +/** + * When passed to the 'h' param of tfb_set_font_by_size(), means that any font + * height is acceptable. + */ +#define TFB_FONT_ANY_HEIGHT 0 + +/** @} */ + +/** + * Opaque font type + */ +typedef void *tfb_font_t; + +/** + * Font info structure + * + * tfb_iterate_over_fonts() passes a pointer to a struct tfb_font_info * for + * each statically embedded font in the library to the callback function. + */ +struct tfb_font_info { + + const char *name; /**< Font's file name */ + u32 width; /**< Font's character width in pixels */ + u32 height; /**< Font's character height in pixels */ + u32 psf_version; /**< PSF version: either 1 or 2 */ + tfb_font_t font_id; /**< An opaque identifier of the font */ +}; + +/** + * Callback type accepted by tfb_iterate_over_fonts(). + */ +typedef bool (*tfb_font_iter_func)(struct tfb_font_info *cb, void *user_arg); + +/** + * Iterate over the fonts embedded in the library. + * + * tfb_iterate_over_fonts() calls 'cb' once for each embedded font passing to + * it a pointer a struct tfb_font_info structure and the user_arg until either + * the font list is over or the callback returned false. + * + * @param[in] cb An user callback function + * @param[in] user_arg An arbitrary user pointer that will be passed to the + * callback function. + */ +void tfb_iterate_over_fonts(tfb_font_iter_func cb, void *user_arg); + +/** + * Set the font used by the functions for drawing text + * + * @param[in] font_id An opaque identifier provided by the library either + * as a member of struct tfb_font_info, or returned as + * an out parameter by tfb_dyn_load_font(). + * + * @return #TFB_SUCCESS in case of success or + * #TFB_ERR_INVALID_FONT_ID otherwise. + */ +int tfb_set_current_font(tfb_font_t font_id); + +/** + * Load dynamically a PSF font file + * + * @param[in] file File path + * @param[in,out] font_id Address of a tfb_font_t variable that will + * be set by the function in case of success. + * + * @return #TFB_SUCCESS in case of success or one of the + * following errors: + * #TFB_ERR_READ_FONT_FILE_FAILED, + * #TFB_ERR_OUT_OF_MEMORY. + */ +int tfb_dyn_load_font(const char *file, tfb_font_t *font_id); + +/** + * Unload a dynamically-loaded font + * + * @param[in] font_id Opaque pointer returned by tfb_dyn_load_font() + * + * @return #TFB_SUCCESS in case of success or + * #TFB_ERR_NOT_A_DYN_LOADED_FONT if the caller passed + * to it the font_id of an embedded font. + */ +int tfb_dyn_unload_font(tfb_font_t font_id); + +/** + * Select the first font matching the given (w, h) criteria + * + * The tfb_set_font_by_size() function iterates over the fonts embedded in the + * library and sets the first font having width = w and height = h. + * + * @param[in] w Desired width of the font. + * The caller may pass #TFB_FONT_ANY_WIDTH to tell the + * function that any font width is acceptable. + * + * @param[in] h Desired height of the font. + * The caller may pass #TFB_FONT_ANY_HEIGHT to tell the + * function that any font width is acceptable. + * + * @return #TFB_SUCCESS in case a font matching the given criteria has + * been found or #TFB_ERR_FONT_NOT_FOUND otherwise. + */ +int tfb_set_font_by_size(int w, int h); + +/** + * Get current font's width + * + * @return the width (in pixels) of the current font or 0 in case there + * is no currently selected font. + */ +int tfb_get_curr_font_width(void); + +/** + * Get current font's height + * + * @return the height (in pixels) of the current font or 0 in case there + * is no currently selected font. + */ +int tfb_get_curr_font_height(void); + +/* + * ---------------------------------------------------------------------------- + * + * Drawing functions + * + * ---------------------------------------------------------------------------- + */ + +/** + * Value for 1 degree (of 360) of hue, when passed to tfb_make_color_hsv() + */ +#define TFB_HUE_DEGREE 256 + +/** + * Get a representation of the RGB color (r, g, b) for the current video mode + * + * @param[in] r Red color component [0, 255] + * @param[in] g Green color component [0, 255] + * @param[in] b Blue color component [0, 255] + * + * @return A framebuffer-specific representation of the RGB color + * passed using the r, g, b parameters. + */ +inline u32 tfb_make_color(u8 r, u8 g, u8 b); + +/** + * Get a representation of the HSV color (h, s, v) for the current video mode + * + * @param[in] h Hue [0, 360 * #TFB_HUE_DEGREE] + * @param[in] s Saturation [0, 255] + * @param[in] v Value (Brightness) [0, 255] + * + * @return A framebuffer-specific representation of the HSV color + * passed using the h, s, v parameters. + * + * \note 1 degree of hue is #TFB_HUE_DEGREE, not simply 1. This is necessary + * in order to increase the precision of the internal integer-only + * computations. + */ + +u32 tfb_make_color_hsv(u32 h, u8 s, u8 v); + +/** + * Set the color of the pixel at (x, y) to 'color' + * + * @param[in] x Window-relative X coordinate of the pixel + * @param[in] y Window-relative Y coordinate of the pixel + * @param[in] color A color returned by tfb_make_color() + * + * \note By default, the library uses as "window" the whole screen, therefore + * by default the point (x, y) corresponds to the pixel at (x, y) on the + * screen. But, after calling tfb_set_window() the origin of the + * coordinate system gets shifted. + */ +inline void tfb_draw_pixel(int x, int y, u32 color); + +/** + * Draw a horizonal line on-screen + * + * @param[in] x Window-relative X coordinate of line's first point + * @param[in] y Window-relative Y coordinate of line's first point + * @param[in] len Length of the line, in pixels + * @param[in] color Color of the line. See tfb_make_color(). + * + * Calling tfb_draw_hline(x, y, len, color) is equivalent to calling: + * tfb_draw_line(x, y, x + len, y, color) + * + * The only difference between the two functions is in the implementation: given + * the simpler task of tfb_draw_hline(), it can be implemented in much more + * efficient way. + */ +void tfb_draw_hline(int x, int y, int len, u32 color); + +/** + * Draw a vertical line on-screen + * + * @param[in] x Window-relative X coordinate of line's first point + * @param[in] y Window-relative Y coordinate of line's first point + * @param[in] len Length of the line, in pixels + * @param[in] color Color of the line. See tfb_make_color(). + * + * Calling tfb_draw_vline(x, y, len, color) is equivalent to calling: + * tfb_draw_line(x, y, x, y + len, color) + * + * The only difference between the two functions is in the implementation: given + * the simpler task of tfb_draw_vline(), it can be implemented in much more + * efficient way. + */ +void tfb_draw_vline(int x, int y, int len, u32 color); + +/** + * Draw a line on-screen + * + * @param[in] x0 Window-relative X coordinate of line's first point + * @param[in] y0 Window-relative Y coordinate of line's first point + * @param[in] x1 Window-relative X coordinate of line's second point + * @param[in] y1 Window-relative Y coordinate of line's second point + * @param[in] color Color of the line. See tfb_make_color(). + */ +void tfb_draw_line(int x0, int y0, int x1, int y1, u32 color); + +/** + * Draw an empty rectangle on-screen + * + * @param[in] x Window-relative X coordinate of rect's top-left corner + * @param[in] y Window-relative Y coordinate of rect's top-left corner + * @param[in] w Width of the rectangle + * @param[in] h Height of the rectangle + * @param[in] color Color of the rectangle + */ +void tfb_draw_rect(int x, int y, int w, int h, u32 color); + +/** + * Draw filled rectangle on-screen + * + * @param[in] x Window-relative X coordinate of rect's top-left corner + * @param[in] y Window-relative Y coordinate of rect's top-left corner + * @param[in] w Width of the rectangle + * @param[in] h Height of the rectangle + * @param[in] color Color of the rectangle + */ +void tfb_fill_rect(int x, int y, int w, int h, u32 color); + +/** + * Draw an empty circle on-screen + * + * @param[in] cx X coordinate of circle's center + * @param[in] cy Y coordinate of circle's center + * @param[in] r Circle's radius + * @param[in] color Circle's color + */ +void tfb_draw_circle(int cx, int cy, int r, u32 color); + +/** + * Draw a filled circle on-screen + * + * @param[in] cx X coordinate of circle's center + * @param[in] cy Y coordinate of circle's center + * @param[in] r Circle's radius + * @param[in] color Circle's color + */ +void tfb_fill_circle(int cx, int cy, int r, u32 color); + +/** + * Blit a 32-bit RGBA buffer to the screen at the specified coordinates. + * + * @param[in] buf The buffer + * @param[in] x Window-relative X coordinate of the top-left corner of + * the buffer + * @param[in] y Window-relative Y coordinate of the top-left corner of + * the buffer + * @param[in] w Width of the buffer + * @param[in] h Height of the buffer + * @param[in] bg Background color. Pixels with this color are not + * blitted to the screen. + * @param[in] vflip If true, the buffer is flipped vertically + */ +void blit_buf(unsigned char *buf, int x, int y, int w, int h, struct col bg, bool vflip); + +/** + * Set all the pixels of the screen to the supplied color + * + * @param[in] color The color. See tfb_make_color(). + */ +void tfb_clear_screen(u32 color); + +/** + * Set all the pixels of the current window to the supplied color + * + * @param[in] color The color. See tfb_make_color(). + * + * \note Unless tfb_set_window() has been called, the current window is by + * default large as the whole screen. + */ +void tfb_clear_win(u32 color); + +/** + * Get screen's physical width in mm + * + * @return the width of the screen in mm + */ +u32 tfb_screen_width_mm(void); + +/** + * Get screen's physical height in mm + * + * @return the height of the screen in mm + */ +u32 tfb_screen_height_mm(void); + +/** + * Get the screen's rotation as a multiple of 90 degrees + * 1: 90 degrees + * 2: 180 degrees + * 3: 270 degrees + */ +int tfb_get_rotation(void); + +/** + * Flush a given region to the actual framebuffer + * + * @param[in] x Window-relative X coordinate of region's position + * @param[in] y Window-relative Y coordinate of region's position + * @param[in] w Width of the region (in pixels) + * @param[in] h Height of the region (in pixels) + * + * In case tfb_acquire_fb() has been called with #TFB_FL_USE_DOUBLE_BUFFER, + * this function copies the pixels in the specified region to actual + * framebuffer. By default double buffering is not used and this function has no + * effect. + */ +void tfb_flush_rect(int x, int y, int w, int h); + +/** + * Flush the current window to the actual framebuffer + * + * A shortcut for tfb_flush_rect(0, 0, tfb_win_width(), tfb_win_height()). + * + * @see tfb_flush_rect + * @see tfb_set_window + */ +void tfb_flush_window(void); + +/** + * Flush the framebuffer, causing it to update. This is different + * to tfb_flush_window() as it doesn't deal with double_buffering, + * rather it handles the case where the framebuffer has to be "ACTIVATED". + * + * @return #TFB_SUCCESS on success or #TFB_ERR_FB_FLUSH_IOCTL_FAILED + * on failure. + * + * @see tfb_flush_window + */ +int tfb_flush_fb(void); + +/* Essential variables */ +extern void *__fb_buffer; +extern void *__fb_real_buffer; +extern int __fb_screen_w; +extern int __fb_screen_h; +extern size_t __fb_size; +extern size_t __fb_pitch; +extern size_t __fb_pitch_div4; /* see the comment in drawing.c */ + +/* Window-related variables */ +extern int __fb_win_w; +extern int __fb_win_h; +extern int __fb_off_x; +extern int __fb_off_y; +extern int __fb_win_end_x; +extern int __fb_win_end_y; + +/* Color-related variables */ +extern u32 __fb_r_mask; +extern u32 __fb_g_mask; +extern u32 __fb_b_mask; +extern u8 __fb_r_mask_size; +extern u8 __fb_g_mask_size; +extern u8 __fb_b_mask_size; +extern u8 __fb_r_pos; +extern u8 __fb_g_pos; +extern u8 __fb_b_pos; + +extern uint32_t tfb_red; +extern uint32_t tfb_blue; +extern uint32_t tfb_white; +extern uint32_t tfb_gray; +extern uint32_t tfb_black; + +inline u32 tfb_make_color(u8 r, u8 g, u8 b) +{ + return ((r << __fb_r_pos) & __fb_r_mask) | ((g << __fb_g_pos) & __fb_g_mask) | + ((b << __fb_b_pos) & __fb_b_mask); +} + +inline void tfb_draw_pixel(int x, int y, u32 color) +{ + x += __fb_off_x; + y += __fb_off_y; + + if ((u32)x < (u32)__fb_win_end_x && (u32)y < (u32)__fb_win_end_y) + ((volatile u32 *)__fb_buffer)[x + y * __fb_pitch_div4] = color; +} + +inline u32 tfb_screen_width(void) +{ + return __fb_screen_w; +} +inline u32 tfb_screen_height(void) +{ + return __fb_screen_h; +} +inline u32 tfb_win_width(void) +{ + return __fb_win_w; +} +inline u32 tfb_win_height(void) +{ + return __fb_win_h; +} + +/* undef the the convenience types defined above */ +#undef u8 +#undef u32 diff --git a/include/timespec.h b/include/timespec.h index aaaa314..41a2469 100644 --- a/include/timespec.h +++ b/include/timespec.h @@ -27,7 +27,7 @@ * OTHER DEALINGS IN THE SOFTWARE. * * For more information, please refer to -*/ + */ #ifndef DAN_TIMESPEC_H #define DAN_TIMESPEC_H @@ -48,7 +48,7 @@ struct timespec timespec_min(struct timespec ts1, struct timespec ts2); struct timespec timespec_max(struct timespec ts1, struct timespec ts2); struct timespec timespec_clamp(struct timespec ts1, struct timespec min, struct timespec max); -int timespec_cmp(struct timespec ts1, struct timespec ts2); +int timespec_cmp(struct timespec ts1, struct timespec ts2); bool timespec_eq(struct timespec ts1, struct timespec ts2); bool timespec_gt(struct timespec ts1, struct timespec ts2); bool timespec_ge(struct timespec ts1, struct timespec ts2); diff --git a/meson.build b/meson.build index 0048cb2..4f1f017 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,6 @@ project('pbsplash', 'c') cc = meson.get_compiler('c') deps = [ - dependency('tfblib'), cc.find_library('m', required : false) ] diff --git a/src/animate.c b/src/animate.c index 2e79c99..4cfc6c1 100644 --- a/src/animate.c +++ b/src/animate.c @@ -4,11 +4,11 @@ #include #include -struct col color = {.r = 255, .g = 255, .b = 255, .a = 255}; +struct col color = { .r = 255, .g = 255, .b = 255, .a = 255 }; -#define PI 3.1415926535897932384626433832795 +#define PI 3.1415926535897932384626433832795 #define n_circles 3 -#define speed 2.5 +#define speed 2.5 static void circles_wave(int frame, int w, int y_off, long dpi) { @@ -18,15 +18,14 @@ static void circles_wave(int frame, int w, int y_off, long dpi) int rad = MM_TO_PX(dpi, 1); int dist = rad * 3.5; int amplitude = rad * 1; - int left = ((float)w / 2) - (dist * (n_circles - 1) / 2.0); + for (unsigned int i = 0; i < n_circles; i++) { int x = left + (i * dist); double offset = sin(f / 60.0 * PI + i); int y = y_off + offset * amplitude; - tfb_fill_rect(x - rad - 3, y_off - amplitude - rad - 3, - rad * 2 + 6, amplitude * 2 + rad * 2 + 6, - tfb_black); + tfb_fill_rect(x - rad - 3, y_off - amplitude - rad - 3, rad * 2 + 6, + amplitude * 2 + rad * 2 + 6, tfb_black); tfb_fill_circle(x, y, rad, t_col); } } diff --git a/src/drawing.c b/src/drawing.c new file mode 100644 index 0000000..1f6d996 --- /dev/null +++ b/src/drawing.c @@ -0,0 +1,308 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +#include +#include +#include +#include +#include +#include + +#include "pbsplash.h" +#include "tfblib.h" + +extern inline uint32_t tfb_make_color(uint8_t red, uint8_t green, uint8_t blue); +extern inline void tfb_draw_pixel(int x, int y, uint32_t color); +extern inline uint32_t tfb_screen_width(void); +extern inline uint32_t tfb_screen_height(void); +extern inline uint32_t tfb_win_width(void); +extern inline uint32_t tfb_win_height(void); + +void *__fb_buffer; +void *__fb_real_buffer; +size_t __fb_size; +size_t __fb_pitch; +size_t __fb_pitch_div4; /* + * Used in tfb_draw_pixel* to save a (x << 2) operation. + * If we had to use __fb_pitch, we'd had to write: + * *(uint32_t *)(__fb_buffer + (x << 2) + y * __fb_pitch) + * which clearly requires an additional shift operation + * that we can skip by using __fb_pitch_div4 + an early + * cast to uint32_t. + */ + +int __fb_screen_w; +int __fb_screen_h; +int __fb_win_w; +int __fb_win_h; +int __fb_off_x; +int __fb_off_y; +int __fb_win_end_x; +int __fb_win_end_y; + +uint32_t __fb_r_mask; +uint32_t __fb_g_mask; +uint32_t __fb_b_mask; +uint8_t __fb_r_mask_size; +uint8_t __fb_g_mask_size; +uint8_t __fb_b_mask_size; +uint8_t __fb_r_pos; +uint8_t __fb_g_pos; +uint8_t __fb_b_pos; + +int tfb_set_center_window_size(uint32_t w, uint32_t h) +{ + return tfb_set_window(__fb_screen_w / 2 - w / 2, __fb_screen_h / 2 - h / 2, w, h); +} + +void tfb_clear_screen(uint32_t color) +{ + if (__fb_pitch == (uint32_t)4 * __fb_screen_w) { + memset(__fb_buffer, color, __fb_size >> 2); + return; + } + + for (int y = 0; y < __fb_screen_h; y++) + tfb_draw_hline(0, y, __fb_screen_w, color); +} + +void tfb_clear_win(uint32_t color) +{ + tfb_fill_rect(0, 0, __fb_win_w, __fb_win_h, color); +} + +void tfb_draw_hline(int x, int y, int len, uint32_t color) +{ + if (x < 0) { + len += x; + x = 0; + } + + x += __fb_off_x; + y += __fb_off_y; + + if (len < 0 || y < __fb_off_y || y >= __fb_win_end_y) + return; + + len = MIN(len, MAX(0, (int)__fb_win_end_x - x)); + memset(__fb_buffer + y * __fb_pitch + (x << 2), color, len); +} + +void tfb_draw_vline(int x, int y, int len, uint32_t color) +{ + int yend; + + if (y < 0) { + len += y; + y = 0; + } + + x += __fb_off_x; + y += __fb_off_y; + + if (len < 0 || x < __fb_off_x || x >= __fb_win_end_x) + return; + + yend = MIN(y + len, __fb_win_end_y); + + volatile uint32_t *buf = ((volatile uint32_t *)__fb_buffer) + y * __fb_pitch_div4 + x; + + for (; y < yend; y++, buf += __fb_pitch_div4) + *buf = color; +} + +void tfb_fill_rect(int x, int y, int w, int h, uint32_t color) +{ + uint32_t yend; + void *dest; + + if (w < 0) { + x += w; + w = -w; + } + + if (h < 0) { + y += h; + h = -h; + } + + x += __fb_off_x; + y += __fb_off_y; + + if (x < 0) { + w += x; + x = 0; + } + + if (y < 0) { + h += y; + y = 0; + } + + if (w < 0 || h < 0) + return; + + w = MIN(w, MAX(0, (int)__fb_win_end_x - x)); + yend = MIN(y + h, __fb_win_end_y); + + dest = __fb_buffer + y * __fb_pitch + (x << 2); + + for (uint32_t cy = y; cy < yend; cy++, dest += __fb_pitch) + memset(dest, color, w); +} + +void tfb_draw_rect(int x, int y, int w, int h, uint32_t color) +{ + tfb_draw_hline(x, y, w, color); + tfb_draw_vline(x, y, h, color); + tfb_draw_vline(x + w - 1, y, h, color); + tfb_draw_hline(x, y + h - 1, w, color); +} + +static void midpoint_line(int x, int y, int x1, int y1, uint32_t color, bool swap_xy) +{ + const int dx = INT_ABS(x1 - x); + const int dy = INT_ABS(y1 - y); + const int sx = x1 > x ? 1 : -1; + const int sy = y1 > y ? 1 : -1; + const int incE = dy << 1; + const int incNE = (dy - dx) << 1; + const int inc_d[2] = { incNE, incE }; + const int inc_y[2] = { sy, 0 }; + + int d = (dy << 1) - dx; + + if (swap_xy) { + tfb_draw_pixel(y, x, color); + + while (x != x1) { + x += sx; + y += inc_y[d <= 0]; + d += inc_d[d <= 0]; + tfb_draw_pixel(y, x, color); + } + + } else { + tfb_draw_pixel(x, y, color); + + while (x != x1) { + x += sx; + y += inc_y[d <= 0]; + d += inc_d[d <= 0]; + tfb_draw_pixel(x, y, color); + } + } +} + +void tfb_draw_line(int x0, int y0, int x1, int y1, uint32_t color) +{ + if (INT_ABS(y1 - y0) <= INT_ABS(x1 - x0)) + midpoint_line(x0, y0, x1, y1, color, false); + else + midpoint_line(y0, x0, y1, x1, color, true); +} + +/* + * Based on the pseudocode in: + * https://sites.google.com/site/johnkennedyshome/home/downloadable-papers/bcircle.pdf + * + * Written by John Kennedy, Mathematics Department, Santa Monica College. + */ +void tfb_draw_circle(int cx, int cy, int r, uint32_t color) +{ + int x = r; + int y = 0; + int xch = 1 - 2 * r; + int ych = 1; + int rerr = 0; + + while (x >= y) { + tfb_draw_pixel(cx + x, cy + y, color); + tfb_draw_pixel(cx - x, cy + y, color); + tfb_draw_pixel(cx - x, cy - y, color); + tfb_draw_pixel(cx + x, cy - y, color); + tfb_draw_pixel(cx + y, cy + x, color); + tfb_draw_pixel(cx - y, cy + x, color); + tfb_draw_pixel(cx - y, cy - x, color); + tfb_draw_pixel(cx + y, cy - x, color); + + y++; + rerr += ych; + ych += 2; + + if (2 * rerr + xch > 0) { + x--; + rerr += xch; + xch += 2; + } + } +} + +/* + * Simple algorithm for drawing a filled circle which just scans the whole + * 2R x 2R square containing the circle. + */ +void tfb_fill_circle(int cx, int cy, int r, uint32_t color) +{ + const int r2 = r * r + r; + + for (int y = -r; y <= r; y++) + for (int x = -r; x <= r; x++) + if (x * x + y * y <= r2) + tfb_draw_pixel(cx + x, cy + y, color); +} + +#define DEBUGRENDER 0 + +/* x and y are expected to be relative to the screen rotation, however the buffer + * width and height won't be, we need to handle rotating the buffer here. + */ +void blit_buf(unsigned char *buf, int x, int y, int w, int h, struct col bg, bool vflip) +{ + struct col prev_col = { .r = 0, .g = 0, .b = 0, .a = 0 }; + unsigned int col = tfb_make_color(bg.r, bg.g, bg.b); + int tmp, rot = tfb_get_rotation(); + if (vflip) + rot = (rot + 2) % 4; + switch (rot) { + case 1: + tmp = w; + w = h; + h = tmp; + case 0: + default: + break; + } + + + for (size_t i = 0; i < w; i++) { + for (size_t j = 0; j < h; j++) { +#if DEBUGRENDER == 1 + if (i == 0 || i == w - 1 || j == 0 || j == h - 1) { + tfb_draw_pixel(x + i, y + h - j, tfb_red); + continue; + } +#endif + struct col rgba = *(struct col *)(buf + (j * w + i) * 4); + if (rgba.a == 0 || rgba.rgba == bg.rgba) + continue; + + // Alpha blending + if (rgba.a != 255) { + rgba.r = (rgba.r * rgba.a + bg.r * (255 - rgba.a)) >> 8; + rgba.g = (rgba.g * rgba.a + bg.g * (255 - rgba.a)) >> 8; + rgba.b = (rgba.b * rgba.a + bg.b * (255 - rgba.a)) >> 8; + } + + // No need to generate the colour again if it's the same as the previous one + if (rgba.rgba != prev_col.rgba) { + prev_col.rgba = rgba.rgba; + col = tfb_make_color(rgba.r, rgba.g, rgba.b); + } + + if (vflip) + tfb_draw_pixel(x + i, y + h - j, col); + else + tfb_draw_pixel(x + i, y + j, col); + } + } +} diff --git a/src/fb.c b/src/fb.c new file mode 100644 index 0000000..2c774f2 --- /dev/null +++ b/src/fb.c @@ -0,0 +1,261 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pbsplash.h" +#include "tfblib.h" + +#define DEFAULT_FB_DEVICE "/dev/fb0" +#define DEFAULT_TTY_DEVICE "/dev/tty" + +struct fb_var_screeninfo __fbi; + +#define ROTATE_SWAP_XY (__fbi.rotate == 1 || __fbi.rotate == 3) + +int __tfb_ttyfd = -1; + +static int fbfd = -1; + +static void tfb_init_colors(void); + +int tfb_set_window(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + if (x + w > (uint32_t)__fb_screen_w) { + fprintf(stderr, "tfb_set_window: window exceeds screen width\n"); + } + + if (y + h > (uint32_t)__fb_screen_h) { + fprintf(stderr, "tfb_set_window: window exceeds screen height\n"); + } + + __fb_off_x = __fbi.xoffset + x; + __fb_off_y = __fbi.yoffset + y; + __fb_win_w = w; + __fb_win_h = h; + __fb_win_end_x = __fb_off_x + __fb_win_w; + __fb_win_end_y = __fb_off_y + __fb_win_h; + + return 0; +} + +int tfb_acquire_fb(uint32_t flags, const char *fb_device, const char *tty_device) +{ + static struct fb_fix_screeninfo fb_fixinfo; + + if (!fb_device) + fb_device = DEFAULT_FB_DEVICE; + + if (!tty_device) + tty_device = DEFAULT_TTY_DEVICE; + + fbfd = open(fb_device, O_RDWR); + + if (fbfd < 0) { + perror("Couldn't open framebuffer device"); + return -1; + } + + if (ioctl(fbfd, FBIOGET_FSCREENINFO, &fb_fixinfo) != 0) { + perror("Couldn't get fb fixed info"); + close(fbfd); + return -1; + } + + if (ioctl(fbfd, FBIOGET_VSCREENINFO, &__fbi) != 0) { + perror("Couldn't get fb vscreen info"); + close(fbfd); + return -1; + } + + __fb_pitch = fb_fixinfo.line_length; + __fb_size = __fb_pitch * __fbi.yres; + __fb_pitch_div4 = __fb_pitch >> 2; + + if (__fbi.bits_per_pixel != 32) { + fprintf(stderr, "Unsupported framebuffer format: %u\n", __fbi.bits_per_pixel); + close(fbfd); + return -1; + } + + if (__fbi.red.msb_right || __fbi.green.msb_right || __fbi.blue.msb_right) { + fprintf(stderr, "Sanity check failed for RGB masks: %u %u %u\n", + __fbi.red.msb_right, __fbi.green.msb_right, __fbi.blue.msb_right); + close(fbfd); + return -1; + } + + __tfb_ttyfd = open(tty_device, O_RDWR); + + if (__tfb_ttyfd < 0) { + perror("Couldn't open tty device"); + close(fbfd); + return -1; + } + + if (!(flags & TFB_FL_NO_TTY_KD_GRAPHICS)) { + if (ioctl(__tfb_ttyfd, KDSETMODE, KD_GRAPHICS) != 0) { + perror("Couldn't set tty to graphics mode"); + close(fbfd); + ioctl(__tfb_ttyfd, KDSETMODE, KD_TEXT); + close(__tfb_ttyfd); + return -1; + } + } + + __fb_real_buffer = mmap(NULL, __fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); + if (__fb_real_buffer == MAP_FAILED) { + perror("Couldn't mmap framebuffer"); + close(fbfd); + close(__tfb_ttyfd); + return -1; + } + + if (flags & TFB_FL_USE_DOUBLE_BUFFER) { + __fb_buffer = malloc(__fb_size); + if (!__fb_buffer) { + perror("Couldn't allocate double buffer"); + tfb_release_fb(); + return -1; + } + } else { + __fb_buffer = __fb_real_buffer; + } + + __fb_screen_w = ROTATE_SWAP_XY ? __fbi.yres : __fbi.xres; + __fb_screen_h = ROTATE_SWAP_XY ? __fbi.xres : __fbi.yres; + + __fb_r_pos = __fbi.red.offset; + __fb_r_mask_size = __fbi.red.length; + __fb_r_mask = ((1 << __fb_r_mask_size) - 1) << __fb_r_pos; + + __fb_g_pos = __fbi.green.offset; + __fb_g_mask_size = __fbi.green.length; + __fb_g_mask = ((1 << __fb_g_mask_size) - 1) << __fb_g_pos; + + __fb_b_pos = __fbi.blue.offset; + __fb_b_mask_size = __fbi.blue.length; + __fb_b_mask = ((1 << __fb_b_mask_size) - 1) << __fb_b_pos; + + tfb_set_window(0, 0, __fb_screen_w, __fb_screen_h); + tfb_init_colors(); + + return 0; +} + +void tfb_release_fb(void) +{ + if (__fb_real_buffer) + munmap(__fb_real_buffer, __fb_size); + + if (__fb_buffer != __fb_real_buffer) + free(__fb_buffer); + + if (__tfb_ttyfd != -1) { + ioctl(__tfb_ttyfd, KDSETMODE, KD_TEXT); + close(__tfb_ttyfd); + } + + if (fbfd != -1) + close(fbfd); +} + +int tfb_get_rotation(void) +{ + return __fbi.rotate; +} + +void tfb_flush_rect(int x, int y, int w, int h) +{ + int yend; + + if (__fb_buffer == __fb_real_buffer) + return; + + x += __fb_off_x; + y += __fb_off_y; + + if (x < 0) { + w += x; + x = 0; + } + + if (y < 0) { + h += y; + y = 0; + } + + if (w < 0 || h < 0) + return; + + w = MIN(w, MAX(0, __fb_win_end_x - x)); + yend = MIN(y + h, __fb_win_end_y); + + size_t offset = y * __fb_pitch + (__fb_off_x << 2); + void *dest = __fb_real_buffer + offset; + void *src = __fb_buffer + offset; + uint32_t rect_pitch = w << 2; + + for (int cy = y; cy < yend; cy++, src += __fb_pitch, dest += __fb_pitch) + memcpy(dest, src, rect_pitch); +} + +void tfb_flush_window(void) +{ + tfb_flush_rect(0, 0, __fb_win_w, __fb_win_h); +} + +int tfb_flush_fb(void) +{ + __fbi.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; + if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &__fbi) < 0) { + perror("Couldn't flush framebuffer"); + return -1; + } + + return 0; +} + +uint32_t tfb_screen_width_mm(void) +{ + return ROTATE_SWAP_XY ? __fbi.height : __fbi.width; +} +uint32_t tfb_screen_height_mm(void) +{ + return ROTATE_SWAP_XY ? __fbi.width : __fbi.height; +} + +/* + * ---------------------------------------------------------------------------- + * + * Colors + * + * ---------------------------------------------------------------------------- + */ + +uint32_t tfb_red; +uint32_t tfb_blue; +uint32_t tfb_white; +uint32_t tfb_gray; +uint32_t tfb_black; + +static void tfb_init_colors(void) +{ + tfb_red = tfb_make_color(255, 0, 0); + tfb_blue = tfb_make_color(0, 0, 255); + tfb_white = tfb_make_color(255, 255, 255); + tfb_gray = tfb_make_color(128, 128, 128); + tfb_black = tfb_make_color(0, 0, 0); +} diff --git a/src/meson.build b/src/meson.build index f4a8919..532e797 100644 --- a/src/meson.build +++ b/src/meson.build @@ -3,6 +3,8 @@ src = [ 'nanosvg.c', 'timespec.c', 'pbsplash.c', + 'fb.c', + 'drawing.c', ] executable('pbsplash', src, diff --git a/src/pbsplash.c b/src/pbsplash.c index ee34db5..196c66d 100644 --- a/src/pbsplash.c +++ b/src/pbsplash.c @@ -1,48 +1,46 @@ #include +#include +#include +#include #include #include -#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include #define NANOSVG_ALL_COLOR_KEYWORDS // Include full list of color keywords. #include "nanosvg.h" #include "nanosvgrast.h" -#include "timespec.h" #include "pbsplash.h" +#include "timespec.h" -#define MSG_MAX_LEN 4096 +#define MSG_MAX_LEN 4096 #define DEFAULT_FONT_PATH "/usr/share/pbsplash/OpenSans-Regular.svg" -#define LOGO_SIZE_MAX_MM 45 -#define FONT_SIZE_PT 9 -#define FONT_SIZE_B_PT 6 -#define B_MESSAGE_OFFSET_MM 3 -#define PT_TO_MM 0.38f -#define TTY_PATH_LEN 11 - -#define DEBUGRENDER 0 +#define LOGO_SIZE_MAX_MM 45 +#define FONT_SIZE_PT 9 +#define FONT_SIZE_B_PT 6 +#define B_MESSAGE_OFFSET_MM 3 +#define PT_TO_MM 0.38f +#define TTY_PATH_LEN 11 volatile sig_atomic_t terminate = 0; bool debug = false; -struct col background_color = { .r = 0, .g = 0, .b = 0, .a = 255 }; +struct col bg = { .r = 0, .g = 0, .b = 0, .a = 255 }; static int screenWidth, screenHeight; #define zalloc(size) calloc(1, size) -#define LOG(fmt, ...) \ - do { \ - if (debug) \ - printf(fmt, ##__VA_ARGS__); \ +#define LOG(fmt, ...) \ + do { \ + if (debug) \ + printf(fmt, ##__VA_ARGS__); \ } while (0) static int usage() @@ -74,55 +72,6 @@ static void term(int signum) terminate = 1; } -static void blit_buf(unsigned char *buf, int x, int y, int w, int h, bool vflip, - bool redraw) -{ - struct col prev_col = { .r = 0, .g = 0, .b = 0, .a = 0 }; - unsigned int col = tfb_make_color( - background_color.r, background_color.g, background_color.b); - - for (size_t i = 0; i < w; i++) { - for (size_t j = 0; j < h; j++) { -#if DEBUGRENDER == 1 - if (i == 0 || i == w - 1 || j == 0 || j == h - 1) { - tfb_draw_pixel(x + i, y + h - j, tfb_red); - continue; - } -#endif - struct col rgba = - *(struct col *)(buf + (j * w + i) * 4); - if (rgba.a == 0 || rgba.rgba == background_color.rgba) - continue; - - // Alpha blending - if (rgba.a != 255) { - rgba.r = - (rgba.r * rgba.a + - background_color.r * (255 - rgba.a)) >> - 8; - rgba.g = - (rgba.g * rgba.a + - background_color.g * (255 - rgba.a)) >> - 8; - rgba.b = - (rgba.b * rgba.a + - background_color.b * (255 - rgba.a)) >> - 8; - } - - // No need to generate the colour again if it's the same as the previous one - if (rgba.rgba != prev_col.rgba) { - prev_col.rgba = rgba.rgba; - col = tfb_make_color(rgba.r, rgba.g, rgba.b); - } - if (vflip) - tfb_draw_pixel(x + i, y + h - j, col); - else - tfb_draw_pixel(x + i, y + j, col); - } - } -} - static void draw_svg(NSVGimage *image, int x, int y, int w, int h) { float sz = (int)((float)w / (float)image->width * 100.f) / 100.f; @@ -131,25 +80,24 @@ static void draw_svg(NSVGimage *image, int x, int y, int w, int h) unsigned char *img = zalloc(w * h * 4); nsvgRasterize(rast, image, 0, 0, sz, img, w, h, w * 4); - blit_buf(img, x, y, w, h, false, false); + blit_buf(img, x, y, w, h, false); free(img); nsvgDeleteRasterizer(rast); } -static void draw_text(const NSVGimage *font, const char *text, int x, int y, int width, - int height, float scale, unsigned int tfb_col) +static void draw_text(const NSVGimage *font, const char *text, int x, int y, int width, int height, + float scale, unsigned int tfb_col) { - LOG("text '%s': fontsz=%f, x=%d, y=%d, dimensions: %d x %d\n", text, - scale, x, y, width, height); + LOG("text '%s': fontsz=%f, x=%d, y=%d, dimensions: %d x %d\n", text, scale, x, y, width, + height); NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text)); unsigned char *img = zalloc(width * height * 4); NSVGrasterizer *rast = nsvgCreateRasterizer(); - nsvgRasterizeText(rast, font, 0, 0, scale, img, width, height, - width * 4, text); + nsvgRasterizeText(rast, font, 0, 0, scale, img, width, height, width * 4, text); - blit_buf(img, x, y, width, height, true, false); + blit_buf(img, x, y, width, height, true); free(img); free(shapes); @@ -170,7 +118,7 @@ static inline float getShapeWidth(const NSVGimage *font, const NSVGshape *shape) * based on the font size and the font SVG file. */ static const char *getTextDimensions(const NSVGimage *font, const char *text, float scale, - int *width, int *height) + int *width, int *height) { int i, j; int fontHeight = (font->fontAscent - font->fontDescent) * scale; @@ -198,7 +146,7 @@ static const char *getTextDimensions(const NSVGimage *font, const char *text, fl i--; if (i < 1) { fprintf(stderr, - "ERROR: Text is too long to fit on screen!"); + "ERROR: Text is too long to fit on screen!"); goto out; } } else { @@ -210,7 +158,7 @@ static const char *getTextDimensions(const NSVGimage *font, const char *text, fl if (i <= 0) { line_has_space = false; fprintf(stderr, - "ERROR: Text is too long to fit on screen!"); + "ERROR: Text is too long to fit on screen!"); goto out; } } @@ -274,21 +222,21 @@ static void calculate_dpi_info(struct dpi_info *dpi_info) dpi_info->logo_size_max_mm = (screenWidth * 0.75f) / dpi_info->pixels_per_milli; dpi_info->logo_size_px = - (float)(screenWidth < screenHeight ? screenWidth : - screenHeight) * - 0.75f; + (float)(screenWidth < screenHeight ? screenWidth : screenHeight) * 0.75f; if (w_mm > 0 && h_mm > 0) { if (w_mm < h_mm) { if (w_mm > dpi_info->logo_size_max_mm * 1.2f) - dpi_info->logo_size_px = dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli; + dpi_info->logo_size_px = + dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli; } else { if (h_mm > dpi_info->logo_size_max_mm * 1.2f) - dpi_info->logo_size_px = dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli; + dpi_info->logo_size_px = + dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli; } } - printf("%dx%d @ %dx%dmm, dpi=%ld, logo_size_px=%f\n", screenWidth, - screenHeight, w_mm, h_mm, dpi_info->dpi, dpi_info->logo_size_px); + printf("%dx%d @ %dx%dmm, dpi=%ld, logo_size_px=%f\n", screenWidth, screenHeight, w_mm, h_mm, + dpi_info->dpi, dpi_info->logo_size_px); } struct msg_info { @@ -301,12 +249,13 @@ struct msg_info { float fontsz; }; -static void load_message(struct msg_info *msg_info, const struct dpi_info *dpi_info, float font_size_pt, const NSVGimage *font) +static void load_message(struct msg_info *msg_info, const struct dpi_info *dpi_info, + float font_size_pt, const NSVGimage *font) { - msg_info->fontsz = (font_size_pt * PT_TO_MM) / - (font->fontAscent - font->fontDescent) * - dpi_info->pixels_per_milli; - msg_info->message = getTextDimensions(font, msg_info->src_message, msg_info->fontsz, &msg_info->width, &msg_info->height); + msg_info->fontsz = (font_size_pt * PT_TO_MM) / (font->fontAscent - font->fontDescent) * + dpi_info->pixels_per_milli; + msg_info->message = getTextDimensions(font, msg_info->src_message, msg_info->fontsz, + &msg_info->width, &msg_info->height); msg_info->x = (screenWidth - msg_info->width) / 2; // Y coordinate is set later } @@ -331,7 +280,7 @@ struct messages { static inline void show_message(const struct msg_info *msg_info, const NSVGimage *font) { draw_text(font, msg_info->message, msg_info->x, msg_info->y, msg_info->width, - msg_info->height, msg_info->fontsz, tfb_gray); + msg_info->height, msg_info->fontsz, tfb_gray); } static void show_messages(struct messages *msgs, const struct dpi_info *dpi_info) @@ -346,14 +295,16 @@ static void show_messages(struct messages *msgs, const struct dpi_info *dpi_info font_failed = true; fprintf(stderr, "failed to load SVG font, can't render messages\n"); fprintf(stderr, " font_path: %s\n", msgs->font_path); - fprintf(stderr, "msg: %s\n\nbottom_message: %s\n", msgs->msg->src_message, msgs->bottom_msg->src_message); + fprintf(stderr, "msg: %s\n\nbottom_message: %s\n", msgs->msg->src_message, + msgs->bottom_msg->src_message); return; } if (msgs->bottom_msg) { if (!msgs->bottom_msg->message) { load_message(msgs->bottom_msg, dpi_info, msgs->font_size_b_pt, msgs->font); - msgs->bottom_msg->y = screenHeight - msgs->bottom_msg->height - MM_TO_PX(dpi_info->dpi, B_MESSAGE_OFFSET_MM); + msgs->bottom_msg->y = screenHeight - msgs->bottom_msg->height - + MM_TO_PX(dpi_info->dpi, B_MESSAGE_OFFSET_MM); } show_message(msgs->bottom_msg, msgs->font); } @@ -362,9 +313,15 @@ static void show_messages(struct messages *msgs, const struct dpi_info *dpi_info if (!msgs->msg->message) { load_message(msgs->msg, dpi_info, msgs->font_size_pt, msgs->font); if (msgs->bottom_msg) - msgs->msg->y = msgs->bottom_msg->y - msgs->msg->height - (MM_TO_PX(dpi_info->dpi, msgs->font_size_b_pt * PT_TO_MM) * 0.6); + msgs->msg->y = + msgs->bottom_msg->y - msgs->msg->height - + (MM_TO_PX(dpi_info->dpi, msgs->font_size_b_pt * PT_TO_MM) * + 0.6); else - msgs->msg->y = screenHeight - msgs->msg->height - (MM_TO_PX(dpi_info->dpi, msgs->font_size_pt * PT_TO_MM) * 2); + msgs->msg->y = + screenHeight - msgs->msg->height - + (MM_TO_PX(dpi_info->dpi, msgs->font_size_pt * PT_TO_MM) * + 2); } show_message(msgs->msg, msgs->font); } @@ -394,15 +351,16 @@ static int load_image(const struct dpi_info *dpi_info, struct image_info *image_ if (image_info->image->width < image_info->image->height * 1.1) logo_size_px = MM_TO_PX(dpi_info->dpi, 25); - float sz = - (float)logo_size_px / - (image_info->image->width > image_info->image->height ? image_info->image->height : image_info->image->width); + float sz = (float)logo_size_px / (image_info->image->width > image_info->image->height ? + image_info->image->height : + image_info->image->width); image_info->width = image_info->image->width * sz + 0.5; image_info->height = image_info->image->height * sz + 0.5; if (image_info->width > (dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli)) { float scalefactor = - ((float)(dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli) / image_info->width); - //printf("Got scale factor: %f\n", scalefactor); + ((float)(dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli) / + image_info->width); + // printf("Got scale factor: %f\n", scalefactor); image_info->width = dpi_info->logo_size_max_mm * dpi_info->pixels_per_milli; image_info->height *= scalefactor; } @@ -476,24 +434,21 @@ int main(int argc, char **argv) case 'o': msgs.font_size_b_pt = strtof(optarg, &end); if (end == optarg) { - fprintf(stderr, "Invalid font size: %s\n", - optarg); + fprintf(stderr, "Invalid font size: %s\n", optarg); return usage(); } break; case 'p': msgs.font_size_pt = strtof(optarg, &end); if (end == optarg) { - fprintf(stderr, "Invalid font size: %s\n", - optarg); + fprintf(stderr, "Invalid font size: %s\n", optarg); return usage(); } break; case 'q': dpi_info.logo_size_max_mm = strtof(optarg, &end); if (end == optarg) { - fprintf(stderr, "Invalid max logo size: %s\n", - optarg); + fprintf(stderr, "Invalid max logo size: %s\n", optarg); return usage(); } break; @@ -525,10 +480,9 @@ int main(int argc, char **argv) LOG("active tty: '%s'\n", active_tty); - if ((rc = tfb_acquire_fb(/*TFB_FL_NO_TTY_KD_GRAPHICS */ 0, "/dev/fb0", - active_tty)) != TFB_SUCCESS) { - fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", - rc); + if ((rc = tfb_acquire_fb(/*TFB_FL_NO_TTY_KD_GRAPHICS */ 0, "/dev/fb0", active_tty)) != + TFB_SUCCESS) { + fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", rc); rc = 1; return rc; } @@ -544,8 +498,7 @@ int main(int argc, char **argv) float animation_y = image_info.y + image_info.height + MM_TO_PX(dpi_info.dpi, 5); - tfb_clear_screen(tfb_make_color(background_color.r, background_color.g, - background_color.b)); + tfb_clear_screen(tfb_make_color(bg.r, bg.g, bg.b)); draw_svg(image_info.image, image_info.x, image_info.y, image_info.width, image_info.height); @@ -593,7 +546,7 @@ no_messages: tfb_flush_fb(); clock_gettime(CLOCK_REALTIME, &end); diff = timespec_sub(end, start); - //printf("%05d: %09ld\n", tick, diff.tv_nsec); + // printf("%05d: %09ld\n", tick, diff.tv_nsec); if (diff.tv_nsec < 1000000000 / target_fps) { struct timespec sleep_time = { .tv_sec = 0, @@ -607,7 +560,8 @@ out: // Before we exit print the logo so it will persist if (image_info.image) { ioctl(tty, KDSETMODE, KD_TEXT); - draw_svg(image_info.image, image_info.x, image_info.y, image_info.width, image_info.height); + draw_svg(image_info.image, image_info.x, image_info.y, image_info.width, + image_info.height); } // Draw the messages again so they will persist diff --git a/src/timespec.c b/src/timespec.c index 896a396..4764294 100644 --- a/src/timespec.c +++ b/src/timespec.c @@ -27,11 +27,11 @@ * OTHER DEALINGS IN THE SOFTWARE. * * For more information, please refer to -*/ + */ /** \file timespec.c * \brief Functions for working with timespec structures. - * + * * This library aims to provide a comprehensive set of functions with * well-defined behaviour that handle all edge cases (e.g. negative values) in * a sensible manner. @@ -54,13 +54,13 @@ * * Furthermore, any timespec structure processed or returned by library functions * is normalised according to the rules in timespec_normalise(). -*/ + */ +#include #include #include #include #include -#include #include "timespec.h" @@ -68,41 +68,41 @@ /** \fn struct timespec timespec_add(struct timespec ts1, struct timespec ts2) * \brief Returns the result of adding two timespec structures. -*/ + */ struct timespec timespec_add(struct timespec ts1, struct timespec ts2) { /* Normalise inputs to prevent tv_nsec rollover if whole-second values * are packed in it. - */ + */ ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - - ts1.tv_sec += ts2.tv_sec; + + ts1.tv_sec += ts2.tv_sec; ts1.tv_nsec += ts2.tv_nsec; - + return timespec_normalise(ts1); } /** \fn struct timespec timespec_sub(struct timespec ts1, struct timespec ts2) * \brief Returns the result of subtracting ts2 from ts1. -*/ + */ struct timespec timespec_sub(struct timespec ts1, struct timespec ts2) { /* Normalise inputs to prevent tv_nsec rollover if whole-second values * are packed in it. - */ + */ ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - - ts1.tv_sec -= ts2.tv_sec; + + ts1.tv_sec -= ts2.tv_sec; ts1.tv_nsec -= ts2.tv_nsec; - + return timespec_normalise(ts1); } /** \fn struct timespec timespec_mod(struct timespec ts1, struct timespec ts2) * \brief Returns the remainder left over after dividing ts1 by ts2 (ts1%ts2). -*/ + */ struct timespec timespec_mod(struct timespec ts1, struct timespec ts2) { int i = 0; @@ -111,64 +111,55 @@ struct timespec timespec_mod(struct timespec ts1, struct timespec ts2) /* Normalise inputs to prevent tv_nsec rollover if whole-second values * are packed in it. - */ + */ ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); /* If ts2 is zero, just return ts1 - */ - if (ts2.tv_sec == 0 && ts2.tv_nsec == 0) - { + */ + if (ts2.tv_sec == 0 && ts2.tv_nsec == 0) { return ts1; } /* If inputs are negative, flip and record sign - */ - if (ts1.tv_sec < 0 || ts1.tv_nsec < 0) - { + */ + if (ts1.tv_sec < 0 || ts1.tv_nsec < 0) { neg1 = true; ts1.tv_sec = -ts1.tv_sec; ts1.tv_nsec = -ts1.tv_nsec; } - if (ts2.tv_sec < 0 || ts2.tv_nsec < 0) - { + if (ts2.tv_sec < 0 || ts2.tv_nsec < 0) { neg2 = true; ts2.tv_sec = -ts2.tv_sec; ts2.tv_nsec = -ts2.tv_nsec; } /* Shift ts2 until it is larger than ts1 or is about to overflow - */ - while ((ts2.tv_sec < (LONG_MAX >> 1)) && timespec_ge(ts1, ts2)) - { + */ + while ((ts2.tv_sec < (LONG_MAX >> 1)) && timespec_ge(ts1, ts2)) { i++; ts2.tv_nsec <<= 1; ts2.tv_sec <<= 1; - if (ts2.tv_nsec > NSEC_PER_SEC) - { - ts2.tv_nsec -= NSEC_PER_SEC; - ts2.tv_sec++; - } + if (ts2.tv_nsec > NSEC_PER_SEC) { + ts2.tv_nsec -= NSEC_PER_SEC; + ts2.tv_sec++; + } } /* Division by repeated subtraction - */ - while (i >= 0) - { - if (timespec_ge(ts1, ts2)) - { + */ + while (i >= 0) { + if (timespec_ge(ts1, ts2)) { ts1 = timespec_sub(ts1, ts2); } - if (i == 0) - { + if (i == 0) { break; } i--; - if (ts2.tv_sec & 1) - { + if (ts2.tv_sec & 1) { ts2.tv_nsec += NSEC_PER_SEC; } ts2.tv_nsec >>= 1; @@ -176,16 +167,14 @@ struct timespec timespec_mod(struct timespec ts1, struct timespec ts2) } /* If signs differ and result is nonzero, subtract once more to cross zero - */ - if (neg1 ^ neg2 && (ts1.tv_sec != 0 || ts1.tv_nsec != 0)) - { + */ + if (neg1 ^ neg2 && (ts1.tv_sec != 0 || ts1.tv_nsec != 0)) { ts1 = timespec_sub(ts1, ts2); } /* Restore sign - */ - if (neg1) - { + */ + if (neg1) { ts1.tv_sec = -ts1.tv_sec; ts1.tv_nsec = -ts1.tv_nsec; } @@ -195,9 +184,10 @@ struct timespec timespec_mod(struct timespec ts1, struct timespec ts2) /** \fn struct timespec timespec_min(struct timespec ts1, struct timespec ts2) * \brief Return the lesser one of the two given timespec values. -*/ -struct timespec timespec_min(struct timespec ts1, struct timespec ts2) { - if(timespec_le(ts1, ts2)) { + */ +struct timespec timespec_min(struct timespec ts1, struct timespec ts2) +{ + if (timespec_le(ts1, ts2)) { return ts1; } else { return ts2; @@ -206,9 +196,10 @@ struct timespec timespec_min(struct timespec ts1, struct timespec ts2) { /** \fn struct timespec timespec_max(struct timespec ts1, struct timespec ts2) * \brief Return the greater one of the two given timespec values. -*/ -struct timespec timespec_max(struct timespec ts1, struct timespec ts2) { - if(timespec_ge(ts1, ts2)) { + */ +struct timespec timespec_max(struct timespec ts1, struct timespec ts2) +{ + if (timespec_ge(ts1, ts2)) { return ts1; } else { return ts2; @@ -217,12 +208,13 @@ struct timespec timespec_max(struct timespec ts1, struct timespec ts2) { /** \fn struct timespec timespec_clamp(struct timespec ts, struct timespec min, struct timespec max) * \brief Clamp the value of TS between MIN and MAX. -*/ -struct timespec timespec_clamp(struct timespec ts, struct timespec min, struct timespec max) { - if(timespec_gt(ts, max)) { + */ +struct timespec timespec_clamp(struct timespec ts, struct timespec min, struct timespec max) +{ + if (timespec_gt(ts, max)) { return max; } - if(timespec_lt(ts, min)) { + if (timespec_lt(ts, min)) { return min; } return ts; @@ -230,97 +222,95 @@ struct timespec timespec_clamp(struct timespec ts, struct timespec min, struct t /** \fn int timespec_cmp(struct timespec ts1, struct timespec ts2) * \brief Returns (1, 0, -1) if ts1 is (greater than, equal to, less than) to ts2. -*/ + */ int timespec_cmp(struct timespec ts1, struct timespec ts2) { ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - - if(ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec) - { + + if (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec) { return 0; - } - else if((ts1.tv_sec > ts2.tv_sec) - || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec)) - { + } else if ((ts1.tv_sec > ts2.tv_sec) || + (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec)) { return 1; - } - else { + } else { return -1; } } /** \fn bool timespec_eq(struct timespec ts1, struct timespec ts2) * \brief Returns true if the two timespec structures are equal. -*/ + */ bool timespec_eq(struct timespec ts1, struct timespec ts2) { ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - + return (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec); } /** \fn bool timespec_gt(struct timespec ts1, struct timespec ts2) * \brief Returns true if ts1 is greater than ts2. -*/ + */ bool timespec_gt(struct timespec ts1, struct timespec ts2) { ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - + return (ts1.tv_sec > ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec)); } /** \fn bool timespec_ge(struct timespec ts1, struct timespec ts2) * \brief Returns true if ts1 is greater than or equal to ts2. -*/ + */ bool timespec_ge(struct timespec ts1, struct timespec ts2) { ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - - return (ts1.tv_sec > ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec >= ts2.tv_nsec)); + + return (ts1.tv_sec > ts2.tv_sec || + (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec >= ts2.tv_nsec)); } /** \fn bool timespec_lt(struct timespec ts1, struct timespec ts2) * \brief Returns true if ts1 is less than ts2. -*/ + */ bool timespec_lt(struct timespec ts1, struct timespec ts2) { ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - + return (ts1.tv_sec < ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec < ts2.tv_nsec)); } /** \fn bool timespec_le(struct timespec ts1, struct timespec ts2) * \brief Returns true if ts1 is less than or equal to ts2. -*/ + */ bool timespec_le(struct timespec ts1, struct timespec ts2) { ts1 = timespec_normalise(ts1); ts2 = timespec_normalise(ts2); - - return (ts1.tv_sec < ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec <= ts2.tv_nsec)); + + return (ts1.tv_sec < ts2.tv_sec || + (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec <= ts2.tv_nsec)); } /** \fn struct timespec timespec_from_double(double s) * \brief Converts a fractional number of seconds to a timespec. -*/ + */ struct timespec timespec_from_double(double s) { struct timespec ts = { - .tv_sec = s, + .tv_sec = s, .tv_nsec = (s - (long)(s)) * NSEC_PER_SEC, }; - + return timespec_normalise(ts); } /** \fn double timespec_to_double(struct timespec ts) * \brief Converts a timespec to a fractional number of seconds. -*/ + */ double timespec_to_double(struct timespec ts) { return ((double)(ts.tv_sec) + ((double)(ts.tv_nsec) / NSEC_PER_SEC)); @@ -328,48 +318,45 @@ double timespec_to_double(struct timespec ts) /** \fn struct timespec timespec_from_timeval(struct timeval tv) * \brief Converts a timeval to a timespec. -*/ + */ struct timespec timespec_from_timeval(struct timeval tv) { - struct timespec ts = { - .tv_sec = tv.tv_sec, - .tv_nsec = tv.tv_usec * 1000 - }; - + struct timespec ts = { .tv_sec = tv.tv_sec, .tv_nsec = tv.tv_usec * 1000 }; + return timespec_normalise(ts); } /** \fn struct timeval timespec_to_timeval(struct timespec ts) * \brief Converts a timespec to a timeval. -*/ + */ struct timeval timespec_to_timeval(struct timespec ts) { ts = timespec_normalise(ts); - + struct timeval tv = { - .tv_sec = ts.tv_sec, + .tv_sec = ts.tv_sec, .tv_usec = ts.tv_nsec / 1000, }; - + return tv; } /** \fn struct timespec timespec_from_ms(long milliseconds) * \brief Converts an integer number of milliseconds to a timespec. -*/ + */ struct timespec timespec_from_ms(long milliseconds) { struct timespec ts = { - .tv_sec = (milliseconds / 1000), + .tv_sec = (milliseconds / 1000), .tv_nsec = (milliseconds % 1000) * 1000000, }; - + return timespec_normalise(ts); } /** \fn long timespec_to_ms(struct timespec ts) * \brief Converts a timespec to an integer number of milliseconds. -*/ + */ long timespec_to_ms(struct timespec ts) { return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); @@ -386,31 +373,28 @@ long timespec_to_ms(struct timespec ts) * * 2) If tv_nsec is negative, decrement tv_sec and roll tv_nsec up to represent * the same value attainable by ADDING nanoseconds to tv_sec. -*/ + */ struct timespec timespec_normalise(struct timespec ts) { - while(ts.tv_nsec >= NSEC_PER_SEC) - { + while (ts.tv_nsec >= NSEC_PER_SEC) { ++(ts.tv_sec); ts.tv_nsec -= NSEC_PER_SEC; } - - while(ts.tv_nsec <= -NSEC_PER_SEC) - { + + while (ts.tv_nsec <= -NSEC_PER_SEC) { --(ts.tv_sec); ts.tv_nsec += NSEC_PER_SEC; } - - if(ts.tv_nsec < 0) - { + + if (ts.tv_nsec < 0) { /* Negative nanoseconds isn't valid according to POSIX. * Decrement tv_sec and roll tv_nsec over. - */ - + */ + --(ts.tv_sec); ts.tv_nsec = (NSEC_PER_SEC + ts.tv_nsec); } - + return ts; } @@ -424,564 +408,583 @@ struct timespec timespec_now() #ifdef TEST #include -#define TEST_NORMALISE(ts_sec, ts_nsec, expect_sec, expect_nsec) { \ - struct timespec in = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ - struct timespec got = timespec_normalise(in); \ - if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \ - { \ - printf("%s:%d: timespec_normalise({%ld, %ld}) returned wrong values\n", __FILE__, __LINE__, \ - (long)(ts_sec), (long)(ts_nsec)); \ - printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \ - printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \ - ++result; \ - } \ -} +#define TEST_NORMALISE(ts_sec, ts_nsec, expect_sec, expect_nsec) \ + { \ + struct timespec in = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ + struct timespec got = timespec_normalise(in); \ + if (got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) { \ + printf("%s:%d: timespec_normalise({%ld, %ld}) returned wrong values\n", \ + __FILE__, __LINE__, (long)(ts_sec), (long)(ts_nsec)); \ + printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), \ + (long)(expect_nsec)); \ + printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), \ + (long)(got.tv_nsec)); \ + ++result; \ + } \ + } -#define TEST_BINOP(func, ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, expect_sec, expect_nsec) { \ - struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \ - struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \ - struct timespec got = func(ts1, ts2); \ - if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \ - { \ - printf(#func "({%ld, %ld}, {%ld, %ld}) returned wrong values\n", \ - (long)(ts1_sec), (long)(ts1_nsec), (long)(ts2_sec), (long)(ts2_nsec)); \ - printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \ - printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \ - ++result; \ - } \ -} +#define TEST_BINOP(func, ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, expect_sec, expect_nsec) \ + { \ + struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \ + struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \ + struct timespec got = func(ts1, ts2); \ + if (got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) { \ + printf(#func "({%ld, %ld}, {%ld, %ld}) returned wrong values\n", \ + (long)(ts1_sec), (long)(ts1_nsec), (long)(ts2_sec), \ + (long)(ts2_nsec)); \ + printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), \ + (long)(expect_nsec)); \ + printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), \ + (long)(got.tv_nsec)); \ + ++result; \ + } \ + } -#define TEST_TRINOP(func, ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, ts3_sec, ts3_nsec, expect_sec, expect_nsec) { \ - struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \ - struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \ - struct timespec ts3 = { .tv_sec = ts3_sec, .tv_nsec = ts3_nsec }; \ - struct timespec got = func(ts1, ts2, ts3); \ - if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \ - { \ - printf(#func "({%ld, %ld}, {%ld, %ld}, {%ld, %ld}) returned wrong values\n", \ - (long)(ts1_sec), (long)(ts1_nsec), \ - (long)(ts2_sec), (long)(ts2_nsec), \ - (long)(ts3_sec), (long)(ts3_nsec)); \ - printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \ - printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \ - ++result; \ - } \ -} +#define TEST_TRINOP(func, ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, ts3_sec, ts3_nsec, expect_sec, \ + expect_nsec) \ + { \ + struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \ + struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \ + struct timespec ts3 = { .tv_sec = ts3_sec, .tv_nsec = ts3_nsec }; \ + struct timespec got = func(ts1, ts2, ts3); \ + if (got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) { \ + printf(#func \ + "({%ld, %ld}, {%ld, %ld}, {%ld, %ld}) returned wrong values\n", \ + (long)(ts1_sec), (long)(ts1_nsec), (long)(ts2_sec), \ + (long)(ts2_nsec), (long)(ts3_sec), (long)(ts3_nsec)); \ + printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), \ + (long)(expect_nsec)); \ + printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), \ + (long)(got.tv_nsec)); \ + ++result; \ + } \ + } -#define TEST_TEST_FUNC(func, ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, expect) { \ - struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \ - struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \ - int got = func(ts1, ts2); \ - if(got != expect) \ - { \ - printf("%s:%d: " #func "({%ld, %ld}, {%ld, %ld}) returned %d, expected %s\n", __FILE__, __LINE__, \ - (long)(ts1_sec), (long)(ts1_nsec), (long)(ts2_sec), (long)(ts2_nsec), \ - got, #expect); \ - ++result; \ - } \ -} +#define TEST_TEST_FUNC(func, ts1_sec, ts1_nsec, ts2_sec, ts2_nsec, expect) \ + { \ + struct timespec ts1 = { .tv_sec = ts1_sec, .tv_nsec = ts1_nsec }; \ + struct timespec ts2 = { .tv_sec = ts2_sec, .tv_nsec = ts2_nsec }; \ + int got = func(ts1, ts2); \ + if (got != expect) { \ + printf("%s:%d: " #func \ + "({%ld, %ld}, {%ld, %ld}) returned %d, expected %s\n", \ + __FILE__, __LINE__, (long)(ts1_sec), (long)(ts1_nsec), \ + (long)(ts2_sec), (long)(ts2_nsec), got, #expect); \ + ++result; \ + } \ + } -#define TEST_FROM_DOUBLE(d_secs, expect_sec, expect_nsec) { \ - struct timespec got = timespec_from_double(d_secs); \ - if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \ - { \ - printf("%s:%d: timespec_from_double(%f) returned wrong values\n", __FILE__, __LINE__, (double)(d_secs)); \ - printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \ - printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \ - ++result; \ - } \ -} +#define TEST_FROM_DOUBLE(d_secs, expect_sec, expect_nsec) \ + { \ + struct timespec got = timespec_from_double(d_secs); \ + if (got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) { \ + printf("%s:%d: timespec_from_double(%f) returned wrong values\n", \ + __FILE__, __LINE__, (double)(d_secs)); \ + printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), \ + (long)(expect_nsec)); \ + printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), \ + (long)(got.tv_nsec)); \ + ++result; \ + } \ + } -#define TEST_TO_DOUBLE(ts_sec, ts_nsec, expect) { \ - struct timespec ts = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ - double got = timespec_to_double(ts); \ - if(got != expect) { \ - printf("%s:%d: timespec_to_double({%ld, %ld}) returned wrong value\n", __FILE__, __LINE__, \ - (long)(ts_sec), (long)(ts_nsec)); \ - printf(" Expected: %f\n", (double)(expect)); \ - printf(" Got: %f\n", got); \ - ++result; \ - } \ -} +#define TEST_TO_DOUBLE(ts_sec, ts_nsec, expect) \ + { \ + struct timespec ts = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ + double got = timespec_to_double(ts); \ + if (got != expect) { \ + printf("%s:%d: timespec_to_double({%ld, %ld}) returned wrong value\n", \ + __FILE__, __LINE__, (long)(ts_sec), (long)(ts_nsec)); \ + printf(" Expected: %f\n", (double)(expect)); \ + printf(" Got: %f\n", got); \ + ++result; \ + } \ + } -#define TEST_FROM_TIMEVAL(in_sec, in_usec, expect_sec, expect_nsec) { \ - struct timeval tv = { .tv_sec = in_sec, .tv_usec = in_usec }; \ - struct timespec got = timespec_from_timeval(tv); \ - if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \ - { \ - printf("%s:%d: timespec_from_timeval({%ld, %ld}) returned wrong values\n", __FILE__, __LINE__, \ - (long)(in_sec), (long)(in_usec)); \ - printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \ - printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \ - ++result; \ - } \ -} +#define TEST_FROM_TIMEVAL(in_sec, in_usec, expect_sec, expect_nsec) \ + { \ + struct timeval tv = { .tv_sec = in_sec, .tv_usec = in_usec }; \ + struct timespec got = timespec_from_timeval(tv); \ + if (got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) { \ + printf("%s:%d: timespec_from_timeval({%ld, %ld}) returned wrong values\n", \ + __FILE__, __LINE__, (long)(in_sec), (long)(in_usec)); \ + printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), \ + (long)(expect_nsec)); \ + printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), \ + (long)(got.tv_nsec)); \ + ++result; \ + } \ + } -#define TEST_TO_TIMEVAL(ts_sec, ts_nsec, expect_sec, expect_usec) { \ - struct timespec ts = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ - struct timeval got = timespec_to_timeval(ts); \ - if(got.tv_sec != expect_sec || got.tv_usec != expect_usec) \ - { \ - printf("%s:%d: timespec_to_timeval({%ld, %ld}) returned wrong values\n", __FILE__, __LINE__, \ - (long)(ts_sec), (long)(ts_nsec)); \ - printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_usec)); \ - printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_usec)); \ - ++result; \ - } \ -} +#define TEST_TO_TIMEVAL(ts_sec, ts_nsec, expect_sec, expect_usec) \ + { \ + struct timespec ts = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ + struct timeval got = timespec_to_timeval(ts); \ + if (got.tv_sec != expect_sec || got.tv_usec != expect_usec) { \ + printf("%s:%d: timespec_to_timeval({%ld, %ld}) returned wrong values\n", \ + __FILE__, __LINE__, (long)(ts_sec), (long)(ts_nsec)); \ + printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), \ + (long)(expect_usec)); \ + printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), \ + (long)(got.tv_usec)); \ + ++result; \ + } \ + } -#define TEST_FROM_MS(msecs, expect_sec, expect_nsec) { \ - struct timespec got = timespec_from_ms(msecs); \ - if(got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) \ - { \ - printf("%s:%d: timespec_from_ms(%ld) returned wrong values\n", __FILE__, __LINE__, (long)(msecs)); \ - printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), (long)(expect_nsec)); \ - printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), (long)(got.tv_nsec)); \ - ++result; \ - } \ -} +#define TEST_FROM_MS(msecs, expect_sec, expect_nsec) \ + { \ + struct timespec got = timespec_from_ms(msecs); \ + if (got.tv_sec != expect_sec || got.tv_nsec != expect_nsec) { \ + printf("%s:%d: timespec_from_ms(%ld) returned wrong values\n", __FILE__, \ + __LINE__, (long)(msecs)); \ + printf(" Expected: {%ld, %ld}\n", (long)(expect_sec), \ + (long)(expect_nsec)); \ + printf(" Got: {%ld, %ld}\n", (long)(got.tv_sec), \ + (long)(got.tv_nsec)); \ + ++result; \ + } \ + } -#define TEST_TO_MS(ts_sec, ts_nsec, expect) { \ - struct timespec ts = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ - long got = timespec_to_ms(ts); \ - if(got != expect) { \ - printf("%s:%d: timespec_to_ms({%ld, %ld}) returned wrong value\n", __FILE__, __LINE__, \ - (long)(ts_sec), (long)(ts_nsec)); \ - printf(" Expected: %ld\n", (long)(expect)); \ - printf(" Got: %ld\n", got); \ - ++result; \ - } \ -} +#define TEST_TO_MS(ts_sec, ts_nsec, expect) \ + { \ + struct timespec ts = { .tv_sec = ts_sec, .tv_nsec = ts_nsec }; \ + long got = timespec_to_ms(ts); \ + if (got != expect) { \ + printf("%s:%d: timespec_to_ms({%ld, %ld}) returned wrong value\n", \ + __FILE__, __LINE__, (long)(ts_sec), (long)(ts_nsec)); \ + printf(" Expected: %ld\n", (long)(expect)); \ + printf(" Got: %ld\n", got); \ + ++result; \ + } \ + } int main() { int result = 0; - + // timespec_add - - TEST_BINOP(timespec_add, 0,0, 0,0, 0,0); - TEST_BINOP(timespec_add, 0,0, 1,0, 1,0); - TEST_BINOP(timespec_add, 1,0, 0,0, 1,0); - TEST_BINOP(timespec_add, 1,0, 1,0, 2,0); - TEST_BINOP(timespec_add, 1,500000000, 1,0, 2,500000000); - TEST_BINOP(timespec_add, 1,0, 1,500000000, 2,500000000); - TEST_BINOP(timespec_add, 1,500000000, 1,500000000, 3,0); - TEST_BINOP(timespec_add, 1,500000000, 1,499999999, 2,999999999); - TEST_BINOP(timespec_add, 1,500000000, 1,500000000, 3,0); - TEST_BINOP(timespec_add, 1,999999999, 1,999999999, 3,999999998); - TEST_BINOP(timespec_add, 0,500000000, 1,500000000, 2,0); - TEST_BINOP(timespec_add, 1,500000000, 0,500000000, 2,0); - + + TEST_BINOP(timespec_add, 0, 0, 0, 0, 0, 0); + TEST_BINOP(timespec_add, 0, 0, 1, 0, 1, 0); + TEST_BINOP(timespec_add, 1, 0, 0, 0, 1, 0); + TEST_BINOP(timespec_add, 1, 0, 1, 0, 2, 0); + TEST_BINOP(timespec_add, 1, 500000000, 1, 0, 2, 500000000); + TEST_BINOP(timespec_add, 1, 0, 1, 500000000, 2, 500000000); + TEST_BINOP(timespec_add, 1, 500000000, 1, 500000000, 3, 0); + TEST_BINOP(timespec_add, 1, 500000000, 1, 499999999, 2, 999999999); + TEST_BINOP(timespec_add, 1, 500000000, 1, 500000000, 3, 0); + TEST_BINOP(timespec_add, 1, 999999999, 1, 999999999, 3, 999999998); + TEST_BINOP(timespec_add, 0, 500000000, 1, 500000000, 2, 0); + TEST_BINOP(timespec_add, 1, 500000000, 0, 500000000, 2, 0); + // timespec_sub - - TEST_BINOP(timespec_sub, 0,0, 0,0, 0,0); - TEST_BINOP(timespec_sub, 1,0, 0,0, 1,0); - TEST_BINOP(timespec_sub, 1,0, 1,0, 0,0); - TEST_BINOP(timespec_sub, 1,500000000, 0,500000000, 1,0); - TEST_BINOP(timespec_sub, 5,500000000, 2,999999999, 2,500000001); - TEST_BINOP(timespec_sub, 0,0, 1,0, -1,0); - TEST_BINOP(timespec_sub, 0,500000000, 1,500000000, -1,0); - TEST_BINOP(timespec_sub, 0,0, 1,500000000, -2,500000000); - TEST_BINOP(timespec_sub, 1,0, 1,500000000, -1,500000000); - TEST_BINOP(timespec_sub, 1,0, 1,499999999, -1,500000001); - + + TEST_BINOP(timespec_sub, 0, 0, 0, 0, 0, 0); + TEST_BINOP(timespec_sub, 1, 0, 0, 0, 1, 0); + TEST_BINOP(timespec_sub, 1, 0, 1, 0, 0, 0); + TEST_BINOP(timespec_sub, 1, 500000000, 0, 500000000, 1, 0); + TEST_BINOP(timespec_sub, 5, 500000000, 2, 999999999, 2, 500000001); + TEST_BINOP(timespec_sub, 0, 0, 1, 0, -1, 0); + TEST_BINOP(timespec_sub, 0, 500000000, 1, 500000000, -1, 0); + TEST_BINOP(timespec_sub, 0, 0, 1, 500000000, -2, 500000000); + TEST_BINOP(timespec_sub, 1, 0, 1, 500000000, -1, 500000000); + TEST_BINOP(timespec_sub, 1, 0, 1, 499999999, -1, 500000001); + // timespec_mod - - TEST_BINOP(timespec_mod, 0,0, 0,0, 0,0); - TEST_BINOP(timespec_mod, 0,0, 1,0, 0,0); - TEST_BINOP(timespec_mod, 1,0, 0,0, 1,0); - TEST_BINOP(timespec_mod, 1,0, 1,0, 0,0); - TEST_BINOP(timespec_mod, 10,0, 1,0, 0,0); - TEST_BINOP(timespec_mod, 10,0, 3,0, 1,0); - TEST_BINOP(timespec_mod, 10,0, -3,0, -2,0); - TEST_BINOP(timespec_mod, -10,0, 3,0, 2,0); - TEST_BINOP(timespec_mod, -10,0, -3,0, -1,0); - TEST_BINOP(timespec_mod, 10,0, 5,0, 0,0); - TEST_BINOP(timespec_mod, 10,0, -5,0, 0,0); - TEST_BINOP(timespec_mod, -10,0, 5,0, 0,0); - TEST_BINOP(timespec_mod, -10,0, -5,0, 0,0); - TEST_BINOP(timespec_mod, 1,500000000, 0,500000000, 0,0); - TEST_BINOP(timespec_mod, 5,500000000, 2,999999999, 2,500000001); - TEST_BINOP(timespec_mod, 0,500000000, 1,500000000, 0,500000000); - TEST_BINOP(timespec_mod, 0,0, 1,500000000, 0,0); - TEST_BINOP(timespec_mod, 1,0, 1,500000000, 1,0); - TEST_BINOP(timespec_mod, 1,0, 0,1, 0,0); - TEST_BINOP(timespec_mod, 1,123456789, 0,1000, 0,789); - TEST_BINOP(timespec_mod, 1,0, 0,9999999, 0,100); - TEST_BINOP(timespec_mod, 12345,54321, 0,100001, 0,5555); - TEST_BINOP(timespec_mod, LONG_MAX,0, 0,1, 0,0); - TEST_BINOP(timespec_mod, LONG_MAX,0, LONG_MAX,1, LONG_MAX,0); - + + TEST_BINOP(timespec_mod, 0, 0, 0, 0, 0, 0); + TEST_BINOP(timespec_mod, 0, 0, 1, 0, 0, 0); + TEST_BINOP(timespec_mod, 1, 0, 0, 0, 1, 0); + TEST_BINOP(timespec_mod, 1, 0, 1, 0, 0, 0); + TEST_BINOP(timespec_mod, 10, 0, 1, 0, 0, 0); + TEST_BINOP(timespec_mod, 10, 0, 3, 0, 1, 0); + TEST_BINOP(timespec_mod, 10, 0, -3, 0, -2, 0); + TEST_BINOP(timespec_mod, -10, 0, 3, 0, 2, 0); + TEST_BINOP(timespec_mod, -10, 0, -3, 0, -1, 0); + TEST_BINOP(timespec_mod, 10, 0, 5, 0, 0, 0); + TEST_BINOP(timespec_mod, 10, 0, -5, 0, 0, 0); + TEST_BINOP(timespec_mod, -10, 0, 5, 0, 0, 0); + TEST_BINOP(timespec_mod, -10, 0, -5, 0, 0, 0); + TEST_BINOP(timespec_mod, 1, 500000000, 0, 500000000, 0, 0); + TEST_BINOP(timespec_mod, 5, 500000000, 2, 999999999, 2, 500000001); + TEST_BINOP(timespec_mod, 0, 500000000, 1, 500000000, 0, 500000000); + TEST_BINOP(timespec_mod, 0, 0, 1, 500000000, 0, 0); + TEST_BINOP(timespec_mod, 1, 0, 1, 500000000, 1, 0); + TEST_BINOP(timespec_mod, 1, 0, 0, 1, 0, 0); + TEST_BINOP(timespec_mod, 1, 123456789, 0, 1000, 0, 789); + TEST_BINOP(timespec_mod, 1, 0, 0, 9999999, 0, 100); + TEST_BINOP(timespec_mod, 12345, 54321, 0, 100001, 0, 5555); + TEST_BINOP(timespec_mod, LONG_MAX, 0, 0, 1, 0, 0); + TEST_BINOP(timespec_mod, LONG_MAX, 0, LONG_MAX, 1, LONG_MAX, 0); + // timespec_clamp - - TEST_TRINOP(timespec_clamp, 0,0, 0,0, 0,0, 0,0); - - TEST_TRINOP(timespec_clamp, 1000,0, 2000,0, 3000,0, 2000,0); - TEST_TRINOP(timespec_clamp, 1500,0, 2000,0, 3000,0, 2000,0); - TEST_TRINOP(timespec_clamp, 1999,0, 2000,0, 3000,0, 2000,0); - TEST_TRINOP(timespec_clamp, 2000,0, 2000,0, 3000,0, 2000,0); - TEST_TRINOP(timespec_clamp, 2001,0, 2000,0, 3000,0, 2001,0); - TEST_TRINOP(timespec_clamp, 2250,0, 2000,0, 3000,0, 2250,0); - TEST_TRINOP(timespec_clamp, 2500,0, 2000,0, 3000,0, 2500,0); - TEST_TRINOP(timespec_clamp, 2750,0, 2000,0, 3000,0, 2750,0); - TEST_TRINOP(timespec_clamp, 2999,0, 2000,0, 3000,0, 2999,0); - TEST_TRINOP(timespec_clamp, 3000,0, 2000,0, 3000,0, 3000,0); - TEST_TRINOP(timespec_clamp, 3001,0, 2000,0, 3000,0, 3000,0); - TEST_TRINOP(timespec_clamp, 3500,0, 2000,0, 3000,0, 3000,0); - TEST_TRINOP(timespec_clamp, 4000,0, 2000,0, 3000,0, 3000,0); - - TEST_TRINOP(timespec_clamp, 0,1000, 0,2000, 0,3000, 0,2000); - TEST_TRINOP(timespec_clamp, 0,1500, 0,2000, 0,3000, 0,2000); - TEST_TRINOP(timespec_clamp, 0,1999, 0,2000, 0,3000, 0,2000); - TEST_TRINOP(timespec_clamp, 0,2000, 0,2000, 0,3000, 0,2000); - TEST_TRINOP(timespec_clamp, 0,2001, 0,2000, 0,3000, 0,2001); - TEST_TRINOP(timespec_clamp, 0,2250, 0,2000, 0,3000, 0,2250); - TEST_TRINOP(timespec_clamp, 0,2500, 0,2000, 0,3000, 0,2500); - TEST_TRINOP(timespec_clamp, 0,2750, 0,2000, 0,3000, 0,2750); - TEST_TRINOP(timespec_clamp, 0,2999, 0,2000, 0,3000, 0,2999); - TEST_TRINOP(timespec_clamp, 0,3000, 0,2000, 0,3000, 0,3000); - TEST_TRINOP(timespec_clamp, 0,3001, 0,2000, 0,3000, 0,3000); - TEST_TRINOP(timespec_clamp, 0,3500, 0,2000, 0,3000, 0,3000); - TEST_TRINOP(timespec_clamp, 0,4000, 0,2000, 0,3000, 0,3000); - - TEST_TRINOP(timespec_clamp,0,-1000, 0,-3000, 0,-2000, 0,-2000); - TEST_TRINOP(timespec_clamp,0,-1500, 0,-3000, 0,-2000, 0,-2000); - TEST_TRINOP(timespec_clamp,0,-1999, 0,-3000, 0,-2000, 0,-2000); - TEST_TRINOP(timespec_clamp,0,-3000, 0,-3000, 0,-2000, 0,-3000); - TEST_TRINOP(timespec_clamp,0,-2001, 0,-3000, 0,-2000, 0,-2001); - TEST_TRINOP(timespec_clamp,0,-2250, 0,-3000, 0,-2000, 0,-2250); - TEST_TRINOP(timespec_clamp,0,-2500, 0,-3000, 0,-2000, 0,-2500); - TEST_TRINOP(timespec_clamp,0,-2750, 0,-3000, 0,-2000, 0,-2750); - TEST_TRINOP(timespec_clamp,0,-2999, 0,-3000, 0,-2000, 0,-2999); - TEST_TRINOP(timespec_clamp,0,-2000, 0,-3000, 0,-2000, 0,-2000); - TEST_TRINOP(timespec_clamp,0,-3001, 0,-3000, 0,-2000, 0,-3000); - TEST_TRINOP(timespec_clamp,0,-3500, 0,-3000, 0,-2000, 0,-3000); - TEST_TRINOP(timespec_clamp,0,-2000, 0,-3000, 0,-2000, 0,-2000); - - TEST_TRINOP(timespec_clamp,0,-4000, 0,-3000, 0,3000, 0,-3000); - TEST_TRINOP(timespec_clamp,0,-3001, 0,-3000, 0,3000, 0,-3000); - TEST_TRINOP(timespec_clamp,0,-3000, 0,-3000, 0,3000, 0,-3000); - TEST_TRINOP(timespec_clamp,0,-2999, 0,-3000, 0,3000, 0,-2999); - TEST_TRINOP(timespec_clamp,0,-1500, 0,-3000, 0,3000, 0,-1500); - TEST_TRINOP(timespec_clamp,0, -1, 0,-3000, 0,3000, 0, -1); - TEST_TRINOP(timespec_clamp,0, 0, 0,-3000, 0,3000, 0, 0); - TEST_TRINOP(timespec_clamp,0, 1, 0,-3000, 0,3000, 0, 1); - TEST_TRINOP(timespec_clamp,0, 1500, 0,-3000, 0,3000, 0, 1500); - TEST_TRINOP(timespec_clamp,0, 2999, 0,-3000, 0,3000, 0, 2999); - TEST_TRINOP(timespec_clamp,0, 3000, 0,-3000, 0,3000, 0, 3000); - TEST_TRINOP(timespec_clamp,0, 3001, 0,-3000, 0,3000, 0, 3000); - TEST_TRINOP(timespec_clamp,0, 4000, 0,-3000, 0,3000, 0, 3000); - + + TEST_TRINOP(timespec_clamp, 0, 0, 0, 0, 0, 0, 0, 0); + + TEST_TRINOP(timespec_clamp, 1000, 0, 2000, 0, 3000, 0, 2000, 0); + TEST_TRINOP(timespec_clamp, 1500, 0, 2000, 0, 3000, 0, 2000, 0); + TEST_TRINOP(timespec_clamp, 1999, 0, 2000, 0, 3000, 0, 2000, 0); + TEST_TRINOP(timespec_clamp, 2000, 0, 2000, 0, 3000, 0, 2000, 0); + TEST_TRINOP(timespec_clamp, 2001, 0, 2000, 0, 3000, 0, 2001, 0); + TEST_TRINOP(timespec_clamp, 2250, 0, 2000, 0, 3000, 0, 2250, 0); + TEST_TRINOP(timespec_clamp, 2500, 0, 2000, 0, 3000, 0, 2500, 0); + TEST_TRINOP(timespec_clamp, 2750, 0, 2000, 0, 3000, 0, 2750, 0); + TEST_TRINOP(timespec_clamp, 2999, 0, 2000, 0, 3000, 0, 2999, 0); + TEST_TRINOP(timespec_clamp, 3000, 0, 2000, 0, 3000, 0, 3000, 0); + TEST_TRINOP(timespec_clamp, 3001, 0, 2000, 0, 3000, 0, 3000, 0); + TEST_TRINOP(timespec_clamp, 3500, 0, 2000, 0, 3000, 0, 3000, 0); + TEST_TRINOP(timespec_clamp, 4000, 0, 2000, 0, 3000, 0, 3000, 0); + + TEST_TRINOP(timespec_clamp, 0, 1000, 0, 2000, 0, 3000, 0, 2000); + TEST_TRINOP(timespec_clamp, 0, 1500, 0, 2000, 0, 3000, 0, 2000); + TEST_TRINOP(timespec_clamp, 0, 1999, 0, 2000, 0, 3000, 0, 2000); + TEST_TRINOP(timespec_clamp, 0, 2000, 0, 2000, 0, 3000, 0, 2000); + TEST_TRINOP(timespec_clamp, 0, 2001, 0, 2000, 0, 3000, 0, 2001); + TEST_TRINOP(timespec_clamp, 0, 2250, 0, 2000, 0, 3000, 0, 2250); + TEST_TRINOP(timespec_clamp, 0, 2500, 0, 2000, 0, 3000, 0, 2500); + TEST_TRINOP(timespec_clamp, 0, 2750, 0, 2000, 0, 3000, 0, 2750); + TEST_TRINOP(timespec_clamp, 0, 2999, 0, 2000, 0, 3000, 0, 2999); + TEST_TRINOP(timespec_clamp, 0, 3000, 0, 2000, 0, 3000, 0, 3000); + TEST_TRINOP(timespec_clamp, 0, 3001, 0, 2000, 0, 3000, 0, 3000); + TEST_TRINOP(timespec_clamp, 0, 3500, 0, 2000, 0, 3000, 0, 3000); + TEST_TRINOP(timespec_clamp, 0, 4000, 0, 2000, 0, 3000, 0, 3000); + + TEST_TRINOP(timespec_clamp, 0, -1000, 0, -3000, 0, -2000, 0, -2000); + TEST_TRINOP(timespec_clamp, 0, -1500, 0, -3000, 0, -2000, 0, -2000); + TEST_TRINOP(timespec_clamp, 0, -1999, 0, -3000, 0, -2000, 0, -2000); + TEST_TRINOP(timespec_clamp, 0, -3000, 0, -3000, 0, -2000, 0, -3000); + TEST_TRINOP(timespec_clamp, 0, -2001, 0, -3000, 0, -2000, 0, -2001); + TEST_TRINOP(timespec_clamp, 0, -2250, 0, -3000, 0, -2000, 0, -2250); + TEST_TRINOP(timespec_clamp, 0, -2500, 0, -3000, 0, -2000, 0, -2500); + TEST_TRINOP(timespec_clamp, 0, -2750, 0, -3000, 0, -2000, 0, -2750); + TEST_TRINOP(timespec_clamp, 0, -2999, 0, -3000, 0, -2000, 0, -2999); + TEST_TRINOP(timespec_clamp, 0, -2000, 0, -3000, 0, -2000, 0, -2000); + TEST_TRINOP(timespec_clamp, 0, -3001, 0, -3000, 0, -2000, 0, -3000); + TEST_TRINOP(timespec_clamp, 0, -3500, 0, -3000, 0, -2000, 0, -3000); + TEST_TRINOP(timespec_clamp, 0, -2000, 0, -3000, 0, -2000, 0, -2000); + + TEST_TRINOP(timespec_clamp, 0, -4000, 0, -3000, 0, 3000, 0, -3000); + TEST_TRINOP(timespec_clamp, 0, -3001, 0, -3000, 0, 3000, 0, -3000); + TEST_TRINOP(timespec_clamp, 0, -3000, 0, -3000, 0, 3000, 0, -3000); + TEST_TRINOP(timespec_clamp, 0, -2999, 0, -3000, 0, 3000, 0, -2999); + TEST_TRINOP(timespec_clamp, 0, -1500, 0, -3000, 0, 3000, 0, -1500); + TEST_TRINOP(timespec_clamp, 0, -1, 0, -3000, 0, 3000, 0, -1); + TEST_TRINOP(timespec_clamp, 0, 0, 0, -3000, 0, 3000, 0, 0); + TEST_TRINOP(timespec_clamp, 0, 1, 0, -3000, 0, 3000, 0, 1); + TEST_TRINOP(timespec_clamp, 0, 1500, 0, -3000, 0, 3000, 0, 1500); + TEST_TRINOP(timespec_clamp, 0, 2999, 0, -3000, 0, 3000, 0, 2999); + TEST_TRINOP(timespec_clamp, 0, 3000, 0, -3000, 0, 3000, 0, 3000); + TEST_TRINOP(timespec_clamp, 0, 3001, 0, -3000, 0, 3000, 0, 3000); + TEST_TRINOP(timespec_clamp, 0, 4000, 0, -3000, 0, 3000, 0, 3000); + // timespec_min - - TEST_BINOP(timespec_min, 0,0, 0,0, 0,0); - TEST_BINOP(timespec_min, 0,0, 1,0, 0,0); - TEST_BINOP(timespec_min, 1,0, 0,0, 0,0); - TEST_BINOP(timespec_min, 1,0, 1,0, 1,0); - TEST_BINOP(timespec_min, 10,0, 1,0, 1,0); - TEST_BINOP(timespec_min, 10,0, 3,0, 3,0); - TEST_BINOP(timespec_min, 10,0, -3,0, -3,0); - TEST_BINOP(timespec_min, -10,0, 3,0, -10,0); - TEST_BINOP(timespec_min, -10,0, -3,0, -10,0); - TEST_BINOP(timespec_min, 10,0, 5,0, 5,0); - TEST_BINOP(timespec_min, 10,0, -5,0, -5,0); - TEST_BINOP(timespec_min, -10,0, 5,0, -10,0); - TEST_BINOP(timespec_min, -10,0, -5,0, -10,0); - TEST_BINOP(timespec_min, 1,500000000, 0,500000000, 0,500000000); - TEST_BINOP(timespec_min, 5,500000000, 2,999999999, 2,999999999); - TEST_BINOP(timespec_min, 0,500000000, 1,500000000, 0,500000000); - TEST_BINOP(timespec_min, 0,0, 1,500000000, 0,0); - TEST_BINOP(timespec_min, 1,0, 1,500000000, 1,0); - TEST_BINOP(timespec_min, 1,0, 0,1, 0,1); - TEST_BINOP(timespec_min, 1,123456789, 0,1000, 0,1000); - TEST_BINOP(timespec_min, 1,0, 0,9999999, 0,9999999); - TEST_BINOP(timespec_min, 12345,54321, 0,100001, 0,100001); - TEST_BINOP(timespec_min, LONG_MIN,0, 0,1, LONG_MIN,0); - TEST_BINOP(timespec_min, LONG_MIN,0, 0,-1, LONG_MIN,0); - TEST_BINOP(timespec_min, LONG_MIN,0, LONG_MAX,0, LONG_MIN,0); - TEST_BINOP(timespec_min, LONG_MIN,0, LONG_MIN,0, LONG_MIN,0); - TEST_BINOP(timespec_min, LONG_MAX,0, 0,1, 0,1); - TEST_BINOP(timespec_min, LONG_MAX,0, 0,-1, 0,-1); - TEST_BINOP(timespec_min, LONG_MAX,0, LONG_MAX,0, LONG_MAX,0); - TEST_BINOP(timespec_min, LONG_MAX,0, LONG_MIN,0, LONG_MIN,0); - + + TEST_BINOP(timespec_min, 0, 0, 0, 0, 0, 0); + TEST_BINOP(timespec_min, 0, 0, 1, 0, 0, 0); + TEST_BINOP(timespec_min, 1, 0, 0, 0, 0, 0); + TEST_BINOP(timespec_min, 1, 0, 1, 0, 1, 0); + TEST_BINOP(timespec_min, 10, 0, 1, 0, 1, 0); + TEST_BINOP(timespec_min, 10, 0, 3, 0, 3, 0); + TEST_BINOP(timespec_min, 10, 0, -3, 0, -3, 0); + TEST_BINOP(timespec_min, -10, 0, 3, 0, -10, 0); + TEST_BINOP(timespec_min, -10, 0, -3, 0, -10, 0); + TEST_BINOP(timespec_min, 10, 0, 5, 0, 5, 0); + TEST_BINOP(timespec_min, 10, 0, -5, 0, -5, 0); + TEST_BINOP(timespec_min, -10, 0, 5, 0, -10, 0); + TEST_BINOP(timespec_min, -10, 0, -5, 0, -10, 0); + TEST_BINOP(timespec_min, 1, 500000000, 0, 500000000, 0, 500000000); + TEST_BINOP(timespec_min, 5, 500000000, 2, 999999999, 2, 999999999); + TEST_BINOP(timespec_min, 0, 500000000, 1, 500000000, 0, 500000000); + TEST_BINOP(timespec_min, 0, 0, 1, 500000000, 0, 0); + TEST_BINOP(timespec_min, 1, 0, 1, 500000000, 1, 0); + TEST_BINOP(timespec_min, 1, 0, 0, 1, 0, 1); + TEST_BINOP(timespec_min, 1, 123456789, 0, 1000, 0, 1000); + TEST_BINOP(timespec_min, 1, 0, 0, 9999999, 0, 9999999); + TEST_BINOP(timespec_min, 12345, 54321, 0, 100001, 0, 100001); + TEST_BINOP(timespec_min, LONG_MIN, 0, 0, 1, LONG_MIN, 0); + TEST_BINOP(timespec_min, LONG_MIN, 0, 0, -1, LONG_MIN, 0); + TEST_BINOP(timespec_min, LONG_MIN, 0, LONG_MAX, 0, LONG_MIN, 0); + TEST_BINOP(timespec_min, LONG_MIN, 0, LONG_MIN, 0, LONG_MIN, 0); + TEST_BINOP(timespec_min, LONG_MAX, 0, 0, 1, 0, 1); + TEST_BINOP(timespec_min, LONG_MAX, 0, 0, -1, 0, -1); + TEST_BINOP(timespec_min, LONG_MAX, 0, LONG_MAX, 0, LONG_MAX, 0); + TEST_BINOP(timespec_min, LONG_MAX, 0, LONG_MIN, 0, LONG_MIN, 0); + // timespec_max - - TEST_BINOP(timespec_max, 0,0, 0,0, 0,0); - TEST_BINOP(timespec_max, 0,0, 1,0, 1,0); - TEST_BINOP(timespec_max, 1,0, 0,0, 1,0); - TEST_BINOP(timespec_max, 1,0, 1,0, 1,0); - TEST_BINOP(timespec_max, 10,0, 1,0, 10,0); - TEST_BINOP(timespec_max, 10,0, 3,0, 10,0); - TEST_BINOP(timespec_max, 10,0, -3,0, 10,0); - TEST_BINOP(timespec_max, -10,0, 3,0, 3,0); - TEST_BINOP(timespec_max, -10,0, -3,0, -3,0); - TEST_BINOP(timespec_max, 10,0, 5,0, 10,0); - TEST_BINOP(timespec_max, 10,0, -5,0, 10,0); - TEST_BINOP(timespec_max, -10,0, 5,0, 5,0); - TEST_BINOP(timespec_max, -10,0, -5,0, -5,0); - TEST_BINOP(timespec_max, 1,500000000, 0,500000000, 1,500000000); - TEST_BINOP(timespec_max, 5,500000000, 2,999999999, 5,500000000); - TEST_BINOP(timespec_max, 0,500000000, 1,500000000, 1,500000000); - TEST_BINOP(timespec_max, 0,0, 1,500000000, 1,500000000); - TEST_BINOP(timespec_max, 1,0, 1,500000000, 1,500000000); - TEST_BINOP(timespec_max, 1,0, 0,1, 1,0); - TEST_BINOP(timespec_max, 1,123456789, 0,1000, 1,123456789); - TEST_BINOP(timespec_max, 1,0, 0,9999999, 1,0); - TEST_BINOP(timespec_max, 12345,54321, 0,100001, 12345,54321); - TEST_BINOP(timespec_max, LONG_MIN,0, 0,1, 0,1); - TEST_BINOP(timespec_max, LONG_MIN,0, 0,-1, 0,-1); - TEST_BINOP(timespec_max, LONG_MIN,0, LONG_MAX,0, LONG_MAX,0); - TEST_BINOP(timespec_max, LONG_MIN,0, LONG_MIN,0, LONG_MIN,0); - TEST_BINOP(timespec_max, LONG_MAX,0, 0,1, LONG_MAX,0); - TEST_BINOP(timespec_max, LONG_MAX,0, 0,-1, LONG_MAX,0); - TEST_BINOP(timespec_max, LONG_MAX,0, LONG_MAX,0, LONG_MAX,0); - TEST_BINOP(timespec_max, LONG_MAX,0, LONG_MIN,0, LONG_MAX,0); - + + TEST_BINOP(timespec_max, 0, 0, 0, 0, 0, 0); + TEST_BINOP(timespec_max, 0, 0, 1, 0, 1, 0); + TEST_BINOP(timespec_max, 1, 0, 0, 0, 1, 0); + TEST_BINOP(timespec_max, 1, 0, 1, 0, 1, 0); + TEST_BINOP(timespec_max, 10, 0, 1, 0, 10, 0); + TEST_BINOP(timespec_max, 10, 0, 3, 0, 10, 0); + TEST_BINOP(timespec_max, 10, 0, -3, 0, 10, 0); + TEST_BINOP(timespec_max, -10, 0, 3, 0, 3, 0); + TEST_BINOP(timespec_max, -10, 0, -3, 0, -3, 0); + TEST_BINOP(timespec_max, 10, 0, 5, 0, 10, 0); + TEST_BINOP(timespec_max, 10, 0, -5, 0, 10, 0); + TEST_BINOP(timespec_max, -10, 0, 5, 0, 5, 0); + TEST_BINOP(timespec_max, -10, 0, -5, 0, -5, 0); + TEST_BINOP(timespec_max, 1, 500000000, 0, 500000000, 1, 500000000); + TEST_BINOP(timespec_max, 5, 500000000, 2, 999999999, 5, 500000000); + TEST_BINOP(timespec_max, 0, 500000000, 1, 500000000, 1, 500000000); + TEST_BINOP(timespec_max, 0, 0, 1, 500000000, 1, 500000000); + TEST_BINOP(timespec_max, 1, 0, 1, 500000000, 1, 500000000); + TEST_BINOP(timespec_max, 1, 0, 0, 1, 1, 0); + TEST_BINOP(timespec_max, 1, 123456789, 0, 1000, 1, 123456789); + TEST_BINOP(timespec_max, 1, 0, 0, 9999999, 1, 0); + TEST_BINOP(timespec_max, 12345, 54321, 0, 100001, 12345, 54321); + TEST_BINOP(timespec_max, LONG_MIN, 0, 0, 1, 0, 1); + TEST_BINOP(timespec_max, LONG_MIN, 0, 0, -1, 0, -1); + TEST_BINOP(timespec_max, LONG_MIN, 0, LONG_MAX, 0, LONG_MAX, 0); + TEST_BINOP(timespec_max, LONG_MIN, 0, LONG_MIN, 0, LONG_MIN, 0); + TEST_BINOP(timespec_max, LONG_MAX, 0, 0, 1, LONG_MAX, 0); + TEST_BINOP(timespec_max, LONG_MAX, 0, 0, -1, LONG_MAX, 0); + TEST_BINOP(timespec_max, LONG_MAX, 0, LONG_MAX, 0, LONG_MAX, 0); + TEST_BINOP(timespec_max, LONG_MAX, 0, LONG_MIN, 0, LONG_MAX, 0); + // timespec_cmp - - TEST_TEST_FUNC(timespec_cmp, 0,0, 0,0, 0); - TEST_TEST_FUNC(timespec_cmp, 100,0, 100,0, 0); - TEST_TEST_FUNC(timespec_cmp, -100,0, -100,0, 0); - - TEST_TEST_FUNC(timespec_cmp, 1,0, 0,0, 1); - TEST_TEST_FUNC(timespec_cmp, 0,0, 1,0, -1); - TEST_TEST_FUNC(timespec_cmp, 0,1, 0,0, 1); - TEST_TEST_FUNC(timespec_cmp, 0,0, 0,1, -1); - TEST_TEST_FUNC(timespec_cmp, 1,0, 0,100, 1); - TEST_TEST_FUNC(timespec_cmp, 0,100 , 1,0, -1); - - TEST_TEST_FUNC(timespec_cmp, -0,-0, 0,0, 0); - TEST_TEST_FUNC(timespec_cmp, -10,-500000000, -11,500000000, 0); - TEST_TEST_FUNC(timespec_cmp, -10,-500000001, -11,499999999, 0); - TEST_TEST_FUNC(timespec_cmp, -10,-500000001, -11,500000001, -1); - TEST_TEST_FUNC(timespec_cmp, -11,500000001, -10,-500000001, 1); - + + TEST_TEST_FUNC(timespec_cmp, 0, 0, 0, 0, 0); + TEST_TEST_FUNC(timespec_cmp, 100, 0, 100, 0, 0); + TEST_TEST_FUNC(timespec_cmp, -100, 0, -100, 0, 0); + + TEST_TEST_FUNC(timespec_cmp, 1, 0, 0, 0, 1); + TEST_TEST_FUNC(timespec_cmp, 0, 0, 1, 0, -1); + TEST_TEST_FUNC(timespec_cmp, 0, 1, 0, 0, 1); + TEST_TEST_FUNC(timespec_cmp, 0, 0, 0, 1, -1); + TEST_TEST_FUNC(timespec_cmp, 1, 0, 0, 100, 1); + TEST_TEST_FUNC(timespec_cmp, 0, 100, 1, 0, -1); + + TEST_TEST_FUNC(timespec_cmp, -0, -0, 0, 0, 0); + TEST_TEST_FUNC(timespec_cmp, -10, -500000000, -11, 500000000, 0); + TEST_TEST_FUNC(timespec_cmp, -10, -500000001, -11, 499999999, 0); + TEST_TEST_FUNC(timespec_cmp, -10, -500000001, -11, 500000001, -1); + TEST_TEST_FUNC(timespec_cmp, -11, 500000001, -10, -500000001, 1); + // timespec_eq - - TEST_TEST_FUNC(timespec_eq, 0,0, 0,0, true); - TEST_TEST_FUNC(timespec_eq, 100,0, 100,0, true); - TEST_TEST_FUNC(timespec_eq, -200,0, -200,0, true); - TEST_TEST_FUNC(timespec_eq, 0,300, 0,300, true); - TEST_TEST_FUNC(timespec_eq, 0,-400, 0,-400, true); - - TEST_TEST_FUNC(timespec_eq, 100,1, 100,0, false); - TEST_TEST_FUNC(timespec_eq, 101,0, 100,0, false); - TEST_TEST_FUNC(timespec_eq, -100,0, 100,0, false); - TEST_TEST_FUNC(timespec_eq, 0,10, 0,-10, false); - - TEST_TEST_FUNC(timespec_eq, -0,-0, 0,0, true); - TEST_TEST_FUNC(timespec_eq, -10,-500000000, -11,500000000, true); - TEST_TEST_FUNC(timespec_eq, -10,-500000001, -11,499999999, true); - TEST_TEST_FUNC(timespec_eq, -10,-500000001, -11,500000001, false); - + + TEST_TEST_FUNC(timespec_eq, 0, 0, 0, 0, true); + TEST_TEST_FUNC(timespec_eq, 100, 0, 100, 0, true); + TEST_TEST_FUNC(timespec_eq, -200, 0, -200, 0, true); + TEST_TEST_FUNC(timespec_eq, 0, 300, 0, 300, true); + TEST_TEST_FUNC(timespec_eq, 0, -400, 0, -400, true); + + TEST_TEST_FUNC(timespec_eq, 100, 1, 100, 0, false); + TEST_TEST_FUNC(timespec_eq, 101, 0, 100, 0, false); + TEST_TEST_FUNC(timespec_eq, -100, 0, 100, 0, false); + TEST_TEST_FUNC(timespec_eq, 0, 10, 0, -10, false); + + TEST_TEST_FUNC(timespec_eq, -0, -0, 0, 0, true); + TEST_TEST_FUNC(timespec_eq, -10, -500000000, -11, 500000000, true); + TEST_TEST_FUNC(timespec_eq, -10, -500000001, -11, 499999999, true); + TEST_TEST_FUNC(timespec_eq, -10, -500000001, -11, 500000001, false); + // timespec_gt - - TEST_TEST_FUNC(timespec_gt, 1,0, 0,0, true); - TEST_TEST_FUNC(timespec_gt, 0,0, -1,0, true); - TEST_TEST_FUNC(timespec_gt, 0,1, 0,0, true); - TEST_TEST_FUNC(timespec_gt, 0,0, 0,-1, true); - - TEST_TEST_FUNC(timespec_gt, 1,0, 1,0, false); - TEST_TEST_FUNC(timespec_gt, 1,1, 1,1, false); - TEST_TEST_FUNC(timespec_gt, -1,0, 0,0, false); - TEST_TEST_FUNC(timespec_gt, 0,-1, 0,0, false); - - TEST_TEST_FUNC(timespec_gt, 0,0, -0,-0, false); - TEST_TEST_FUNC(timespec_gt, -10,-500000000, -11,500000000, false); - TEST_TEST_FUNC(timespec_gt, -11,500000000, -10,-500000000, false); - TEST_TEST_FUNC(timespec_gt, -10,-500000001, -11,499999999, false); - TEST_TEST_FUNC(timespec_gt, -11,499999999, -11,499999999, false); - TEST_TEST_FUNC(timespec_gt, -10,-500000001, -11,500000001, false); - TEST_TEST_FUNC(timespec_gt, -11,500000001, -10,-500000001, true); - + + TEST_TEST_FUNC(timespec_gt, 1, 0, 0, 0, true); + TEST_TEST_FUNC(timespec_gt, 0, 0, -1, 0, true); + TEST_TEST_FUNC(timespec_gt, 0, 1, 0, 0, true); + TEST_TEST_FUNC(timespec_gt, 0, 0, 0, -1, true); + + TEST_TEST_FUNC(timespec_gt, 1, 0, 1, 0, false); + TEST_TEST_FUNC(timespec_gt, 1, 1, 1, 1, false); + TEST_TEST_FUNC(timespec_gt, -1, 0, 0, 0, false); + TEST_TEST_FUNC(timespec_gt, 0, -1, 0, 0, false); + + TEST_TEST_FUNC(timespec_gt, 0, 0, -0, -0, false); + TEST_TEST_FUNC(timespec_gt, -10, -500000000, -11, 500000000, false); + TEST_TEST_FUNC(timespec_gt, -11, 500000000, -10, -500000000, false); + TEST_TEST_FUNC(timespec_gt, -10, -500000001, -11, 499999999, false); + TEST_TEST_FUNC(timespec_gt, -11, 499999999, -11, 499999999, false); + TEST_TEST_FUNC(timespec_gt, -10, -500000001, -11, 500000001, false); + TEST_TEST_FUNC(timespec_gt, -11, 500000001, -10, -500000001, true); + // timespec_ge - - TEST_TEST_FUNC(timespec_ge, 1,0, 0,0, true); - TEST_TEST_FUNC(timespec_ge, 0,0, -1,0, true); - TEST_TEST_FUNC(timespec_ge, 0,1, 0,0, true); - TEST_TEST_FUNC(timespec_ge, 0,0, 0,-1, true); - TEST_TEST_FUNC(timespec_ge, 1,0, 1,0, true); - TEST_TEST_FUNC(timespec_ge, 1,1, 1,1, true); - - TEST_TEST_FUNC(timespec_ge, -1,0, 0,0, false); - TEST_TEST_FUNC(timespec_ge, 0,-1, 0,0, false); - - TEST_TEST_FUNC(timespec_ge, 0,0, -0,-0, true); - TEST_TEST_FUNC(timespec_ge, -10,-500000000, -11,500000000, true); - TEST_TEST_FUNC(timespec_ge, -11,500000000, -10,-500000000, true); - TEST_TEST_FUNC(timespec_ge, -10,-500000001, -11,499999999, true); - TEST_TEST_FUNC(timespec_ge, -11,499999999, -11,499999999, true); - TEST_TEST_FUNC(timespec_ge, -10,-500000001, -11,500000001, false); - TEST_TEST_FUNC(timespec_ge, -11,500000001, -10,-500000001, true); - + + TEST_TEST_FUNC(timespec_ge, 1, 0, 0, 0, true); + TEST_TEST_FUNC(timespec_ge, 0, 0, -1, 0, true); + TEST_TEST_FUNC(timespec_ge, 0, 1, 0, 0, true); + TEST_TEST_FUNC(timespec_ge, 0, 0, 0, -1, true); + TEST_TEST_FUNC(timespec_ge, 1, 0, 1, 0, true); + TEST_TEST_FUNC(timespec_ge, 1, 1, 1, 1, true); + + TEST_TEST_FUNC(timespec_ge, -1, 0, 0, 0, false); + TEST_TEST_FUNC(timespec_ge, 0, -1, 0, 0, false); + + TEST_TEST_FUNC(timespec_ge, 0, 0, -0, -0, true); + TEST_TEST_FUNC(timespec_ge, -10, -500000000, -11, 500000000, true); + TEST_TEST_FUNC(timespec_ge, -11, 500000000, -10, -500000000, true); + TEST_TEST_FUNC(timespec_ge, -10, -500000001, -11, 499999999, true); + TEST_TEST_FUNC(timespec_ge, -11, 499999999, -11, 499999999, true); + TEST_TEST_FUNC(timespec_ge, -10, -500000001, -11, 500000001, false); + TEST_TEST_FUNC(timespec_ge, -11, 500000001, -10, -500000001, true); + // timespec_lt - - TEST_TEST_FUNC(timespec_lt, 0,0, 1,0, true); - TEST_TEST_FUNC(timespec_lt, -1,0, 0,0, true); - TEST_TEST_FUNC(timespec_lt, 0,0, 0,1, true); - TEST_TEST_FUNC(timespec_lt, 0,-1, 0,0, true); - - TEST_TEST_FUNC(timespec_lt, 1,0, 1,0, false); - TEST_TEST_FUNC(timespec_lt, 1,1, 1,1, false); - TEST_TEST_FUNC(timespec_lt, 0,0, -1,0, false); - TEST_TEST_FUNC(timespec_lt, 0,0, 0,-1, false); - - TEST_TEST_FUNC(timespec_lt, 0,0, -0,-0, false); - TEST_TEST_FUNC(timespec_lt, -10,-500000000, -11,500000000, false); - TEST_TEST_FUNC(timespec_lt, -11,500000000, -10,-500000000, false); - TEST_TEST_FUNC(timespec_lt, -10,-500000001, -11,499999999, false); - TEST_TEST_FUNC(timespec_lt, -11,499999999, -11,499999999, false); - TEST_TEST_FUNC(timespec_lt, -10,-500000001, -11,500000001, true); - TEST_TEST_FUNC(timespec_lt, -11,500000001, -10,-500000001, false); - + + TEST_TEST_FUNC(timespec_lt, 0, 0, 1, 0, true); + TEST_TEST_FUNC(timespec_lt, -1, 0, 0, 0, true); + TEST_TEST_FUNC(timespec_lt, 0, 0, 0, 1, true); + TEST_TEST_FUNC(timespec_lt, 0, -1, 0, 0, true); + + TEST_TEST_FUNC(timespec_lt, 1, 0, 1, 0, false); + TEST_TEST_FUNC(timespec_lt, 1, 1, 1, 1, false); + TEST_TEST_FUNC(timespec_lt, 0, 0, -1, 0, false); + TEST_TEST_FUNC(timespec_lt, 0, 0, 0, -1, false); + + TEST_TEST_FUNC(timespec_lt, 0, 0, -0, -0, false); + TEST_TEST_FUNC(timespec_lt, -10, -500000000, -11, 500000000, false); + TEST_TEST_FUNC(timespec_lt, -11, 500000000, -10, -500000000, false); + TEST_TEST_FUNC(timespec_lt, -10, -500000001, -11, 499999999, false); + TEST_TEST_FUNC(timespec_lt, -11, 499999999, -11, 499999999, false); + TEST_TEST_FUNC(timespec_lt, -10, -500000001, -11, 500000001, true); + TEST_TEST_FUNC(timespec_lt, -11, 500000001, -10, -500000001, false); + // timespec_le - - TEST_TEST_FUNC(timespec_le, 0,0, 1,0, true); - TEST_TEST_FUNC(timespec_le, -1,0, 0,0, true); - TEST_TEST_FUNC(timespec_le, 0,0, 0,1, true); - TEST_TEST_FUNC(timespec_le, 0,-1, 0,0, true); - TEST_TEST_FUNC(timespec_le, 1,0, 1,0, true); - TEST_TEST_FUNC(timespec_le, 1,1, 1,1, true); - - TEST_TEST_FUNC(timespec_le, 0,0, -1,0, false); - TEST_TEST_FUNC(timespec_le, 0,0, 0,-1, false); - - TEST_TEST_FUNC(timespec_le, 0,0, -0,-0, true); - TEST_TEST_FUNC(timespec_le, -10,-500000000, -11,500000000, true); - TEST_TEST_FUNC(timespec_le, -11,500000000, -10,-500000000, true); - TEST_TEST_FUNC(timespec_le, -10,-500000001, -11,499999999, true); - TEST_TEST_FUNC(timespec_le, -11,499999999, -11,499999999, true); - TEST_TEST_FUNC(timespec_le, -10,-500000001, -11,500000001, true); - TEST_TEST_FUNC(timespec_le, -11,500000001, -10,-500000001, false); - + + TEST_TEST_FUNC(timespec_le, 0, 0, 1, 0, true); + TEST_TEST_FUNC(timespec_le, -1, 0, 0, 0, true); + TEST_TEST_FUNC(timespec_le, 0, 0, 0, 1, true); + TEST_TEST_FUNC(timespec_le, 0, -1, 0, 0, true); + TEST_TEST_FUNC(timespec_le, 1, 0, 1, 0, true); + TEST_TEST_FUNC(timespec_le, 1, 1, 1, 1, true); + + TEST_TEST_FUNC(timespec_le, 0, 0, -1, 0, false); + TEST_TEST_FUNC(timespec_le, 0, 0, 0, -1, false); + + TEST_TEST_FUNC(timespec_le, 0, 0, -0, -0, true); + TEST_TEST_FUNC(timespec_le, -10, -500000000, -11, 500000000, true); + TEST_TEST_FUNC(timespec_le, -11, 500000000, -10, -500000000, true); + TEST_TEST_FUNC(timespec_le, -10, -500000001, -11, 499999999, true); + TEST_TEST_FUNC(timespec_le, -11, 499999999, -11, 499999999, true); + TEST_TEST_FUNC(timespec_le, -10, -500000001, -11, 500000001, true); + TEST_TEST_FUNC(timespec_le, -11, 500000001, -10, -500000001, false); + // timespec_from_double - - TEST_FROM_DOUBLE(0.0, 0,0); - TEST_FROM_DOUBLE(10.0, 10,0); - TEST_FROM_DOUBLE(-10.0, -10,0); - TEST_FROM_DOUBLE(0.5, 0,500000000); - TEST_FROM_DOUBLE(-0.5, -1,500000000); - TEST_FROM_DOUBLE(10.5, 10,500000000); - TEST_FROM_DOUBLE(-10.5, -11,500000000); - + + TEST_FROM_DOUBLE(0.0, 0, 0); + TEST_FROM_DOUBLE(10.0, 10, 0); + TEST_FROM_DOUBLE(-10.0, -10, 0); + TEST_FROM_DOUBLE(0.5, 0, 500000000); + TEST_FROM_DOUBLE(-0.5, -1, 500000000); + TEST_FROM_DOUBLE(10.5, 10, 500000000); + TEST_FROM_DOUBLE(-10.5, -11, 500000000); + // timespec_to_double - - TEST_TO_DOUBLE(0,0, 0.0); - TEST_TO_DOUBLE(10,0, 10.0); - TEST_TO_DOUBLE(-10,0, -10.0); - TEST_TO_DOUBLE(0,500000000, 0.5); - TEST_TO_DOUBLE(0,-500000000, -0.5); - TEST_TO_DOUBLE(10,500000000, 10.5); - TEST_TO_DOUBLE(10,-500000000, 9.5); - TEST_TO_DOUBLE(-10,500000000, -9.5); - TEST_TO_DOUBLE(-10,-500000000, -10.5); - + + TEST_TO_DOUBLE(0, 0, 0.0); + TEST_TO_DOUBLE(10, 0, 10.0); + TEST_TO_DOUBLE(-10, 0, -10.0); + TEST_TO_DOUBLE(0, 500000000, 0.5); + TEST_TO_DOUBLE(0, -500000000, -0.5); + TEST_TO_DOUBLE(10, 500000000, 10.5); + TEST_TO_DOUBLE(10, -500000000, 9.5); + TEST_TO_DOUBLE(-10, 500000000, -9.5); + TEST_TO_DOUBLE(-10, -500000000, -10.5); + // timespec_from_timeval - - TEST_FROM_TIMEVAL(0,0, 0,0); - TEST_FROM_TIMEVAL(1,0, 1,0); - TEST_FROM_TIMEVAL(1000,0, 1000,0); - TEST_FROM_TIMEVAL(0,0, 0,0); - TEST_FROM_TIMEVAL(-1,0, -1,0); - TEST_FROM_TIMEVAL(-1000,0, -1000,0); - - TEST_FROM_TIMEVAL(1,1, 1,1000); - TEST_FROM_TIMEVAL(1,1000, 1,1000000); - TEST_FROM_TIMEVAL(1,-1, 0,999999000); - TEST_FROM_TIMEVAL(1,-1000, 0,999000000); - TEST_FROM_TIMEVAL(-1,-1, -2,999999000); - TEST_FROM_TIMEVAL(-1,-1000, -2,999000000); - + + TEST_FROM_TIMEVAL(0, 0, 0, 0); + TEST_FROM_TIMEVAL(1, 0, 1, 0); + TEST_FROM_TIMEVAL(1000, 0, 1000, 0); + TEST_FROM_TIMEVAL(0, 0, 0, 0); + TEST_FROM_TIMEVAL(-1, 0, -1, 0); + TEST_FROM_TIMEVAL(-1000, 0, -1000, 0); + + TEST_FROM_TIMEVAL(1, 1, 1, 1000); + TEST_FROM_TIMEVAL(1, 1000, 1, 1000000); + TEST_FROM_TIMEVAL(1, -1, 0, 999999000); + TEST_FROM_TIMEVAL(1, -1000, 0, 999000000); + TEST_FROM_TIMEVAL(-1, -1, -2, 999999000); + TEST_FROM_TIMEVAL(-1, -1000, -2, 999000000); + // timespec_to_timeval - - TEST_TO_TIMEVAL(0,0, 0,0); - TEST_TO_TIMEVAL(1,0, 1,0); - TEST_TO_TIMEVAL(10,0, 10,0); - TEST_TO_TIMEVAL(-1,0, -1,0); - TEST_TO_TIMEVAL(-10,0, -10,0); - - TEST_TO_TIMEVAL(1,1, 1,0); - TEST_TO_TIMEVAL(1,999, 1,0); - TEST_TO_TIMEVAL(1,1000, 1,1); - TEST_TO_TIMEVAL(1,1001, 1,1); - TEST_TO_TIMEVAL(1,2000, 1,2); - TEST_TO_TIMEVAL(1,2000000, 1,2000); - - TEST_TO_TIMEVAL(1,-1, 0,999999); - TEST_TO_TIMEVAL(1,-999, 0,999999); - TEST_TO_TIMEVAL(1,-1000, 0,999999); - TEST_TO_TIMEVAL(1,-1001, 0,999998); - TEST_TO_TIMEVAL(1,-2000, 0,999998); - TEST_TO_TIMEVAL(1,-2000000, 0,998000); - - TEST_TO_TIMEVAL(-1,-1, -2,999999); - TEST_TO_TIMEVAL(-1,-999, -2,999999); - TEST_TO_TIMEVAL(-1,-1000, -2,999999); - TEST_TO_TIMEVAL(-1,-1001, -2,999998); - TEST_TO_TIMEVAL(-1,-2000, -2,999998); - TEST_TO_TIMEVAL(-1,-2000000, -2,998000); - - TEST_TO_TIMEVAL(1,1500000000, 2,500000); - TEST_TO_TIMEVAL(1,-1500000000, -1,500000); - TEST_TO_TIMEVAL(-1,-1500000000, -3,500000); - + + TEST_TO_TIMEVAL(0, 0, 0, 0); + TEST_TO_TIMEVAL(1, 0, 1, 0); + TEST_TO_TIMEVAL(10, 0, 10, 0); + TEST_TO_TIMEVAL(-1, 0, -1, 0); + TEST_TO_TIMEVAL(-10, 0, -10, 0); + + TEST_TO_TIMEVAL(1, 1, 1, 0); + TEST_TO_TIMEVAL(1, 999, 1, 0); + TEST_TO_TIMEVAL(1, 1000, 1, 1); + TEST_TO_TIMEVAL(1, 1001, 1, 1); + TEST_TO_TIMEVAL(1, 2000, 1, 2); + TEST_TO_TIMEVAL(1, 2000000, 1, 2000); + + TEST_TO_TIMEVAL(1, -1, 0, 999999); + TEST_TO_TIMEVAL(1, -999, 0, 999999); + TEST_TO_TIMEVAL(1, -1000, 0, 999999); + TEST_TO_TIMEVAL(1, -1001, 0, 999998); + TEST_TO_TIMEVAL(1, -2000, 0, 999998); + TEST_TO_TIMEVAL(1, -2000000, 0, 998000); + + TEST_TO_TIMEVAL(-1, -1, -2, 999999); + TEST_TO_TIMEVAL(-1, -999, -2, 999999); + TEST_TO_TIMEVAL(-1, -1000, -2, 999999); + TEST_TO_TIMEVAL(-1, -1001, -2, 999998); + TEST_TO_TIMEVAL(-1, -2000, -2, 999998); + TEST_TO_TIMEVAL(-1, -2000000, -2, 998000); + + TEST_TO_TIMEVAL(1, 1500000000, 2, 500000); + TEST_TO_TIMEVAL(1, -1500000000, -1, 500000); + TEST_TO_TIMEVAL(-1, -1500000000, -3, 500000); + // timespec_from_ms - - TEST_FROM_MS(0, 0,0); - TEST_FROM_MS(1, 0,1000000); - TEST_FROM_MS(-1, -1,999000000); - TEST_FROM_MS(1500, 1,500000000); - TEST_FROM_MS(-1000, -1,0); - TEST_FROM_MS(-1500, -2,500000000); - + + TEST_FROM_MS(0, 0, 0); + TEST_FROM_MS(1, 0, 1000000); + TEST_FROM_MS(-1, -1, 999000000); + TEST_FROM_MS(1500, 1, 500000000); + TEST_FROM_MS(-1000, -1, 0); + TEST_FROM_MS(-1500, -2, 500000000); + // timespec_to_ms - - TEST_TO_MS(0,0, 0); - TEST_TO_MS(10,0, 10000); - TEST_TO_MS(-10,0, -10000); - TEST_TO_MS(0,500000000, 500); - TEST_TO_MS(0,-500000000, -500); - TEST_TO_MS(10,500000000, 10500); - TEST_TO_MS(10,-500000000, 9500); - TEST_TO_MS(-10,500000000, -9500); - TEST_TO_MS(-10,-500000000, -10500); - + + TEST_TO_MS(0, 0, 0); + TEST_TO_MS(10, 0, 10000); + TEST_TO_MS(-10, 0, -10000); + TEST_TO_MS(0, 500000000, 500); + TEST_TO_MS(0, -500000000, -500); + TEST_TO_MS(10, 500000000, 10500); + TEST_TO_MS(10, -500000000, 9500); + TEST_TO_MS(-10, 500000000, -9500); + TEST_TO_MS(-10, -500000000, -10500); + // timespec_normalise - - TEST_NORMALISE(0,0, 0,0); - - TEST_NORMALISE(0,1000000000, 1,0); - TEST_NORMALISE(0,1500000000, 1,500000000); - TEST_NORMALISE(0,-1000000000, -1,0); - TEST_NORMALISE(0,-1500000000, -2,500000000); - - TEST_NORMALISE(5,1000000000, 6,0); - TEST_NORMALISE(5,1500000000, 6,500000000); - TEST_NORMALISE(-5,-1000000000, -6,0); - TEST_NORMALISE(-5,-1500000000, -7,500000000); - - TEST_NORMALISE(0,2000000000, 2,0); - TEST_NORMALISE(0,2100000000, 2,100000000); - TEST_NORMALISE(0,-2000000000, -2,0); - TEST_NORMALISE(0,-2100000000, -3,900000000); - - TEST_NORMALISE(1,-500000001, 0,499999999); - TEST_NORMALISE(1,-500000000, 0,500000000); - TEST_NORMALISE(1,-499999999, 0,500000001); - TEST_NORMALISE(0,-499999999, -1,500000001); - - TEST_NORMALISE(-1,500000000, -1,500000000); - TEST_NORMALISE(-1,499999999, -1,499999999); - - if(result > 0) - { + + TEST_NORMALISE(0, 0, 0, 0); + + TEST_NORMALISE(0, 1000000000, 1, 0); + TEST_NORMALISE(0, 1500000000, 1, 500000000); + TEST_NORMALISE(0, -1000000000, -1, 0); + TEST_NORMALISE(0, -1500000000, -2, 500000000); + + TEST_NORMALISE(5, 1000000000, 6, 0); + TEST_NORMALISE(5, 1500000000, 6, 500000000); + TEST_NORMALISE(-5, -1000000000, -6, 0); + TEST_NORMALISE(-5, -1500000000, -7, 500000000); + + TEST_NORMALISE(0, 2000000000, 2, 0); + TEST_NORMALISE(0, 2100000000, 2, 100000000); + TEST_NORMALISE(0, -2000000000, -2, 0); + TEST_NORMALISE(0, -2100000000, -3, 900000000); + + TEST_NORMALISE(1, -500000001, 0, 499999999); + TEST_NORMALISE(1, -500000000, 0, 500000000); + TEST_NORMALISE(1, -499999999, 0, 500000001); + TEST_NORMALISE(0, -499999999, -1, 500000001); + + TEST_NORMALISE(-1, 500000000, -1, 500000000); + TEST_NORMALISE(-1, 499999999, -1, 499999999); + + if (result > 0) { printf("%d tests failed\n", result); - } - else{ + } else { printf("All tests passed\n"); } - + return !!result; /* Don't overflow the exit status */ } #endif \ No newline at end of file