View | Details | Raw Unified | Return to bug 272730 | Differences between
and this patch

Collapse All | Expand All

(-)b/cad/PrusaSlicer/Makefile (-4 / +10 lines)
Lines 1-8 Link Here
1
PORTNAME=	PrusaSlicer
1
PORTNAME=	PrusaSlicer
2
DISTVERSIONPREFIX=version_
2
DISTVERSIONPREFIX=version_
3
DISTVERSION=	2.5.1
3
DISTVERSION=	2.6.0
4
PORTREVISION=	7
4
PORTREVISION=	1
5
CATEGORIES=	cad
5
CATEGORIES=	cad
6
DIST_SUBDIR=	PrusaSlicer
6
7
7
MAINTAINER=	teodorsigaev@gmail.com
8
MAINTAINER=	teodorsigaev@gmail.com
8
COMMENT=	Slicing application for 3D printers
9
COMMENT=	Slicing application for 3D printers
Lines 14-25 LICENSE_FILE= ${WRKSRC}/LICENSE Link Here
14
BUILD_DEPENDS=	cereal>=1.3.0.10:devel/cereal \
15
BUILD_DEPENDS=	cereal>=1.3.0.10:devel/cereal \
15
		cgal>=5.0.2:math/cgal \
16
		cgal>=5.0.2:math/cgal \
16
		opencascade>=7.7.0:cad/opencascade
17
		opencascade>=7.7.0:cad/opencascade
18
17
LIB_DEPENDS=	libtbb.so:devel/onetbb \
19
LIB_DEPENDS=	libtbb.so:devel/onetbb \
18
		libboost_log.so:devel/boost-libs \
20
		libboost_log.so:devel/boost-libs \
19
		libImath.so:math/Imath \
21
		libImath.so:math/Imath \
20
		libnlopt.so:math/nlopt \
22
		libnlopt.so:math/nlopt \
23
		libqhull_r.so:math/qhull \
21
		libcurl.so:ftp/curl \
24
		libcurl.so:ftp/curl \
22
		libexpat.so:textproc/expat2 \
25
		libexpat.so:textproc/expat2 \
26
		libiconv.so:converters/libiconv \
23
		libopenvdb.so:misc/openvdb \
27
		libopenvdb.so:misc/openvdb \
24
		libgmp.so:math/gmp \
28
		libgmp.so:math/gmp \
25
		libmpfr.so:math/mpfr \
29
		libmpfr.so:math/mpfr \
Lines 31-37 LIB_DEPENDS= libtbb.so:devel/onetbb \ Link Here
31
		libfreeimage.so:graphics/freeimage \
35
		libfreeimage.so:graphics/freeimage \
32
		libfreetype.so:print/freetype2 \
36
		libfreetype.so:print/freetype2 \
33
		libavcodec.so:multimedia/ffmpeg \
37
		libavcodec.so:multimedia/ffmpeg \
34
		libharfbuzz.so:print/harfbuzz
38
		libharfbuzz.so:print/harfbuzz \
39
		libwayland-egl.so:graphics/wayland
35
40
36
USES=		cmake cpe desktop-file-utils eigen:3 gettext gl pkgconfig jpeg iconv gnome xorg
41
USES=		cmake cpe desktop-file-utils eigen:3 gettext gl pkgconfig jpeg iconv gnome xorg
37
CPE_VENDOR=	prusa3d
42
CPE_VENDOR=	prusa3d
Lines 44-50 USE_XORG= x11 Link Here
44
49
45
CMAKE_ARGS+=	-DwxWidgets_CONFIG_EXECUTABLE="${WX_CONFIG}" \
50
CMAKE_ARGS+=	-DwxWidgets_CONFIG_EXECUTABLE="${WX_CONFIG}" \
46
		-DSLIC3R_GTK=3 \
51
		-DSLIC3R_GTK=3 \
47
		-DSLIC3R_FHS=1
52
		-DSLIC3R_FHS=1 \
53
                -DSLIC3R_PCH=OFF
48
54
49
PORTDATA=	*
55
PORTDATA=	*
50
56
(-)b/cad/PrusaSlicer/distinfo (-3 / +3 lines)
Lines 1-3 Link Here
1
TIMESTAMP = 1679421999
1
TIMESTAMP = 1690319127
2
SHA256 (prusa3d-PrusaSlicer-version_2.5.1_GH0.tar.gz) = 4fa14a4604ccf8042c3cbefe4c0a481d293e075030920799fe3f5e6247ef93ca
2
SHA256 (PrusaSlicer/prusa3d-PrusaSlicer-version_2.6.0_GH0.tar.gz) = a15f68e3b18a047c8c9a18a9d91629d2c777be1932087684cf6d2332d0888e77
3
SIZE (prusa3d-PrusaSlicer-version_2.5.1_GH0.tar.gz) = 48888707
3
SIZE (PrusaSlicer/prusa3d-PrusaSlicer-version_2.6.0_GH0.tar.gz) = 56430180
(-)b/cad/PrusaSlicer/files/patch-CMakeLists.txt (-5 / +14 lines)
Lines 1-6 Link Here
1
--- CMakeLists.txt.orig	2022-09-06 07:09:19 UTC
1
--- CMakeLists.txt.orig	2023-06-19 12:07:14 UTC
2
+++ CMakeLists.txt
2
+++ CMakeLists.txt
3
@@ -4,6 +4,7 @@ project(PrusaSlicer)
3
@@ -4,6 +4,7 @@ include(CMakeDependentOption)
4
 include("version.inc")
4
 include("version.inc")
5
 include(GNUInstallDirs)
5
 include(GNUInstallDirs)
6
 include(CMakeDependentOption)
6
 include(CMakeDependentOption)
Lines 8-14 Link Here
8
 
8
 
9
 set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources")
9
 set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources")
10
 file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN)
10
 file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN)
11
@@ -197,7 +198,7 @@ if (APPLE)
11
@@ -207,7 +208,7 @@ endif ()
12
     endif ()
12
     endif ()
13
 endif ()
13
 endif ()
14
 
14
 
Lines 17-23 Link Here
17
     find_package(PkgConfig REQUIRED)
17
     find_package(PkgConfig REQUIRED)
18
 
18
 
19
     if (CMAKE_VERSION VERSION_LESS "3.1")
19
     if (CMAKE_VERSION VERSION_LESS "3.1")
20
@@ -597,8 +598,8 @@ elseif (SLIC3R_FHS)
20
@@ -446,7 +447,7 @@ find_package(EXPAT REQUIRED)
21
 # no matter what.
22
 find_package(EXPAT REQUIRED)
23
 
24
-add_library(libexpat INTERFACE)
25
+# add_library(libexpat INTERFACE)
26
 
27
 if (TARGET EXPAT::EXPAT )
28
     target_link_libraries(libexpat INTERFACE EXPAT::EXPAT)
29
@@ -627,8 +628,8 @@ elseif (SLIC3R_FHS)
21
     install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/ DESTINATION ${SLIC3R_FHS_RESOURCES}
30
     install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/ DESTINATION ${SLIC3R_FHS_RESOURCES}
22
         PATTERN "*/udev" EXCLUDE
31
         PATTERN "*/udev" EXCLUDE
23
     )
32
     )
Lines 28-34 Link Here
28
     foreach(SIZE 32 128 192)
37
     foreach(SIZE 32 128 192)
29
         install(FILES ${SLIC3R_RESOURCES_DIR}/icons/PrusaSlicer_${SIZE}px.png
38
         install(FILES ${SLIC3R_RESOURCES_DIR}/icons/PrusaSlicer_${SIZE}px.png
30
             DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME PrusaSlicer.png
39
             DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME PrusaSlicer.png
31
@@ -607,7 +608,8 @@ elseif (SLIC3R_FHS)
40
@@ -637,7 +638,8 @@ elseif (SLIC3R_FHS)
32
             DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME PrusaSlicer-gcodeviewer.png
41
             DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME PrusaSlicer-gcodeviewer.png
33
         )
42
         )
34
     endforeach()
43
     endforeach()
(-)b/cad/PrusaSlicer/files/patch-src_CMakeLists.txt (-3 / +12 lines)
Lines 1-10 Link Here
1
--- src/CMakeLists.txt.orig	2022-09-06 07:09:19 UTC
1
--- src/CMakeLists.txt.orig	2023-06-19 12:07:14 UTC
2
+++ src/CMakeLists.txt
2
+++ src/CMakeLists.txt
3
@@ -127,7 +127,7 @@ if (NOT WIN32 AND NOT APPLE)
3
@@ -78,7 +78,7 @@ if (SLIC3R_GUI)
4
 
5
     find_package(JPEG QUIET)
6
     find_package(TIFF QUIET)
7
-    find_package(NanoSVG REQUIRED)
8
+    # find_package(NanoSVG REQUIRED)
9
 
10
     string(REGEX MATCH "wxpng" WX_PNG_BUILTIN ${wxWidgets_LIBRARIES})
11
     if (PNG_FOUND AND NOT WX_PNG_BUILTIN)
12
@@ -147,7 +147,7 @@ endif ()
4
     set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
13
     set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
5
 endif ()
14
 endif ()
6
 
15
 
7
-target_link_libraries(PrusaSlicer libslic3r cereal)
16
-target_link_libraries(PrusaSlicer libslic3r libcereal)
8
+target_link_libraries(PrusaSlicer libslic3r)
17
+target_link_libraries(PrusaSlicer libslic3r)
9
 
18
 
10
 if (APPLE)
19
 if (APPLE)
(-)b/cad/PrusaSlicer/files/patch-src_avrdude_arduino.c (+10 lines)
Added Link Here
1
--- src/avrdude/arduino.c.orig	2023-07-25 13:23:52 UTC
2
+++ src/avrdude/arduino.c
3
@@ -28,6 +28,7 @@
4
 #include "ac_cfg.h"
5
 
6
 #include <stdio.h>
7
+#include <stdlib.h>
8
 #include <string.h>
9
 #include <unistd.h>
10
 
(-)b/cad/PrusaSlicer/files/patch-src_libnanosvg_nanosvg.h (+3109 lines)
Added Link Here
1
--- src/libnanosvg/nanosvg.h.orig	1970-01-01 01:00:00.000000000 +0100
2
+++ src/libnanosvg/nanosvg.h	2022-12-22 00:42:08.000000000 +0100
3
@@ -0,0 +1,3106 @@
4
+/*
5
+ * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
6
+ *
7
+ * This software is provided 'as-is', without any express or implied
8
+ * warranty.  In no event will the authors be held liable for any damages
9
+ * arising from the use of this software.
10
+ *
11
+ * Permission is granted to anyone to use this software for any purpose,
12
+ * including commercial applications, and to alter it and redistribute it
13
+ * freely, subject to the following restrictions:
14
+ *
15
+ * 1. The origin of this software must not be misrepresented; you must not
16
+ * claim that you wrote the original software. If you use this software
17
+ * in a product, an acknowledgment in the product documentation would be
18
+ * appreciated but is not required.
19
+ * 2. Altered source versions must be plainly marked as such, and must not be
20
+ * misrepresented as being the original software.
21
+ * 3. This notice may not be removed or altered from any source distribution.
22
+ *
23
+ * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
24
+ * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
25
+ *
26
+ * Arc calculation code based on canvg (https://code.google.com/p/canvg/)
27
+ *
28
+ * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
29
+ *
30
+ */
31
+
32
+#ifndef NANOSVG_H
33
+#define NANOSVG_H
34
+
35
+#ifndef NANOSVG_CPLUSPLUS
36
+#ifdef __cplusplus
37
+extern "C" {
38
+#endif
39
+#endif
40
+
41
+// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
42
+//
43
+// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
44
+//
45
+// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
46
+//
47
+// The shapes in the SVG images are transformed by the viewBox and converted to specified units.
48
+// That is, you should get the same looking data as your designed in your favorite app.
49
+//
50
+// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
51
+// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
52
+//
53
+// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
54
+// DPI (dots-per-inch) controls how the unit conversion is done.
55
+//
56
+// If you don't know or care about the units stuff, "px" and 96 should get you going.
57
+
58
+
59
+/* Example Usage:
60
+	// Load SVG
61
+	NSVGimage* image;
62
+	image = nsvgParseFromFile("test.svg", "px", 96);
63
+	printf("size: %f x %f\n", image->width, image->height);
64
+	// Use...
65
+	for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
66
+		for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
67
+			for (int i = 0; i < path->npts-1; i += 3) {
68
+				float* p = &path->pts[i*2];
69
+				drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
70
+			}
71
+		}
72
+	}
73
+	// Delete
74
+	nsvgDelete(image);
75
+*/
76
+
77
+enum NSVGpaintType {
78
+	NSVG_PAINT_UNDEF = -1,
79
+	NSVG_PAINT_NONE = 0,
80
+	NSVG_PAINT_COLOR = 1,
81
+	NSVG_PAINT_LINEAR_GRADIENT = 2,
82
+	NSVG_PAINT_RADIAL_GRADIENT = 3
83
+};
84
+
85
+enum NSVGspreadType {
86
+	NSVG_SPREAD_PAD = 0,
87
+	NSVG_SPREAD_REFLECT = 1,
88
+	NSVG_SPREAD_REPEAT = 2
89
+};
90
+
91
+enum NSVGlineJoin {
92
+	NSVG_JOIN_MITER = 0,
93
+	NSVG_JOIN_ROUND = 1,
94
+	NSVG_JOIN_BEVEL = 2
95
+};
96
+
97
+enum NSVGlineCap {
98
+	NSVG_CAP_BUTT = 0,
99
+	NSVG_CAP_ROUND = 1,
100
+	NSVG_CAP_SQUARE = 2
101
+};
102
+
103
+enum NSVGfillRule {
104
+	NSVG_FILLRULE_NONZERO = 0,
105
+	NSVG_FILLRULE_EVENODD = 1
106
+};
107
+
108
+enum NSVGflags {
109
+	NSVG_FLAGS_VISIBLE = 0x01
110
+};
111
+
112
+typedef struct NSVGgradientStop {
113
+	unsigned int color;
114
+	float offset;
115
+} NSVGgradientStop;
116
+
117
+typedef struct NSVGgradient {
118
+	float xform[6];
119
+	char spread;
120
+	float fx, fy;
121
+	int nstops;
122
+	NSVGgradientStop stops[1];
123
+} NSVGgradient;
124
+
125
+typedef struct NSVGpaint {
126
+	signed char type;
127
+	union {
128
+		unsigned int color;
129
+		NSVGgradient* gradient;
130
+	};
131
+} NSVGpaint;
132
+
133
+typedef struct NSVGpath
134
+{
135
+	float* pts;					// Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
136
+	int npts;					// Total number of bezier points.
137
+	char closed;				// Flag indicating if shapes should be treated as closed.
138
+	float bounds[4];			// Tight bounding box of the shape [minx,miny,maxx,maxy].
139
+	struct NSVGpath* next;		// Pointer to next path, or NULL if last element.
140
+} NSVGpath;
141
+
142
+typedef struct NSVGshape
143
+{
144
+	char id[64];				// Optional 'id' attr of the shape or its group
145
+	NSVGpaint fill;				// Fill paint
146
+	NSVGpaint stroke;			// Stroke paint
147
+	float opacity;				// Opacity of the shape.
148
+	float strokeWidth;			// Stroke width (scaled).
149
+	float strokeDashOffset;		// Stroke dash offset (scaled).
150
+	float strokeDashArray[8];	// Stroke dash array (scaled).
151
+	char strokeDashCount;		// Number of dash values in dash array.
152
+	char strokeLineJoin;		// Stroke join type.
153
+	char strokeLineCap;			// Stroke cap type.
154
+	float miterLimit;			// Miter limit
155
+	char fillRule;				// Fill rule, see NSVGfillRule.
156
+	unsigned char flags;		// Logical or of NSVG_FLAGS_* flags
157
+	float bounds[4];			// Tight bounding box of the shape [minx,miny,maxx,maxy].
158
+	char fillGradient[64];		// Optional 'id' of fill gradient
159
+	char strokeGradient[64];	// Optional 'id' of stroke gradient
160
+	float xform[6];				// Root transformation for fill/stroke gradient
161
+	NSVGpath* paths;			// Linked list of paths in the image.
162
+	struct NSVGshape* next;		// Pointer to next shape, or NULL if last element.
163
+} NSVGshape;
164
+
165
+typedef struct NSVGimage
166
+{
167
+	float width;				// Width of the image.
168
+	float height;				// Height of the image.
169
+	NSVGshape* shapes;			// Linked list of shapes in the image.
170
+} NSVGimage;
171
+
172
+// Parses SVG file from a file, returns SVG image as paths.
173
+NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
174
+
175
+// Parses SVG file from a null terminated string, returns SVG image as paths.
176
+// Important note: changes the string.
177
+NSVGimage* nsvgParse(char* input, const char* units, float dpi);
178
+
179
+// Duplicates a path.
180
+NSVGpath* nsvgDuplicatePath(NSVGpath* p);
181
+
182
+// Deletes an image.
183
+void nsvgDelete(NSVGimage* image);
184
+
185
+#ifndef NANOSVG_CPLUSPLUS
186
+#ifdef __cplusplus
187
+}
188
+#endif
189
+#endif
190
+
191
+#ifdef NANOSVG_IMPLEMENTATION
192
+
193
+#include <string.h>
194
+#include <stdlib.h>
195
+#include <stdio.h>
196
+#include <math.h>
197
+
198
+#define NSVG_PI (3.14159265358979323846264338327f)
199
+#define NSVG_KAPPA90 (0.5522847493f)	// Length proportional to radius of a cubic bezier handle for 90deg arcs.
200
+
201
+#define NSVG_ALIGN_MIN 0
202
+#define NSVG_ALIGN_MID 1
203
+#define NSVG_ALIGN_MAX 2
204
+#define NSVG_ALIGN_NONE 0
205
+#define NSVG_ALIGN_MEET 1
206
+#define NSVG_ALIGN_SLICE 2
207
+
208
+#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
209
+#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))
210
+
211
+#ifdef _MSC_VER
212
+	#pragma warning (disable: 4996) // Switch off security warnings
213
+	#pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
214
+	#ifdef __cplusplus
215
+	#define NSVG_INLINE inline
216
+	#else
217
+	#define NSVG_INLINE
218
+	#endif
219
+#else
220
+	#define NSVG_INLINE inline
221
+#endif
222
+
223
+
224
+static int nsvg__isspace(char c)
225
+{
226
+	return strchr(" \t\n\v\f\r", c) != 0;
227
+}
228
+
229
+static int nsvg__isdigit(char c)
230
+{
231
+	return c >= '0' && c <= '9';
232
+}
233
+
234
+static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
235
+static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
236
+
237
+
238
+// Simple XML parser
239
+
240
+#define NSVG_XML_TAG 1
241
+#define NSVG_XML_CONTENT 2
242
+#define NSVG_XML_MAX_ATTRIBS 256
243
+
244
+static void nsvg__parseContent(char* s,
245
+							   void (*contentCb)(void* ud, const char* s),
246
+							   void* ud)
247
+{
248
+	// Trim start white spaces
249
+	while (*s && nsvg__isspace(*s)) s++;
250
+	if (!*s) return;
251
+
252
+	if (contentCb)
253
+		(*contentCb)(ud, s);
254
+}
255
+
256
+static void nsvg__parseElement(char* s,
257
+							   void (*startelCb)(void* ud, const char* el, const char** attr),
258
+							   void (*endelCb)(void* ud, const char* el),
259
+							   void* ud)
260
+{
261
+	const char* attr[NSVG_XML_MAX_ATTRIBS];
262
+	int nattr = 0;
263
+	char* name;
264
+	int start = 0;
265
+	int end = 0;
266
+	char quote;
267
+
268
+	// Skip white space after the '<'
269
+	while (*s && nsvg__isspace(*s)) s++;
270
+
271
+	// Check if the tag is end tag
272
+	if (*s == '/') {
273
+		s++;
274
+		end = 1;
275
+	} else {
276
+		start = 1;
277
+	}
278
+
279
+	// Skip comments, data and preprocessor stuff.
280
+	if (!*s || *s == '?' || *s == '!')
281
+		return;
282
+
283
+	// Get tag name
284
+	name = s;
285
+	while (*s && !nsvg__isspace(*s)) s++;
286
+	if (*s) { *s++ = '\0'; }
287
+
288
+	// Get attribs
289
+	while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
290
+		char* name = NULL;
291
+		char* value = NULL;
292
+
293
+		// Skip white space before the attrib name
294
+		while (*s && nsvg__isspace(*s)) s++;
295
+		if (!*s) break;
296
+		if (*s == '/') {
297
+			end = 1;
298
+			break;
299
+		}
300
+		name = s;
301
+		// Find end of the attrib name.
302
+		while (*s && !nsvg__isspace(*s) && *s != '=') s++;
303
+		if (*s) { *s++ = '\0'; }
304
+		// Skip until the beginning of the value.
305
+		while (*s && *s != '\"' && *s != '\'') s++;
306
+		if (!*s) break;
307
+		quote = *s;
308
+		s++;
309
+		// Store value and find the end of it.
310
+		value = s;
311
+		while (*s && *s != quote) s++;
312
+		if (*s) { *s++ = '\0'; }
313
+
314
+		// Store only well formed attributes
315
+		if (name && value) {
316
+			attr[nattr++] = name;
317
+			attr[nattr++] = value;
318
+		}
319
+	}
320
+
321
+	// List terminator
322
+	attr[nattr++] = 0;
323
+	attr[nattr++] = 0;
324
+
325
+	// Call callbacks.
326
+	if (start && startelCb)
327
+		(*startelCb)(ud, name, attr);
328
+	if (end && endelCb)
329
+		(*endelCb)(ud, name);
330
+}
331
+
332
+int nsvg__parseXML(char* input,
333
+				   void (*startelCb)(void* ud, const char* el, const char** attr),
334
+				   void (*endelCb)(void* ud, const char* el),
335
+				   void (*contentCb)(void* ud, const char* s),
336
+				   void* ud)
337
+{
338
+	char* s = input;
339
+	char* mark = s;
340
+	int state = NSVG_XML_CONTENT;
341
+	while (*s) {
342
+		if (*s == '<' && state == NSVG_XML_CONTENT) {
343
+			// Start of a tag
344
+			*s++ = '\0';
345
+			nsvg__parseContent(mark, contentCb, ud);
346
+			mark = s;
347
+			state = NSVG_XML_TAG;
348
+		} else if (*s == '>' && state == NSVG_XML_TAG) {
349
+			// Start of a content or new tag.
350
+			*s++ = '\0';
351
+			nsvg__parseElement(mark, startelCb, endelCb, ud);
352
+			mark = s;
353
+			state = NSVG_XML_CONTENT;
354
+		} else {
355
+			s++;
356
+		}
357
+	}
358
+
359
+	return 1;
360
+}
361
+
362
+
363
+/* Simple SVG parser. */
364
+
365
+#define NSVG_MAX_ATTR 128
366
+
367
+enum NSVGgradientUnits {
368
+	NSVG_USER_SPACE = 0,
369
+	NSVG_OBJECT_SPACE = 1
370
+};
371
+
372
+#define NSVG_MAX_DASHES 8
373
+
374
+enum NSVGunits {
375
+	NSVG_UNITS_USER,
376
+	NSVG_UNITS_PX,
377
+	NSVG_UNITS_PT,
378
+	NSVG_UNITS_PC,
379
+	NSVG_UNITS_MM,
380
+	NSVG_UNITS_CM,
381
+	NSVG_UNITS_IN,
382
+	NSVG_UNITS_PERCENT,
383
+	NSVG_UNITS_EM,
384
+	NSVG_UNITS_EX
385
+};
386
+
387
+typedef struct NSVGcoordinate {
388
+	float value;
389
+	int units;
390
+} NSVGcoordinate;
391
+
392
+typedef struct NSVGlinearData {
393
+	NSVGcoordinate x1, y1, x2, y2;
394
+} NSVGlinearData;
395
+
396
+typedef struct NSVGradialData {
397
+	NSVGcoordinate cx, cy, r, fx, fy;
398
+} NSVGradialData;
399
+
400
+typedef struct NSVGgradientData
401
+{
402
+	char id[64];
403
+	char ref[64];
404
+	signed char type;
405
+	union {
406
+		NSVGlinearData linear;
407
+		NSVGradialData radial;
408
+	};
409
+	char spread;
410
+	char units;
411
+	float xform[6];
412
+	int nstops;
413
+	NSVGgradientStop* stops;
414
+	struct NSVGgradientData* next;
415
+} NSVGgradientData;
416
+
417
+typedef struct NSVGattrib
418
+{
419
+	char id[64];
420
+	float xform[6];
421
+	unsigned int fillColor;
422
+	unsigned int strokeColor;
423
+	float opacity;
424
+	float fillOpacity;
425
+	float strokeOpacity;
426
+	char fillGradient[64];
427
+	char strokeGradient[64];
428
+	float strokeWidth;
429
+	float strokeDashOffset;
430
+	float strokeDashArray[NSVG_MAX_DASHES];
431
+	int strokeDashCount;
432
+	char strokeLineJoin;
433
+	char strokeLineCap;
434
+	float miterLimit;
435
+	char fillRule;
436
+	float fontSize;
437
+	unsigned int stopColor;
438
+	float stopOpacity;
439
+	float stopOffset;
440
+	char hasFill;
441
+	char hasStroke;
442
+	char visible;
443
+} NSVGattrib;
444
+
445
+typedef struct NSVGparser
446
+{
447
+	NSVGattrib attr[NSVG_MAX_ATTR];
448
+	int attrHead;
449
+	float* pts;
450
+	int npts;
451
+	int cpts;
452
+	NSVGpath* plist;
453
+	NSVGimage* image;
454
+	NSVGgradientData* gradients;
455
+	NSVGshape* shapesTail;
456
+	float viewMinx, viewMiny, viewWidth, viewHeight;
457
+	int alignX, alignY, alignType;
458
+	float dpi;
459
+	char pathFlag;
460
+	char defsFlag;
461
+} NSVGparser;
462
+
463
+static void nsvg__xformIdentity(float* t)
464
+{
465
+	t[0] = 1.0f; t[1] = 0.0f;
466
+	t[2] = 0.0f; t[3] = 1.0f;
467
+	t[4] = 0.0f; t[5] = 0.0f;
468
+}
469
+
470
+static void nsvg__xformSetTranslation(float* t, float tx, float ty)
471
+{
472
+	t[0] = 1.0f; t[1] = 0.0f;
473
+	t[2] = 0.0f; t[3] = 1.0f;
474
+	t[4] = tx; t[5] = ty;
475
+}
476
+
477
+static void nsvg__xformSetScale(float* t, float sx, float sy)
478
+{
479
+	t[0] = sx; t[1] = 0.0f;
480
+	t[2] = 0.0f; t[3] = sy;
481
+	t[4] = 0.0f; t[5] = 0.0f;
482
+}
483
+
484
+static void nsvg__xformSetSkewX(float* t, float a)
485
+{
486
+	t[0] = 1.0f; t[1] = 0.0f;
487
+	t[2] = tanf(a); t[3] = 1.0f;
488
+	t[4] = 0.0f; t[5] = 0.0f;
489
+}
490
+
491
+static void nsvg__xformSetSkewY(float* t, float a)
492
+{
493
+	t[0] = 1.0f; t[1] = tanf(a);
494
+	t[2] = 0.0f; t[3] = 1.0f;
495
+	t[4] = 0.0f; t[5] = 0.0f;
496
+}
497
+
498
+static void nsvg__xformSetRotation(float* t, float a)
499
+{
500
+	float cs = cosf(a), sn = sinf(a);
501
+	t[0] = cs; t[1] = sn;
502
+	t[2] = -sn; t[3] = cs;
503
+	t[4] = 0.0f; t[5] = 0.0f;
504
+}
505
+
506
+static void nsvg__xformMultiply(float* t, float* s)
507
+{
508
+	float t0 = t[0] * s[0] + t[1] * s[2];
509
+	float t2 = t[2] * s[0] + t[3] * s[2];
510
+	float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
511
+	t[1] = t[0] * s[1] + t[1] * s[3];
512
+	t[3] = t[2] * s[1] + t[3] * s[3];
513
+	t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
514
+	t[0] = t0;
515
+	t[2] = t2;
516
+	t[4] = t4;
517
+}
518
+
519
+static void nsvg__xformInverse(float* inv, float* t)
520
+{
521
+	double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
522
+	if (det > -1e-6 && det < 1e-6) {
523
+		nsvg__xformIdentity(t);
524
+		return;
525
+	}
526
+	invdet = 1.0 / det;
527
+	inv[0] = (float)(t[3] * invdet);
528
+	inv[2] = (float)(-t[2] * invdet);
529
+	inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
530
+	inv[1] = (float)(-t[1] * invdet);
531
+	inv[3] = (float)(t[0] * invdet);
532
+	inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
533
+}
534
+
535
+static void nsvg__xformPremultiply(float* t, float* s)
536
+{
537
+	float s2[6];
538
+	memcpy(s2, s, sizeof(float)*6);
539
+	nsvg__xformMultiply(s2, t);
540
+	memcpy(t, s2, sizeof(float)*6);
541
+}
542
+
543
+static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)
544
+{
545
+	*dx = x*t[0] + y*t[2] + t[4];
546
+	*dy = x*t[1] + y*t[3] + t[5];
547
+}
548
+
549
+static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)
550
+{
551
+	*dx = x*t[0] + y*t[2];
552
+	*dy = x*t[1] + y*t[3];
553
+}
554
+
555
+#define NSVG_EPSILON (1e-12)
556
+
557
+static int nsvg__ptInBounds(float* pt, float* bounds)
558
+{
559
+	return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
560
+}
561
+
562
+
563
+static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
564
+{
565
+	double it = 1.0-t;
566
+	return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
567
+}
568
+
569
+static void nsvg__curveBounds(float* bounds, float* curve)
570
+{
571
+	int i, j, count;
572
+	double roots[2], a, b, c, b2ac, t, v;
573
+	float* v0 = &curve[0];
574
+	float* v1 = &curve[2];
575
+	float* v2 = &curve[4];
576
+	float* v3 = &curve[6];
577
+
578
+	// Start the bounding box by end points
579
+	bounds[0] = nsvg__minf(v0[0], v3[0]);
580
+	bounds[1] = nsvg__minf(v0[1], v3[1]);
581
+	bounds[2] = nsvg__maxf(v0[0], v3[0]);
582
+	bounds[3] = nsvg__maxf(v0[1], v3[1]);
583
+
584
+	// Bezier curve fits inside the convex hull of it's control points.
585
+	// If control points are inside the bounds, we're done.
586
+	if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
587
+		return;
588
+
589
+	// Add bezier curve inflection points in X and Y.
590
+	for (i = 0; i < 2; i++) {
591
+		a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
592
+		b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
593
+		c = 3.0 * v1[i] - 3.0 * v0[i];
594
+		count = 0;
595
+		if (fabs(a) < NSVG_EPSILON) {
596
+			if (fabs(b) > NSVG_EPSILON) {
597
+				t = -c / b;
598
+				if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
599
+					roots[count++] = t;
600
+			}
601
+		} else {
602
+			b2ac = b*b - 4.0*c*a;
603
+			if (b2ac > NSVG_EPSILON) {
604
+				t = (-b + sqrt(b2ac)) / (2.0 * a);
605
+				if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
606
+					roots[count++] = t;
607
+				t = (-b - sqrt(b2ac)) / (2.0 * a);
608
+				if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
609
+					roots[count++] = t;
610
+			}
611
+		}
612
+		for (j = 0; j < count; j++) {
613
+			v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);
614
+			bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);
615
+			bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);
616
+		}
617
+	}
618
+}
619
+
620
+static NSVGparser* nsvg__createParser(void)
621
+{
622
+	NSVGparser* p;
623
+	p = (NSVGparser*)malloc(sizeof(NSVGparser));
624
+	if (p == NULL) goto error;
625
+	memset(p, 0, sizeof(NSVGparser));
626
+
627
+	p->image = (NSVGimage*)malloc(sizeof(NSVGimage));
628
+	if (p->image == NULL) goto error;
629
+	memset(p->image, 0, sizeof(NSVGimage));
630
+
631
+	// Init style
632
+	nsvg__xformIdentity(p->attr[0].xform);
633
+	memset(p->attr[0].id, 0, sizeof p->attr[0].id);
634
+	p->attr[0].fillColor = NSVG_RGB(0,0,0);
635
+	p->attr[0].strokeColor = NSVG_RGB(0,0,0);
636
+	p->attr[0].opacity = 1;
637
+	p->attr[0].fillOpacity = 1;
638
+	p->attr[0].strokeOpacity = 1;
639
+	p->attr[0].stopOpacity = 1;
640
+	p->attr[0].strokeWidth = 1;
641
+	p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
642
+	p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
643
+	p->attr[0].miterLimit = 4;
644
+	p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
645
+	p->attr[0].hasFill = 1;
646
+	p->attr[0].visible = 1;
647
+
648
+	return p;
649
+
650
+error:
651
+	if (p) {
652
+		if (p->image) free(p->image);
653
+		free(p);
654
+	}
655
+	return NULL;
656
+}
657
+
658
+static void nsvg__deletePaths(NSVGpath* path)
659
+{
660
+	while (path) {
661
+		NSVGpath *next = path->next;
662
+		if (path->pts != NULL)
663
+			free(path->pts);
664
+		free(path);
665
+		path = next;
666
+	}
667
+}
668
+
669
+static void nsvg__deletePaint(NSVGpaint* paint)
670
+{
671
+	if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT)
672
+		free(paint->gradient);
673
+}
674
+
675
+static void nsvg__deleteGradientData(NSVGgradientData* grad)
676
+{
677
+	NSVGgradientData* next;
678
+	while (grad != NULL) {
679
+		next = grad->next;
680
+		free(grad->stops);
681
+		free(grad);
682
+		grad = next;
683
+	}
684
+}
685
+
686
+static void nsvg__deleteParser(NSVGparser* p)
687
+{
688
+	if (p != NULL) {
689
+		nsvg__deletePaths(p->plist);
690
+		nsvg__deleteGradientData(p->gradients);
691
+		nsvgDelete(p->image);
692
+		free(p->pts);
693
+		free(p);
694
+	}
695
+}
696
+
697
+static void nsvg__resetPath(NSVGparser* p)
698
+{
699
+	p->npts = 0;
700
+}
701
+
702
+static void nsvg__addPoint(NSVGparser* p, float x, float y)
703
+{
704
+	if (p->npts+1 > p->cpts) {
705
+		p->cpts = p->cpts ? p->cpts*2 : 8;
706
+		p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));
707
+		if (!p->pts) return;
708
+	}
709
+	p->pts[p->npts*2+0] = x;
710
+	p->pts[p->npts*2+1] = y;
711
+	p->npts++;
712
+}
713
+
714
+static void nsvg__moveTo(NSVGparser* p, float x, float y)
715
+{
716
+	if (p->npts > 0) {
717
+		p->pts[(p->npts-1)*2+0] = x;
718
+		p->pts[(p->npts-1)*2+1] = y;
719
+	} else {
720
+		nsvg__addPoint(p, x, y);
721
+	}
722
+}
723
+
724
+static void nsvg__lineTo(NSVGparser* p, float x, float y)
725
+{
726
+	float px,py, dx,dy;
727
+	if (p->npts > 0) {
728
+		px = p->pts[(p->npts-1)*2+0];
729
+		py = p->pts[(p->npts-1)*2+1];
730
+		dx = x - px;
731
+		dy = y - py;
732
+		nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);
733
+		nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);
734
+		nsvg__addPoint(p, x, y);
735
+	}
736
+}
737
+
738
+static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
739
+{
740
+	if (p->npts > 0) {
741
+		nsvg__addPoint(p, cpx1, cpy1);
742
+		nsvg__addPoint(p, cpx2, cpy2);
743
+		nsvg__addPoint(p, x, y);
744
+	}
745
+}
746
+
747
+static NSVGattrib* nsvg__getAttr(NSVGparser* p)
748
+{
749
+	return &p->attr[p->attrHead];
750
+}
751
+
752
+static void nsvg__pushAttr(NSVGparser* p)
753
+{
754
+	if (p->attrHead < NSVG_MAX_ATTR-1) {
755
+		p->attrHead++;
756
+		memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib));
757
+	}
758
+}
759
+
760
+static void nsvg__popAttr(NSVGparser* p)
761
+{
762
+	if (p->attrHead > 0)
763
+		p->attrHead--;
764
+}
765
+
766
+static float nsvg__actualOrigX(NSVGparser* p)
767
+{
768
+	return p->viewMinx;
769
+}
770
+
771
+static float nsvg__actualOrigY(NSVGparser* p)
772
+{
773
+	return p->viewMiny;
774
+}
775
+
776
+static float nsvg__actualWidth(NSVGparser* p)
777
+{
778
+	return p->viewWidth;
779
+}
780
+
781
+static float nsvg__actualHeight(NSVGparser* p)
782
+{
783
+	return p->viewHeight;
784
+}
785
+
786
+static float nsvg__actualLength(NSVGparser* p)
787
+{
788
+	float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);
789
+	return sqrtf(w*w + h*h) / sqrtf(2.0f);
790
+}
791
+
792
+static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)
793
+{
794
+	NSVGattrib* attr = nsvg__getAttr(p);
795
+	switch (c.units) {
796
+		case NSVG_UNITS_USER:		return c.value;
797
+		case NSVG_UNITS_PX:			return c.value;
798
+		case NSVG_UNITS_PT:			return c.value / 72.0f * p->dpi;
799
+		case NSVG_UNITS_PC:			return c.value / 6.0f * p->dpi;
800
+		case NSVG_UNITS_MM:			return c.value / 25.4f * p->dpi;
801
+		case NSVG_UNITS_CM:			return c.value / 2.54f * p->dpi;
802
+		case NSVG_UNITS_IN:			return c.value * p->dpi;
803
+		case NSVG_UNITS_EM:			return c.value * attr->fontSize;
804
+		case NSVG_UNITS_EX:			return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
805
+		case NSVG_UNITS_PERCENT:	return orig + c.value / 100.0f * length;
806
+		default:					return c.value;
807
+	}
808
+	return c.value;
809
+}
810
+
811
+static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
812
+{
813
+	NSVGgradientData* grad = p->gradients;
814
+	if (id == NULL || *id == '\0')
815
+		return NULL;
816
+	while (grad != NULL) {
817
+		if (strcmp(grad->id, id) == 0)
818
+			return grad;
819
+		grad = grad->next;
820
+	}
821
+	return NULL;
822
+}
823
+
824
+static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, float *xform, signed char* paintType)
825
+{
826
+	NSVGgradientData* data = NULL;
827
+	NSVGgradientData* ref = NULL;
828
+	NSVGgradientStop* stops = NULL;
829
+	NSVGgradient* grad;
830
+	float ox, oy, sw, sh, sl;
831
+	int nstops = 0;
832
+	int refIter;
833
+
834
+	data = nsvg__findGradientData(p, id);
835
+	if (data == NULL) return NULL;
836
+
837
+	// TODO: use ref to fill in all unset values too.
838
+	ref = data;
839
+	refIter = 0;
840
+	while (ref != NULL) {
841
+		NSVGgradientData* nextRef = NULL;
842
+		if (stops == NULL && ref->stops != NULL) {
843
+			stops = ref->stops;
844
+			nstops = ref->nstops;
845
+			break;
846
+		}
847
+		nextRef = nsvg__findGradientData(p, ref->ref);
848
+		if (nextRef == ref) break; // prevent infite loops on malformed data
849
+		ref = nextRef;
850
+		refIter++;
851
+		if (refIter > 32) break; // prevent infite loops on malformed data
852
+	}
853
+	if (stops == NULL) return NULL;
854
+
855
+	grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1));
856
+	if (grad == NULL) return NULL;
857
+
858
+	// The shape width and height.
859
+	if (data->units == NSVG_OBJECT_SPACE) {
860
+		ox = localBounds[0];
861
+		oy = localBounds[1];
862
+		sw = localBounds[2] - localBounds[0];
863
+		sh = localBounds[3] - localBounds[1];
864
+	} else {
865
+		ox = nsvg__actualOrigX(p);
866
+		oy = nsvg__actualOrigY(p);
867
+		sw = nsvg__actualWidth(p);
868
+		sh = nsvg__actualHeight(p);
869
+	}
870
+	sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);
871
+
872
+	if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {
873
+		float x1, y1, x2, y2, dx, dy;
874
+		x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);
875
+		y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);
876
+		x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);
877
+		y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);
878
+		// Calculate transform aligned to the line
879
+		dx = x2 - x1;
880
+		dy = y2 - y1;
881
+		grad->xform[0] = dy; grad->xform[1] = -dx;
882
+		grad->xform[2] = dx; grad->xform[3] = dy;
883
+		grad->xform[4] = x1; grad->xform[5] = y1;
884
+	} else {
885
+		float cx, cy, fx, fy, r;
886
+		cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);
887
+		cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);
888
+		fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);
889
+		fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);
890
+		r = nsvg__convertToPixels(p, data->radial.r, 0, sl);
891
+		// Calculate transform aligned to the circle
892
+		grad->xform[0] = r; grad->xform[1] = 0;
893
+		grad->xform[2] = 0; grad->xform[3] = r;
894
+		grad->xform[4] = cx; grad->xform[5] = cy;
895
+		grad->fx = fx / r;
896
+		grad->fy = fy / r;
897
+	}
898
+
899
+	nsvg__xformMultiply(grad->xform, data->xform);
900
+	nsvg__xformMultiply(grad->xform, xform);
901
+
902
+	grad->spread = data->spread;
903
+	memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
904
+	grad->nstops = nstops;
905
+
906
+	*paintType = data->type;
907
+
908
+	return grad;
909
+}
910
+
911
+static float nsvg__getAverageScale(float* t)
912
+{
913
+	float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
914
+	float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
915
+	return (sx + sy) * 0.5f;
916
+}
917
+
918
+static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
919
+{
920
+	NSVGpath* path;
921
+	float curve[4*2], curveBounds[4];
922
+	int i, first = 1;
923
+	for (path = shape->paths; path != NULL; path = path->next) {
924
+		nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform);
925
+		for (i = 0; i < path->npts-1; i += 3) {
926
+			nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);
927
+			nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);
928
+			nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);
929
+			nsvg__curveBounds(curveBounds, curve);
930
+			if (first) {
931
+				bounds[0] = curveBounds[0];
932
+				bounds[1] = curveBounds[1];
933
+				bounds[2] = curveBounds[2];
934
+				bounds[3] = curveBounds[3];
935
+				first = 0;
936
+			} else {
937
+				bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
938
+				bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
939
+				bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
940
+				bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
941
+			}
942
+			curve[0] = curve[6];
943
+			curve[1] = curve[7];
944
+		}
945
+	}
946
+}
947
+
948
+static void nsvg__addShape(NSVGparser* p)
949
+{
950
+	NSVGattrib* attr = nsvg__getAttr(p);
951
+	float scale = 1.0f;
952
+	NSVGshape* shape;
953
+	NSVGpath* path;
954
+	int i;
955
+
956
+	if (p->plist == NULL)
957
+		return;
958
+
959
+	shape = (NSVGshape*)malloc(sizeof(NSVGshape));
960
+	if (shape == NULL) goto error;
961
+	memset(shape, 0, sizeof(NSVGshape));
962
+
963
+	memcpy(shape->id, attr->id, sizeof shape->id);
964
+	memcpy(shape->fillGradient, attr->fillGradient, sizeof shape->fillGradient);
965
+	memcpy(shape->strokeGradient, attr->strokeGradient, sizeof shape->strokeGradient);
966
+	memcpy(shape->xform, attr->xform, sizeof shape->xform);
967
+	scale = nsvg__getAverageScale(attr->xform);
968
+	shape->strokeWidth = attr->strokeWidth * scale;
969
+	shape->strokeDashOffset = attr->strokeDashOffset * scale;
970
+	shape->strokeDashCount = (char)attr->strokeDashCount;
971
+	for (i = 0; i < attr->strokeDashCount; i++)
972
+		shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
973
+	shape->strokeLineJoin = attr->strokeLineJoin;
974
+	shape->strokeLineCap = attr->strokeLineCap;
975
+	shape->miterLimit = attr->miterLimit;
976
+	shape->fillRule = attr->fillRule;
977
+	shape->opacity = attr->opacity;
978
+
979
+	shape->paths = p->plist;
980
+	p->plist = NULL;
981
+
982
+	// Calculate shape bounds
983
+	shape->bounds[0] = shape->paths->bounds[0];
984
+	shape->bounds[1] = shape->paths->bounds[1];
985
+	shape->bounds[2] = shape->paths->bounds[2];
986
+	shape->bounds[3] = shape->paths->bounds[3];
987
+	for (path = shape->paths->next; path != NULL; path = path->next) {
988
+		shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);
989
+		shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);
990
+		shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);
991
+		shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);
992
+	}
993
+
994
+	// Set fill
995
+	if (attr->hasFill == 0) {
996
+		shape->fill.type = NSVG_PAINT_NONE;
997
+	} else if (attr->hasFill == 1) {
998
+		shape->fill.type = NSVG_PAINT_COLOR;
999
+		shape->fill.color = attr->fillColor;
1000
+		shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;
1001
+	} else if (attr->hasFill == 2) {
1002
+		shape->fill.type = NSVG_PAINT_UNDEF;
1003
+	}
1004
+
1005
+	// Set stroke
1006
+	if (attr->hasStroke == 0) {
1007
+		shape->stroke.type = NSVG_PAINT_NONE;
1008
+	} else if (attr->hasStroke == 1) {
1009
+		shape->stroke.type = NSVG_PAINT_COLOR;
1010
+		shape->stroke.color = attr->strokeColor;
1011
+		shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;
1012
+	} else if (attr->hasStroke == 2) {
1013
+		shape->stroke.type = NSVG_PAINT_UNDEF;
1014
+	}
1015
+
1016
+	// Set flags
1017
+	shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
1018
+
1019
+	// Add to tail
1020
+	if (p->image->shapes == NULL)
1021
+		p->image->shapes = shape;
1022
+	else
1023
+		p->shapesTail->next = shape;
1024
+	p->shapesTail = shape;
1025
+
1026
+	return;
1027
+
1028
+error:
1029
+	if (shape) free(shape);
1030
+}
1031
+
1032
+static void nsvg__addPath(NSVGparser* p, char closed)
1033
+{
1034
+	NSVGattrib* attr = nsvg__getAttr(p);
1035
+	NSVGpath* path = NULL;
1036
+	float bounds[4];
1037
+	float* curve;
1038
+	int i;
1039
+
1040
+	if (p->npts < 4)
1041
+		return;
1042
+
1043
+	if (closed)
1044
+		nsvg__lineTo(p, p->pts[0], p->pts[1]);
1045
+
1046
+	// Expect 1 + N*3 points (N = number of cubic bezier segments).
1047
+	if ((p->npts % 3) != 1)
1048
+		return;
1049
+
1050
+	path = (NSVGpath*)malloc(sizeof(NSVGpath));
1051
+	if (path == NULL) goto error;
1052
+	memset(path, 0, sizeof(NSVGpath));
1053
+
1054
+	path->pts = (float*)malloc(p->npts*2*sizeof(float));
1055
+	if (path->pts == NULL) goto error;
1056
+	path->closed = closed;
1057
+	path->npts = p->npts;
1058
+
1059
+	// Transform path.
1060
+	for (i = 0; i < p->npts; ++i)
1061
+		nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform);
1062
+
1063
+	// Find bounds
1064
+	for (i = 0; i < path->npts-1; i += 3) {
1065
+		curve = &path->pts[i*2];
1066
+		nsvg__curveBounds(bounds, curve);
1067
+		if (i == 0) {
1068
+			path->bounds[0] = bounds[0];
1069
+			path->bounds[1] = bounds[1];
1070
+			path->bounds[2] = bounds[2];
1071
+			path->bounds[3] = bounds[3];
1072
+		} else {
1073
+			path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]);
1074
+			path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]);
1075
+			path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]);
1076
+			path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]);
1077
+		}
1078
+	}
1079
+
1080
+	path->next = p->plist;
1081
+	p->plist = path;
1082
+
1083
+	return;
1084
+
1085
+error:
1086
+	if (path != NULL) {
1087
+		if (path->pts != NULL) free(path->pts);
1088
+		free(path);
1089
+	}
1090
+}
1091
+
1092
+// We roll our own string to float because the std library one uses locale and messes things up.
1093
+static double nsvg__atof(const char* s)
1094
+{
1095
+	char* cur = (char*)s;
1096
+	char* end = NULL;
1097
+	double res = 0.0, sign = 1.0;
1098
+	double intPart = 0.0, fracPart = 0.0;
1099
+	char hasIntPart = 0, hasFracPart = 0;
1100
+
1101
+	// Parse optional sign
1102
+	if (*cur == '+') {
1103
+		cur++;
1104
+	} else if (*cur == '-') {
1105
+		sign = -1;
1106
+		cur++;
1107
+	}
1108
+
1109
+	// Parse integer part
1110
+	if (nsvg__isdigit(*cur)) {
1111
+		// Parse digit sequence
1112
+#ifdef _MSC_VER
1113
+		intPart = (double)_strtoi64(cur, &end, 10);
1114
+#else
1115
+		intPart = (double)strtoll(cur, &end, 10);
1116
+#endif
1117
+		if (cur != end) {
1118
+			res = intPart;
1119
+			hasIntPart = 1;
1120
+			cur = end;
1121
+		}
1122
+	}
1123
+
1124
+	// Parse fractional part.
1125
+	if (*cur == '.') {
1126
+		cur++; // Skip '.'
1127
+		if (nsvg__isdigit(*cur)) {
1128
+			// Parse digit sequence
1129
+#ifdef _MSC_VER
1130
+			fracPart = (double)_strtoi64(cur, &end, 10);
1131
+#else
1132
+			fracPart = (double)strtoll(cur, &end, 10);
1133
+#endif
1134
+			if (cur != end) {
1135
+				res += fracPart / pow(10.0, (double)(end - cur));
1136
+				hasFracPart = 1;
1137
+				cur = end;
1138
+			}
1139
+		}
1140
+	}
1141
+
1142
+	// A valid number should have integer or fractional part.
1143
+	if (!hasIntPart && !hasFracPart)
1144
+		return 0.0;
1145
+
1146
+	// Parse optional exponent
1147
+	if (*cur == 'e' || *cur == 'E') {
1148
+		double expPart = 0.0;
1149
+		cur++; // skip 'E'
1150
+		expPart = (double)strtol(cur, &end, 10); // Parse digit sequence with sign
1151
+		if (cur != end) {
1152
+			res *= pow(10.0, expPart);
1153
+		}
1154
+	}
1155
+
1156
+	return res * sign;
1157
+}
1158
+
1159
+
1160
+static const char* nsvg__parseNumber(const char* s, char* it, const int size)
1161
+{
1162
+	const int last = size-1;
1163
+	int i = 0;
1164
+
1165
+	// sign
1166
+	if (*s == '-' || *s == '+') {
1167
+		if (i < last) it[i++] = *s;
1168
+		s++;
1169
+	}
1170
+	// integer part
1171
+	while (*s && nsvg__isdigit(*s)) {
1172
+		if (i < last) it[i++] = *s;
1173
+		s++;
1174
+	}
1175
+	if (*s == '.') {
1176
+		// decimal point
1177
+		if (i < last) it[i++] = *s;
1178
+		s++;
1179
+		// fraction part
1180
+		while (*s && nsvg__isdigit(*s)) {
1181
+			if (i < last) it[i++] = *s;
1182
+			s++;
1183
+		}
1184
+	}
1185
+	// exponent
1186
+	if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
1187
+		if (i < last) it[i++] = *s;
1188
+		s++;
1189
+		if (*s == '-' || *s == '+') {
1190
+			if (i < last) it[i++] = *s;
1191
+			s++;
1192
+		}
1193
+		while (*s && nsvg__isdigit(*s)) {
1194
+			if (i < last) it[i++] = *s;
1195
+			s++;
1196
+		}
1197
+	}
1198
+	it[i] = '\0';
1199
+
1200
+	return s;
1201
+}
1202
+
1203
+static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it)
1204
+{
1205
+	it[0] = '\0';
1206
+	while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
1207
+	if (!*s) return s;
1208
+	if (*s == '0' || *s == '1') {
1209
+		it[0] = *s++;
1210
+		it[1] = '\0';
1211
+		return s;
1212
+	}
1213
+	return s;
1214
+}
1215
+
1216
+static const char* nsvg__getNextPathItem(const char* s, char* it)
1217
+{
1218
+	it[0] = '\0';
1219
+	// Skip white spaces and commas
1220
+	while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
1221
+	if (!*s) return s;
1222
+	if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
1223
+		s = nsvg__parseNumber(s, it, 64);
1224
+	} else {
1225
+		// Parse command
1226
+		it[0] = *s++;
1227
+		it[1] = '\0';
1228
+		return s;
1229
+	}
1230
+
1231
+	return s;
1232
+}
1233
+
1234
+static unsigned int nsvg__parseColorHex(const char* str)
1235
+{
1236
+	unsigned int r=0, g=0, b=0;
1237
+	if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 )		// 2 digit hex
1238
+		return NSVG_RGB(r, g, b);
1239
+	if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 )		// 1 digit hex, e.g. #abc -> 0xccbbaa
1240
+		return NSVG_RGB(r*17, g*17, b*17);			// same effect as (r<<4|r), (g<<4|g), ..
1241
+	return NSVG_RGB(128, 128, 128);
1242
+}
1243
+
1244
+// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters).
1245
+// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors
1246
+// for backwards compatibility. Note: other image viewers return black instead.
1247
+
1248
+static unsigned int nsvg__parseColorRGB(const char* str)
1249
+{
1250
+	int i;
1251
+	unsigned int rgbi[3];
1252
+	float rgbf[3];
1253
+	// try decimal integers first
1254
+	if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) {
1255
+		// integers failed, try percent values (float, locale independent)
1256
+		const char delimiter[3] = {',', ',', ')'};
1257
+		str += 4; // skip "rgb("
1258
+		for (i = 0; i < 3; i++) {
1259
+			while (*str && (nsvg__isspace(*str))) str++; 	// skip leading spaces
1260
+			if (*str == '+') str++;				// skip '+' (don't allow '-')
1261
+			if (!*str) break;
1262
+			rgbf[i] = nsvg__atof(str);
1263
+
1264
+			// Note 1: it would be great if nsvg__atof() returned how many
1265
+			// bytes it consumed but it doesn't. We need to skip the number,
1266
+			// the '%' character, spaces, and the delimiter ',' or ')'.
1267
+
1268
+			// Note 2: The following code does not allow values like "33.%",
1269
+			// i.e. a decimal point w/o fractional part, but this is consistent
1270
+			// with other image viewers, e.g. firefox, chrome, eog, gimp.
1271
+
1272
+			while (*str && nsvg__isdigit(*str)) str++;		// skip integer part
1273
+			if (*str == '.') {
1274
+				str++;
1275
+				if (!nsvg__isdigit(*str)) break;		// error: no digit after '.'
1276
+				while (*str && nsvg__isdigit(*str)) str++;	// skip fractional part
1277
+			}
1278
+			if (*str == '%') str++; else break;
1279
+			while (nsvg__isspace(*str)) str++;
1280
+			if (*str == delimiter[i]) str++;
1281
+			else break;
1282
+		}
1283
+		if (i == 3) {
1284
+			rgbi[0] = roundf(rgbf[0] * 2.55f);
1285
+			rgbi[1] = roundf(rgbf[1] * 2.55f);
1286
+			rgbi[2] = roundf(rgbf[2] * 2.55f);
1287
+		} else {
1288
+			rgbi[0] = rgbi[1] = rgbi[2] = 128;
1289
+		}
1290
+	}
1291
+	// clip values as the CSS spec requires
1292
+	for (i = 0; i < 3; i++) {
1293
+		if (rgbi[i] > 255) rgbi[i] = 255;
1294
+	}
1295
+	return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]);
1296
+}
1297
+
1298
+typedef struct NSVGNamedColor {
1299
+	const char* name;
1300
+	unsigned int color;
1301
+} NSVGNamedColor;
1302
+
1303
+NSVGNamedColor nsvg__colors[] = {
1304
+
1305
+	{ "red", NSVG_RGB(255, 0, 0) },
1306
+	{ "green", NSVG_RGB( 0, 128, 0) },
1307
+	{ "blue", NSVG_RGB( 0, 0, 255) },
1308
+	{ "yellow", NSVG_RGB(255, 255, 0) },
1309
+	{ "cyan", NSVG_RGB( 0, 255, 255) },
1310
+	{ "magenta", NSVG_RGB(255, 0, 255) },
1311
+	{ "black", NSVG_RGB( 0, 0, 0) },
1312
+	{ "grey", NSVG_RGB(128, 128, 128) },
1313
+	{ "gray", NSVG_RGB(128, 128, 128) },
1314
+	{ "white", NSVG_RGB(255, 255, 255) },
1315
+
1316
+#ifdef NANOSVG_ALL_COLOR_KEYWORDS
1317
+	{ "aliceblue", NSVG_RGB(240, 248, 255) },
1318
+	{ "antiquewhite", NSVG_RGB(250, 235, 215) },
1319
+	{ "aqua", NSVG_RGB( 0, 255, 255) },
1320
+	{ "aquamarine", NSVG_RGB(127, 255, 212) },
1321
+	{ "azure", NSVG_RGB(240, 255, 255) },
1322
+	{ "beige", NSVG_RGB(245, 245, 220) },
1323
+	{ "bisque", NSVG_RGB(255, 228, 196) },
1324
+	{ "blanchedalmond", NSVG_RGB(255, 235, 205) },
1325
+	{ "blueviolet", NSVG_RGB(138, 43, 226) },
1326
+	{ "brown", NSVG_RGB(165, 42, 42) },
1327
+	{ "burlywood", NSVG_RGB(222, 184, 135) },
1328
+	{ "cadetblue", NSVG_RGB( 95, 158, 160) },
1329
+	{ "chartreuse", NSVG_RGB(127, 255, 0) },
1330
+	{ "chocolate", NSVG_RGB(210, 105, 30) },
1331
+	{ "coral", NSVG_RGB(255, 127, 80) },
1332
+	{ "cornflowerblue", NSVG_RGB(100, 149, 237) },
1333
+	{ "cornsilk", NSVG_RGB(255, 248, 220) },
1334
+	{ "crimson", NSVG_RGB(220, 20, 60) },
1335
+	{ "darkblue", NSVG_RGB( 0, 0, 139) },
1336
+	{ "darkcyan", NSVG_RGB( 0, 139, 139) },
1337
+	{ "darkgoldenrod", NSVG_RGB(184, 134, 11) },
1338
+	{ "darkgray", NSVG_RGB(169, 169, 169) },
1339
+	{ "darkgreen", NSVG_RGB( 0, 100, 0) },
1340
+	{ "darkgrey", NSVG_RGB(169, 169, 169) },
1341
+	{ "darkkhaki", NSVG_RGB(189, 183, 107) },
1342
+	{ "darkmagenta", NSVG_RGB(139, 0, 139) },
1343
+	{ "darkolivegreen", NSVG_RGB( 85, 107, 47) },
1344
+	{ "darkorange", NSVG_RGB(255, 140, 0) },
1345
+	{ "darkorchid", NSVG_RGB(153, 50, 204) },
1346
+	{ "darkred", NSVG_RGB(139, 0, 0) },
1347
+	{ "darksalmon", NSVG_RGB(233, 150, 122) },
1348
+	{ "darkseagreen", NSVG_RGB(143, 188, 143) },
1349
+	{ "darkslateblue", NSVG_RGB( 72, 61, 139) },
1350
+	{ "darkslategray", NSVG_RGB( 47, 79, 79) },
1351
+	{ "darkslategrey", NSVG_RGB( 47, 79, 79) },
1352
+	{ "darkturquoise", NSVG_RGB( 0, 206, 209) },
1353
+	{ "darkviolet", NSVG_RGB(148, 0, 211) },
1354
+	{ "deeppink", NSVG_RGB(255, 20, 147) },
1355
+	{ "deepskyblue", NSVG_RGB( 0, 191, 255) },
1356
+	{ "dimgray", NSVG_RGB(105, 105, 105) },
1357
+	{ "dimgrey", NSVG_RGB(105, 105, 105) },
1358
+	{ "dodgerblue", NSVG_RGB( 30, 144, 255) },
1359
+	{ "firebrick", NSVG_RGB(178, 34, 34) },
1360
+	{ "floralwhite", NSVG_RGB(255, 250, 240) },
1361
+	{ "forestgreen", NSVG_RGB( 34, 139, 34) },
1362
+	{ "fuchsia", NSVG_RGB(255, 0, 255) },
1363
+	{ "gainsboro", NSVG_RGB(220, 220, 220) },
1364
+	{ "ghostwhite", NSVG_RGB(248, 248, 255) },
1365
+	{ "gold", NSVG_RGB(255, 215, 0) },
1366
+	{ "goldenrod", NSVG_RGB(218, 165, 32) },
1367
+	{ "greenyellow", NSVG_RGB(173, 255, 47) },
1368
+	{ "honeydew", NSVG_RGB(240, 255, 240) },
1369
+	{ "hotpink", NSVG_RGB(255, 105, 180) },
1370
+	{ "indianred", NSVG_RGB(205, 92, 92) },
1371
+	{ "indigo", NSVG_RGB( 75, 0, 130) },
1372
+	{ "ivory", NSVG_RGB(255, 255, 240) },
1373
+	{ "khaki", NSVG_RGB(240, 230, 140) },
1374
+	{ "lavender", NSVG_RGB(230, 230, 250) },
1375
+	{ "lavenderblush", NSVG_RGB(255, 240, 245) },
1376
+	{ "lawngreen", NSVG_RGB(124, 252, 0) },
1377
+	{ "lemonchiffon", NSVG_RGB(255, 250, 205) },
1378
+	{ "lightblue", NSVG_RGB(173, 216, 230) },
1379
+	{ "lightcoral", NSVG_RGB(240, 128, 128) },
1380
+	{ "lightcyan", NSVG_RGB(224, 255, 255) },
1381
+	{ "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
1382
+	{ "lightgray", NSVG_RGB(211, 211, 211) },
1383
+	{ "lightgreen", NSVG_RGB(144, 238, 144) },
1384
+	{ "lightgrey", NSVG_RGB(211, 211, 211) },
1385
+	{ "lightpink", NSVG_RGB(255, 182, 193) },
1386
+	{ "lightsalmon", NSVG_RGB(255, 160, 122) },
1387
+	{ "lightseagreen", NSVG_RGB( 32, 178, 170) },
1388
+	{ "lightskyblue", NSVG_RGB(135, 206, 250) },
1389
+	{ "lightslategray", NSVG_RGB(119, 136, 153) },
1390
+	{ "lightslategrey", NSVG_RGB(119, 136, 153) },
1391
+	{ "lightsteelblue", NSVG_RGB(176, 196, 222) },
1392
+	{ "lightyellow", NSVG_RGB(255, 255, 224) },
1393
+	{ "lime", NSVG_RGB( 0, 255, 0) },
1394
+	{ "limegreen", NSVG_RGB( 50, 205, 50) },
1395
+	{ "linen", NSVG_RGB(250, 240, 230) },
1396
+	{ "maroon", NSVG_RGB(128, 0, 0) },
1397
+	{ "mediumaquamarine", NSVG_RGB(102, 205, 170) },
1398
+	{ "mediumblue", NSVG_RGB( 0, 0, 205) },
1399
+	{ "mediumorchid", NSVG_RGB(186, 85, 211) },
1400
+	{ "mediumpurple", NSVG_RGB(147, 112, 219) },
1401
+	{ "mediumseagreen", NSVG_RGB( 60, 179, 113) },
1402
+	{ "mediumslateblue", NSVG_RGB(123, 104, 238) },
1403
+	{ "mediumspringgreen", NSVG_RGB( 0, 250, 154) },
1404
+	{ "mediumturquoise", NSVG_RGB( 72, 209, 204) },
1405
+	{ "mediumvioletred", NSVG_RGB(199, 21, 133) },
1406
+	{ "midnightblue", NSVG_RGB( 25, 25, 112) },
1407
+	{ "mintcream", NSVG_RGB(245, 255, 250) },
1408
+	{ "mistyrose", NSVG_RGB(255, 228, 225) },
1409
+	{ "moccasin", NSVG_RGB(255, 228, 181) },
1410
+	{ "navajowhite", NSVG_RGB(255, 222, 173) },
1411
+	{ "navy", NSVG_RGB( 0, 0, 128) },
1412
+	{ "oldlace", NSVG_RGB(253, 245, 230) },
1413
+	{ "olive", NSVG_RGB(128, 128, 0) },
1414
+	{ "olivedrab", NSVG_RGB(107, 142, 35) },
1415
+	{ "orange", NSVG_RGB(255, 165, 0) },
1416
+	{ "orangered", NSVG_RGB(255, 69, 0) },
1417
+	{ "orchid", NSVG_RGB(218, 112, 214) },
1418
+	{ "palegoldenrod", NSVG_RGB(238, 232, 170) },
1419
+	{ "palegreen", NSVG_RGB(152, 251, 152) },
1420
+	{ "paleturquoise", NSVG_RGB(175, 238, 238) },
1421
+	{ "palevioletred", NSVG_RGB(219, 112, 147) },
1422
+	{ "papayawhip", NSVG_RGB(255, 239, 213) },
1423
+	{ "peachpuff", NSVG_RGB(255, 218, 185) },
1424
+	{ "peru", NSVG_RGB(205, 133, 63) },
1425
+	{ "pink", NSVG_RGB(255, 192, 203) },
1426
+	{ "plum", NSVG_RGB(221, 160, 221) },
1427
+	{ "powderblue", NSVG_RGB(176, 224, 230) },
1428
+	{ "purple", NSVG_RGB(128, 0, 128) },
1429
+	{ "rosybrown", NSVG_RGB(188, 143, 143) },
1430
+	{ "royalblue", NSVG_RGB( 65, 105, 225) },
1431
+	{ "saddlebrown", NSVG_RGB(139, 69, 19) },
1432
+	{ "salmon", NSVG_RGB(250, 128, 114) },
1433
+	{ "sandybrown", NSVG_RGB(244, 164, 96) },
1434
+	{ "seagreen", NSVG_RGB( 46, 139, 87) },
1435
+	{ "seashell", NSVG_RGB(255, 245, 238) },
1436
+	{ "sienna", NSVG_RGB(160, 82, 45) },
1437
+	{ "silver", NSVG_RGB(192, 192, 192) },
1438
+	{ "skyblue", NSVG_RGB(135, 206, 235) },
1439
+	{ "slateblue", NSVG_RGB(106, 90, 205) },
1440
+	{ "slategray", NSVG_RGB(112, 128, 144) },
1441
+	{ "slategrey", NSVG_RGB(112, 128, 144) },
1442
+	{ "snow", NSVG_RGB(255, 250, 250) },
1443
+	{ "springgreen", NSVG_RGB( 0, 255, 127) },
1444
+	{ "steelblue", NSVG_RGB( 70, 130, 180) },
1445
+	{ "tan", NSVG_RGB(210, 180, 140) },
1446
+	{ "teal", NSVG_RGB( 0, 128, 128) },
1447
+	{ "thistle", NSVG_RGB(216, 191, 216) },
1448
+	{ "tomato", NSVG_RGB(255, 99, 71) },
1449
+	{ "turquoise", NSVG_RGB( 64, 224, 208) },
1450
+	{ "violet", NSVG_RGB(238, 130, 238) },
1451
+	{ "wheat", NSVG_RGB(245, 222, 179) },
1452
+	{ "whitesmoke", NSVG_RGB(245, 245, 245) },
1453
+	{ "yellowgreen", NSVG_RGB(154, 205, 50) },
1454
+#endif
1455
+};
1456
+
1457
+static unsigned int nsvg__parseColorName(const char* str)
1458
+{
1459
+	int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
1460
+
1461
+	for (i = 0; i < ncolors; i++) {
1462
+		if (strcmp(nsvg__colors[i].name, str) == 0) {
1463
+			return nsvg__colors[i].color;
1464
+		}
1465
+	}
1466
+
1467
+	return NSVG_RGB(128, 128, 128);
1468
+}
1469
+
1470
+static unsigned int nsvg__parseColor(const char* str)
1471
+{
1472
+	size_t len = 0;
1473
+	while(*str == ' ') ++str;
1474
+	len = strlen(str);
1475
+	if (len >= 1 && *str == '#')
1476
+		return nsvg__parseColorHex(str);
1477
+	else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(')
1478
+		return nsvg__parseColorRGB(str);
1479
+	return nsvg__parseColorName(str);
1480
+}
1481
+
1482
+static float nsvg__parseOpacity(const char* str)
1483
+{
1484
+	float val = nsvg__atof(str);
1485
+	if (val < 0.0f) val = 0.0f;
1486
+	if (val > 1.0f) val = 1.0f;
1487
+	return val;
1488
+}
1489
+
1490
+static float nsvg__parseMiterLimit(const char* str)
1491
+{
1492
+	float val = nsvg__atof(str);
1493
+	if (val < 0.0f) val = 0.0f;
1494
+	return val;
1495
+}
1496
+
1497
+static int nsvg__parseUnits(const char* units)
1498
+{
1499
+	if (units[0] == 'p' && units[1] == 'x')
1500
+		return NSVG_UNITS_PX;
1501
+	else if (units[0] == 'p' && units[1] == 't')
1502
+		return NSVG_UNITS_PT;
1503
+	else if (units[0] == 'p' && units[1] == 'c')
1504
+		return NSVG_UNITS_PC;
1505
+	else if (units[0] == 'm' && units[1] == 'm')
1506
+		return NSVG_UNITS_MM;
1507
+	else if (units[0] == 'c' && units[1] == 'm')
1508
+		return NSVG_UNITS_CM;
1509
+	else if (units[0] == 'i' && units[1] == 'n')
1510
+		return NSVG_UNITS_IN;
1511
+	else if (units[0] == '%')
1512
+		return NSVG_UNITS_PERCENT;
1513
+	else if (units[0] == 'e' && units[1] == 'm')
1514
+		return NSVG_UNITS_EM;
1515
+	else if (units[0] == 'e' && units[1] == 'x')
1516
+		return NSVG_UNITS_EX;
1517
+	return NSVG_UNITS_USER;
1518
+}
1519
+
1520
+static int nsvg__isCoordinate(const char* s)
1521
+{
1522
+	// optional sign
1523
+	if (*s == '-' || *s == '+')
1524
+		s++;
1525
+	// must have at least one digit, or start by a dot
1526
+	return (nsvg__isdigit(*s) || *s == '.');
1527
+}
1528
+
1529
+static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
1530
+{
1531
+	NSVGcoordinate coord = {0, NSVG_UNITS_USER};
1532
+	char buf[64];
1533
+	coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
1534
+	coord.value = nsvg__atof(buf);
1535
+	return coord;
1536
+}
1537
+
1538
+static NSVGcoordinate nsvg__coord(float v, int units)
1539
+{
1540
+	NSVGcoordinate coord = {v, units};
1541
+	return coord;
1542
+}
1543
+
1544
+static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length)
1545
+{
1546
+	NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);
1547
+	return nsvg__convertToPixels(p, coord, orig, length);
1548
+}
1549
+
1550
+static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na)
1551
+{
1552
+	const char* end;
1553
+	const char* ptr;
1554
+	char it[64];
1555
+
1556
+	*na = 0;
1557
+	ptr = str;
1558
+	while (*ptr && *ptr != '(') ++ptr;
1559
+	if (*ptr == 0)
1560
+		return 1;
1561
+	end = ptr;
1562
+	while (*end && *end != ')') ++end;
1563
+	if (*end == 0)
1564
+		return 1;
1565
+
1566
+	while (ptr < end) {
1567
+		if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
1568
+			if (*na >= maxNa) return 0;
1569
+			ptr = nsvg__parseNumber(ptr, it, 64);
1570
+			args[(*na)++] = (float)nsvg__atof(it);
1571
+		} else {
1572
+			++ptr;
1573
+		}
1574
+	}
1575
+	return (int)(end - str);
1576
+}
1577
+
1578
+
1579
+static int nsvg__parseMatrix(float* xform, const char* str)
1580
+{
1581
+	float t[6];
1582
+	int na = 0;
1583
+	int len = nsvg__parseTransformArgs(str, t, 6, &na);
1584
+	if (na != 6) return len;
1585
+	memcpy(xform, t, sizeof(float)*6);
1586
+	return len;
1587
+}
1588
+
1589
+static int nsvg__parseTranslate(float* xform, const char* str)
1590
+{
1591
+	float args[2];
1592
+	float t[6];
1593
+	int na = 0;
1594
+	int len = nsvg__parseTransformArgs(str, args, 2, &na);
1595
+	if (na == 1) args[1] = 0.0;
1596
+
1597
+	nsvg__xformSetTranslation(t, args[0], args[1]);
1598
+	memcpy(xform, t, sizeof(float)*6);
1599
+	return len;
1600
+}
1601
+
1602
+static int nsvg__parseScale(float* xform, const char* str)
1603
+{
1604
+	float args[2];
1605
+	int na = 0;
1606
+	float t[6];
1607
+	int len = nsvg__parseTransformArgs(str, args, 2, &na);
1608
+	if (na == 1) args[1] = args[0];
1609
+	nsvg__xformSetScale(t, args[0], args[1]);
1610
+	memcpy(xform, t, sizeof(float)*6);
1611
+	return len;
1612
+}
1613
+
1614
+static int nsvg__parseSkewX(float* xform, const char* str)
1615
+{
1616
+	float args[1];
1617
+	int na = 0;
1618
+	float t[6];
1619
+	int len = nsvg__parseTransformArgs(str, args, 1, &na);
1620
+	nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);
1621
+	memcpy(xform, t, sizeof(float)*6);
1622
+	return len;
1623
+}
1624
+
1625
+static int nsvg__parseSkewY(float* xform, const char* str)
1626
+{
1627
+	float args[1];
1628
+	int na = 0;
1629
+	float t[6];
1630
+	int len = nsvg__parseTransformArgs(str, args, 1, &na);
1631
+	nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);
1632
+	memcpy(xform, t, sizeof(float)*6);
1633
+	return len;
1634
+}
1635
+
1636
+static int nsvg__parseRotate(float* xform, const char* str)
1637
+{
1638
+	float args[3];
1639
+	int na = 0;
1640
+	float m[6];
1641
+	float t[6];
1642
+	int len = nsvg__parseTransformArgs(str, args, 3, &na);
1643
+	if (na == 1)
1644
+		args[1] = args[2] = 0.0f;
1645
+	nsvg__xformIdentity(m);
1646
+
1647
+	if (na > 1) {
1648
+		nsvg__xformSetTranslation(t, -args[1], -args[2]);
1649
+		nsvg__xformMultiply(m, t);
1650
+	}
1651
+
1652
+	nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);
1653
+	nsvg__xformMultiply(m, t);
1654
+
1655
+	if (na > 1) {
1656
+		nsvg__xformSetTranslation(t, args[1], args[2]);
1657
+		nsvg__xformMultiply(m, t);
1658
+	}
1659
+
1660
+	memcpy(xform, m, sizeof(float)*6);
1661
+
1662
+	return len;
1663
+}
1664
+
1665
+static void nsvg__parseTransform(float* xform, const char* str)
1666
+{
1667
+	float t[6];
1668
+	int len;
1669
+	nsvg__xformIdentity(xform);
1670
+	while (*str)
1671
+	{
1672
+		if (strncmp(str, "matrix", 6) == 0)
1673
+			len = nsvg__parseMatrix(t, str);
1674
+		else if (strncmp(str, "translate", 9) == 0)
1675
+			len = nsvg__parseTranslate(t, str);
1676
+		else if (strncmp(str, "scale", 5) == 0)
1677
+			len = nsvg__parseScale(t, str);
1678
+		else if (strncmp(str, "rotate", 6) == 0)
1679
+			len = nsvg__parseRotate(t, str);
1680
+		else if (strncmp(str, "skewX", 5) == 0)
1681
+			len = nsvg__parseSkewX(t, str);
1682
+		else if (strncmp(str, "skewY", 5) == 0)
1683
+			len = nsvg__parseSkewY(t, str);
1684
+		else{
1685
+			++str;
1686
+			continue;
1687
+		}
1688
+		if (len != 0) {
1689
+			str += len;
1690
+		} else {
1691
+			++str;
1692
+			continue;
1693
+		}
1694
+
1695
+		nsvg__xformPremultiply(xform, t);
1696
+	}
1697
+}
1698
+
1699
+static void nsvg__parseUrl(char* id, const char* str)
1700
+{
1701
+	int i = 0;
1702
+	str += 4; // "url(";
1703
+	if (*str && *str == '#')
1704
+		str++;
1705
+	while (i < 63 && *str && *str != ')') {
1706
+		id[i] = *str++;
1707
+		i++;
1708
+	}
1709
+	id[i] = '\0';
1710
+}
1711
+
1712
+static char nsvg__parseLineCap(const char* str)
1713
+{
1714
+	if (strcmp(str, "butt") == 0)
1715
+		return NSVG_CAP_BUTT;
1716
+	else if (strcmp(str, "round") == 0)
1717
+		return NSVG_CAP_ROUND;
1718
+	else if (strcmp(str, "square") == 0)
1719
+		return NSVG_CAP_SQUARE;
1720
+	// TODO: handle inherit.
1721
+	return NSVG_CAP_BUTT;
1722
+}
1723
+
1724
+static char nsvg__parseLineJoin(const char* str)
1725
+{
1726
+	if (strcmp(str, "miter") == 0)
1727
+		return NSVG_JOIN_MITER;
1728
+	else if (strcmp(str, "round") == 0)
1729
+		return NSVG_JOIN_ROUND;
1730
+	else if (strcmp(str, "bevel") == 0)
1731
+		return NSVG_JOIN_BEVEL;
1732
+	// TODO: handle inherit.
1733
+	return NSVG_JOIN_MITER;
1734
+}
1735
+
1736
+static char nsvg__parseFillRule(const char* str)
1737
+{
1738
+	if (strcmp(str, "nonzero") == 0)
1739
+		return NSVG_FILLRULE_NONZERO;
1740
+	else if (strcmp(str, "evenodd") == 0)
1741
+		return NSVG_FILLRULE_EVENODD;
1742
+	// TODO: handle inherit.
1743
+	return NSVG_FILLRULE_NONZERO;
1744
+}
1745
+
1746
+static const char* nsvg__getNextDashItem(const char* s, char* it)
1747
+{
1748
+	int n = 0;
1749
+	it[0] = '\0';
1750
+	// Skip white spaces and commas
1751
+	while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
1752
+	// Advance until whitespace, comma or end.
1753
+	while (*s && (!nsvg__isspace(*s) && *s != ',')) {
1754
+		if (n < 63)
1755
+			it[n++] = *s;
1756
+		s++;
1757
+	}
1758
+	it[n++] = '\0';
1759
+	return s;
1760
+}
1761
+
1762
+static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray)
1763
+{
1764
+	char item[64];
1765
+	int count = 0, i;
1766
+	float sum = 0.0f;
1767
+
1768
+	// Handle "none"
1769
+	if (str[0] == 'n')
1770
+		return 0;
1771
+
1772
+	// Parse dashes
1773
+	while (*str) {
1774
+		str = nsvg__getNextDashItem(str, item);
1775
+		if (!*item) break;
1776
+		if (count < NSVG_MAX_DASHES)
1777
+			strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));
1778
+	}
1779
+
1780
+	for (i = 0; i < count; i++)
1781
+		sum += strokeDashArray[i];
1782
+	if (sum <= 1e-6f)
1783
+		count = 0;
1784
+
1785
+	return count;
1786
+}
1787
+
1788
+static void nsvg__parseStyle(NSVGparser* p, const char* str);
1789
+
1790
+static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
1791
+{
1792
+	float xform[6];
1793
+	NSVGattrib* attr = nsvg__getAttr(p);
1794
+	if (!attr) return 0;
1795
+
1796
+	if (strcmp(name, "style") == 0) {
1797
+		nsvg__parseStyle(p, value);
1798
+	} else if (strcmp(name, "display") == 0) {
1799
+		if (strcmp(value, "none") == 0)
1800
+			attr->visible = 0;
1801
+		// Don't reset ->visible on display:inline, one display:none hides the whole subtree
1802
+
1803
+	} else if (strcmp(name, "fill") == 0) {
1804
+		if (strcmp(value, "none") == 0) {
1805
+			attr->hasFill = 0;
1806
+		} else if (strncmp(value, "url(", 4) == 0) {
1807
+			attr->hasFill = 2;
1808
+			nsvg__parseUrl(attr->fillGradient, value);
1809
+		} else {
1810
+			attr->hasFill = 1;
1811
+			attr->fillColor = nsvg__parseColor(value);
1812
+		}
1813
+	} else if (strcmp(name, "opacity") == 0) {
1814
+		attr->opacity = nsvg__parseOpacity(value);
1815
+	} else if (strcmp(name, "fill-opacity") == 0) {
1816
+		attr->fillOpacity = nsvg__parseOpacity(value);
1817
+	} else if (strcmp(name, "stroke") == 0) {
1818
+		if (strcmp(value, "none") == 0) {
1819
+			attr->hasStroke = 0;
1820
+		} else if (strncmp(value, "url(", 4) == 0) {
1821
+			attr->hasStroke = 2;
1822
+			nsvg__parseUrl(attr->strokeGradient, value);
1823
+		} else {
1824
+			attr->hasStroke = 1;
1825
+			attr->strokeColor = nsvg__parseColor(value);
1826
+		}
1827
+	} else if (strcmp(name, "stroke-width") == 0) {
1828
+		attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
1829
+	} else if (strcmp(name, "stroke-dasharray") == 0) {
1830
+		attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray);
1831
+	} else if (strcmp(name, "stroke-dashoffset") == 0) {
1832
+		attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
1833
+	} else if (strcmp(name, "stroke-opacity") == 0) {
1834
+		attr->strokeOpacity = nsvg__parseOpacity(value);
1835
+	} else if (strcmp(name, "stroke-linecap") == 0) {
1836
+		attr->strokeLineCap = nsvg__parseLineCap(value);
1837
+	} else if (strcmp(name, "stroke-linejoin") == 0) {
1838
+		attr->strokeLineJoin = nsvg__parseLineJoin(value);
1839
+	} else if (strcmp(name, "stroke-miterlimit") == 0) {
1840
+		attr->miterLimit = nsvg__parseMiterLimit(value);
1841
+	} else if (strcmp(name, "fill-rule") == 0) {
1842
+		attr->fillRule = nsvg__parseFillRule(value);
1843
+	} else if (strcmp(name, "font-size") == 0) {
1844
+		attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
1845
+	} else if (strcmp(name, "transform") == 0) {
1846
+		nsvg__parseTransform(xform, value);
1847
+		nsvg__xformPremultiply(attr->xform, xform);
1848
+	} else if (strcmp(name, "stop-color") == 0) {
1849
+		attr->stopColor = nsvg__parseColor(value);
1850
+	} else if (strcmp(name, "stop-opacity") == 0) {
1851
+		attr->stopOpacity = nsvg__parseOpacity(value);
1852
+	} else if (strcmp(name, "offset") == 0) {
1853
+		attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
1854
+	} else if (strcmp(name, "id") == 0) {
1855
+		strncpy(attr->id, value, 63);
1856
+		attr->id[63] = '\0';
1857
+	} else {
1858
+		return 0;
1859
+	}
1860
+	return 1;
1861
+}
1862
+
1863
+static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end)
1864
+{
1865
+	const char* str;
1866
+	const char* val;
1867
+	char name[512];
1868
+	char value[512];
1869
+	int n;
1870
+
1871
+	str = start;
1872
+	while (str < end && *str != ':') ++str;
1873
+
1874
+	val = str;
1875
+
1876
+	// Right Trim
1877
+	while (str > start &&  (*str == ':' || nsvg__isspace(*str))) --str;
1878
+	++str;
1879
+
1880
+	n = (int)(str - start);
1881
+	if (n > 511) n = 511;
1882
+	if (n) memcpy(name, start, n);
1883
+	name[n] = 0;
1884
+
1885
+	while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
1886
+
1887
+	n = (int)(end - val);
1888
+	if (n > 511) n = 511;
1889
+	if (n) memcpy(value, val, n);
1890
+	value[n] = 0;
1891
+
1892
+	return nsvg__parseAttr(p, name, value);
1893
+}
1894
+
1895
+static void nsvg__parseStyle(NSVGparser* p, const char* str)
1896
+{
1897
+	const char* start;
1898
+	const char* end;
1899
+
1900
+	while (*str) {
1901
+		// Left Trim
1902
+		while(*str && nsvg__isspace(*str)) ++str;
1903
+		start = str;
1904
+		while(*str && *str != ';') ++str;
1905
+		end = str;
1906
+
1907
+		// Right Trim
1908
+		while (end > start &&  (*end == ';' || nsvg__isspace(*end))) --end;
1909
+		++end;
1910
+
1911
+		nsvg__parseNameValue(p, start, end);
1912
+		if (*str) ++str;
1913
+	}
1914
+}
1915
+
1916
+static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
1917
+{
1918
+	int i;
1919
+	for (i = 0; attr[i]; i += 2)
1920
+	{
1921
+		if (strcmp(attr[i], "style") == 0)
1922
+			nsvg__parseStyle(p, attr[i + 1]);
1923
+		else
1924
+			nsvg__parseAttr(p, attr[i], attr[i + 1]);
1925
+	}
1926
+}
1927
+
1928
+static int nsvg__getArgsPerElement(char cmd)
1929
+{
1930
+	switch (cmd) {
1931
+		case 'v':
1932
+		case 'V':
1933
+		case 'h':
1934
+		case 'H':
1935
+			return 1;
1936
+		case 'm':
1937
+		case 'M':
1938
+		case 'l':
1939
+		case 'L':
1940
+		case 't':
1941
+		case 'T':
1942
+			return 2;
1943
+		case 'q':
1944
+		case 'Q':
1945
+		case 's':
1946
+		case 'S':
1947
+			return 4;
1948
+		case 'c':
1949
+		case 'C':
1950
+			return 6;
1951
+		case 'a':
1952
+		case 'A':
1953
+			return 7;
1954
+		case 'z':
1955
+		case 'Z':
1956
+			return 0;
1957
+	}
1958
+	return -1;
1959
+}
1960
+
1961
+static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
1962
+{
1963
+	if (rel) {
1964
+		*cpx += args[0];
1965
+		*cpy += args[1];
1966
+	} else {
1967
+		*cpx = args[0];
1968
+		*cpy = args[1];
1969
+	}
1970
+	nsvg__moveTo(p, *cpx, *cpy);
1971
+}
1972
+
1973
+static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
1974
+{
1975
+	if (rel) {
1976
+		*cpx += args[0];
1977
+		*cpy += args[1];
1978
+	} else {
1979
+		*cpx = args[0];
1980
+		*cpy = args[1];
1981
+	}
1982
+	nsvg__lineTo(p, *cpx, *cpy);
1983
+}
1984
+
1985
+static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
1986
+{
1987
+	if (rel)
1988
+		*cpx += args[0];
1989
+	else
1990
+		*cpx = args[0];
1991
+	nsvg__lineTo(p, *cpx, *cpy);
1992
+}
1993
+
1994
+static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
1995
+{
1996
+	if (rel)
1997
+		*cpy += args[0];
1998
+	else
1999
+		*cpy = args[0];
2000
+	nsvg__lineTo(p, *cpx, *cpy);
2001
+}
2002
+
2003
+static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
2004
+								 float* cpx2, float* cpy2, float* args, int rel)
2005
+{
2006
+	float x2, y2, cx1, cy1, cx2, cy2;
2007
+
2008
+	if (rel) {
2009
+		cx1 = *cpx + args[0];
2010
+		cy1 = *cpy + args[1];
2011
+		cx2 = *cpx + args[2];
2012
+		cy2 = *cpy + args[3];
2013
+		x2 = *cpx + args[4];
2014
+		y2 = *cpy + args[5];
2015
+	} else {
2016
+		cx1 = args[0];
2017
+		cy1 = args[1];
2018
+		cx2 = args[2];
2019
+		cy2 = args[3];
2020
+		x2 = args[4];
2021
+		y2 = args[5];
2022
+	}
2023
+
2024
+	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
2025
+
2026
+	*cpx2 = cx2;
2027
+	*cpy2 = cy2;
2028
+	*cpx = x2;
2029
+	*cpy = y2;
2030
+}
2031
+
2032
+static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,
2033
+									  float* cpx2, float* cpy2, float* args, int rel)
2034
+{
2035
+	float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
2036
+
2037
+	x1 = *cpx;
2038
+	y1 = *cpy;
2039
+	if (rel) {
2040
+		cx2 = *cpx + args[0];
2041
+		cy2 = *cpy + args[1];
2042
+		x2 = *cpx + args[2];
2043
+		y2 = *cpy + args[3];
2044
+	} else {
2045
+		cx2 = args[0];
2046
+		cy2 = args[1];
2047
+		x2 = args[2];
2048
+		y2 = args[3];
2049
+	}
2050
+
2051
+	cx1 = 2*x1 - *cpx2;
2052
+	cy1 = 2*y1 - *cpy2;
2053
+
2054
+	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
2055
+
2056
+	*cpx2 = cx2;
2057
+	*cpy2 = cy2;
2058
+	*cpx = x2;
2059
+	*cpy = y2;
2060
+}
2061
+
2062
+static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
2063
+								float* cpx2, float* cpy2, float* args, int rel)
2064
+{
2065
+	float x1, y1, x2, y2, cx, cy;
2066
+	float cx1, cy1, cx2, cy2;
2067
+
2068
+	x1 = *cpx;
2069
+	y1 = *cpy;
2070
+	if (rel) {
2071
+		cx = *cpx + args[0];
2072
+		cy = *cpy + args[1];
2073
+		x2 = *cpx + args[2];
2074
+		y2 = *cpy + args[3];
2075
+	} else {
2076
+		cx = args[0];
2077
+		cy = args[1];
2078
+		x2 = args[2];
2079
+		y2 = args[3];
2080
+	}
2081
+
2082
+	// Convert to cubic bezier
2083
+	cx1 = x1 + 2.0f/3.0f*(cx - x1);
2084
+	cy1 = y1 + 2.0f/3.0f*(cy - y1);
2085
+	cx2 = x2 + 2.0f/3.0f*(cx - x2);
2086
+	cy2 = y2 + 2.0f/3.0f*(cy - y2);
2087
+
2088
+	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
2089
+
2090
+	*cpx2 = cx;
2091
+	*cpy2 = cy;
2092
+	*cpx = x2;
2093
+	*cpy = y2;
2094
+}
2095
+
2096
+static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
2097
+									 float* cpx2, float* cpy2, float* args, int rel)
2098
+{
2099
+	float x1, y1, x2, y2, cx, cy;
2100
+	float cx1, cy1, cx2, cy2;
2101
+
2102
+	x1 = *cpx;
2103
+	y1 = *cpy;
2104
+	if (rel) {
2105
+		x2 = *cpx + args[0];
2106
+		y2 = *cpy + args[1];
2107
+	} else {
2108
+		x2 = args[0];
2109
+		y2 = args[1];
2110
+	}
2111
+
2112
+	cx = 2*x1 - *cpx2;
2113
+	cy = 2*y1 - *cpy2;
2114
+
2115
+	// Convert to cubix bezier
2116
+	cx1 = x1 + 2.0f/3.0f*(cx - x1);
2117
+	cy1 = y1 + 2.0f/3.0f*(cy - y1);
2118
+	cx2 = x2 + 2.0f/3.0f*(cx - x2);
2119
+	cy2 = y2 + 2.0f/3.0f*(cy - y2);
2120
+
2121
+	nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
2122
+
2123
+	*cpx2 = cx;
2124
+	*cpy2 = cy;
2125
+	*cpx = x2;
2126
+	*cpy = y2;
2127
+}
2128
+
2129
+static float nsvg__sqr(float x) { return x*x; }
2130
+static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
2131
+
2132
+static float nsvg__vecrat(float ux, float uy, float vx, float vy)
2133
+{
2134
+	return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
2135
+}
2136
+
2137
+static float nsvg__vecang(float ux, float uy, float vx, float vy)
2138
+{
2139
+	float r = nsvg__vecrat(ux,uy, vx,vy);
2140
+	if (r < -1.0f) r = -1.0f;
2141
+	if (r > 1.0f) r = 1.0f;
2142
+	return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);
2143
+}
2144
+
2145
+static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
2146
+{
2147
+	// Ported from canvg (https://code.google.com/p/canvg/)
2148
+	float rx, ry, rotx;
2149
+	float x1, y1, x2, y2, cx, cy, dx, dy, d;
2150
+	float x1p, y1p, cxp, cyp, s, sa, sb;
2151
+	float ux, uy, vx, vy, a1, da;
2152
+	float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
2153
+	float sinrx, cosrx;
2154
+	int fa, fs;
2155
+	int i, ndivs;
2156
+	float hda, kappa;
2157
+
2158
+	rx = fabsf(args[0]);				// y radius
2159
+	ry = fabsf(args[1]);				// x radius
2160
+	rotx = args[2] / 180.0f * NSVG_PI;		// x rotation angle
2161
+	fa = fabsf(args[3]) > 1e-6 ? 1 : 0;	// Large arc
2162
+	fs = fabsf(args[4]) > 1e-6 ? 1 : 0;	// Sweep direction
2163
+	x1 = *cpx;							// start point
2164
+	y1 = *cpy;
2165
+	if (rel) {							// end point
2166
+		x2 = *cpx + args[5];
2167
+		y2 = *cpy + args[6];
2168
+	} else {
2169
+		x2 = args[5];
2170
+		y2 = args[6];
2171
+	}
2172
+
2173
+	dx = x1 - x2;
2174
+	dy = y1 - y2;
2175
+	d = sqrtf(dx*dx + dy*dy);
2176
+	if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
2177
+		// The arc degenerates to a line
2178
+		nsvg__lineTo(p, x2, y2);
2179
+		*cpx = x2;
2180
+		*cpy = y2;
2181
+		return;
2182
+	}
2183
+
2184
+	sinrx = sinf(rotx);
2185
+	cosrx = cosf(rotx);
2186
+
2187
+	// Convert to center point parameterization.
2188
+	// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
2189
+	// 1) Compute x1', y1'
2190
+	x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
2191
+	y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
2192
+	d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
2193
+	if (d > 1) {
2194
+		d = sqrtf(d);
2195
+		rx *= d;
2196
+		ry *= d;
2197
+	}
2198
+	// 2) Compute cx', cy'
2199
+	s = 0.0f;
2200
+	sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);
2201
+	sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
2202
+	if (sa < 0.0f) sa = 0.0f;
2203
+	if (sb > 0.0f)
2204
+		s = sqrtf(sa / sb);
2205
+	if (fa == fs)
2206
+		s = -s;
2207
+	cxp = s * rx * y1p / ry;
2208
+	cyp = s * -ry * x1p / rx;
2209
+
2210
+	// 3) Compute cx,cy from cx',cy'
2211
+	cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;
2212
+	cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;
2213
+
2214
+	// 4) Calculate theta1, and delta theta.
2215
+	ux = (x1p - cxp) / rx;
2216
+	uy = (y1p - cyp) / ry;
2217
+	vx = (-x1p - cxp) / rx;
2218
+	vy = (-y1p - cyp) / ry;
2219
+	a1 = nsvg__vecang(1.0f,0.0f, ux,uy);	// Initial angle
2220
+	da = nsvg__vecang(ux,uy, vx,vy);		// Delta angle
2221
+
2222
+//	if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
2223
+//	if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
2224
+
2225
+	if (fs == 0 && da > 0)
2226
+		da -= 2 * NSVG_PI;
2227
+	else if (fs == 1 && da < 0)
2228
+		da += 2 * NSVG_PI;
2229
+
2230
+	// Approximate the arc using cubic spline segments.
2231
+	t[0] = cosrx; t[1] = sinrx;
2232
+	t[2] = -sinrx; t[3] = cosrx;
2233
+	t[4] = cx; t[5] = cy;
2234
+
2235
+	// Split arc into max 90 degree segments.
2236
+	// The loop assumes an iteration per end point (including start and end), this +1.
2237
+	ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
2238
+	hda = (da / (float)ndivs) / 2.0f;
2239
+	// Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite)
2240
+	if ((hda < 1e-3f) && (hda > -1e-3f))
2241
+		hda *= 0.5f;
2242
+	else
2243
+		hda = (1.0f - cosf(hda)) / sinf(hda);
2244
+	kappa = fabsf(4.0f / 3.0f * hda);
2245
+	if (da < 0.0f)
2246
+		kappa = -kappa;
2247
+
2248
+	for (i = 0; i <= ndivs; i++) {
2249
+		a = a1 + da * ((float)i/(float)ndivs);
2250
+		dx = cosf(a);
2251
+		dy = sinf(a);
2252
+		nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
2253
+		nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent
2254
+		if (i > 0)
2255
+			nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y);
2256
+		px = x;
2257
+		py = y;
2258
+		ptanx = tanx;
2259
+		ptany = tany;
2260
+	}
2261
+
2262
+	*cpx = x2;
2263
+	*cpy = y2;
2264
+}
2265
+
2266
+static void nsvg__parsePath(NSVGparser* p, const char** attr)
2267
+{
2268
+	const char* s = NULL;
2269
+	char cmd = '\0';
2270
+	float args[10];
2271
+	int nargs;
2272
+	int rargs = 0;
2273
+	char initPoint;
2274
+	float cpx, cpy, cpx2, cpy2;
2275
+	const char* tmp[4];
2276
+	char closedFlag;
2277
+	int i;
2278
+	char item[64];
2279
+
2280
+	for (i = 0; attr[i]; i += 2) {
2281
+		if (strcmp(attr[i], "d") == 0) {
2282
+			s = attr[i + 1];
2283
+		} else {
2284
+			tmp[0] = attr[i];
2285
+			tmp[1] = attr[i + 1];
2286
+			tmp[2] = 0;
2287
+			tmp[3] = 0;
2288
+			nsvg__parseAttribs(p, tmp);
2289
+		}
2290
+	}
2291
+
2292
+	if (s) {
2293
+		nsvg__resetPath(p);
2294
+		cpx = 0; cpy = 0;
2295
+		cpx2 = 0; cpy2 = 0;
2296
+		initPoint = 0;
2297
+		closedFlag = 0;
2298
+		nargs = 0;
2299
+
2300
+		while (*s) {
2301
+			item[0] = '\0';
2302
+			if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4))
2303
+				s = nsvg__getNextPathItemWhenArcFlag(s, item);
2304
+			if (!*item)
2305
+				s = nsvg__getNextPathItem(s, item);
2306
+			if (!*item) break;
2307
+			if (cmd != '\0' && nsvg__isCoordinate(item)) {
2308
+				if (nargs < 10)
2309
+					args[nargs++] = (float)nsvg__atof(item);
2310
+				if (nargs >= rargs) {
2311
+					switch (cmd) {
2312
+						case 'm':
2313
+						case 'M':
2314
+							nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
2315
+							// Moveto can be followed by multiple coordinate pairs,
2316
+							// which should be treated as linetos.
2317
+							cmd = (cmd == 'm') ? 'l' : 'L';
2318
+							rargs = nsvg__getArgsPerElement(cmd);
2319
+							cpx2 = cpx; cpy2 = cpy;
2320
+							initPoint = 1;
2321
+							break;
2322
+						case 'l':
2323
+						case 'L':
2324
+							nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
2325
+							cpx2 = cpx; cpy2 = cpy;
2326
+							break;
2327
+						case 'H':
2328
+						case 'h':
2329
+							nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
2330
+							cpx2 = cpx; cpy2 = cpy;
2331
+							break;
2332
+						case 'V':
2333
+						case 'v':
2334
+							nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
2335
+							cpx2 = cpx; cpy2 = cpy;
2336
+							break;
2337
+						case 'C':
2338
+						case 'c':
2339
+							nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
2340
+							break;
2341
+						case 'S':
2342
+						case 's':
2343
+							nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
2344
+							break;
2345
+						case 'Q':
2346
+						case 'q':
2347
+							nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
2348
+							break;
2349
+						case 'T':
2350
+						case 't':
2351
+							nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);
2352
+							break;
2353
+						case 'A':
2354
+						case 'a':
2355
+							nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
2356
+							cpx2 = cpx; cpy2 = cpy;
2357
+							break;
2358
+						default:
2359
+							if (nargs >= 2) {
2360
+								cpx = args[nargs-2];
2361
+								cpy = args[nargs-1];
2362
+								cpx2 = cpx; cpy2 = cpy;
2363
+							}
2364
+							break;
2365
+					}
2366
+					nargs = 0;
2367
+				}
2368
+			} else {
2369
+				cmd = item[0];
2370
+				if (cmd == 'M' || cmd == 'm') {
2371
+					// Commit path.
2372
+					if (p->npts > 0)
2373
+						nsvg__addPath(p, closedFlag);
2374
+					// Start new subpath.
2375
+					nsvg__resetPath(p);
2376
+					closedFlag = 0;
2377
+					nargs = 0;
2378
+				} else if (initPoint == 0) {
2379
+					// Do not allow other commands until initial point has been set (moveTo called once).
2380
+					cmd = '\0';
2381
+				}
2382
+				if (cmd == 'Z' || cmd == 'z') {
2383
+					closedFlag = 1;
2384
+					// Commit path.
2385
+					if (p->npts > 0) {
2386
+						// Move current point to first point
2387
+						cpx = p->pts[0];
2388
+						cpy = p->pts[1];
2389
+						cpx2 = cpx; cpy2 = cpy;
2390
+						nsvg__addPath(p, closedFlag);
2391
+					}
2392
+					// Start new subpath.
2393
+					nsvg__resetPath(p);
2394
+					nsvg__moveTo(p, cpx, cpy);
2395
+					closedFlag = 0;
2396
+					nargs = 0;
2397
+				}
2398
+				rargs = nsvg__getArgsPerElement(cmd);
2399
+				if (rargs == -1) {
2400
+					// Command not recognized
2401
+					cmd = '\0';
2402
+					rargs = 0;
2403
+				}
2404
+			}
2405
+		}
2406
+		// Commit path.
2407
+		if (p->npts)
2408
+			nsvg__addPath(p, closedFlag);
2409
+	}
2410
+
2411
+	nsvg__addShape(p);
2412
+}
2413
+
2414
+static void nsvg__parseRect(NSVGparser* p, const char** attr)
2415
+{
2416
+	float x = 0.0f;
2417
+	float y = 0.0f;
2418
+	float w = 0.0f;
2419
+	float h = 0.0f;
2420
+	float rx = -1.0f; // marks not set
2421
+	float ry = -1.0f;
2422
+	int i;
2423
+
2424
+	for (i = 0; attr[i]; i += 2) {
2425
+		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
2426
+			if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
2427
+			if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
2428
+			if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));
2429
+			if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));
2430
+			if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
2431
+			if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
2432
+		}
2433
+	}
2434
+
2435
+	if (rx < 0.0f && ry > 0.0f) rx = ry;
2436
+	if (ry < 0.0f && rx > 0.0f) ry = rx;
2437
+	if (rx < 0.0f) rx = 0.0f;
2438
+	if (ry < 0.0f) ry = 0.0f;
2439
+	if (rx > w/2.0f) rx = w/2.0f;
2440
+	if (ry > h/2.0f) ry = h/2.0f;
2441
+
2442
+	if (w != 0.0f && h != 0.0f) {
2443
+		nsvg__resetPath(p);
2444
+
2445
+		if (rx < 0.00001f || ry < 0.0001f) {
2446
+			nsvg__moveTo(p, x, y);
2447
+			nsvg__lineTo(p, x+w, y);
2448
+			nsvg__lineTo(p, x+w, y+h);
2449
+			nsvg__lineTo(p, x, y+h);
2450
+		} else {
2451
+			// Rounded rectangle
2452
+			nsvg__moveTo(p, x+rx, y);
2453
+			nsvg__lineTo(p, x+w-rx, y);
2454
+			nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry);
2455
+			nsvg__lineTo(p, x+w, y+h-ry);
2456
+			nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);
2457
+			nsvg__lineTo(p, x+rx, y+h);
2458
+			nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);
2459
+			nsvg__lineTo(p, x, y+ry);
2460
+			nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
2461
+		}
2462
+
2463
+		nsvg__addPath(p, 1);
2464
+
2465
+		nsvg__addShape(p);
2466
+	}
2467
+}
2468
+
2469
+static void nsvg__parseCircle(NSVGparser* p, const char** attr)
2470
+{
2471
+	float cx = 0.0f;
2472
+	float cy = 0.0f;
2473
+	float r = 0.0f;
2474
+	int i;
2475
+
2476
+	for (i = 0; attr[i]; i += 2) {
2477
+		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
2478
+			if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
2479
+			if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
2480
+			if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));
2481
+		}
2482
+	}
2483
+
2484
+	if (r > 0.0f) {
2485
+		nsvg__resetPath(p);
2486
+
2487
+		nsvg__moveTo(p, cx+r, cy);
2488
+		nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);
2489
+		nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);
2490
+		nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
2491
+		nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
2492
+
2493
+		nsvg__addPath(p, 1);
2494
+
2495
+		nsvg__addShape(p);
2496
+	}
2497
+}
2498
+
2499
+static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
2500
+{
2501
+	float cx = 0.0f;
2502
+	float cy = 0.0f;
2503
+	float rx = 0.0f;
2504
+	float ry = 0.0f;
2505
+	int i;
2506
+
2507
+	for (i = 0; attr[i]; i += 2) {
2508
+		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
2509
+			if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
2510
+			if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
2511
+			if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
2512
+			if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
2513
+		}
2514
+	}
2515
+
2516
+	if (rx > 0.0f && ry > 0.0f) {
2517
+
2518
+		nsvg__resetPath(p);
2519
+
2520
+		nsvg__moveTo(p, cx+rx, cy);
2521
+		nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
2522
+		nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);
2523
+		nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
2524
+		nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
2525
+
2526
+		nsvg__addPath(p, 1);
2527
+
2528
+		nsvg__addShape(p);
2529
+	}
2530
+}
2531
+
2532
+static void nsvg__parseLine(NSVGparser* p, const char** attr)
2533
+{
2534
+	float x1 = 0.0;
2535
+	float y1 = 0.0;
2536
+	float x2 = 0.0;
2537
+	float y2 = 0.0;
2538
+	int i;
2539
+
2540
+	for (i = 0; attr[i]; i += 2) {
2541
+		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
2542
+			if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
2543
+			if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
2544
+			if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
2545
+			if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
2546
+		}
2547
+	}
2548
+
2549
+	nsvg__resetPath(p);
2550
+
2551
+	nsvg__moveTo(p, x1, y1);
2552
+	nsvg__lineTo(p, x2, y2);
2553
+
2554
+	nsvg__addPath(p, 0);
2555
+
2556
+	nsvg__addShape(p);
2557
+}
2558
+
2559
+static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
2560
+{
2561
+	int i;
2562
+	const char* s;
2563
+	float args[2];
2564
+	int nargs, npts = 0;
2565
+	char item[64];
2566
+
2567
+	nsvg__resetPath(p);
2568
+
2569
+	for (i = 0; attr[i]; i += 2) {
2570
+		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
2571
+			if (strcmp(attr[i], "points") == 0) {
2572
+				s = attr[i + 1];
2573
+				nargs = 0;
2574
+				while (*s) {
2575
+					s = nsvg__getNextPathItem(s, item);
2576
+					args[nargs++] = (float)nsvg__atof(item);
2577
+					if (nargs >= 2) {
2578
+						if (npts == 0)
2579
+							nsvg__moveTo(p, args[0], args[1]);
2580
+						else
2581
+							nsvg__lineTo(p, args[0], args[1]);
2582
+						nargs = 0;
2583
+						npts++;
2584
+					}
2585
+				}
2586
+			}
2587
+		}
2588
+	}
2589
+
2590
+	nsvg__addPath(p, (char)closeFlag);
2591
+
2592
+	nsvg__addShape(p);
2593
+}
2594
+
2595
+static void nsvg__parseSVG(NSVGparser* p, const char** attr)
2596
+{
2597
+	int i;
2598
+	for (i = 0; attr[i]; i += 2) {
2599
+		if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
2600
+			if (strcmp(attr[i], "width") == 0) {
2601
+				p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
2602
+			} else if (strcmp(attr[i], "height") == 0) {
2603
+				p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
2604
+			} else if (strcmp(attr[i], "viewBox") == 0) {
2605
+				const char *s = attr[i + 1];
2606
+				char buf[64];
2607
+				s = nsvg__parseNumber(s, buf, 64);
2608
+				p->viewMinx = nsvg__atof(buf);
2609
+				while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
2610
+				if (!*s) return;
2611
+				s = nsvg__parseNumber(s, buf, 64);
2612
+				p->viewMiny = nsvg__atof(buf);
2613
+				while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
2614
+				if (!*s) return;
2615
+				s = nsvg__parseNumber(s, buf, 64);
2616
+				p->viewWidth = nsvg__atof(buf);
2617
+				while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
2618
+				if (!*s) return;
2619
+				s = nsvg__parseNumber(s, buf, 64);
2620
+				p->viewHeight = nsvg__atof(buf);
2621
+			} else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
2622
+				if (strstr(attr[i + 1], "none") != 0) {
2623
+					// No uniform scaling
2624
+					p->alignType = NSVG_ALIGN_NONE;
2625
+				} else {
2626
+					// Parse X align
2627
+					if (strstr(attr[i + 1], "xMin") != 0)
2628
+						p->alignX = NSVG_ALIGN_MIN;
2629
+					else if (strstr(attr[i + 1], "xMid") != 0)
2630
+						p->alignX = NSVG_ALIGN_MID;
2631
+					else if (strstr(attr[i + 1], "xMax") != 0)
2632
+						p->alignX = NSVG_ALIGN_MAX;
2633
+					// Parse X align
2634
+					if (strstr(attr[i + 1], "yMin") != 0)
2635
+						p->alignY = NSVG_ALIGN_MIN;
2636
+					else if (strstr(attr[i + 1], "yMid") != 0)
2637
+						p->alignY = NSVG_ALIGN_MID;
2638
+					else if (strstr(attr[i + 1], "yMax") != 0)
2639
+						p->alignY = NSVG_ALIGN_MAX;
2640
+					// Parse meet/slice
2641
+					p->alignType = NSVG_ALIGN_MEET;
2642
+					if (strstr(attr[i + 1], "slice") != 0)
2643
+						p->alignType = NSVG_ALIGN_SLICE;
2644
+				}
2645
+			}
2646
+		}
2647
+	}
2648
+}
2649
+
2650
+static void nsvg__parseGradient(NSVGparser* p, const char** attr, signed char type)
2651
+{
2652
+	int i;
2653
+	NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));
2654
+	if (grad == NULL) return;
2655
+	memset(grad, 0, sizeof(NSVGgradientData));
2656
+	grad->units = NSVG_OBJECT_SPACE;
2657
+	grad->type = type;
2658
+	if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {
2659
+		grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
2660
+		grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
2661
+		grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);
2662
+		grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
2663
+	} else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {
2664
+		grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
2665
+		grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
2666
+		grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
2667
+	}
2668
+
2669
+	nsvg__xformIdentity(grad->xform);
2670
+
2671
+	for (i = 0; attr[i]; i += 2) {
2672
+		if (strcmp(attr[i], "id") == 0) {
2673
+			strncpy(grad->id, attr[i+1], 63);
2674
+			grad->id[63] = '\0';
2675
+		} else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
2676
+			if (strcmp(attr[i], "gradientUnits") == 0) {
2677
+				if (strcmp(attr[i+1], "objectBoundingBox") == 0)
2678
+					grad->units = NSVG_OBJECT_SPACE;
2679
+				else
2680
+					grad->units = NSVG_USER_SPACE;
2681
+			} else if (strcmp(attr[i], "gradientTransform") == 0) {
2682
+				nsvg__parseTransform(grad->xform, attr[i + 1]);
2683
+			} else if (strcmp(attr[i], "cx") == 0) {
2684
+				grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);
2685
+			} else if (strcmp(attr[i], "cy") == 0) {
2686
+				grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);
2687
+			} else if (strcmp(attr[i], "r") == 0) {
2688
+				grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);
2689
+			} else if (strcmp(attr[i], "fx") == 0) {
2690
+				grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);
2691
+			} else if (strcmp(attr[i], "fy") == 0) {
2692
+				grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);
2693
+			} else if (strcmp(attr[i], "x1") == 0) {
2694
+				grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);
2695
+			} else if (strcmp(attr[i], "y1") == 0) {
2696
+				grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);
2697
+			} else if (strcmp(attr[i], "x2") == 0) {
2698
+				grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);
2699
+			} else if (strcmp(attr[i], "y2") == 0) {
2700
+				grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);
2701
+			} else if (strcmp(attr[i], "spreadMethod") == 0) {
2702
+				if (strcmp(attr[i+1], "pad") == 0)
2703
+					grad->spread = NSVG_SPREAD_PAD;
2704
+				else if (strcmp(attr[i+1], "reflect") == 0)
2705
+					grad->spread = NSVG_SPREAD_REFLECT;
2706
+				else if (strcmp(attr[i+1], "repeat") == 0)
2707
+					grad->spread = NSVG_SPREAD_REPEAT;
2708
+			} else if (strcmp(attr[i], "xlink:href") == 0) {
2709
+				const char *href = attr[i+1];
2710
+				strncpy(grad->ref, href+1, 62);
2711
+				grad->ref[62] = '\0';
2712
+			}
2713
+		}
2714
+	}
2715
+
2716
+	grad->next = p->gradients;
2717
+	p->gradients = grad;
2718
+}
2719
+
2720
+static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
2721
+{
2722
+	NSVGattrib* curAttr = nsvg__getAttr(p);
2723
+	NSVGgradientData* grad;
2724
+	NSVGgradientStop* stop;
2725
+	int i, idx;
2726
+
2727
+	curAttr->stopOffset = 0;
2728
+	curAttr->stopColor = 0;
2729
+	curAttr->stopOpacity = 1.0f;
2730
+
2731
+	for (i = 0; attr[i]; i += 2) {
2732
+		nsvg__parseAttr(p, attr[i], attr[i + 1]);
2733
+	}
2734
+
2735
+	// Add stop to the last gradient.
2736
+	grad = p->gradients;
2737
+	if (grad == NULL) return;
2738
+
2739
+	grad->nstops++;
2740
+	grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops);
2741
+	if (grad->stops == NULL) return;
2742
+
2743
+	// Insert
2744
+	idx = grad->nstops-1;
2745
+	for (i = 0; i < grad->nstops-1; i++) {
2746
+		if (curAttr->stopOffset < grad->stops[i].offset) {
2747
+			idx = i;
2748
+			break;
2749
+		}
2750
+	}
2751
+	if (idx != grad->nstops-1) {
2752
+		for (i = grad->nstops-1; i > idx; i--)
2753
+			grad->stops[i] = grad->stops[i-1];
2754
+	}
2755
+
2756
+	stop = &grad->stops[idx];
2757
+	stop->color = curAttr->stopColor;
2758
+	stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
2759
+	stop->offset = curAttr->stopOffset;
2760
+}
2761
+
2762
+static void nsvg__startElement(void* ud, const char* el, const char** attr)
2763
+{
2764
+	NSVGparser* p = (NSVGparser*)ud;
2765
+
2766
+	if (p->defsFlag) {
2767
+		// Skip everything but gradients in defs
2768
+		if (strcmp(el, "linearGradient") == 0) {
2769
+			nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
2770
+		} else if (strcmp(el, "radialGradient") == 0) {
2771
+			nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
2772
+		} else if (strcmp(el, "stop") == 0) {
2773
+			nsvg__parseGradientStop(p, attr);
2774
+		}
2775
+		return;
2776
+	}
2777
+
2778
+	if (strcmp(el, "g") == 0) {
2779
+		nsvg__pushAttr(p);
2780
+		nsvg__parseAttribs(p, attr);
2781
+	} else if (strcmp(el, "path") == 0) {
2782
+		if (p->pathFlag)	// Do not allow nested paths.
2783
+			return;
2784
+		nsvg__pushAttr(p);
2785
+		nsvg__parsePath(p, attr);
2786
+		nsvg__popAttr(p);
2787
+	} else if (strcmp(el, "rect") == 0) {
2788
+		nsvg__pushAttr(p);
2789
+		nsvg__parseRect(p, attr);
2790
+		nsvg__popAttr(p);
2791
+	} else if (strcmp(el, "circle") == 0) {
2792
+		nsvg__pushAttr(p);
2793
+		nsvg__parseCircle(p, attr);
2794
+		nsvg__popAttr(p);
2795
+	} else if (strcmp(el, "ellipse") == 0) {
2796
+		nsvg__pushAttr(p);
2797
+		nsvg__parseEllipse(p, attr);
2798
+		nsvg__popAttr(p);
2799
+	} else if (strcmp(el, "line") == 0)  {
2800
+		nsvg__pushAttr(p);
2801
+		nsvg__parseLine(p, attr);
2802
+		nsvg__popAttr(p);
2803
+	} else if (strcmp(el, "polyline") == 0)  {
2804
+		nsvg__pushAttr(p);
2805
+		nsvg__parsePoly(p, attr, 0);
2806
+		nsvg__popAttr(p);
2807
+	} else if (strcmp(el, "polygon") == 0)  {
2808
+		nsvg__pushAttr(p);
2809
+		nsvg__parsePoly(p, attr, 1);
2810
+		nsvg__popAttr(p);
2811
+	} else  if (strcmp(el, "linearGradient") == 0) {
2812
+		nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
2813
+	} else if (strcmp(el, "radialGradient") == 0) {
2814
+		nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
2815
+	} else if (strcmp(el, "stop") == 0) {
2816
+		nsvg__parseGradientStop(p, attr);
2817
+	} else if (strcmp(el, "defs") == 0) {
2818
+		p->defsFlag = 1;
2819
+	} else if (strcmp(el, "svg") == 0) {
2820
+		nsvg__parseSVG(p, attr);
2821
+	}
2822
+}
2823
+
2824
+static void nsvg__endElement(void* ud, const char* el)
2825
+{
2826
+	NSVGparser* p = (NSVGparser*)ud;
2827
+
2828
+	if (strcmp(el, "g") == 0) {
2829
+		nsvg__popAttr(p);
2830
+	} else if (strcmp(el, "path") == 0) {
2831
+		p->pathFlag = 0;
2832
+	} else if (strcmp(el, "defs") == 0) {
2833
+		p->defsFlag = 0;
2834
+	}
2835
+}
2836
+
2837
+static void nsvg__content(void* ud, const char* s)
2838
+{
2839
+	NSVG_NOTUSED(ud);
2840
+	NSVG_NOTUSED(s);
2841
+	// empty
2842
+}
2843
+
2844
+static void nsvg__imageBounds(NSVGparser* p, float* bounds)
2845
+{
2846
+	NSVGshape* shape;
2847
+	shape = p->image->shapes;
2848
+	if (shape == NULL) {
2849
+		bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
2850
+		return;
2851
+	}
2852
+	bounds[0] = shape->bounds[0];
2853
+	bounds[1] = shape->bounds[1];
2854
+	bounds[2] = shape->bounds[2];
2855
+	bounds[3] = shape->bounds[3];
2856
+	for (shape = shape->next; shape != NULL; shape = shape->next) {
2857
+		bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
2858
+		bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
2859
+		bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
2860
+		bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
2861
+	}
2862
+}
2863
+
2864
+static float nsvg__viewAlign(float content, float container, int type)
2865
+{
2866
+	if (type == NSVG_ALIGN_MIN)
2867
+		return 0;
2868
+	else if (type == NSVG_ALIGN_MAX)
2869
+		return container - content;
2870
+	// mid
2871
+	return (container - content) * 0.5f;
2872
+}
2873
+
2874
+static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
2875
+{
2876
+	float t[6];
2877
+	nsvg__xformSetTranslation(t, tx, ty);
2878
+	nsvg__xformMultiply (grad->xform, t);
2879
+
2880
+	nsvg__xformSetScale(t, sx, sy);
2881
+	nsvg__xformMultiply (grad->xform, t);
2882
+}
2883
+
2884
+static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
2885
+{
2886
+	NSVGshape* shape;
2887
+	NSVGpath* path;
2888
+	float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
2889
+	int i;
2890
+	float* pt;
2891
+
2892
+	// Guess image size if not set completely.
2893
+	nsvg__imageBounds(p, bounds);
2894
+
2895
+	if (p->viewWidth == 0) {
2896
+		if (p->image->width > 0) {
2897
+			p->viewWidth = p->image->width;
2898
+		} else {
2899
+			p->viewMinx = bounds[0];
2900
+			p->viewWidth = bounds[2] - bounds[0];
2901
+		}
2902
+	}
2903
+	if (p->viewHeight == 0) {
2904
+		if (p->image->height > 0) {
2905
+			p->viewHeight = p->image->height;
2906
+		} else {
2907
+			p->viewMiny = bounds[1];
2908
+			p->viewHeight = bounds[3] - bounds[1];
2909
+		}
2910
+	}
2911
+	if (p->image->width == 0)
2912
+		p->image->width = p->viewWidth;
2913
+	if (p->image->height == 0)
2914
+		p->image->height = p->viewHeight;
2915
+
2916
+	tx = -p->viewMinx;
2917
+	ty = -p->viewMiny;
2918
+	sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
2919
+	sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
2920
+	// Unit scaling
2921
+	us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f);
2922
+
2923
+	// Fix aspect ratio
2924
+	if (p->alignType == NSVG_ALIGN_MEET) {
2925
+		// fit whole image into viewbox
2926
+		sx = sy = nsvg__minf(sx, sy);
2927
+		tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
2928
+		ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
2929
+	} else if (p->alignType == NSVG_ALIGN_SLICE) {
2930
+		// fill whole viewbox with image
2931
+		sx = sy = nsvg__maxf(sx, sy);
2932
+		tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
2933
+		ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
2934
+	}
2935
+
2936
+	// Transform
2937
+	sx *= us;
2938
+	sy *= us;
2939
+	avgs = (sx+sy) / 2.0f;
2940
+	for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
2941
+		shape->bounds[0] = (shape->bounds[0] + tx) * sx;
2942
+		shape->bounds[1] = (shape->bounds[1] + ty) * sy;
2943
+		shape->bounds[2] = (shape->bounds[2] + tx) * sx;
2944
+		shape->bounds[3] = (shape->bounds[3] + ty) * sy;
2945
+		for (path = shape->paths; path != NULL; path = path->next) {
2946
+			path->bounds[0] = (path->bounds[0] + tx) * sx;
2947
+			path->bounds[1] = (path->bounds[1] + ty) * sy;
2948
+			path->bounds[2] = (path->bounds[2] + tx) * sx;
2949
+			path->bounds[3] = (path->bounds[3] + ty) * sy;
2950
+			for (i =0; i < path->npts; i++) {
2951
+				pt = &path->pts[i*2];
2952
+				pt[0] = (pt[0] + tx) * sx;
2953
+				pt[1] = (pt[1] + ty) * sy;
2954
+			}
2955
+		}
2956
+
2957
+		if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {
2958
+			nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);
2959
+			memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);
2960
+			nsvg__xformInverse(shape->fill.gradient->xform, t);
2961
+		}
2962
+		if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {
2963
+			nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy);
2964
+			memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6);
2965
+			nsvg__xformInverse(shape->stroke.gradient->xform, t);
2966
+		}
2967
+
2968
+		shape->strokeWidth *= avgs;
2969
+		shape->strokeDashOffset *= avgs;
2970
+		for (i = 0; i < shape->strokeDashCount; i++)
2971
+			shape->strokeDashArray[i] *= avgs;
2972
+	}
2973
+}
2974
+
2975
+static void nsvg__createGradients(NSVGparser* p)
2976
+{
2977
+	NSVGshape* shape;
2978
+
2979
+	for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
2980
+		if (shape->fill.type == NSVG_PAINT_UNDEF) {
2981
+			if (shape->fillGradient[0] != '\0') {
2982
+				float inv[6], localBounds[4];
2983
+				nsvg__xformInverse(inv, shape->xform);
2984
+				nsvg__getLocalBounds(localBounds, shape, inv);
2985
+				shape->fill.gradient = nsvg__createGradient(p, shape->fillGradient, localBounds, shape->xform, &shape->fill.type);
2986
+			}
2987
+			if (shape->fill.type == NSVG_PAINT_UNDEF) {
2988
+				shape->fill.type = NSVG_PAINT_NONE;
2989
+			}
2990
+		}
2991
+		if (shape->stroke.type == NSVG_PAINT_UNDEF) {
2992
+			if (shape->strokeGradient[0] != '\0') {
2993
+				float inv[6], localBounds[4];
2994
+				nsvg__xformInverse(inv, shape->xform);
2995
+				nsvg__getLocalBounds(localBounds, shape, inv);
2996
+				shape->stroke.gradient = nsvg__createGradient(p, shape->strokeGradient, localBounds, shape->xform, &shape->stroke.type);
2997
+			}
2998
+			if (shape->stroke.type == NSVG_PAINT_UNDEF) {
2999
+				shape->stroke.type = NSVG_PAINT_NONE;
3000
+			}
3001
+		}
3002
+	}
3003
+}
3004
+
3005
+NSVGimage* nsvgParse(char* input, const char* units, float dpi)
3006
+{
3007
+	NSVGparser* p;
3008
+	NSVGimage* ret = 0;
3009
+
3010
+	p = nsvg__createParser();
3011
+	if (p == NULL) {
3012
+		return NULL;
3013
+	}
3014
+	p->dpi = dpi;
3015
+
3016
+	nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
3017
+
3018
+	// Create gradients after all definitions have been parsed
3019
+	nsvg__createGradients(p);
3020
+
3021
+	// Scale to viewBox
3022
+	nsvg__scaleToViewbox(p, units);
3023
+
3024
+	ret = p->image;
3025
+	p->image = NULL;
3026
+
3027
+	nsvg__deleteParser(p);
3028
+
3029
+	return ret;
3030
+}
3031
+
3032
+NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
3033
+{
3034
+	FILE* fp = NULL;
3035
+	size_t size;
3036
+	char* data = NULL;
3037
+	NSVGimage* image = NULL;
3038
+
3039
+	fp = fopen(filename, "rb");
3040
+	if (!fp) goto error;
3041
+	fseek(fp, 0, SEEK_END);
3042
+	size = ftell(fp);
3043
+	fseek(fp, 0, SEEK_SET);
3044
+	data = (char*)malloc(size+1);
3045
+	if (data == NULL) goto error;
3046
+	if (fread(data, 1, size, fp) != size) goto error;
3047
+	data[size] = '\0';	// Must be null terminated.
3048
+	fclose(fp);
3049
+	image = nsvgParse(data, units, dpi);
3050
+	free(data);
3051
+
3052
+	return image;
3053
+
3054
+error:
3055
+	if (fp) fclose(fp);
3056
+	if (data) free(data);
3057
+	if (image) nsvgDelete(image);
3058
+	return NULL;
3059
+}
3060
+
3061
+NSVGpath* nsvgDuplicatePath(NSVGpath* p)
3062
+{
3063
+    NSVGpath* res = NULL;
3064
+
3065
+    if (p == NULL)
3066
+        return NULL;
3067
+
3068
+    res = (NSVGpath*)malloc(sizeof(NSVGpath));
3069
+    if (res == NULL) goto error;
3070
+    memset(res, 0, sizeof(NSVGpath));
3071
+
3072
+    res->pts = (float*)malloc(p->npts*2*sizeof(float));
3073
+    if (res->pts == NULL) goto error;
3074
+    memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
3075
+    res->npts = p->npts;
3076
+
3077
+    memcpy(res->bounds, p->bounds, sizeof(p->bounds));
3078
+
3079
+    res->closed = p->closed;
3080
+
3081
+    return res;
3082
+
3083
+error:
3084
+    if (res != NULL) {
3085
+        free(res->pts);
3086
+        free(res);
3087
+    }
3088
+    return NULL;
3089
+}
3090
+
3091
+void nsvgDelete(NSVGimage* image)
3092
+{
3093
+	NSVGshape *snext, *shape;
3094
+	if (image == NULL) return;
3095
+	shape = image->shapes;
3096
+	while (shape != NULL) {
3097
+		snext = shape->next;
3098
+		nsvg__deletePaths(shape->paths);
3099
+		nsvg__deletePaint(&shape->fill);
3100
+		nsvg__deletePaint(&shape->stroke);
3101
+		free(shape);
3102
+		shape = snext;
3103
+	}
3104
+	free(image);
3105
+}
3106
+
3107
+#endif // NANOSVG_IMPLEMENTATION
3108
+
3109
+#endif // NANOSVG_H
(-)b/cad/PrusaSlicer/files/patch-src_libnanosvg_nanosvgrast.h (+1485 lines)
Added Link Here
1
--- src/libnanosvg/nanosvgrast.h.orig	1970-01-01 01:00:00.000000000 +0100
2
+++ src/libnanosvg/nanosvgrast.h	2022-12-22 00:42:08.000000000 +0100
3
@@ -0,0 +1,1482 @@
4
+/*
5
+ * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
6
+ *
7
+ * This software is provided 'as-is', without any express or implied
8
+ * warranty.  In no event will the authors be held liable for any damages
9
+ * arising from the use of this software.
10
+ *
11
+ * Permission is granted to anyone to use this software for any purpose,
12
+ * including commercial applications, and to alter it and redistribute it
13
+ * freely, subject to the following restrictions:
14
+ *
15
+ * 1. The origin of this software must not be misrepresented; you must not
16
+ * claim that you wrote the original software. If you use this software
17
+ * in a product, an acknowledgment in the product documentation would be
18
+ * appreciated but is not required.
19
+ * 2. Altered source versions must be plainly marked as such, and must not be
20
+ * misrepresented as being the original software.
21
+ * 3. This notice may not be removed or altered from any source distribution.
22
+ *
23
+ * The polygon rasterization is heavily based on stb_truetype rasterizer
24
+ * by Sean Barrett - http://nothings.org/
25
+ *
26
+ */
27
+
28
+/* Modified by FLTK to support non-square X,Y axes scaling.
29
+ *
30
+ * Added: nsvgRasterizeXY()
31
+*/
32
+
33
+
34
+#ifndef NANOSVGRAST_H
35
+#define NANOSVGRAST_H
36
+
37
+#include "nanosvg.h"
38
+
39
+#ifndef NANOSVGRAST_CPLUSPLUS
40
+#ifdef __cplusplus
41
+extern "C" {
42
+#endif
43
+#endif
44
+
45
+typedef struct NSVGrasterizer NSVGrasterizer;
46
+
47
+/* Example Usage:
48
+	// Load SVG
49
+	NSVGimage* image;
50
+	image = nsvgParseFromFile("test.svg", "px", 96);
51
+
52
+	// Create rasterizer (can be used to render multiple images).
53
+	struct NSVGrasterizer* rast = nsvgCreateRasterizer();
54
+	// Allocate memory for image
55
+	unsigned char* img = malloc(w*h*4);
56
+	// Rasterize
57
+	nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
58
+
59
+	// For non-square X,Y scaling, use
60
+	nsvgRasterizeXY(rast, image, 0,0,1,1, img, w, h, w*4);
61
+*/
62
+
63
+// Allocated rasterizer context.
64
+NSVGrasterizer* nsvgCreateRasterizer(void);
65
+
66
+// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
67
+//   r - pointer to rasterizer context
68
+//   image - pointer to image to rasterize
69
+//   tx,ty - image offset (applied after scaling)
70
+//   scale - image scale (assumes square aspect ratio)
71
+//   dst - pointer to destination image data, 4 bytes per pixel (RGBA)
72
+//   w - width of the image to render
73
+//   h - height of the image to render
74
+//   stride - number of bytes per scaleline in the destination buffer
75
+void nsvgRasterize(NSVGrasterizer* r,
76
+				   NSVGimage* image, float tx, float ty, float scale,
77
+				   unsigned char* dst, int w, int h, int stride);
78
+
79
+// As above, but allow X and Y axes to scale independently for non-square aspects
80
+void nsvgRasterizeXY(NSVGrasterizer* r,
81
+				   NSVGimage* image, float tx, float ty,
82
+				   float sx, float sy,
83
+				   unsigned char* dst, int w, int h, int stride);
84
+
85
+// Deletes rasterizer context.
86
+void nsvgDeleteRasterizer(NSVGrasterizer*);
87
+
88
+
89
+#ifndef NANOSVGRAST_CPLUSPLUS
90
+#ifdef __cplusplus
91
+}
92
+#endif
93
+#endif
94
+
95
+#ifdef NANOSVGRAST_IMPLEMENTATION
96
+
97
+#include <math.h>
98
+#include <stdlib.h>
99
+#include <string.h>
100
+
101
+#define NSVG__SUBSAMPLES	5
102
+#define NSVG__FIXSHIFT		10
103
+#define NSVG__FIX			(1 << NSVG__FIXSHIFT)
104
+#define NSVG__FIXMASK		(NSVG__FIX-1)
105
+#define NSVG__MEMPAGE_SIZE	1024
106
+
107
+typedef struct NSVGedge {
108
+	float x0,y0, x1,y1;
109
+	int dir;
110
+	struct NSVGedge* next;
111
+} NSVGedge;
112
+
113
+typedef struct NSVGpoint {
114
+	float x, y;
115
+	float dx, dy;
116
+	float len;
117
+	float dmx, dmy;
118
+	unsigned char flags;
119
+} NSVGpoint;
120
+
121
+typedef struct NSVGactiveEdge {
122
+	int x,dx;
123
+	float ey;
124
+	int dir;
125
+	struct NSVGactiveEdge *next;
126
+} NSVGactiveEdge;
127
+
128
+typedef struct NSVGmemPage {
129
+	unsigned char mem[NSVG__MEMPAGE_SIZE];
130
+	int size;
131
+	struct NSVGmemPage* next;
132
+} NSVGmemPage;
133
+
134
+typedef struct NSVGcachedPaint {
135
+	signed char type;
136
+	char spread;
137
+	float xform[6];
138
+	unsigned int colors[256];
139
+} NSVGcachedPaint;
140
+
141
+struct NSVGrasterizer
142
+{
143
+	float px, py;
144
+
145
+	float tessTol;
146
+	float distTol;
147
+
148
+	NSVGedge* edges;
149
+	int nedges;
150
+	int cedges;
151
+
152
+	NSVGpoint* points;
153
+	int npoints;
154
+	int cpoints;
155
+
156
+	NSVGpoint* points2;
157
+	int npoints2;
158
+	int cpoints2;
159
+
160
+	NSVGactiveEdge* freelist;
161
+	NSVGmemPage* pages;
162
+	NSVGmemPage* curpage;
163
+
164
+	unsigned char* scanline;
165
+	int cscanline;
166
+
167
+	unsigned char* bitmap;
168
+	int width, height, stride;
169
+};
170
+
171
+NSVGrasterizer* nsvgCreateRasterizer(void)
172
+{
173
+	NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
174
+	if (r == NULL) goto error;
175
+	memset(r, 0, sizeof(NSVGrasterizer));
176
+
177
+	r->tessTol = 0.25f;
178
+	r->distTol = 0.01f;
179
+
180
+	return r;
181
+
182
+error:
183
+	nsvgDeleteRasterizer(r);
184
+	return NULL;
185
+}
186
+
187
+void nsvgDeleteRasterizer(NSVGrasterizer* r)
188
+{
189
+	NSVGmemPage* p;
190
+
191
+	if (r == NULL) return;
192
+
193
+	p = r->pages;
194
+	while (p != NULL) {
195
+		NSVGmemPage* next = p->next;
196
+		free(p);
197
+		p = next;
198
+	}
199
+
200
+	if (r->edges) free(r->edges);
201
+	if (r->points) free(r->points);
202
+	if (r->points2) free(r->points2);
203
+	if (r->scanline) free(r->scanline);
204
+
205
+	free(r);
206
+}
207
+
208
+static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
209
+{
210
+	NSVGmemPage *newp;
211
+
212
+	// If using existing chain, return the next page in chain
213
+	if (cur != NULL && cur->next != NULL) {
214
+		return cur->next;
215
+	}
216
+
217
+	// Alloc new page
218
+	newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
219
+	if (newp == NULL) return NULL;
220
+	memset(newp, 0, sizeof(NSVGmemPage));
221
+
222
+	// Add to linked list
223
+	if (cur != NULL)
224
+		cur->next = newp;
225
+	else
226
+		r->pages = newp;
227
+
228
+	return newp;
229
+}
230
+
231
+static void nsvg__resetPool(NSVGrasterizer* r)
232
+{
233
+	NSVGmemPage* p = r->pages;
234
+	while (p != NULL) {
235
+		p->size = 0;
236
+		p = p->next;
237
+	}
238
+	r->curpage = r->pages;
239
+}
240
+
241
+static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
242
+{
243
+	unsigned char* buf;
244
+	if (size > NSVG__MEMPAGE_SIZE) return NULL;
245
+	if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
246
+		r->curpage = nsvg__nextPage(r, r->curpage);
247
+	}
248
+	buf = &r->curpage->mem[r->curpage->size];
249
+	r->curpage->size += size;
250
+	return buf;
251
+}
252
+
253
+static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
254
+{
255
+	float dx = x2 - x1;
256
+	float dy = y2 - y1;
257
+	return dx*dx + dy*dy < tol*tol;
258
+}
259
+
260
+static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
261
+{
262
+	NSVGpoint* pt;
263
+
264
+	if (r->npoints > 0) {
265
+		pt = &r->points[r->npoints-1];
266
+		if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
267
+			pt->flags = (unsigned char)(pt->flags | flags);
268
+			return;
269
+		}
270
+	}
271
+
272
+	if (r->npoints+1 > r->cpoints) {
273
+		r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
274
+		r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
275
+		if (r->points == NULL) return;
276
+	}
277
+
278
+	pt = &r->points[r->npoints];
279
+	pt->x = x;
280
+	pt->y = y;
281
+	pt->flags = (unsigned char)flags;
282
+	r->npoints++;
283
+}
284
+
285
+static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
286
+{
287
+	if (r->npoints+1 > r->cpoints) {
288
+		r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
289
+		r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
290
+		if (r->points == NULL) return;
291
+	}
292
+	r->points[r->npoints] = pt;
293
+	r->npoints++;
294
+}
295
+
296
+static void nsvg__duplicatePoints(NSVGrasterizer* r)
297
+{
298
+	if (r->npoints > r->cpoints2) {
299
+		r->cpoints2 = r->npoints;
300
+		r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);
301
+		if (r->points2 == NULL) return;
302
+	}
303
+
304
+	memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);
305
+	r->npoints2 = r->npoints;
306
+}
307
+
308
+static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
309
+{
310
+	NSVGedge* e;
311
+
312
+	// Skip horizontal edges
313
+	if (y0 == y1)
314
+		return;
315
+
316
+	if (r->nedges+1 > r->cedges) {
317
+		r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
318
+		r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
319
+		if (r->edges == NULL) return;
320
+	}
321
+
322
+	e = &r->edges[r->nedges];
323
+	r->nedges++;
324
+
325
+	if (y0 < y1) {
326
+		e->x0 = x0;
327
+		e->y0 = y0;
328
+		e->x1 = x1;
329
+		e->y1 = y1;
330
+		e->dir = 1;
331
+	} else {
332
+		e->x0 = x1;
333
+		e->y0 = y1;
334
+		e->x1 = x0;
335
+		e->y1 = y0;
336
+		e->dir = -1;
337
+	}
338
+}
339
+
340
+static float nsvg__normalize(float *x, float* y)
341
+{
342
+	float d = sqrtf((*x)*(*x) + (*y)*(*y));
343
+	if (d > 1e-6f) {
344
+		float id = 1.0f / d;
345
+		*x *= id;
346
+		*y *= id;
347
+	}
348
+	return d;
349
+}
350
+
351
+static float nsvg__absf(float x) { return x < 0 ? -x : x; }
352
+
353
+static void nsvg__flattenCubicBez(NSVGrasterizer* r,
354
+								  float x1, float y1, float x2, float y2,
355
+								  float x3, float y3, float x4, float y4,
356
+								  int level, int type)
357
+{
358
+	float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
359
+	float dx,dy,d2,d3;
360
+
361
+	if (level > 10) return;
362
+
363
+	x12 = (x1+x2)*0.5f;
364
+	y12 = (y1+y2)*0.5f;
365
+	x23 = (x2+x3)*0.5f;
366
+	y23 = (y2+y3)*0.5f;
367
+	x34 = (x3+x4)*0.5f;
368
+	y34 = (y3+y4)*0.5f;
369
+	x123 = (x12+x23)*0.5f;
370
+	y123 = (y12+y23)*0.5f;
371
+
372
+	dx = x4 - x1;
373
+	dy = y4 - y1;
374
+	d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
375
+	d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
376
+
377
+	if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
378
+		nsvg__addPathPoint(r, x4, y4, type);
379
+		return;
380
+	}
381
+
382
+	x234 = (x23+x34)*0.5f;
383
+	y234 = (y23+y34)*0.5f;
384
+	x1234 = (x123+x234)*0.5f;
385
+	y1234 = (y123+y234)*0.5f;
386
+
387
+	nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
388
+	nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
389
+}
390
+
391
+static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float sx, float sy)
392
+{
393
+	int i, j;
394
+	NSVGpath* path;
395
+
396
+	for (path = shape->paths; path != NULL; path = path->next) {
397
+		r->npoints = 0;
398
+		// Flatten path
399
+		nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, 0);
400
+		for (i = 0; i < path->npts-1; i += 3) {
401
+			float* p = &path->pts[i*2];
402
+			nsvg__flattenCubicBez(r, p[0]*sx,p[1]*sy, p[2]*sx,p[3]*sy, p[4]*sx,p[5]*sy, p[6]*sx,p[7]*sy, 0, 0);
403
+		}
404
+		// Close path
405
+		nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, 0);
406
+		// Build edges
407
+		for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
408
+			nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
409
+	}
410
+}
411
+
412
+enum NSVGpointFlags
413
+{
414
+	NSVG_PT_CORNER = 0x01,
415
+	NSVG_PT_BEVEL = 0x02,
416
+	NSVG_PT_LEFT = 0x04
417
+};
418
+
419
+static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
420
+{
421
+	float w = lineWidth * 0.5f;
422
+	float dx = p1->x - p0->x;
423
+	float dy = p1->y - p0->y;
424
+	float len = nsvg__normalize(&dx, &dy);
425
+	float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
426
+	float dlx = dy, dly = -dx;
427
+	float lx = px - dlx*w, ly = py - dly*w;
428
+	float rx = px + dlx*w, ry = py + dly*w;
429
+	left->x = lx; left->y = ly;
430
+	right->x = rx; right->y = ry;
431
+}
432
+
433
+static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
434
+{
435
+	float w = lineWidth * 0.5f;
436
+	float px = p->x, py = p->y;
437
+	float dlx = dy, dly = -dx;
438
+	float lx = px - dlx*w, ly = py - dly*w;
439
+	float rx = px + dlx*w, ry = py + dly*w;
440
+
441
+	nsvg__addEdge(r, lx, ly, rx, ry);
442
+
443
+	if (connect) {
444
+		nsvg__addEdge(r, left->x, left->y, lx, ly);
445
+		nsvg__addEdge(r, rx, ry, right->x, right->y);
446
+	}
447
+	left->x = lx; left->y = ly;
448
+	right->x = rx; right->y = ry;
449
+}
450
+
451
+static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
452
+{
453
+	float w = lineWidth * 0.5f;
454
+	float px = p->x - dx*w, py = p->y - dy*w;
455
+	float dlx = dy, dly = -dx;
456
+	float lx = px - dlx*w, ly = py - dly*w;
457
+	float rx = px + dlx*w, ry = py + dly*w;
458
+
459
+	nsvg__addEdge(r, lx, ly, rx, ry);
460
+
461
+	if (connect) {
462
+		nsvg__addEdge(r, left->x, left->y, lx, ly);
463
+		nsvg__addEdge(r, rx, ry, right->x, right->y);
464
+	}
465
+	left->x = lx; left->y = ly;
466
+	right->x = rx; right->y = ry;
467
+}
468
+
469
+#ifndef NSVG_PI
470
+#define NSVG_PI (3.14159265358979323846264338327f)
471
+#endif
472
+
473
+static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
474
+{
475
+	int i;
476
+	float w = lineWidth * 0.5f;
477
+	float px = p->x, py = p->y;
478
+	float dlx = dy, dly = -dx;
479
+	float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
480
+
481
+	for (i = 0; i < ncap; i++) {
482
+		float a = (float)i/(float)(ncap-1)*NSVG_PI;
483
+		float ax = cosf(a) * w, ay = sinf(a) * w;
484
+		float x = px - dlx*ax - dx*ay;
485
+		float y = py - dly*ax - dy*ay;
486
+
487
+		if (i > 0)
488
+			nsvg__addEdge(r, prevx, prevy, x, y);
489
+
490
+		prevx = x;
491
+		prevy = y;
492
+
493
+		if (i == 0) {
494
+			lx = x; ly = y;
495
+		} else if (i == ncap-1) {
496
+			rx = x; ry = y;
497
+		}
498
+	}
499
+
500
+	if (connect) {
501
+		nsvg__addEdge(r, left->x, left->y, lx, ly);
502
+		nsvg__addEdge(r, rx, ry, right->x, right->y);
503
+	}
504
+
505
+	left->x = lx; left->y = ly;
506
+	right->x = rx; right->y = ry;
507
+}
508
+
509
+static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
510
+{
511
+	float w = lineWidth * 0.5f;
512
+	float dlx0 = p0->dy, dly0 = -p0->dx;
513
+	float dlx1 = p1->dy, dly1 = -p1->dx;
514
+	float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
515
+	float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
516
+	float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
517
+	float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
518
+
519
+	nsvg__addEdge(r, lx0, ly0, left->x, left->y);
520
+	nsvg__addEdge(r, lx1, ly1, lx0, ly0);
521
+
522
+	nsvg__addEdge(r, right->x, right->y, rx0, ry0);
523
+	nsvg__addEdge(r, rx0, ry0, rx1, ry1);
524
+
525
+	left->x = lx1; left->y = ly1;
526
+	right->x = rx1; right->y = ry1;
527
+}
528
+
529
+static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
530
+{
531
+	float w = lineWidth * 0.5f;
532
+	float dlx0 = p0->dy, dly0 = -p0->dx;
533
+	float dlx1 = p1->dy, dly1 = -p1->dx;
534
+	float lx0, rx0, lx1, rx1;
535
+	float ly0, ry0, ly1, ry1;
536
+
537
+	if (p1->flags & NSVG_PT_LEFT) {
538
+		lx0 = lx1 = p1->x - p1->dmx * w;
539
+		ly0 = ly1 = p1->y - p1->dmy * w;
540
+		nsvg__addEdge(r, lx1, ly1, left->x, left->y);
541
+
542
+		rx0 = p1->x + (dlx0 * w);
543
+		ry0 = p1->y + (dly0 * w);
544
+		rx1 = p1->x + (dlx1 * w);
545
+		ry1 = p1->y + (dly1 * w);
546
+		nsvg__addEdge(r, right->x, right->y, rx0, ry0);
547
+		nsvg__addEdge(r, rx0, ry0, rx1, ry1);
548
+	} else {
549
+		lx0 = p1->x - (dlx0 * w);
550
+		ly0 = p1->y - (dly0 * w);
551
+		lx1 = p1->x - (dlx1 * w);
552
+		ly1 = p1->y - (dly1 * w);
553
+		nsvg__addEdge(r, lx0, ly0, left->x, left->y);
554
+		nsvg__addEdge(r, lx1, ly1, lx0, ly0);
555
+
556
+		rx0 = rx1 = p1->x + p1->dmx * w;
557
+		ry0 = ry1 = p1->y + p1->dmy * w;
558
+		nsvg__addEdge(r, right->x, right->y, rx1, ry1);
559
+	}
560
+
561
+	left->x = lx1; left->y = ly1;
562
+	right->x = rx1; right->y = ry1;
563
+}
564
+
565
+static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
566
+{
567
+	int i, n;
568
+	float w = lineWidth * 0.5f;
569
+	float dlx0 = p0->dy, dly0 = -p0->dx;
570
+	float dlx1 = p1->dy, dly1 = -p1->dx;
571
+	float a0 = atan2f(dly0, dlx0);
572
+	float a1 = atan2f(dly1, dlx1);
573
+	float da = a1 - a0;
574
+	float lx, ly, rx, ry;
575
+
576
+	if (da < NSVG_PI) da += NSVG_PI*2;
577
+	if (da > NSVG_PI) da -= NSVG_PI*2;
578
+
579
+	n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
580
+	if (n < 2) n = 2;
581
+	if (n > ncap) n = ncap;
582
+
583
+	lx = left->x;
584
+	ly = left->y;
585
+	rx = right->x;
586
+	ry = right->y;
587
+
588
+	for (i = 0; i < n; i++) {
589
+		float u = (float)i/(float)(n-1);
590
+		float a = a0 + u*da;
591
+		float ax = cosf(a) * w, ay = sinf(a) * w;
592
+		float lx1 = p1->x - ax, ly1 = p1->y - ay;
593
+		float rx1 = p1->x + ax, ry1 = p1->y + ay;
594
+
595
+		nsvg__addEdge(r, lx1, ly1, lx, ly);
596
+		nsvg__addEdge(r, rx, ry, rx1, ry1);
597
+
598
+		lx = lx1; ly = ly1;
599
+		rx = rx1; ry = ry1;
600
+	}
601
+
602
+	left->x = lx; left->y = ly;
603
+	right->x = rx; right->y = ry;
604
+}
605
+
606
+static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
607
+{
608
+	float w = lineWidth * 0.5f;
609
+	float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
610
+	float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
611
+
612
+	nsvg__addEdge(r, lx, ly, left->x, left->y);
613
+	nsvg__addEdge(r, right->x, right->y, rx, ry);
614
+
615
+	left->x = lx; left->y = ly;
616
+	right->x = rx; right->y = ry;
617
+}
618
+
619
+static int nsvg__curveDivs(float r, float arc, float tol)
620
+{
621
+	float da = acosf(r / (r + tol)) * 2.0f;
622
+	int divs = (int)ceilf(arc / da);
623
+	if (divs < 2) divs = 2;
624
+	return divs;
625
+}
626
+
627
+static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)
628
+{
629
+	int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol);	// Calculate divisions per half circle.
630
+	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};
631
+	NSVGpoint* p0, *p1;
632
+	int j, s, e;
633
+
634
+	// Build stroke edges
635
+	if (closed) {
636
+		// Looping
637
+		p0 = &points[npoints-1];
638
+		p1 = &points[0];
639
+		s = 0;
640
+		e = npoints;
641
+	} else {
642
+		// Add cap
643
+		p0 = &points[0];
644
+		p1 = &points[1];
645
+		s = 1;
646
+		e = npoints-1;
647
+	}
648
+
649
+	if (closed) {
650
+		nsvg__initClosed(&left, &right, p0, p1, lineWidth);
651
+		firstLeft = left;
652
+		firstRight = right;
653
+	} else {
654
+		// Add cap
655
+		float dx = p1->x - p0->x;
656
+		float dy = p1->y - p0->y;
657
+		nsvg__normalize(&dx, &dy);
658
+		if (lineCap == NSVG_CAP_BUTT)
659
+			nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
660
+		else if (lineCap == NSVG_CAP_SQUARE)
661
+			nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
662
+		else if (lineCap == NSVG_CAP_ROUND)
663
+			nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
664
+	}
665
+
666
+	for (j = s; j < e; ++j) {
667
+		if (p1->flags & NSVG_PT_CORNER) {
668
+			if (lineJoin == NSVG_JOIN_ROUND)
669
+				nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
670
+			else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
671
+				nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
672
+			else
673
+				nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
674
+		} else {
675
+			nsvg__straightJoin(r, &left, &right, p1, lineWidth);
676
+		}
677
+		p0 = p1++;
678
+	}
679
+
680
+	if (closed) {
681
+		// Loop it
682
+		nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
683
+		nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
684
+	} else {
685
+		// Add cap
686
+		float dx = p1->x - p0->x;
687
+		float dy = p1->y - p0->y;
688
+		nsvg__normalize(&dx, &dy);
689
+		if (lineCap == NSVG_CAP_BUTT)
690
+			nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
691
+		else if (lineCap == NSVG_CAP_SQUARE)
692
+			nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
693
+		else if (lineCap == NSVG_CAP_ROUND)
694
+			nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
695
+	}
696
+}
697
+
698
+static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)
699
+{
700
+	int i, j;
701
+	NSVGpoint* p0, *p1;
702
+
703
+	p0 = &r->points[r->npoints-1];
704
+	p1 = &r->points[0];
705
+	for (i = 0; i < r->npoints; i++) {
706
+		// Calculate segment direction and length
707
+		p0->dx = p1->x - p0->x;
708
+		p0->dy = p1->y - p0->y;
709
+		p0->len = nsvg__normalize(&p0->dx, &p0->dy);
710
+		// Advance
711
+		p0 = p1++;
712
+	}
713
+
714
+	// calculate joins
715
+	p0 = &r->points[r->npoints-1];
716
+	p1 = &r->points[0];
717
+	for (j = 0; j < r->npoints; j++) {
718
+		float dlx0, dly0, dlx1, dly1, dmr2, cross;
719
+		dlx0 = p0->dy;
720
+		dly0 = -p0->dx;
721
+		dlx1 = p1->dy;
722
+		dly1 = -p1->dx;
723
+		// Calculate extrusions
724
+		p1->dmx = (dlx0 + dlx1) * 0.5f;
725
+		p1->dmy = (dly0 + dly1) * 0.5f;
726
+		dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
727
+		if (dmr2 > 0.000001f) {
728
+			float s2 = 1.0f / dmr2;
729
+			if (s2 > 600.0f) {
730
+				s2 = 600.0f;
731
+			}
732
+			p1->dmx *= s2;
733
+			p1->dmy *= s2;
734
+		}
735
+
736
+		// Clear flags, but keep the corner.
737
+		p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
738
+
739
+		// Keep track of left turns.
740
+		cross = p1->dx * p0->dy - p0->dx * p1->dy;
741
+		if (cross > 0.0f)
742
+			p1->flags |= NSVG_PT_LEFT;
743
+
744
+		// Check to see if the corner needs to be beveled.
745
+		if (p1->flags & NSVG_PT_CORNER) {
746
+			if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
747
+				p1->flags |= NSVG_PT_BEVEL;
748
+			}
749
+		}
750
+
751
+		p0 = p1++;
752
+	}
753
+}
754
+
755
+static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float sx, float sy)
756
+{
757
+	int i, j, closed;
758
+	NSVGpath* path;
759
+	NSVGpoint* p0, *p1;
760
+	float miterLimit = shape->miterLimit;
761
+	int lineJoin = shape->strokeLineJoin;
762
+	int lineCap = shape->strokeLineCap;
763
+	const float sw = (sx + sy) / 2; // average scaling factor
764
+	const float lineWidth = shape->strokeWidth * sw; // FIXME (?)
765
+
766
+	for (path = shape->paths; path != NULL; path = path->next) {
767
+		// Flatten path
768
+		r->npoints = 0;
769
+		nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, NSVG_PT_CORNER);
770
+		for (i = 0; i < path->npts-1; i += 3) {
771
+			float* p = &path->pts[i*2];
772
+			nsvg__flattenCubicBez(r, p[0]*sx,p[1]*sy, p[2]*sx,p[3]*sy, p[4]*sx,p[5]*sy, p[6]*sx,p[7]*sy, 0, NSVG_PT_CORNER);
773
+		}
774
+		if (r->npoints < 2)
775
+			continue;
776
+
777
+		closed = path->closed;
778
+
779
+		// If the first and last points are the same, remove the last, mark as closed path.
780
+		p0 = &r->points[r->npoints-1];
781
+		p1 = &r->points[0];
782
+		if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
783
+			r->npoints--;
784
+			p0 = &r->points[r->npoints-1];
785
+			closed = 1;
786
+		}
787
+
788
+		if (shape->strokeDashCount > 0) {
789
+			int idash = 0, dashState = 1;
790
+			float totalDist = 0, dashLen, allDashLen, dashOffset;
791
+			NSVGpoint cur;
792
+
793
+			if (closed)
794
+				nsvg__appendPathPoint(r, r->points[0]);
795
+
796
+			// Duplicate points -> points2.
797
+			nsvg__duplicatePoints(r);
798
+
799
+			r->npoints = 0;
800
+ 			cur = r->points2[0];
801
+			nsvg__appendPathPoint(r, cur);
802
+
803
+			// Figure out dash offset.
804
+			allDashLen = 0;
805
+			for (j = 0; j < shape->strokeDashCount; j++)
806
+				allDashLen += shape->strokeDashArray[j];
807
+			if (shape->strokeDashCount & 1)
808
+				allDashLen *= 2.0f;
809
+			// Find location inside pattern
810
+			dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
811
+			if (dashOffset < 0.0f)
812
+				dashOffset += allDashLen;
813
+
814
+			while (dashOffset > shape->strokeDashArray[idash]) {
815
+				dashOffset -= shape->strokeDashArray[idash];
816
+				idash = (idash + 1) % shape->strokeDashCount;
817
+			}
818
+			dashLen = (shape->strokeDashArray[idash] - dashOffset) * sw;
819
+
820
+			for (j = 1; j < r->npoints2; ) {
821
+				float dx = r->points2[j].x - cur.x;
822
+				float dy = r->points2[j].y - cur.y;
823
+				float dist = sqrtf(dx*dx + dy*dy);
824
+
825
+				if ((totalDist + dist) > dashLen) {
826
+					// Calculate intermediate point
827
+					float d = (dashLen - totalDist) / dist;
828
+					float x = cur.x + dx * d;
829
+					float y = cur.y + dy * d;
830
+					nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
831
+
832
+					// Stroke
833
+					if (r->npoints > 1 && dashState) {
834
+						nsvg__prepareStroke(r, miterLimit, lineJoin);
835
+						nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
836
+					}
837
+					// Advance dash pattern
838
+					dashState = !dashState;
839
+					idash = (idash+1) % shape->strokeDashCount;
840
+					dashLen = shape->strokeDashArray[idash] * sw;
841
+					// Restart
842
+					cur.x = x;
843
+					cur.y = y;
844
+					cur.flags = NSVG_PT_CORNER;
845
+					totalDist = 0.0f;
846
+					r->npoints = 0;
847
+					nsvg__appendPathPoint(r, cur);
848
+				} else {
849
+					totalDist += dist;
850
+					cur = r->points2[j];
851
+					nsvg__appendPathPoint(r, cur);
852
+					j++;
853
+				}
854
+			}
855
+			// Stroke any leftover path
856
+			if (r->npoints > 1 && dashState)
857
+				nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
858
+		} else {
859
+			nsvg__prepareStroke(r, miterLimit, lineJoin);
860
+			nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
861
+		}
862
+	}
863
+}
864
+
865
+static int nsvg__cmpEdge(const void *p, const void *q)
866
+{
867
+	const NSVGedge* a = (const NSVGedge*)p;
868
+	const NSVGedge* b = (const NSVGedge*)q;
869
+
870
+	if (a->y0 < b->y0) return -1;
871
+	if (a->y0 > b->y0) return  1;
872
+	return 0;
873
+}
874
+
875
+
876
+static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
877
+{
878
+	 NSVGactiveEdge* z;
879
+
880
+	if (r->freelist != NULL) {
881
+		// Restore from freelist.
882
+		z = r->freelist;
883
+		r->freelist = z->next;
884
+	} else {
885
+		// Alloc new edge.
886
+		z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
887
+		if (z == NULL) return NULL;
888
+	}
889
+
890
+	float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
891
+//	STBTT_assert(e->y0 <= start_point);
892
+	// round dx down to avoid going too far
893
+	if (dxdy < 0)
894
+		z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
895
+	else
896
+		z->dx = (int)floorf(NSVG__FIX * dxdy);
897
+	z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
898
+//	z->x -= off_x * FIX;
899
+	z->ey = e->y1;
900
+	z->next = 0;
901
+	z->dir = e->dir;
902
+
903
+	return z;
904
+}
905
+
906
+static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
907
+{
908
+	z->next = r->freelist;
909
+	r->freelist = z;
910
+}
911
+
912
+static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)
913
+{
914
+	int i = x0 >> NSVG__FIXSHIFT;
915
+	int j = x1 >> NSVG__FIXSHIFT;
916
+	if (i < *xmin) *xmin = i;
917
+	if (j > *xmax) *xmax = j;
918
+	if (i < len && j >= 0) {
919
+		if (i == j) {
920
+			// x0,x1 are the same pixel, so compute combined coverage
921
+			scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
922
+		} else {
923
+			if (i >= 0) // add antialiasing for x0
924
+				scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
925
+			else
926
+				i = -1; // clip
927
+
928
+			if (j < len) // add antialiasing for x1
929
+				scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
930
+			else
931
+				j = len; // clip
932
+
933
+			for (++i; i < j; ++i) // fill pixels between x0 and x1
934
+				scanline[i] = (unsigned char)(scanline[i] + maxWeight);
935
+		}
936
+	}
937
+}
938
+
939
+// note: this routine clips fills that extend off the edges... ideally this
940
+// wouldn't happen, but it could happen if the truetype glyph bounding boxes
941
+// are wrong, or if the user supplies a too-small bitmap
942
+static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule)
943
+{
944
+	// non-zero winding fill
945
+	int x0 = 0, w = 0;
946
+
947
+	if (fillRule == NSVG_FILLRULE_NONZERO) {
948
+		// Non-zero
949
+		while (e != NULL) {
950
+			if (w == 0) {
951
+				// if we're currently at zero, we need to record the edge start point
952
+				x0 = e->x; w += e->dir;
953
+			} else {
954
+				int x1 = e->x; w += e->dir;
955
+				// if we went to zero, we need to draw
956
+				if (w == 0)
957
+					nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
958
+			}
959
+			e = e->next;
960
+		}
961
+	} else if (fillRule == NSVG_FILLRULE_EVENODD) {
962
+		// Even-odd
963
+		while (e != NULL) {
964
+			if (w == 0) {
965
+				// if we're currently at zero, we need to record the edge start point
966
+				x0 = e->x; w = 1;
967
+			} else {
968
+				int x1 = e->x; w = 0;
969
+				nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
970
+			}
971
+			e = e->next;
972
+		}
973
+	}
974
+}
975
+
976
+static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
977
+
978
+static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
979
+{
980
+	return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);
981
+}
982
+
983
+static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
984
+{
985
+	int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
986
+	int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
987
+	int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
988
+	int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
989
+	int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
990
+	return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
991
+}
992
+
993
+static unsigned int nsvg__applyOpacity(unsigned int c, float u)
994
+{
995
+	int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
996
+	int r = (c) & 0xff;
997
+	int g = (c>>8) & 0xff;
998
+	int b = (c>>16) & 0xff;
999
+	int a = (((c>>24) & 0xff)*iu) >> 8;
1000
+	return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
1001
+}
1002
+
1003
+static inline int nsvg__div255(int x)
1004
+{
1005
+    return ((x+1) * 257) >> 16;
1006
+}
1007
+
1008
+static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
1009
+								float tx, float ty, float sx, float sy, NSVGcachedPaint* cache)
1010
+{
1011
+
1012
+	if (cache->type == NSVG_PAINT_COLOR) {
1013
+		int i, cr, cg, cb, ca;
1014
+		cr = cache->colors[0] & 0xff;
1015
+		cg = (cache->colors[0] >> 8) & 0xff;
1016
+		cb = (cache->colors[0] >> 16) & 0xff;
1017
+		ca = (cache->colors[0] >> 24) & 0xff;
1018
+
1019
+		for (i = 0; i < count; i++) {
1020
+			int r,g,b;
1021
+			int a = nsvg__div255((int)cover[0] * ca);
1022
+			int ia = 255 - a;
1023
+			// Premultiply
1024
+			r = nsvg__div255(cr * a);
1025
+			g = nsvg__div255(cg * a);
1026
+			b = nsvg__div255(cb * a);
1027
+
1028
+			// Blend over
1029
+			r += nsvg__div255(ia * (int)dst[0]);
1030
+			g += nsvg__div255(ia * (int)dst[1]);
1031
+			b += nsvg__div255(ia * (int)dst[2]);
1032
+			a += nsvg__div255(ia * (int)dst[3]);
1033
+
1034
+			dst[0] = (unsigned char)r;
1035
+			dst[1] = (unsigned char)g;
1036
+			dst[2] = (unsigned char)b;
1037
+			dst[3] = (unsigned char)a;
1038
+
1039
+			cover++;
1040
+			dst += 4;
1041
+		}
1042
+	} else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
1043
+		// TODO: spread modes.
1044
+		// TODO: plenty of opportunities to optimize.
1045
+		float fx, fy, dx, gy;
1046
+		float* t = cache->xform;
1047
+		int i, cr, cg, cb, ca;
1048
+		unsigned int c;
1049
+
1050
+		fx = ((float)x - tx) / sx;
1051
+		fy = ((float)y - ty) / sy;
1052
+		dx = 1.0f / sx;
1053
+
1054
+		for (i = 0; i < count; i++) {
1055
+			int r,g,b,a,ia;
1056
+			gy = fx*t[1] + fy*t[3] + t[5];
1057
+			c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
1058
+			cr = (c) & 0xff;
1059
+			cg = (c >> 8) & 0xff;
1060
+			cb = (c >> 16) & 0xff;
1061
+			ca = (c >> 24) & 0xff;
1062
+
1063
+			a = nsvg__div255((int)cover[0] * ca);
1064
+			ia = 255 - a;
1065
+
1066
+			// Premultiply
1067
+			r = nsvg__div255(cr * a);
1068
+			g = nsvg__div255(cg * a);
1069
+			b = nsvg__div255(cb * a);
1070
+
1071
+			// Blend over
1072
+			r += nsvg__div255(ia * (int)dst[0]);
1073
+			g += nsvg__div255(ia * (int)dst[1]);
1074
+			b += nsvg__div255(ia * (int)dst[2]);
1075
+			a += nsvg__div255(ia * (int)dst[3]);
1076
+
1077
+			dst[0] = (unsigned char)r;
1078
+			dst[1] = (unsigned char)g;
1079
+			dst[2] = (unsigned char)b;
1080
+			dst[3] = (unsigned char)a;
1081
+
1082
+			cover++;
1083
+			dst += 4;
1084
+			fx += dx;
1085
+		}
1086
+	} else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
1087
+		// TODO: spread modes.
1088
+		// TODO: plenty of opportunities to optimize.
1089
+		// TODO: focus (fx,fy)
1090
+		float fx, fy, dx, gx, gy, gd;
1091
+		float* t = cache->xform;
1092
+		int i, cr, cg, cb, ca;
1093
+		unsigned int c;
1094
+
1095
+		fx = ((float)x - tx) / sx;
1096
+		fy = ((float)y - ty) / sy;
1097
+		dx = 1.0f / sx;
1098
+
1099
+		for (i = 0; i < count; i++) {
1100
+			int r,g,b,a,ia;
1101
+			gx = fx*t[0] + fy*t[2] + t[4];
1102
+			gy = fx*t[1] + fy*t[3] + t[5];
1103
+			gd = sqrtf(gx*gx + gy*gy);
1104
+			c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
1105
+			cr = (c) & 0xff;
1106
+			cg = (c >> 8) & 0xff;
1107
+			cb = (c >> 16) & 0xff;
1108
+			ca = (c >> 24) & 0xff;
1109
+
1110
+			a = nsvg__div255((int)cover[0] * ca);
1111
+			ia = 255 - a;
1112
+
1113
+			// Premultiply
1114
+			r = nsvg__div255(cr * a);
1115
+			g = nsvg__div255(cg * a);
1116
+			b = nsvg__div255(cb * a);
1117
+
1118
+			// Blend over
1119
+			r += nsvg__div255(ia * (int)dst[0]);
1120
+			g += nsvg__div255(ia * (int)dst[1]);
1121
+			b += nsvg__div255(ia * (int)dst[2]);
1122
+			a += nsvg__div255(ia * (int)dst[3]);
1123
+
1124
+			dst[0] = (unsigned char)r;
1125
+			dst[1] = (unsigned char)g;
1126
+			dst[2] = (unsigned char)b;
1127
+			dst[3] = (unsigned char)a;
1128
+
1129
+			cover++;
1130
+			dst += 4;
1131
+			fx += dx;
1132
+		}
1133
+	}
1134
+}
1135
+
1136
+static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float sx, float sy, NSVGcachedPaint* cache, char fillRule)
1137
+{
1138
+	NSVGactiveEdge *active = NULL;
1139
+	int y, s;
1140
+	int e = 0;
1141
+	int maxWeight = (255 / NSVG__SUBSAMPLES);  // weight per vertical scanline
1142
+	int xmin, xmax;
1143
+
1144
+	for (y = 0; y < r->height; y++) {
1145
+		memset(r->scanline, 0, r->width);
1146
+		xmin = r->width;
1147
+		xmax = 0;
1148
+		for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
1149
+			// find center of pixel for this scanline
1150
+			float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
1151
+			NSVGactiveEdge **step = &active;
1152
+
1153
+			// update all active edges;
1154
+			// remove all active edges that terminate before the center of this scanline
1155
+			while (*step) {
1156
+				NSVGactiveEdge *z = *step;
1157
+				if (z->ey <= scany) {
1158
+					*step = z->next; // delete from list
1159
+//					NSVG__assert(z->valid);
1160
+					nsvg__freeActive(r, z);
1161
+				} else {
1162
+					z->x += z->dx; // advance to position for current scanline
1163
+					step = &((*step)->next); // advance through list
1164
+				}
1165
+			}
1166
+
1167
+			// resort the list if needed
1168
+			for (;;) {
1169
+				int changed = 0;
1170
+				step = &active;
1171
+				while (*step && (*step)->next) {
1172
+					if ((*step)->x > (*step)->next->x) {
1173
+						NSVGactiveEdge* t = *step;
1174
+						NSVGactiveEdge* q = t->next;
1175
+						t->next = q->next;
1176
+						q->next = t;
1177
+						*step = q;
1178
+						changed = 1;
1179
+					}
1180
+					step = &(*step)->next;
1181
+				}
1182
+				if (!changed) break;
1183
+			}
1184
+
1185
+			// insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
1186
+			while (e < r->nedges && r->edges[e].y0 <= scany) {
1187
+				if (r->edges[e].y1 > scany) {
1188
+					NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
1189
+					if (z == NULL) break;
1190
+					// find insertion point
1191
+					if (active == NULL) {
1192
+						active = z;
1193
+					} else if (z->x < active->x) {
1194
+						// insert at front
1195
+						z->next = active;
1196
+						active = z;
1197
+					} else {
1198
+						// find thing to insert AFTER
1199
+						NSVGactiveEdge* p = active;
1200
+						while (p->next && p->next->x < z->x)
1201
+							p = p->next;
1202
+						// at this point, p->next->x is NOT < z->x
1203
+						z->next = p->next;
1204
+						p->next = z;
1205
+					}
1206
+				}
1207
+				e++;
1208
+			}
1209
+
1210
+			// now process all active edges in non-zero fashion
1211
+			if (active != NULL)
1212
+				nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
1213
+		}
1214
+		// Blit
1215
+		if (xmin < 0) xmin = 0;
1216
+		if (xmax > r->width-1) xmax = r->width-1;
1217
+		if (xmin <= xmax) {
1218
+			nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, sx, sy, cache);
1219
+		}
1220
+	}
1221
+
1222
+}
1223
+
1224
+static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
1225
+{
1226
+	int x,y;
1227
+
1228
+	// Unpremultiply
1229
+	for (y = 0; y < h; y++) {
1230
+		unsigned char *row = &image[y*stride];
1231
+		for (x = 0; x < w; x++) {
1232
+			int r = row[0], g = row[1], b = row[2], a = row[3];
1233
+			if (a != 0) {
1234
+				row[0] = (unsigned char)(r*255/a);
1235
+				row[1] = (unsigned char)(g*255/a);
1236
+				row[2] = (unsigned char)(b*255/a);
1237
+			}
1238
+			row += 4;
1239
+		}
1240
+	}
1241
+
1242
+	// Defringe
1243
+	for (y = 0; y < h; y++) {
1244
+		unsigned char *row = &image[y*stride];
1245
+		for (x = 0; x < w; x++) {
1246
+			int r = 0, g = 0, b = 0, a = row[3], n = 0;
1247
+			if (a == 0) {
1248
+				if (x-1 > 0 && row[-1] != 0) {
1249
+					r += row[-4];
1250
+					g += row[-3];
1251
+					b += row[-2];
1252
+					n++;
1253
+				}
1254
+				if (x+1 < w && row[7] != 0) {
1255
+					r += row[4];
1256
+					g += row[5];
1257
+					b += row[6];
1258
+					n++;
1259
+				}
1260
+				if (y-1 > 0 && row[-stride+3] != 0) {
1261
+					r += row[-stride];
1262
+					g += row[-stride+1];
1263
+					b += row[-stride+2];
1264
+					n++;
1265
+				}
1266
+				if (y+1 < h && row[stride+3] != 0) {
1267
+					r += row[stride];
1268
+					g += row[stride+1];
1269
+					b += row[stride+2];
1270
+					n++;
1271
+				}
1272
+				if (n > 0) {
1273
+					row[0] = (unsigned char)(r/n);
1274
+					row[1] = (unsigned char)(g/n);
1275
+					row[2] = (unsigned char)(b/n);
1276
+				}
1277
+			}
1278
+			row += 4;
1279
+		}
1280
+	}
1281
+}
1282
+
1283
+
1284
+static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
1285
+{
1286
+	int i, j;
1287
+	NSVGgradient* grad;
1288
+
1289
+	cache->type = paint->type;
1290
+
1291
+	if (paint->type == NSVG_PAINT_COLOR) {
1292
+		cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
1293
+		return;
1294
+	}
1295
+
1296
+	grad = paint->gradient;
1297
+
1298
+	cache->spread = grad->spread;
1299
+	memcpy(cache->xform, grad->xform, sizeof(float)*6);
1300
+
1301
+	if (grad->nstops == 0) {
1302
+		for (i = 0; i < 256; i++)
1303
+			cache->colors[i] = 0;
1304
+	} if (grad->nstops == 1) {
1305
+		for (i = 0; i < 256; i++)
1306
+			cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
1307
+	} else {
1308
+		unsigned int ca, cb = 0;
1309
+		float ua, ub, du, u;
1310
+		int ia, ib, count;
1311
+
1312
+		ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
1313
+		ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
1314
+		ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
1315
+		ia = (int)(ua * 255.0f);
1316
+		ib = (int)(ub * 255.0f);
1317
+		for (i = 0; i < ia; i++) {
1318
+			cache->colors[i] = ca;
1319
+		}
1320
+
1321
+		for (i = 0; i < grad->nstops-1; i++) {
1322
+			ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
1323
+			cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
1324
+			ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
1325
+			ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
1326
+			ia = (int)(ua * 255.0f);
1327
+			ib = (int)(ub * 255.0f);
1328
+			count = ib - ia;
1329
+			if (count <= 0) continue;
1330
+			u = 0;
1331
+			du = 1.0f / (float)count;
1332
+			for (j = 0; j < count; j++) {
1333
+				cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
1334
+				u += du;
1335
+			}
1336
+		}
1337
+
1338
+		for (i = ib; i < 256; i++)
1339
+			cache->colors[i] = cb;
1340
+	}
1341
+
1342
+}
1343
+
1344
+/*
1345
+static void dumpEdges(NSVGrasterizer* r, const char* name)
1346
+{
1347
+	float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
1348
+	NSVGedge *e = NULL;
1349
+	int i;
1350
+	if (r->nedges == 0) return;
1351
+	FILE* fp = fopen(name, "w");
1352
+	if (fp == NULL) return;
1353
+
1354
+	xmin = xmax = r->edges[0].x0;
1355
+	ymin = ymax = r->edges[0].y0;
1356
+	for (i = 0; i < r->nedges; i++) {
1357
+		e = &r->edges[i];
1358
+		xmin = nsvg__minf(xmin, e->x0);
1359
+		xmin = nsvg__minf(xmin, e->x1);
1360
+		xmax = nsvg__maxf(xmax, e->x0);
1361
+		xmax = nsvg__maxf(xmax, e->x1);
1362
+		ymin = nsvg__minf(ymin, e->y0);
1363
+		ymin = nsvg__minf(ymin, e->y1);
1364
+		ymax = nsvg__maxf(ymax, e->y0);
1365
+		ymax = nsvg__maxf(ymax, e->y1);
1366
+	}
1367
+
1368
+	fprintf(fp, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\">", xmin, ymin, (xmax - xmin), (ymax - ymin));
1369
+
1370
+	for (i = 0; i < r->nedges; i++) {
1371
+		e = &r->edges[i];
1372
+		fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#000;\" />", e->x0,e->y0, e->x1,e->y1);
1373
+	}
1374
+
1375
+	for (i = 0; i < r->npoints; i++) {
1376
+		if (i+1 < r->npoints)
1377
+			fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#f00;\" />", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y);
1378
+		fprintf(fp ,"<circle cx=\"%f\" cy=\"%f\" r=\"1\" style=\"fill:%s;\" />", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0");
1379
+	}
1380
+
1381
+	fprintf(fp, "</svg>");
1382
+	fclose(fp);
1383
+}
1384
+*/
1385
+
1386
+void nsvgRasterizeXY(NSVGrasterizer* r,
1387
+				   NSVGimage* image, float tx, float ty,
1388
+				   float sx, float sy,
1389
+				   unsigned char* dst, int w, int h, int stride)
1390
+{
1391
+	NSVGshape *shape = NULL;
1392
+	NSVGedge *e = NULL;
1393
+	NSVGcachedPaint cache;
1394
+	int i;
1395
+
1396
+	r->bitmap = dst;
1397
+	r->width = w;
1398
+	r->height = h;
1399
+	r->stride = stride;
1400
+
1401
+	if (w > r->cscanline) {
1402
+		r->cscanline = w;
1403
+		r->scanline = (unsigned char*)realloc(r->scanline, w);
1404
+		if (r->scanline == NULL) return;
1405
+	}
1406
+
1407
+	for (i = 0; i < h; i++)
1408
+		memset(&dst[i*stride], 0, w*4);
1409
+
1410
+	for (shape = image->shapes; shape != NULL; shape = shape->next) {
1411
+		if (!(shape->flags & NSVG_FLAGS_VISIBLE))
1412
+			continue;
1413
+
1414
+		if (shape->fill.type != NSVG_PAINT_NONE) {
1415
+			nsvg__resetPool(r);
1416
+			r->freelist = NULL;
1417
+			r->nedges = 0;
1418
+
1419
+			nsvg__flattenShape(r, shape, sx, sy);
1420
+
1421
+			// Scale and translate edges
1422
+			for (i = 0; i < r->nedges; i++) {
1423
+				e = &r->edges[i];
1424
+				e->x0 = tx + e->x0;
1425
+				e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1426
+				e->x1 = tx + e->x1;
1427
+				e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1428
+			}
1429
+
1430
+			// Rasterize edges
1431
+			if (r->nedges != 0)
1432
+				qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1433
+
1434
+			// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
1435
+			nsvg__initPaint(&cache, &shape->fill, shape->opacity);
1436
+
1437
+			nsvg__rasterizeSortedEdges(r, tx,ty, sx, sy, &cache, shape->fillRule);
1438
+		}
1439
+		if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * sx) > 0.01f) {
1440
+			nsvg__resetPool(r);
1441
+			r->freelist = NULL;
1442
+			r->nedges = 0;
1443
+
1444
+			nsvg__flattenShapeStroke(r, shape, sx, sy);
1445
+
1446
+//			dumpEdges(r, "edge.svg");
1447
+
1448
+			// Scale and translate edges
1449
+			for (i = 0; i < r->nedges; i++) {
1450
+				e = &r->edges[i];
1451
+				e->x0 = tx + e->x0;
1452
+				e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1453
+				e->x1 = tx + e->x1;
1454
+				e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1455
+			}
1456
+
1457
+			// Rasterize edges
1458
+			if (r->nedges != 0)
1459
+				qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1460
+
1461
+			// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
1462
+			nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
1463
+
1464
+			nsvg__rasterizeSortedEdges(r, tx,ty,sx, sy, &cache, NSVG_FILLRULE_NONZERO);
1465
+		}
1466
+	}
1467
+
1468
+	nsvg__unpremultiplyAlpha(dst, w, h, stride);
1469
+
1470
+	r->bitmap = NULL;
1471
+	r->width = 0;
1472
+	r->height = 0;
1473
+	r->stride = 0;
1474
+}
1475
+
1476
+void nsvgRasterize(NSVGrasterizer* r,
1477
+				   NSVGimage* image, float tx, float ty, float scale,
1478
+				   unsigned char* dst, int w, int h, int stride)
1479
+{
1480
+	nsvgRasterizeXY(r,image, tx, ty, scale, scale, dst, w, h, stride);
1481
+}
1482
+
1483
+#endif // NANOSVGRAST_IMPLEMENTATION
1484
+
1485
+#endif // NANOSVGRAST_H
(-)b/cad/PrusaSlicer/files/patch-src_libslic3r_CMakeLists.txt (-3 / +3 lines)
Lines 1-10 Link Here
1
--- src/libslic3r/CMakeLists.txt.orig	2022-09-06 07:09:19 UTC
1
--- src/libslic3r/CMakeLists.txt.orig	2023-06-19 12:07:14 UTC
2
+++ src/libslic3r/CMakeLists.txt
2
+++ src/libslic3r/CMakeLists.txt
3
@@ -395,7 +395,6 @@ find_package(JPEG REQUIRED)
3
@@ -490,7 +490,6 @@ target_link_libraries(libslic3r
4
 target_link_libraries(libslic3r
4
 target_link_libraries(libslic3r
5
     libnest2d
5
     libnest2d
6
     admesh
6
     admesh
7
-    cereal
7
-    libcereal
8
     libigl
8
     libigl
9
     miniz
9
     miniz
10
     boost_libs
10
     boost_libs
(-)b/cad/PrusaSlicer/files/patch-src_libslic3r_Format_SL1__SVG.cpp (+12 lines)
Added Link Here
1
--- src/libslic3r/Format/SL1_SVG.cpp.orig	2023-07-21 14:55:56 UTC
2
+++ src/libslic3r/Format/SL1_SVG.cpp
3
@@ -6,7 +6,8 @@
4
 #include "libslic3r/Format/ZipperArchiveImport.hpp"
5
 
6
 #define NANOSVG_IMPLEMENTATION
7
-#include "nanosvg/nanosvg.h"
8
+#define NANOSVGRAST_IMPLEMENTATION
9
+#include "libnanosvg/nanosvgrast.h"
10
 
11
 #include <limits>
12
 #include <cstdint>
(-)b/cad/PrusaSlicer/files/patch-src_libslic3r_GCodeSender.cpp (+20 lines)
Added Link Here
1
--- src/libslic3r/GCodeSender.cpp.orig	2023-07-24 22:05:38 UTC
2
+++ src/libslic3r/GCodeSender.cpp
3
@@ -8,7 +8,7 @@
4
 #include <boost/date_time/posix_time/posix_time.hpp>
5
 #include <boost/lexical_cast.hpp>
6
 
7
-#if defined(__APPLE__) || defined(__OpenBSD__)
8
+#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
9
 #include <termios.h>
10
 #endif
11
 #ifdef __APPLE__
12
@@ -146,7 +146,7 @@ GCodeSender::set_baud_rate(unsigned int baud_rate)
13
         if (ioctl(handle, TCSETS2, &ios))
14
             printf("Error in TCSETS2: %s\n", strerror(errno));
15
 		
16
-#elif __OpenBSD__
17
+#elif __OpenBSD__ || __FreeBSD__
18
 		struct termios ios;
19
 		::tcgetattr(handle, &ios);
20
 		::cfsetspeed(&ios, baud_rate);
(-)b/cad/PrusaSlicer/files/patch-src_libslic3r_NSVGUtils.hpp (+11 lines)
Added Link Here
1
--- src/libslic3r/NSVGUtils.hpp.orig	2023-07-25 16:16:15 UTC
2
+++ src/libslic3r/NSVGUtils.hpp
3
@@ -3,7 +3,7 @@
4
 
5
 #include "Polygon.hpp"
6
 #include "ExPolygon.hpp"
7
-#include "nanosvg/nanosvg.h"    // load SVG file
8
+#include "libnanosvg/nanosvg.h"    // load SVG file
9
 
10
 namespace Slic3r {
11
 
(-)b/cad/PrusaSlicer/files/patch-src_libslic3r_SupportSpotsGenerator.cpp (+11 lines)
Added Link Here
1
--- src/libslic3r/SupportSpotsGenerator.cpp.orig	2023-07-25 08:36:31 UTC
2
+++ src/libslic3r/SupportSpotsGenerator.cpp
3
@@ -849,7 +849,7 @@ std::tuple<SupportPoints, PartialObjects> check_stabil
4
                         }
5
                     }
6
                 }
7
-                auto estimate_conn_strength = [bottom_z](const SliceConnection &conn) {
8
+                auto estimate_conn_strength = [bottom_z](const SliceConnection &conn) -> float {
9
                     if (conn.area < EPSILON) { // connection is empty, does not exists. Return max strength so that it is not picked as the
10
                                                // weakest connection.
11
                         return INFINITY;
(-)b/cad/PrusaSlicer/files/patch-src_occt__wrapper_CMakeLists.txt (-3 / +3 lines)
Lines 1-6 Link Here
1
--- src/occt_wrapper/CMakeLists.txt.orig	2022-09-06 07:09:19 UTC
1
--- src/occt_wrapper/CMakeLists.txt.orig	2023-06-19 12:07:14 UTC
2
+++ src/occt_wrapper/CMakeLists.txt
2
+++ src/occt_wrapper/CMakeLists.txt
3
@@ -19,9 +19,11 @@ include(GenerateExportHeader)
3
@@ -19,9 +19,11 @@ generate_export_header(OCCTWrapper)
4
 
4
 
5
 generate_export_header(OCCTWrapper)
5
 generate_export_header(OCCTWrapper)
6
 
6
 
Lines 13-19 Link Here
13
     TKXDESTEP
13
     TKXDESTEP
14
     TKSTEP
14
     TKSTEP
15
     TKSTEP209
15
     TKSTEP209
16
@@ -56,5 +58,5 @@ target_link_libraries(OCCTWrapper ${OCCT_LIBS})
16
@@ -58,5 +60,5 @@ include(GNUInstallDirs)
17
 
17
 
18
 include(GNUInstallDirs)
18
 include(GNUInstallDirs)
19
 
19
 
(-)a/cad/PrusaSlicer/files/patch-src_qhull_CMakeLists.txt (-29 lines)
Removed Link Here
1
--- src/qhull/CMakeLists.txt.orig	2022-09-06 07:09:19 UTC
2
+++ src/qhull/CMakeLists.txt
3
@@ -14,19 +14,8 @@ find_package(Qhull 7.2 QUIET)
4
 
5
 add_library(qhull INTERFACE)
6
 
7
-if(Qhull_FOUND)
8
+#force use of bundled qhull#else(Qhull_FOUND)
9
 
10
-message(STATUS "Using qhull from system.")
11
-if(SLIC3R_STATIC)
12
-    slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhullstatic_r" RelWithDebInfo Release)
13
-    target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r)
14
-else()
15
-    slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhull_r" RelWithDebInfo Release)
16
-    target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhull_r)
17
-endif()
18
-
19
-else(Qhull_FOUND)
20
-
21
 project(qhull)
22
 cmake_minimum_required(VERSION 2.6)
23
 
24
@@ -144,4 +133,4 @@ endif(UNIX)
25
 target_include_directories(${qhull_STATIC} BEFORE PUBLIC ${LIBDIR}/qhull/src)
26
 target_link_libraries(qhull INTERFACE ${qhull_STATIC})
27
 
28
-endif()
29
+#force use of bundled qhull##endif()
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_CMakeLists.txt (-4 / +14 lines)
Lines 1-11 Link Here
1
--- src/slic3r/CMakeLists.txt.orig	2022-09-06 07:09:19 UTC
1
--- src/slic3r/CMakeLists.txt.orig	2023-06-19 12:07:14 UTC
2
+++ src/slic3r/CMakeLists.txt
2
+++ src/slic3r/CMakeLists.txt
3
@@ -260,11 +260,11 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}
3
@@ -293,7 +293,7 @@ set(SLIC3R_GUI_SOURCES
4
     Utils/WxFontUtils.hpp
5
 )
6
 
7
-find_package(NanoSVG REQUIRED)
8
+# find_package(NanoSVG REQUIRED)
9
 
10
 if (APPLE)
11
     list(APPEND SLIC3R_GUI_SOURCES
12
@@ -319,11 +319,12 @@ encoding_check(libslic3r_gui)
4
 
13
 
5
 encoding_check(libslic3r_gui)
14
 encoding_check(libslic3r_gui)
6
 
15
 
7
-target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
16
-target_link_libraries(libslic3r_gui libslic3r avrdude libcereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES} NanoSVG::nanosvg NanoSVG::nanosvgrast)
8
+target_link_libraries(libslic3r_gui libslic3r avrdude imgui GLEW::GLEW OpenGL::GL OpenGL::GLU hidapi libcurl ${wxWidgets_LIBRARIES})
17
+# target_link_libraries(libslic3r_gui libslic3r avrdude imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES} NanoSVG::nanosvg NanoSVG::nanosvgrast)
18
+target_link_libraries(libslic3r_gui libslic3r avrdude imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
9
 
19
 
10
 if (MSVC)
20
 if (MSVC)
11
     target_link_libraries(libslic3r_gui Setupapi.lib)
21
     target_link_libraries(libslic3r_gui Setupapi.lib)
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_BitmapCache.cpp (+32 lines)
Added Link Here
1
--- src/slic3r/GUI/BitmapCache.cpp.orig	2023-07-21 12:45:35 UTC
2
+++ src/slic3r/GUI/BitmapCache.cpp
3
@@ -15,8 +15,9 @@
4
     #include <wx/rawbmp.h>
5
 #endif /* __WXGTK2__ */
6
 
7
-#include <nanosvg/nanosvg.h>
8
-#include <nanosvg/nanosvgrast.h>
9
+#include <wx/display.h>
10
+#include "libnanosvg/nanosvg.h"
11
+#include "libnanosvg/nanosvgrast.h"
12
 
13
 namespace Slic3r { namespace GUI {
14
 
15
@@ -68,7 +69,7 @@ wxBitmapBundle* BitmapCache::insert_bndl(const std::st
16
     wxVector<wxBitmap> bitmaps;
17
 
18
     std::set<double> scales = {1.0};
19
-#ifndef __linux__
20
+#if !defined(__linux__) && !defined(__FreeBSD__)
21
 
22
 #ifdef __APPLE__
23
     scales.emplace(m_scale);
24
@@ -547,7 +548,7 @@ wxBitmapBundle BitmapCache::mksolid(size_t width_in, s
25
     wxVector<wxBitmap> bitmaps;
26
 
27
     std::set<double> scales = { 1.0 };
28
-#ifndef __linux__
29
+#if !defined(__linux__) && !defined(__FreeBSD__)
30
 
31
 #ifdef __APPLE__
32
     scales.emplace(m_scale);
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_ConfigWizard.cpp (+56 lines)
Added Link Here
1
--- src/slic3r/GUI/ConfigWizard.cpp.orig	2023-07-21 14:05:27 UTC
2
+++ src/slic3r/GUI/ConfigWizard.cpp
3
@@ -60,7 +60,7 @@
4
 #include "slic3r/GUI/I18N.hpp"
5
 #include "slic3r/Config/Version.hpp"
6
 
7
-#if defined(__linux__) && defined(__WXGTK3__)
8
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__WXGTK3__)
9
 #define wxLinux_gtk3 true
10
 #else
11
 #define wxLinux_gtk3 false
12
@@ -583,7 +583,7 @@ void PageWelcome::set_run_reason(ConfigWizard::RunReas
13
     const bool data_empty = run_reason == ConfigWizard::RR_DATA_EMPTY;
14
     welcome_text->Show(data_empty);
15
     cbox_reset->Show(!data_empty);
16
-#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION)
17
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(SLIC3R_DESKTOP_INTEGRATION)
18
     if (!DesktopIntegrationDialog::is_integrated())
19
         cbox_integrate->Show(true);
20
     else
21
@@ -1474,7 +1474,7 @@ PageDownloader::PageDownloader(ConfigWizard* parent)
22
         " The model will be downloaded into folder you choose bellow."
23
     ), SLIC3R_APP_NAME));
24
 
25
-#ifdef __linux__
26
+#if defined(__linux__) || defined(__FreeBSD__)
27
     append_text(wxString::Format(_L(
28
         "On Linux systems the process of registration also creates desktop integration files for this version of application."
29
     )));
30
@@ -1535,7 +1535,7 @@ bool DownloaderUtils::Worker::perform_register(const s
31
     }
32
     //key_full = "\"C:\\Program Files\\Prusa3D\\PrusaSlicer\\prusa-slicer-console.exe\" \"%1\"";
33
     key_full = key_string;
34
-#elif __APPLE__
35
+#elif defined(__APPLE__) || defined(__FreeBSD__)
36
     // Apple registers for custom url in info.plist thus it has to be already registered since build.
37
     // The url will always trigger opening of prusaslicer and we have to check that user has allowed it. (GUI_App::MacOpenURL is the triggered method)
38
 #else 
39
@@ -1554,7 +1554,7 @@ void DownloaderUtils::Worker::deregister()
40
         return;
41
     }
42
     key_full = key_string;
43
-#elif __APPLE__
44
+#elif defined(__APPLE__) || defined(__FreeBSD__)
45
     // TODO
46
 #else 
47
     BOOST_LOG_TRIVIAL(debug) << "DesktopIntegrationDialog::undo_downloader_registration";
48
@@ -3106,7 +3106,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_c
49
         if ((check_unsaved_preset_changes = install_bundles.size() > 0))
50
             header = _L_PLURAL("A new vendor was installed and one of its printers will be activated", "New vendors were installed and one of theirs printers will be activated", install_bundles.size());
51
 
52
-#ifdef __linux__
53
+#if defined(__linux__) || defined(__FreeBSD__)
54
     // Desktop integration on Linux
55
     BOOST_LOG_TRIVIAL(debug) << "ConfigWizard::priv::apply_config integrate_desktop" << page_welcome->integrate_desktop()  << " perform_registration_linux " << page_downloader->m_downloader->get_perform_registration_linux();
56
     if (page_welcome->integrate_desktop())
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_ConfigWizard.hpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/ConfigWizard.hpp.orig	2023-07-25 09:21:21 UTC
2
+++ src/slic3r/GUI/ConfigWizard.hpp
3
@@ -22,7 +22,7 @@ namespace DownloaderUtils {
4
         wxWindow*   m_parent{ nullptr };
5
         wxTextCtrl* m_input_path{ nullptr };
6
         bool        downloader_checked{ false };
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
         bool        perform_registration_linux{ false };
10
 #endif // __linux__
11
 
12
@@ -41,7 +41,7 @@ namespace DownloaderUtils {
13
 
14
         bool on_finish();
15
         bool perform_register(const std::string& path_override = {});
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
         bool get_perform_registration_linux() { return perform_registration_linux; }
19
 #endif // __linux__
20
     };
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_DesktopIntegrationDialog.cpp (+8 lines)
Added Link Here
1
--- src/slic3r/GUI/DesktopIntegrationDialog.cpp.orig	2023-07-25 09:24:17 UTC
2
+++ src/slic3r/GUI/DesktopIntegrationDialog.cpp
3
@@ -1,4 +1,4 @@
4
-#ifdef __linux__
5
+#if defined(__linux__) || defined(__FreeBSD__)
6
 #include "DesktopIntegrationDialog.hpp"
7
 #include "GUI_App.hpp"
8
 #include "GUI.hpp"
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_DesktopIntegrationDialog.hpp (+15 lines)
Added Link Here
1
--- src/slic3r/GUI/DesktopIntegrationDialog.hpp.orig	2023-07-25 09:25:50 UTC
2
+++ src/slic3r/GUI/DesktopIntegrationDialog.hpp
3
@@ -1,4 +1,4 @@
4
-#ifdef __linux__
5
+#if defined(__linux__) || defined(__FreeBSD__)
6
 #ifndef slic3r_DesktopIntegrationDialog_hpp_
7
 #define slic3r_DesktopIntegrationDialog_hpp_
8
 
9
@@ -42,4 +42,4 @@ class DesktopIntegrationDialog : public wxDialog (priv
10
 } // namespace Slic3r
11
 
12
 #endif // slic3r_DesktopIntegrationDialog_hpp_
13
-#endif // __linux__
14
\ No newline at end of file
15
+#endif // __linux__
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_ExtraRenderers.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/ExtraRenderers.cpp.orig	2023-07-25 09:27:23 UTC
2
+++ src/slic3r/GUI/ExtraRenderers.cpp
3
@@ -327,7 +327,7 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWin
4
     c_editor->SetSelection(atoi(data.GetText().c_str()));
5
 
6
     
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
10
         // to avoid event propagation to other sidebar items
11
         evt.StopPropagation();
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_Field.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/Field.cpp.orig	2023-07-25 09:29:18 UTC
2
+++ src/slic3r/GUI/Field.cpp
3
@@ -199,7 +199,7 @@ static wxString na_value(bool for_spin_ctrl = false)
4
 
5
 static wxString na_value(bool for_spin_ctrl = false)
6
 {
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     if (for_spin_ctrl)
10
         return "";
11
 #endif
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GLCanvas3D.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/GLCanvas3D.cpp.orig	2023-07-25 09:31:07 UTC
2
+++ src/slic3r/GUI/GLCanvas3D.cpp
3
@@ -97,7 +97,7 @@ float RetinaHelper::get_scale_factor() { return float(
4
 #endif // __WXGTK3__
5
 
6
 // Fixed the collision between BuildVolume::Type::Convex and macro Convex defined inside /usr/include/X11/X.h that is included by WxWidgets 3.0.
7
-#if defined(__linux__) && defined(Convex)
8
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(Convex)
9
 #undef Convex
10
 #endif
11
 
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GLTexture.cpp (+13 lines)
Added Link Here
1
--- src/slic3r/GUI/GLTexture.cpp.orig	2023-07-25 16:08:09 UTC
2
+++ src/slic3r/GUI/GLTexture.cpp
3
@@ -21,8 +21,8 @@
4
 #define STB_DXT_IMPLEMENTATION
5
 #include "stb_dxt/stb_dxt.h"
6
 
7
-#include <nanosvg/nanosvg.h>
8
-#include <nanosvg/nanosvgrast.h>
9
+#include "libnanosvg/nanosvg.h"
10
+#include "libnanosvg/nanosvgrast.h"
11
 
12
 #include "libslic3r/Utils.hpp"
13
 
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI.cpp.orig	2023-07-21 15:02:36 UTC
2
+++ src/slic3r/GUI/GUI.cpp
3
@@ -481,7 +481,7 @@ void desktop_open_folder(const boost::filesystem::path
4
 	const wxString widepath = path.wstring();
5
 	const wchar_t* argv[] = { L"explorer", widepath.GetData(), nullptr };
6
 	::wxExecute(const_cast<wchar_t**>(argv), wxEXEC_ASYNC, nullptr);
7
-#elif __APPLE__
8
+#elif defined(__APPLE__) || defined(__FreeBSD__)
9
 	const char* argv[] = { "open", path.string().c_str(), nullptr };
10
 	::wxExecute(const_cast<char**>(argv), wxEXEC_ASYNC, nullptr);
11
 #else
12
@@ -490,7 +490,7 @@ void desktop_open_folder(const boost::filesystem::path
13
 #endif
14
 }
15
 
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
 namespace {
19
 wxExecuteEnv get_appimage_exec_env()
20
 {
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI.hpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI.hpp.orig	2023-07-21 13:10:36 UTC
2
+++ src/slic3r/GUI/GUI.hpp
3
@@ -84,7 +84,7 @@ void desktop_open_folder(const boost::filesystem::path
4
 // Ask the destop to open the directory specified by path using the default file explorer.
5
 void desktop_open_folder(const boost::filesystem::path& path);
6
 
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined (__FreeBSD__)
9
 // Calling wxExecute on Linux with proper handling of AppImage's env vars.
10
 // argv example: { "xdg-open", path.c_str(), nullptr }
11
 void desktop_execute(const char* argv[]);
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI__App.cpp (-37 / +118 lines)
Lines 1-43 Link Here
1
--- src/slic3r/GUI/GUI_App.cpp.orig	2022-09-06 07:09:19 UTC
1
--- src/slic3r/GUI/GUI_App.cpp.orig	2023-06-19 12:07:14 UTC
2
+++ src/slic3r/GUI/GUI_App.cpp
2
+++ src/slic3r/GUI/GUI_App.cpp
3
@@ -2072,21 +2072,24 @@ bool GUI_App::load_language(wxString language, bool in
3
@@ -395,7 +395,7 @@ class SplashScreen : public wxSplashScreen (private)
4
 	        	BOOST_LOG_TRIVIAL(trace) << boost::format("System language detected (user locales and such): %1%") % m_language_info_system->CanonicalName.ToUTF8().data();
4
 };
5
 	        }
5
 
6
 		}
6
 
7
-        {
7
-#ifdef __linux__
8
+        if (0) {
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
 	    	// Allocating a temporary locale will switch the default wxTranslations to its internal wxTranslations instance.
9
 bool static check_old_linux_datadir(const wxString& app_name) {
10
 	    	wxLocale temp_locale;
10
     // If we are on Linux and the datadir does not exist yet, look into the old
11
 	    	// Set the current translation's language to default, otherwise GetBestTranslation() may not work (see the wxWidgets source code).
11
     // location where the datadir was before version 2.3. If we find it there,
12
-	    	wxTranslations::Get()->SetLanguage(wxLANGUAGE_DEFAULT);
12
@@ -973,7 +973,7 @@ void GUI_App::init_app_config()
13
-	    	// Let the wxFileTranslationsLoader enumerate all translation dictionaries for PrusaSlicer
13
 	// Mac : "~/Library/Application Support/Slic3r"
14
-	    	// and try to match them with the system specific "preferred languages". 
14
 
15
-	    	// There seems to be a support for that on Windows and OSX, while on Linuxes the code just returns wxLocale::GetSystemLanguage().
15
     if (data_dir().empty()) {
16
-	    	// The last parameter gets added to the list of detected dictionaries. This is a workaround 
16
-        #ifndef __linux__
17
-	    	// for not having the English dictionary. Let's hope wxWidgets of various versions process this call the same way.
17
+        #if !defined(__linux__) && !defined(__FreeBSD__)
18
-			wxString best_language = wxTranslations::Get()->GetBestTranslation(SLIC3R_APP_KEY, wxLANGUAGE_ENGLISH);
18
             set_data_dir(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data());
19
-			if (! best_language.IsEmpty()) {
19
         #else
20
-				m_language_info_best = wxLocale::FindLanguageInfo(best_language);
20
             // Since version 2.3, config dir on Linux is in ${XDG_CONFIG_HOME}.
21
-	        	BOOST_LOG_TRIVIAL(trace) << boost::format("Best translation language detected (may be different from user locales): %1%") % m_language_info_best->CanonicalName.ToUTF8().data();
21
@@ -1130,7 +1130,8 @@ bool GUI_App::on_init_inner()
22
-			}
22
 {
23
+        wxTranslations *wx_trp = wxTranslations::Get();
23
     // Set initialization of image handlers before any UI actions - See GH issue #7469
24
+        if (wx_trp) {
24
     wxInitAllImageHandlers();
25
+	    	    wxTranslations::Get()->SetLanguage(wxLANGUAGE_DEFAULT);
25
-
26
+	    	    // Let the wxFileTranslationsLoader enumerate all translation dictionaries for PrusaSlicer
26
+    // Silence warnings generated with wxWidgets 3.2
27
+	    	    // and try to match them with the system specific "preferred languages". 
27
+    wxSizerFlags::DisableConsistencyChecks();
28
+	    	    // There seems to be a support for that on Windows and OSX, while on Linuxes the code just returns wxLocale::GetSystemLanguage().
28
 #if defined(_WIN32) && ! defined(_WIN64)
29
+	    	    // The last parameter gets added to the list of detected dictionaries. This is a workaround 
29
     // Win32 32bit build.
30
+	    	    // for not having the English dictionary. Let's hope wxWidgets of various versions process this call the same way.
30
     if (wxPlatformInfo::Get().GetArchName().substr(0, 2) == "64") {
31
+			      wxString best_language = wxTranslations::Get()->GetBestTranslation(SLIC3R_APP_KEY, wxLANGUAGE_ENGLISH);
31
@@ -1158,7 +1159,7 @@ bool GUI_App::on_init_inner()
32
+			      if (! best_language.IsEmpty()) {
32
     wxCHECK_MSG(wxDirExists(resources_dir), false,
33
+				        m_language_info_best = wxLocale::FindLanguageInfo(best_language);
33
         wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
34
+	        	    BOOST_LOG_TRIVIAL(trace) << boost::format("Best translation language detected (may be different from user locales): %1%") % m_language_info_best->CanonicalName.ToUTF8().data();
34
 
35
+			      }
35
-#ifdef __linux__
36
+        }
36
+#if defined(__linux__) || defined(__FreeBSD__)
37
             #ifdef __linux__
37
     if (! check_old_linux_datadir(GetAppName())) {
38
         std::cerr << "Quitting, user chose to move their data to new location." << std::endl;
39
         return false;
40
@@ -1263,7 +1264,7 @@ bool GUI_App::on_init_inner()
41
         if (!default_splashscreen_pos)
42
             // revert "restore_win_position" value if application wasn't crashed
43
             get_app_config()->set("restore_win_position", "1");
44
-#ifndef __linux__
45
+#if !defined(__linux__) && !defined(__FreeBSD__)
46
         wxYield();
47
 #endif
48
         scrn->SetText(_L("Loading configuration")+ dots);
49
@@ -1411,7 +1412,7 @@ bool GUI_App::on_init_inner()
50
         // and wxEVT_SET_FOCUS before GUI_App::post_init is called) wasn't called before GUI_App::post_init and OpenGL wasn't initialized.
51
         // Since issue #9774 Where same problem occured on MacOS Ventura, we decided to have this check on MacOS as well.
52
 
53
-#if defined(__linux__) || defined(__APPLE__)
54
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
55
         if (!m_post_initialized && m_opengl_initialized) {
56
 #else
57
         if (!m_post_initialized) {
58
@@ -2054,7 +2055,7 @@ bool GUI_App::switch_language()
59
     }
60
 }
61
 
62
-#ifdef __linux__
63
+#if defined(__linux__) || (__FreeBSD__)
64
 static const wxLanguageInfo* linux_get_existing_locale_language(const wxLanguageInfo* language,
65
                                                                 const wxLanguageInfo* system_language)
66
 {
67
@@ -2253,7 +2254,7 @@ bool GUI_App::load_language(wxString language, bool in
68
 				m_language_info_best = wxLocale::FindLanguageInfo(best_language);
69
 	        	BOOST_LOG_TRIVIAL(trace) << boost::format("Best translation language detected (may be different from user locales): %1%") % m_language_info_best->CanonicalName.ToUTF8().data();
70
 			}
71
-            #ifdef __linux__
72
+            #if defined(__linux__) || defined(__FreeBSD__)
38
             wxString lc_all;
73
             wxString lc_all;
39
             if (wxGetEnv("LC_ALL", &lc_all) && ! lc_all.IsEmpty()) {
74
             if (wxGetEnv("LC_ALL", &lc_all) && ! lc_all.IsEmpty()) {
40
@@ -2096,6 +2099,7 @@ bool GUI_App::load_language(wxString language, bool in
75
                 // Best language returned by wxWidgets on Linux apparently does not respect LC_ALL.
76
@@ -2262,6 +2263,7 @@ bool GUI_App::load_language(wxString language, bool in
41
             }
77
             }
42
             #endif
78
             #endif
43
 		}
79
 		}
Lines 45-47 Link Here
45
     }
81
     }
46
 
82
 
47
 	const wxLanguageInfo *language_info = language.empty() ? nullptr : wxLocale::FindLanguageInfo(language);
83
 	const wxLanguageInfo *language_info = language.empty() ? nullptr : wxLocale::FindLanguageInfo(language);
84
@@ -2306,7 +2308,7 @@ bool GUI_App::load_language(wxString language, bool in
85
     } else if (m_language_info_system != nullptr && language_info->CanonicalName.BeforeFirst('_') == m_language_info_system->CanonicalName.BeforeFirst('_'))
86
         language_info = m_language_info_system;
87
 
88
-#ifdef __linux__
89
+#if defined(__linux__) || defined(__FreeBSD__)
90
     // If we can't find this locale , try to use different one for the language
91
     // instead of just reporting that it is impossible to switch.
92
     if (! wxLocale::IsAvailable(language_info->Language)) {
93
@@ -2426,7 +2428,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
94
         local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _L("Take Configuration &Snapshot"), _L("Capture a configuration snapshot"));
95
         local_menu->Append(config_id_base + ConfigMenuUpdateConf, _L("Check for Configuration Updates"), _L("Check for configuration updates"));
96
         local_menu->Append(config_id_base + ConfigMenuUpdateApp, _L("Check for Application Updates"), _L("Check for new version of application"));
97
-#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) 
98
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(SLIC3R_DESKTOP_INTEGRATION) 
99
         //if (DesktopIntegrationDialog::integration_possible())
100
         local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration"));    
101
 #endif //(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION)        
102
@@ -2473,7 +2475,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
103
         case ConfigMenuUpdateApp:
104
             app_version_check(true);
105
             break;
106
-#ifdef __linux__
107
+#if defined(__linux__) || defined(__FreeBSD__)
108
         case ConfigMenuDesktopIntegration:
109
             show_desktop_integration_dialog();
110
             break;
111
@@ -3090,7 +3092,7 @@ void GUI_App::show_desktop_integration_dialog()
112
 
113
 void GUI_App::show_desktop_integration_dialog()
114
 {
115
-#ifdef __linux__
116
+#if defined(__linux__) || defined(__FreeBSD__)
117
     //wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
118
     DesktopIntegrationDialog dialog(mainframe);
119
     dialog.ShowModal();
120
@@ -3110,7 +3112,7 @@ void GUI_App::show_downloader_registration_dialog()
121
     if (msg.ShowModal() == wxID_YES) {
122
         auto downloader_worker = new DownloaderUtils::Worker(nullptr);
123
         downloader_worker->perform_register(app_config->get("url_downloader_dest"));
124
-#ifdef __linux__
125
+#if defined(__linux__) || defined(__FreeBSD__)
126
         if (downloader_worker->get_perform_registration_linux())
127
             DesktopIntegrationDialog::perform_downloader_desktop_integration();
128
 #endif // __linux__
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI__Factories.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI_Factories.cpp.orig	2023-07-21 13:55:55 UTC
2
+++ src/slic3r/GUI/GUI_Factories.cpp
3
@@ -1345,7 +1345,7 @@ void MenuFactory::sys_color_changed(wxMenuBar* menubar
4
     for (size_t id = 0; id < menubar->GetMenuCount(); id++) {
5
         wxMenu* menu = menubar->GetMenu(id);
6
         sys_color_changed_menu(menu);
7
-#ifndef __linux__
8
+#if !(defined(__linux__) || defined (__FreeBSD__))
9
         menu->SetupBitmaps();
10
 #ifdef _WIN32 
11
         // but under MSW we have to update item's bachground color
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI__ObjectLayers.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI_ObjectLayers.cpp.orig	2023-07-25 10:52:56 UTC
2
+++ src/slic3r/GUI/GUI_ObjectLayers.cpp
3
@@ -344,7 +344,7 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* pare
4
         m_enter_pressed     = true;
5
         // Workaround! Under Linux we have to use CallAfter() to avoid crash after pressing ENTER key
6
         // see #7531, #8055, #8408
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
         wxTheApp->CallAfter([this, edit_fn]() {
10
 #endif
11
             // If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
12
@@ -359,7 +359,7 @@ LayerRangeEditor::LayerRangeEditor( ObjectLayers* pare
13
                 SetValue(m_valid_value);
14
                 m_call_kill_focus = true;
15
             }
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
         });
19
 #endif 
20
     }, this->GetId());
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI__ObjectManipulation.cpp (+12 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI_ObjectManipulation.cpp.orig	2023-07-21 13:50:11 UTC
2
+++ src/slic3r/GUI/GUI_ObjectManipulation.cpp
3
@@ -490,7 +490,8 @@ void ObjectManipulation::Show(const bool show)
4
         const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
5
         bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
6
         if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) {
7
-#ifdef __linux__
8
+
9
+#if defined(__linux__) || defined (__FreeBSD__)
10
             m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Local), 2);
11
 #else
12
             m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Local), wxNullBitmap, 2);
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI__Preview.cpp (+28 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI_Preview.cpp.orig	2023-07-25 10:57:11 UTC
2
+++ src/slic3r/GUI/GUI_Preview.cpp
3
@@ -292,7 +292,7 @@ void Preview::reload_print(bool keep_volumes)
4
 
5
 void Preview::reload_print(bool keep_volumes)
6
 {
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     // We are getting mysterious crashes on Linux in gtk due to OpenGL context activation GH #1874 #1955.
10
     // So we are applying a workaround here: a delayed release of OpenGL vertex buffers.
11
     if (!IsShown())
12
@@ -302,14 +302,14 @@ void Preview::reload_print(bool keep_volumes)
13
     }
14
 #endif /* __linux__ */
15
     if (
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
         m_volumes_cleanup_required || 
19
 #endif /* __linux__ */
20
         !keep_volumes)
21
     {
22
         m_canvas->reset_volumes();
23
         m_loaded = false;
24
-#ifdef __linux__
25
+#if defined(__linux__) || defined(__FreeBSD__)
26
         m_volumes_cleanup_required = false;
27
 #endif /* __linux__ */
28
     }
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI__Preview.hpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI_Preview.hpp.orig	2023-07-25 11:01:59 UTC
2
+++ src/slic3r/GUI/GUI_Preview.hpp
3
@@ -85,7 +85,7 @@ class Preview : public wxPanel
4
     BackgroundSlicingProcess* m_process;
5
     GCodeProcessorResult* m_gcode_result;
6
 
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     // We are getting mysterious crashes on Linux in gtk due to OpenGL context activation GH #1874 #1955.
10
     // So we are applying a workaround here.
11
     bool m_volumes_cleanup_required { false };
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_GUI__Utils.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/GUI_Utils.cpp.orig	2023-07-25 11:03:21 UTC
2
+++ src/slic3r/GUI/GUI_Utils.cpp
3
@@ -48,7 +48,7 @@ void on_window_geometry(wxTopLevelWindow *tlw, std::fu
4
     // cf. https://groups.google.com/forum/#!topic/wx-users/c7ntMt6piRI
5
     // OTOH the geometry is available very soon, so we can call the callback right away
6
     callback();
7
-#elif defined __linux__
8
+#elif defined(__linux__) || defined(__FreeBSD__)
9
     tlw->Bind(wxEVT_SHOW, [=](wxShowEvent &evt) {
10
         // On Linux, the geometry is only available after wxEVT_SHOW + CallAfter
11
         // cf. https://groups.google.com/forum/?pli=1#!topic/wx-users/fERSXdpVwAI
12
@@ -116,7 +116,7 @@ int get_dpi_for_window(const wxWindow *window)
13
         if (hdc == NULL) { return DPI_DEFAULT; }
14
         return GetDeviceCaps(hdc, LOGPIXELSX);
15
     }
16
-#elif defined __linux__
17
+#elif defined(__linux__) || defined(__FreeBSD__)
18
     // TODO
19
     return DPI_DEFAULT;
20
 #elif defined __APPLE__
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_Gizmos_GLGizmoEmboss.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp.orig	2023-07-25 16:07:22 UTC
2
+++ src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
3
@@ -29,7 +29,7 @@
4
 #include "libslic3r/BuildVolume.hpp"
5
 
6
 #include "imgui/imgui_stdlib.h" // using std::string for inputs
7
-#include "nanosvg/nanosvg.h"    // load SVG file
8
+#include "libnanosvg/nanosvg.h"    // load SVG file
9
 
10
 #include <wx/font.h>
11
 #include <wx/fontutil.h>
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_ImGuiWrapper.cpp (+13 lines)
Added Link Here
1
--- src/slic3r/GUI/ImGuiWrapper.cpp.orig	2023-07-25 16:14:00 UTC
2
+++ src/slic3r/GUI/ImGuiWrapper.cpp
3
@@ -35,8 +35,8 @@
4
 #include "GUI_App.hpp"
5
 
6
 #include "../Utils/MacDarkMode.hpp"
7
-#include <nanosvg/nanosvg.h>
8
-#include <nanosvg/nanosvgrast.h>
9
+#include "libnanosvg/nanosvg.h"
10
+#include "libnanosvg/nanosvgrast.h"
11
 
12
 // suggest location
13
 #include "libslic3r/ClipperUtils.hpp" // Slic3r::intersection
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_InstanceCheck.cpp (-1 / +10 lines)
Lines 1-4 Link Here
1
--- src/slic3r/GUI/InstanceCheck.cpp.orig	2022-09-06 07:09:19 UTC
1
--- src/slic3r/GUI/InstanceCheck.cpp.orig	2023-06-19 12:07:14 UTC
2
+++ src/slic3r/GUI/InstanceCheck.cpp
2
+++ src/slic3r/GUI/InstanceCheck.cpp
3
@@ -23,7 +23,7 @@
3
@@ -23,7 +23,7 @@
4
 #include <strsafe.h>
4
 #include <strsafe.h>
Lines 18-20 Link Here
18
 
18
 
19
 	static bool  send_message(const std::string &message_text, const std::string &version)
19
 	static bool  send_message(const std::string &message_text, const std::string &version)
20
 	{
20
 	{
21
@@ -310,7 +310,7 @@ bool instance_check(int argc, char** argv, bool app_co
22
 	hashed_path = std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
23
 #else
24
 	boost::system::error_code ec;
25
-#ifdef __linux__
26
+#if defined(__linux__) || defined(__FreeBSD__)
27
 	// If executed by an AppImage, start the AppImage, not the main process.
28
 	// see https://docs.appimage.org/packaging-guide/environment-variables.html#id2
29
 	const char *appimage_env = std::getenv("APPIMAGE");
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_InstanceCheck.hpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/InstanceCheck.hpp.orig	2023-07-25 11:12:36 UTC
2
+++ src/slic3r/GUI/InstanceCheck.hpp
3
@@ -11,7 +11,7 @@
4
 
5
 #include <boost/filesystem.hpp>
6
 
7
-#if __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
 #include <boost/thread.hpp>
10
 #include <mutex>
11
 #include <condition_variable>
12
@@ -38,7 +38,7 @@ class MainFrame;
13
 
14
 class MainFrame;
15
 
16
-#if __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
     #define BACKGROUND_MESSAGE_LISTENER
19
 #endif // __linux__
20
 
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_KBShortcutsDialog.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/KBShortcutsDialog.cpp.orig	2023-07-25 11:17:47 UTC
2
+++ src/slic3r/GUI/KBShortcutsDialog.cpp
3
@@ -54,7 +54,7 @@ KBShortcutsDialog::KBShortcutsDialog()
4
     main_sizer->SetSizeHints(this);
5
     this->CenterOnParent();
6
 
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     // workaround to correct pages layout
10
     book->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [book](wxBookCtrlEvent& e) {
11
         book->GetPage(e.GetSelection())->Fit();
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_Mouse3DController.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/Mouse3DController.cpp.orig	2023-07-25 12:02:33 UTC
2
+++ src/slic3r/GUI/Mouse3DController.cpp
3
@@ -885,7 +885,7 @@ bool Mouse3DController::connect_device()
4
 
5
     for (const DetectedDevices::value_type& device : detected_devices) {
6
         if (device.second.size() == 1) {
7
-#if defined(__linux__)
8
+#if defined(__linux__) || defined(__FreeBSD__) 
9
             hid_device* test_device = hid_open(device.first.first, device.first.second, nullptr);
10
             if (test_device == nullptr) {
11
                 BOOST_LOG_TRIVIAL(error) << "3DConnexion device cannot be opened: " << device.second.front().path <<
12
@@ -910,7 +910,7 @@ bool Mouse3DController::connect_device()
13
                 std::cout << "Test device: " << std::hex << device.first.first << std::dec << "/" << std::hex << device.first.second << std::dec << " \"" << data.path << "\"";
14
 #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
15
 
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
                 hid_device* test_device = hid_open_path(data.path.c_str());
19
                 if (test_device != nullptr) {
20
                     path = data.path;
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_OpenGLManager.cpp (-10 / +9 lines)
Lines 1-12 Link Here
1
--- src/slic3r/GUI/OpenGLManager.cpp.orig	2022-09-06 07:09:19 UTC
1
--- src/slic3r/GUI/OpenGLManager.cpp.orig	2023-07-21 19:13:54 UTC
2
+++ src/slic3r/GUI/OpenGLManager.cpp
2
+++ src/slic3r/GUI/OpenGLManager.cpp
3
@@ -236,7 +236,8 @@ bool OpenGLManager::init_gl()
3
@@ -336,7 +336,7 @@ bool OpenGLManager::init_gl()
4
     if (!m_gl_initialized) {
4
         glewExperimental = true;
5
         if (glewInit() != GLEW_OK) {
5
 #endif // ENABLE_GL_CORE_PROFILE || ENABLE_OPENGL_ES
6
             BOOST_LOG_TRIVIAL(error) << "Unable to init glew library";
6
         GLenum err = glewInit();
7
-            return false;
7
-        if (err != GLEW_OK) {
8
+	    /* Ugly fix for https://github.com/prusa3d/PrusaSlicer/issues/6396 */
8
+        if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) {
9
+            //return false;
9
             BOOST_LOG_TRIVIAL(error) << "Unable to init glew library: " << glewGetErrorString(err);
10
             return false;
10
         }
11
         }
11
         m_gl_initialized = true;
12
         if (GLEW_EXT_texture_compression_s3tc)
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_OptionsGroup.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/OptionsGroup.cpp.orig	2023-07-25 12:28:59 UTC
2
+++ src/slic3r/GUI/OptionsGroup.cpp
3
@@ -1051,7 +1051,7 @@ void ogStaticText::SetPathEnd(const std::string& link)
4
 
5
 void ogStaticText::SetPathEnd(const std::string& link)
6
 {
7
-#ifndef __linux__
8
+#if !defined(__linux__) && !defined(__FreeBSD__)
9
 
10
     Bind(wxEVT_ENTER_WINDOW, [this, link](wxMouseEvent& event) {
11
         SetToolTip(OptionsGroup::get_url(get_app_config()->get("suppress_hyperlinks") != "1" ? link : std::string()));
12
@@ -1104,7 +1104,7 @@ void ogStaticText::FocusText(bool focus)
13
 
14
     SetFont(focus ? Slic3r::GUI::wxGetApp().link_font() :
15
         Slic3r::GUI::wxGetApp().normal_font());
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
     this->GetContainingSizer()->Layout();
19
 #endif
20
     Refresh();
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_Plater.cpp (+29 lines)
Added Link Here
1
--- src/slic3r/GUI/Plater.cpp.orig	2023-07-25 12:32:07 UTC
2
+++ src/slic3r/GUI/Plater.cpp
3
@@ -2452,7 +2452,7 @@ std::vector<size_t> Plater::priv::load_files(const std
4
     // when loading a project file. However, creating the dialog on heap causes issues on macOS, where it does not
5
     // appear at all. Therefore, we create the dialog on stack on Win and macOS, and on heap on Linux, which
6
     // is the only system that needed the workarounds in the first place.
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     auto progress_dlg = new wxProgressDialog(loading, "", 100, find_toplevel_parent(q), wxPD_APP_MODAL | wxPD_AUTO_HIDE);
10
     Slic3r::ScopeGuard([&progress_dlg](){ if (progress_dlg) progress_dlg->Destroy(); progress_dlg = nullptr; });
11
 #else
12
@@ -2498,7 +2498,7 @@ std::vector<size_t> Plater::priv::load_files(const std
13
         bool is_project_file = type_prusa;
14
         try {
15
             if (type_3mf || type_zip_amf) {
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
                 // On Linux Constructor of the ProgressDialog calls DisableOtherWindows() function which causes a disabling of all children of the find_toplevel_parent(q)
19
                 // And a destructor of the ProgressDialog calls ReenableOtherWindows() function which revert previously disabled children.
20
                 // But if printer technology will be changes during project loading, 
21
@@ -4428,7 +4428,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
22
         Vec2d mouse_position = evt.data.first;
23
         wxPoint position(static_cast<int>(mouse_position.x()),
24
                          static_cast<int>(mouse_position.y()));
25
-#ifdef __linux__
26
+#if defined(__linux__) || defined(__FreeBSD__)
27
         // For some reason on Linux the menu isn't displayed if position is
28
         // specified (even though the position is sane).
29
         position = wxDefaultPosition;
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_Preferences.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/Preferences.cpp.orig	2023-07-25 12:35:52 UTC
2
+++ src/slic3r/GUI/Preferences.cpp
3
@@ -18,7 +18,7 @@
4
 #ifdef WIN32
5
 #include <wx/msw/registry.h>
6
 #endif // WIN32
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
 #include "DesktopIntegrationDialog.hpp"
10
 #endif //__linux__
11
 
12
@@ -688,7 +688,7 @@ void PreferencesDialog::accept(wxEvent&)
13
 			downloader->allow(it->second == "1");
14
 		if (!downloader->on_finish())
15
 			return;
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
 		if( downloader->get_perform_registration_linux()) 
19
 			DesktopIntegrationDialog::perform_downloader_desktop_integration();
20
 #endif // __linux__
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_PresetComboBoxes.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/PresetComboBoxes.cpp.orig	2023-07-25 12:38:23 UTC
2
+++ src/slic3r/GUI/PresetComboBoxes.cpp
3
@@ -779,7 +779,7 @@ void PlaterPresetComboBox::show_edit_menu()
4
         [this](wxCommandEvent&) { this->switch_to_tab(); }, "cog", menu, []() { return true; }, wxGetApp().plater());
5
 
6
     if (m_type == Preset::TYPE_FILAMENT) {
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
         // To edit extruder color from the sidebar
10
         append_menu_item(menu, wxID_ANY, _L("Change extruder color"), "",
11
             [this](wxCommandEvent&) { this->change_extruder_color(); }, "funnel", menu, []() { return true; }, wxGetApp().plater());
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_PresetComboBoxes.hpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/PresetComboBoxes.hpp.orig	2023-07-25 12:39:49 UTC
2
+++ src/slic3r/GUI/PresetComboBoxes.hpp
3
@@ -115,7 +115,7 @@ class PresetComboBox : public BitmapComboBox (protecte
4
     void validate_selection(bool predicate = false);
5
     void update_selection();
6
 
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     static const char* separator_head() { return "------- "; }
10
     static const char* separator_tail() { return " -------"; }
11
 #else // __linux__ 
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_PrintHostDialogs.cpp (+58 lines)
Added Link Here
1
--- src/slic3r/GUI/PrintHostDialogs.cpp.orig	2023-07-25 12:41:51 UTC
2
+++ src/slic3r/GUI/PrintHostDialogs.cpp
3
@@ -100,8 +100,8 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::pat
4
     if (size_t extension_start = recent_path.find_last_of('.'); extension_start != std::string::npos)
5
         m_valid_suffix = recent_path.substr(extension_start);
6
     // .gcode suffix control
7
-    auto validate_path = [this](const wxString &path) -> bool {
8
-        if (! path.Lower().EndsWith(m_valid_suffix.Lower())) {
9
+    auto validate_path = [this](const std::wstring &path) -> bool {
10
+        if (! (new wxString(path))->Lower().EndsWith(m_valid_suffix.Lower())) {
11
             MessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), m_valid_suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
12
             if (msg_wingow.ShowModal() == wxID_NO)
13
                 return false;
14
@@ -111,7 +111,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::pat
15
 
16
     auto* btn_ok = add_button(wxID_OK, true, _L("Upload"));
17
     btn_ok->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
18
-        if (validate_path(txt_filename->GetValue())) {
19
+        if (validate_path(txt_filename->GetValue().ToStdWstring())) {
20
             post_upload_action = PrintHostPostUploadAction::None;
21
             EndDialog(wxID_OK);
22
         }
23
@@ -121,7 +121,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::pat
24
     if (post_actions.has(PrintHostPostUploadAction::QueuePrint)) {
25
         auto* btn_print = add_button(wxID_ADD, false, _L("Upload to Queue"));
26
         btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
27
-            if (validate_path(txt_filename->GetValue())) {
28
+            if (validate_path(txt_filename->GetValue().ToStdWstring())) {
29
                 post_upload_action = PrintHostPostUploadAction::QueuePrint;
30
                 EndDialog(wxID_OK);
31
             }
32
@@ -131,7 +131,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::pat
33
     if (post_actions.has(PrintHostPostUploadAction::StartPrint)) {
34
         auto* btn_print = add_button(wxID_YES, false, _L("Upload and Print"));
35
         btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
36
-            if (validate_path(txt_filename->GetValue())) {
37
+            if (validate_path(txt_filename->GetValue().ToStdWstring())) {
38
                 post_upload_action = PrintHostPostUploadAction::StartPrint;
39
                 EndDialog(wxID_OK);
40
             }
41
@@ -142,7 +142,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::pat
42
         // Using wxID_MORE as a button identifier to be different from the other buttons, wxID_MORE has no other meaning here.
43
         auto* btn_simulate = add_button(wxID_MORE, false, _L("Upload and Simulate"));
44
         btn_simulate->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
45
-            if (validate_path(txt_filename->GetValue())) {
46
+            if (validate_path(txt_filename->GetValue().ToStdWstring())) {
47
                 post_upload_action = PrintHostPostUploadAction::StartSimulation;
48
                 EndDialog(wxID_OK);
49
             }        
50
@@ -152,7 +152,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::pat
51
     add_button(wxID_CANCEL);
52
     finalize();
53
 
54
-#ifdef __linux__
55
+#if defined(__linux__) || defined(__FreeBSD__)
56
     // On Linux with GTK2 when text control lose the focus then selection (colored background) disappears but text color stay white
57
     // and as a result the text is invisible with light mode
58
     // see https://github.com/prusa3d/PrusaSlicer/issues/4532
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_RemovableDriveManager.cpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/RemovableDriveManager.cpp.orig	2023-07-25 12:47:49 UTC
2
+++ src/slic3r/GUI/RemovableDriveManager.cpp
3
@@ -738,7 +738,7 @@ namespace search_for_drives_internal 
4
 		//confirms if the file is removable drive and adds it to vector
5
 
6
 		if (
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
 			// Chromium mounts removable drives in a way that produces the same device ID.
10
 			platform_flavor() == PlatformFlavor::LinuxOnChromium ||
11
 #endif
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_Tab.cpp (+56 lines)
Added Link Here
1
--- src/slic3r/GUI/Tab.cpp.orig	2023-07-23 21:37:19 UTC
2
+++ src/slic3r/GUI/Tab.cpp
3
@@ -243,7 +243,7 @@ void Tab::create_preset_tab()
4
     m_h_buttons_sizer->AddSpacer(int(8*scale_factor));
5
     m_h_buttons_sizer->Add(m_btn_compare_preset, 0, wxALIGN_CENTER_VERTICAL);
6
 
7
-    m_top_hsizer->Add(m_h_buttons_sizer, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
8
+    m_top_hsizer->Add(m_h_buttons_sizer, 1, wxEXPAND);
9
     m_top_hsizer->AddSpacer(int(16*scale_factor));
10
     // StretchSpacer has a strange behavior under OSX, so
11
     // There is used just additional sizer for m_mode_sizer with right alignment
12
@@ -252,7 +252,7 @@ void Tab::create_preset_tab()
13
         // Don't set the 2nd parameter to 1, making the sizer rubbery scalable in Y axis may lead 
14
         // to wrong vertical size assigned to wxBitmapComboBoxes, see GH issue #7176.
15
         mode_sizer->Add(m_mode_sizer, 0, wxALIGN_RIGHT);
16
-        m_top_hsizer->Add(mode_sizer, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, wxOSX ? 15 : 10);
17
+        m_top_hsizer->Add(mode_sizer, 1, wxRIGHT, wxOSX ? 15 : 10);
18
     }
19
     // hide whole top sizer to correct layout later
20
     m_top_hsizer->ShowItems(false);
21
@@ -280,7 +280,7 @@ void Tab::create_preset_tab()
22
     // This helps to process all the cursor key events on Windows in the tree control,
23
     // so that the cursor jumps to the last item.
24
     m_treectrl->Bind(wxEVT_TREE_SEL_CHANGED, [this](wxTreeEvent&) {
25
-#ifdef __linux__
26
+#if defined(__linux__) || defined(__FreeBSD__)
27
         // Events queue is opposite On Linux. wxEVT_SET_FOCUS invokes after wxEVT_TREE_SEL_CHANGED,
28
         // and a result wxEVT_KILL_FOCUS doesn't invoke for the TextCtrls.
29
         // see https://github.com/prusa3d/PrusaSlicer/issues/5720
30
@@ -3427,7 +3427,7 @@ void Tab::load_current_preset()
31
                         else
32
 #endif
33
                             wxGetApp().tab_panel()->InsertPage(wxGetApp().tab_panel()->FindPage(this), tab, tab->title());
34
-                        #ifdef __linux__ // the tabs apparently need to be explicitly shown on Linux (pull request #1563)
35
+                        #if defined(__linux__) || defined(__FreeBSD__) // the tabs apparently need to be explicitly shown on Linux (pull request #1563)
36
                             int page_id = wxGetApp().tab_panel()->FindPage(tab);
37
                             wxGetApp().tab_panel()->GetPage(page_id)->Show(true);
38
                         #endif // __linux__
39
@@ -3837,7 +3837,7 @@ bool Tab::tree_sel_change_delayed()
40
     // There is a bug related to Ubuntu overlay scrollbars, see https://github.com/prusa3d/PrusaSlicer/issues/898 and https://github.com/prusa3d/PrusaSlicer/issues/952.
41
     // The issue apparently manifests when Show()ing a window with overlay scrollbars while the UI is frozen. For this reason,
42
     // we will Thaw the UI prematurely on Linux. This means destroing the no_updates object prematurely.
43
-#ifdef __linux__
44
+#if defined(__linux__) || defined(__FreeBSD__)
45
     std::unique_ptr<wxWindowUpdateLocker> no_updates(new wxWindowUpdateLocker(this));
46
 #else
47
     /* On Windows we use DoubleBuffering during rendering,
48
@@ -3883,7 +3883,7 @@ bool Tab::tree_sel_change_delayed()
49
         if (wxGetApp().mainframe!=nullptr && wxGetApp().mainframe->is_active_and_shown_tab(this))
50
             activate_selected_page(throw_if_canceled);
51
 
52
-        #ifdef __linux__
53
+        #if defined(__linux__) || defined(__FreeBSD__)
54
             no_updates.reset(nullptr);
55
         #endif
56
 
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_UnsavedChangesDialog.cpp (+65 lines)
Added Link Here
1
--- src/slic3r/GUI/UnsavedChangesDialog.cpp.orig	2023-07-25 12:52:03 UTC
2
+++ src/slic3r/GUI/UnsavedChangesDialog.cpp
3
@@ -25,7 +25,7 @@ using boost::optional;
4
 
5
 using boost::optional;
6
 
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
 #define wxLinux true
10
 #else
11
 #define wxLinux false
12
@@ -109,7 +109,7 @@ ModelNode::ModelNode(ModelNode* parent, const wxString
13
     UpdateIcons();
14
 }
15
 
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
 wxIcon ModelNode::get_bitmap(const wxString& color)
19
 #else
20
 wxBitmap ModelNode::get_bitmap(const wxString& color)
21
@@ -118,7 +118,7 @@ wxBitmap ModelNode::get_bitmap(const wxString& color)
22
     wxBitmap bmp = get_solid_bmp_bundle(64, 16, into_u8(color))->GetBitmapFor(m_parent_win);
23
     if (!m_toggle)
24
         bmp = bmp.ConvertToDisabled();
25
-#ifndef __linux__
26
+#if !defined(__linux__) && !defined(__FreeBSD__)
27
     return bmp;
28
 #else
29
     wxIcon icon;
30
@@ -222,7 +222,7 @@ void ModelNode::UpdateIcons()
31
     if (!m_toggle)
32
         bmp = bmp.ConvertToDisabled();
33
 
34
-#ifdef __linux__
35
+#if defined(__linux__) || defined(__FreeBSD__)
36
     m_icon.CopyFromBitmap(bmp);
37
 #else
38
     m_icon = bmp;
39
@@ -374,7 +374,7 @@ void DiffModel::GetValue(wxVariant& variant, const wxD
40
     case colToggle:
41
         variant = node->m_toggle;
42
         break;
43
-#ifdef __linux__
44
+#if defined(__linux__) || defined(__FreeBSD__)
45
     case colIconText:
46
         variant << wxDataViewIconText(node->m_text, node->m_icon);
47
         break;
48
@@ -417,7 +417,7 @@ bool DiffModel::SetValue(const wxVariant& variant, con
49
     case colToggle:
50
         node->m_toggle = variant.GetBool();
51
         return true;
52
-#ifdef __linux__
53
+#if defined(__linux__) || defined(__FreeBSD__)
54
     case colIconText: {
55
         wxDataViewIconText data;
56
         data << variant;
57
@@ -622,7 +622,7 @@ void DiffViewCtrl::AppendBmpTextColumn(const wxString&
58
 void DiffViewCtrl::AppendBmpTextColumn(const wxString& label, unsigned model_column, int width, bool set_expander/* = false*/)
59
 {
60
     m_columns_width.emplace(this->GetColumnCount(), width);
61
-#ifdef __linux__
62
+#if defined(__linux__) || defined(__FreeBSD__)
63
     wxDataViewIconTextRenderer* rd = new wxDataViewIconTextRenderer();
64
 #ifdef SUPPORTS_MARKUP
65
     rd->EnableMarkup(true);
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_UnsavedChangesDialog.hpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/UnsavedChangesDialog.hpp.orig	2023-07-25 12:56:44 UTC
2
+++ src/slic3r/GUI/UnsavedChangesDialog.hpp
3
@@ -48,7 +48,7 @@ class ModelNode
4
     wxString            m_mod_color;
5
     wxString            m_new_color;
6
 
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
     wxIcon              get_bitmap(const wxString& color);
10
 #else
11
     wxBitmap            get_bitmap(const wxString& color);
12
@@ -57,7 +57,7 @@ class ModelNode
13
 public:
14
 
15
     bool        m_toggle {true};
16
-#ifdef __linux__
17
+#if defined(__linux__) || defined(__FreeBSD__)
18
     wxIcon      m_icon;
19
     wxIcon      m_old_color_bmp;
20
     wxIcon      m_mod_color_bmp;
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_UpdateDialogs.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/GUI/UpdateDialogs.cpp.orig	2023-07-25 12:59:11 UTC
2
+++ src/slic3r/GUI/UpdateDialogs.cpp
3
@@ -142,7 +142,7 @@ AppUpdateDownloadDialog::AppUpdateDownloadDialog( cons
4
 	versions->Add(new wxStaticText(this, wxID_ANY, ver_online.to_string()));
5
 	content_sizer->Add(versions);
6
 	content_sizer->AddSpacer(VERT_SPACING);
7
-#ifndef __linux__
8
+#if !defined(__linux__) && !defined(__FreeBSD__)
9
 	cbox_run = new wxCheckBox(this, wxID_ANY, _(L("Run installer after download. (Otherwise file explorer will be opened)")));
10
 	content_sizer->Add(cbox_run);
11
 #endif
12
@@ -248,7 +248,7 @@ bool AppUpdateDownloadDialog::run_after_download() con
13
 
14
 bool AppUpdateDownloadDialog::run_after_download() const
15
 {
16
-#ifndef __linux__
17
+#if !defined(__linux__) && !defined(__FreeBSD__)
18
 	return cbox_run->GetValue();
19
 #endif
20
 	return false;
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_wxExtensions.cpp (+41 lines)
Added Link Here
1
--- src/slic3r/GUI/wxExtensions.cpp.orig	2023-07-25 13:02:00 UTC
2
+++ src/slic3r/GUI/wxExtensions.cpp
3
@@ -22,7 +22,7 @@
4
 
5
 #include "libslic3r/Color.hpp"
6
 
7
-#ifndef __linux__
8
+#if !defined(__linux__) && !defined(__FreeBSD__)
9
 // msw_menuitem_bitmaps is used for MSW and OSX
10
 static std::map<int, std::string> msw_menuitem_bitmaps;
11
 void sys_color_changed_menu(wxMenu* menu)
12
@@ -92,7 +92,7 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, con
13
 
14
     wxBitmapBundle* bmp = icon.empty() ? nullptr : get_bmp_bundle(icon);
15
 
16
-#ifndef __linux__
17
+#if !defined(__linux__) && !defined(__FreeBSD__)
18
     if (bmp && bmp->IsOk())
19
         msw_menuitem_bitmaps[id] = icon;
20
 #endif /* no __linux__ */
21
@@ -110,7 +110,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_m
22
     if (!icon.empty()) {
23
         item->SetBitmap(*get_bmp_bundle(icon));
24
 
25
-#ifndef __linux__
26
+#if !defined(__linux__) && !defined(__FreeBSD__)
27
         msw_menuitem_bitmaps[id] = icon;
28
 #endif // no __linux__
29
     }
30
@@ -671,9 +671,9 @@ void ModeButton::focus_button(const bool focus)
31
     GetParent()->Refresh(); // force redraw a background of the selected mode button
32
 #else
33
     SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT : 
34
-#if defined (__linux__) && defined (__WXGTK3__)
35
+#if (defined (__linux__) || defined(__FreeBSD__)) && defined (__WXGTK3__)
36
         wxSYS_COLOUR_GRAYTEXT
37
-#elif defined (__linux__) && defined (__WXGTK2__)
38
+#elif (defined (__linux__) || defined(__FreeBSD__)) && defined (__WXGTK2__)
39
         wxSYS_COLOUR_BTNTEXT
40
 #else 
41
         wxSYS_COLOUR_BTNSHADOW
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_GUI_wxExtensions.hpp (+11 lines)
Added Link Here
1
--- src/slic3r/GUI/wxExtensions.hpp.orig	2023-07-25 13:07:41 UTC
2
+++ src/slic3r/GUI/wxExtensions.hpp
3
@@ -16,7 +16,7 @@
4
 #include <functional>
5
 
6
 
7
-#ifndef __linux__
8
+#if !defined(__linux__) && !defined(__FreeBSD__)
9
 void                sys_color_changed_menu(wxMenu* menu);
10
 #else 
11
 inline void         sys_color_changed_menu(wxMenu* /* menu */) {}
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_Utils_FontConfigHelp.hpp (+11 lines)
Added Link Here
1
--- src/slic3r/Utils/FontConfigHelp.hpp.orig	2023-07-25 13:08:59 UTC
2
+++ src/slic3r/Utils/FontConfigHelp.hpp
3
@@ -1,7 +1,7 @@
4
 #ifndef slic3r_FontConfigHelp_hpp_
5
 #define slic3r_FontConfigHelp_hpp_
6
 
7
-#ifdef __linux__
8
+#if defined(__linux__) || defined(__FreeBSD__)
9
 #define EXIST_FONT_CONFIG_INCLUDE
10
 #endif
11
 
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_Utils_Serial.cpp (+20 lines)
Added Link Here
1
--- src/slic3r/Utils/Serial.cpp.orig	2023-07-25 13:13:16 UTC
2
+++ src/slic3r/Utils/Serial.cpp
3
@@ -49,7 +49,7 @@
4
 	#include <sys/select.h>
5
 #endif
6
 
7
-#if defined(__APPLE__) || defined(__OpenBSD__)
8
+#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__)
9
 	#include <termios.h>
10
 #elif defined __linux__
11
 	#include <fcntl.h>
12
@@ -342,7 +342,7 @@ void Serial::set_baud_rate(unsigned baud_rate)
13
 		ios.c_cc[VTIME] = 1;
14
 		handle_errno(::ioctl(handle, TCSETS2, &ios));
15
 
16
-#elif __OpenBSD__
17
+#elif defined(__OpenBSD__) || defined(__FreeBSD__)
18
 		struct termios ios;
19
 		handle_errno(::tcgetattr(handle, &ios));
20
 		handle_errno(::cfsetspeed(&ios, baud_rate));
(-)b/cad/PrusaSlicer/files/patch-src_slic3r_Utils_WxFontUtils.cpp (+45 lines)
Added Link Here
1
--- src/slic3r/Utils/WxFontUtils.cpp.orig	2023-07-25 13:16:26 UTC
2
+++ src/slic3r/Utils/WxFontUtils.cpp
3
@@ -8,7 +8,7 @@
4
 #include <wx/uri.h>
5
 #include <wx/fontutil.h> // wxNativeFontInfo
6
 #include <wx/osx/core/cfdictionary.h>
7
-#elif defined(__linux__)
8
+#elif defined(__linux__) || defined(__FreeBSD__)
9
 #include "slic3r/Utils/FontConfigHelp.hpp"
10
 #endif
11
 
12
@@ -72,7 +72,7 @@ bool WxFontUtils::can_load(const wxFont &font)
13
 #elif defined(__APPLE__)
14
     return true;
15
     //return is_valid_ttf(get_file_path(font));
16
-#elif defined(__linux__)
17
+#elif defined(__linux__) || defined(__FreeBSD__)
18
     return true;
19
     // font config check file path take about 4000ms for chech them all
20
     //std::string font_path = Slic3r::GUI::get_font_path(font);
21
@@ -93,7 +93,7 @@ std::unique_ptr<Emboss::FontFile> WxFontUtils::create_
22
         return nullptr; 
23
     }
24
     return Emboss::create_font_file(file_path.c_str());
25
-#elif defined(__linux__)
26
+#elif defined(__linux__) || defined(__FreeBSD__)
27
     std::string font_path = Slic3r::GUI::get_font_path(font);
28
     if (font_path.empty()){
29
         BOOST_LOG_TRIVIAL(error) << "Can not read font('" << get_human_readable_name(font) << "'), "
30
@@ -114,7 +114,7 @@ EmbossStyle::Type WxFontUtils::get_actual_type()
31
     return EmbossStyle::Type::wx_win_font_descr;
32
 #elif defined(__APPLE__)
33
     return EmbossStyle::Type::wx_mac_font_descr;
34
-#elif defined(__linux__)
35
+#elif defined(__linux__) || defined(__FreeBSD__)
36
     return EmbossStyle::Type::wx_lin_font_descr;
37
 #else
38
     return EmbossStyle::Type::undefined;
39
@@ -348,4 +348,4 @@ std::unique_ptr<Emboss::FontFile> WxFontUtils::set_bol
40
     // There is NO bold font by wx
41
     font.SetWeight(orig_weight);
42
     return nullptr;
43
-}
44
\ No newline at end of file
45
+}
(-)b/cad/PrusaSlicer/files/patch-tests_fff__print_test__data.cpp (-15 / +6 lines)
Lines 1-19 Link Here
1
--- tests/fff_print/test_data.cpp.orig	2022-09-06 07:09:19 UTC
1
--- tests/fff_print/test_data.cpp.orig	2023-07-25 13:20:52 UTC
2
+++ tests/fff_print/test_data.cpp
2
+++ tests/fff_print/test_data.cpp
3
@@ -11,6 +11,7 @@
3
@@ -8,6 +8,7 @@
4
 #include "libslic3r/Format/STL.hpp"
5
 
6
 #include <cstdlib>
7
+#include <fstream>
4
 #include <string>
8
 #include <string>
5
 
9
 
6
 #include <boost/nowide/cstdio.hpp>
10
 #include <boost/nowide/cstdio.hpp>
7
+#include <boost/nowide/fstream.hpp>
8
 #include <boost/filesystem.hpp>
9
 #include <libslic3r/ModelArrange.hpp>
10
 
11
@@ -286,7 +287,7 @@ std::string gcode(Print & print)
12
     print.set_status_silent();
13
     print.process();
14
     print.export_gcode(temp.string(), nullptr, nullptr);
15
-    std::ifstream t(temp.string());
16
+    boost::nowide::ifstream t(temp.string());
17
 	std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
18
 	boost::nowide::remove(temp.string().c_str());
19
 	return str;
(-)b/cad/PrusaSlicer/files/patch-tests_libslic3r_test__emboss.cpp (-1 / +11 lines)
Added Link Here
0
- 
1
--- tests/libslic3r/test_emboss.cpp.orig	2023-07-25 16:05:40 UTC
2
+++ tests/libslic3r/test_emboss.cpp
3
@@ -195,7 +195,7 @@ TEST_CASE("Visualize glyph from font", "[Emboss]")
4
 #endif // VISUALIZE
5
 
6
 #include "test_utils.hpp"
7
-#include "nanosvg/nanosvg.h"    // load SVG file
8
+#include "libnanosvg/nanosvg.h"    // load SVG file
9
 #include "libslic3r/NSVGUtils.hpp"
10
 ExPolygons heal_and_check(const Polygons &polygons)
11
 {

Return to bug 272730