nanosvgrast.h
changeset 524 b4b49635cbd8
child 527 a26235cc1970
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nanosvgrast.h	Sun Oct 22 00:36:06 2017 -0700
     1.3 @@ -0,0 +1,1447 @@
     1.4 +/*
     1.5 + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
     1.6 + *
     1.7 + * This software is provided 'as-is', without any express or implied
     1.8 + * warranty.  In no event will the authors be held liable for any damages
     1.9 + * arising from the use of this software.
    1.10 + *
    1.11 + * Permission is granted to anyone to use this software for any purpose,
    1.12 + * including commercial applications, and to alter it and redistribute it
    1.13 + * freely, subject to the following restrictions:
    1.14 + *
    1.15 + * 1. The origin of this software must not be misrepresented; you must not
    1.16 + * claim that you wrote the original software. If you use this software
    1.17 + * in a product, an acknowledgment in the product documentation would be
    1.18 + * appreciated but is not required.
    1.19 + * 2. Altered source versions must be plainly marked as such, and must not be
    1.20 + * misrepresented as being the original software.
    1.21 + * 3. This notice may not be removed or altered from any source distribution.
    1.22 + *
    1.23 + * The polygon rasterization is heavily based on stb_truetype rasterizer
    1.24 + * by Sean Barrett - http://nothings.org/
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#ifndef NANOSVGRAST_H
    1.29 +#define NANOSVGRAST_H
    1.30 +
    1.31 +#ifdef __cplusplus
    1.32 +extern "C" {
    1.33 +#endif
    1.34 +
    1.35 +typedef struct NSVGrasterizer NSVGrasterizer;
    1.36 +
    1.37 +/* Example Usage:
    1.38 +	// Load SVG
    1.39 +	struct SNVGImage* image = nsvgParseFromFile("test.svg.");
    1.40 +
    1.41 +	// Create rasterizer (can be used to render multiple images).
    1.42 +	struct NSVGrasterizer* rast = nsvgCreateRasterizer();
    1.43 +	// Allocate memory for image
    1.44 +	unsigned char* img = malloc(w*h*4);
    1.45 +	// Rasterize
    1.46 +	nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
    1.47 +*/
    1.48 +
    1.49 +// Allocated rasterizer context.
    1.50 +NSVGrasterizer* nsvgCreateRasterizer();
    1.51 +
    1.52 +// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
    1.53 +//   r - pointer to rasterizer context
    1.54 +//   image - pointer to image to rasterize
    1.55 +//   tx,ty - image offset (applied after scaling)
    1.56 +//   scale - image scale
    1.57 +//   dst - pointer to destination image data, 4 bytes per pixel (RGBA)
    1.58 +//   w - width of the image to render
    1.59 +//   h - height of the image to render
    1.60 +//   stride - number of bytes per scaleline in the destination buffer
    1.61 +void nsvgRasterize(NSVGrasterizer* r,
    1.62 +				   NSVGimage* image, float tx, float ty, float scale,
    1.63 +				   unsigned char* dst, int w, int h, int stride);
    1.64 +
    1.65 +// Deletes rasterizer context.
    1.66 +void nsvgDeleteRasterizer(NSVGrasterizer*);
    1.67 +
    1.68 +
    1.69 +#ifdef __cplusplus
    1.70 +}
    1.71 +#endif
    1.72 +
    1.73 +#endif // NANOSVGRAST_H
    1.74 +
    1.75 +#ifdef NANOSVGRAST_IMPLEMENTATION
    1.76 +
    1.77 +#include <math.h>
    1.78 +
    1.79 +#define NSVG__SUBSAMPLES	5
    1.80 +#define NSVG__FIXSHIFT		10
    1.81 +#define NSVG__FIX			(1 << NSVG__FIXSHIFT)
    1.82 +#define NSVG__FIXMASK		(NSVG__FIX-1)
    1.83 +#define NSVG__MEMPAGE_SIZE	1024
    1.84 +
    1.85 +typedef struct NSVGedge {
    1.86 +	float x0,y0, x1,y1;
    1.87 +	int dir;
    1.88 +	struct NSVGedge* next;
    1.89 +} NSVGedge;
    1.90 +
    1.91 +typedef struct NSVGpoint {
    1.92 +	float x, y;
    1.93 +	float dx, dy;
    1.94 +	float len;
    1.95 +	float dmx, dmy;
    1.96 +	unsigned char flags;
    1.97 +} NSVGpoint;
    1.98 +
    1.99 +typedef struct NSVGactiveEdge {
   1.100 +	int x,dx;
   1.101 +	float ey;
   1.102 +	int dir;
   1.103 +	struct NSVGactiveEdge *next;
   1.104 +} NSVGactiveEdge;
   1.105 +
   1.106 +typedef struct NSVGmemPage {
   1.107 +	unsigned char mem[NSVG__MEMPAGE_SIZE];
   1.108 +	int size;
   1.109 +	struct NSVGmemPage* next;
   1.110 +} NSVGmemPage;
   1.111 +
   1.112 +typedef struct NSVGcachedPaint {
   1.113 +	char type;
   1.114 +	char spread;
   1.115 +	float xform[6];
   1.116 +	unsigned int colors[256];
   1.117 +} NSVGcachedPaint;
   1.118 +
   1.119 +struct NSVGrasterizer
   1.120 +{
   1.121 +	float px, py;
   1.122 +
   1.123 +	float tessTol;
   1.124 +	float distTol;
   1.125 +
   1.126 +	NSVGedge* edges;
   1.127 +	int nedges;
   1.128 +	int cedges;
   1.129 +
   1.130 +	NSVGpoint* points;
   1.131 +	int npoints;
   1.132 +	int cpoints;
   1.133 +
   1.134 +	NSVGpoint* points2;
   1.135 +	int npoints2;
   1.136 +	int cpoints2;
   1.137 +
   1.138 +	NSVGactiveEdge* freelist;
   1.139 +	NSVGmemPage* pages;
   1.140 +	NSVGmemPage* curpage;
   1.141 +
   1.142 +	unsigned char* scanline;
   1.143 +	int cscanline;
   1.144 +
   1.145 +	unsigned char* bitmap;
   1.146 +	int width, height, stride;
   1.147 +};
   1.148 +
   1.149 +NSVGrasterizer* nsvgCreateRasterizer()
   1.150 +{
   1.151 +	NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
   1.152 +	if (r == NULL) goto error;
   1.153 +	memset(r, 0, sizeof(NSVGrasterizer));
   1.154 +
   1.155 +	r->tessTol = 0.25f;
   1.156 +	r->distTol = 0.01f;
   1.157 +
   1.158 +	return r;
   1.159 +
   1.160 +error:
   1.161 +	nsvgDeleteRasterizer(r);
   1.162 +	return NULL;
   1.163 +}
   1.164 +
   1.165 +void nsvgDeleteRasterizer(NSVGrasterizer* r)
   1.166 +{
   1.167 +	NSVGmemPage* p;
   1.168 +
   1.169 +	if (r == NULL) return;
   1.170 +
   1.171 +	p = r->pages;
   1.172 +	while (p != NULL) {
   1.173 +		NSVGmemPage* next = p->next;
   1.174 +		free(p);
   1.175 +		p = next;
   1.176 +	}
   1.177 +
   1.178 +	if (r->edges) free(r->edges);
   1.179 +	if (r->points) free(r->points);
   1.180 +	if (r->points2) free(r->points2);
   1.181 +	if (r->scanline) free(r->scanline);
   1.182 +
   1.183 +	free(r);
   1.184 +}
   1.185 +
   1.186 +static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
   1.187 +{
   1.188 +	NSVGmemPage *newp;
   1.189 +
   1.190 +	// If using existing chain, return the next page in chain
   1.191 +	if (cur != NULL && cur->next != NULL) {
   1.192 +		return cur->next;
   1.193 +	}
   1.194 +
   1.195 +	// Alloc new page
   1.196 +	newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
   1.197 +	if (newp == NULL) return NULL;
   1.198 +	memset(newp, 0, sizeof(NSVGmemPage));
   1.199 +
   1.200 +	// Add to linked list
   1.201 +	if (cur != NULL)
   1.202 +		cur->next = newp;
   1.203 +	else
   1.204 +		r->pages = newp;
   1.205 +
   1.206 +	return newp;
   1.207 +}
   1.208 +
   1.209 +static void nsvg__resetPool(NSVGrasterizer* r)
   1.210 +{
   1.211 +	NSVGmemPage* p = r->pages;
   1.212 +	while (p != NULL) {
   1.213 +		p->size = 0;
   1.214 +		p = p->next;
   1.215 +	}
   1.216 +	r->curpage = r->pages;
   1.217 +}
   1.218 +
   1.219 +static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
   1.220 +{
   1.221 +	unsigned char* buf;
   1.222 +	if (size > NSVG__MEMPAGE_SIZE) return NULL;
   1.223 +	if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
   1.224 +		r->curpage = nsvg__nextPage(r, r->curpage);
   1.225 +	}
   1.226 +	buf = &r->curpage->mem[r->curpage->size];
   1.227 +	r->curpage->size += size;
   1.228 +	return buf;
   1.229 +}
   1.230 +
   1.231 +static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
   1.232 +{
   1.233 +	float dx = x2 - x1;
   1.234 +	float dy = y2 - y1;
   1.235 +	return dx*dx + dy*dy < tol*tol;
   1.236 +}
   1.237 +
   1.238 +static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
   1.239 +{
   1.240 +	NSVGpoint* pt;
   1.241 +
   1.242 +	if (r->npoints > 0) {
   1.243 +		pt = &r->points[r->npoints-1];
   1.244 +		if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
   1.245 +			pt->flags = (unsigned char)(pt->flags | flags);
   1.246 +			return;
   1.247 +		}
   1.248 +	}
   1.249 +
   1.250 +	if (r->npoints+1 > r->cpoints) {
   1.251 +		r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
   1.252 +		r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
   1.253 +		if (r->points == NULL) return;
   1.254 +	}
   1.255 +
   1.256 +	pt = &r->points[r->npoints];
   1.257 +	pt->x = x;
   1.258 +	pt->y = y;
   1.259 +	pt->flags = (unsigned char)flags;
   1.260 +	r->npoints++;
   1.261 +}
   1.262 +
   1.263 +static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
   1.264 +{
   1.265 +	if (r->npoints+1 > r->cpoints) {
   1.266 +		r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
   1.267 +		r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
   1.268 +		if (r->points == NULL) return;
   1.269 +	}
   1.270 +	r->points[r->npoints] = pt;
   1.271 +	r->npoints++;
   1.272 +}
   1.273 +
   1.274 +static void nsvg__duplicatePoints(NSVGrasterizer* r)
   1.275 +{
   1.276 +	if (r->npoints > r->cpoints2) {
   1.277 +		r->cpoints2 = r->npoints;
   1.278 +		r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);
   1.279 +		if (r->points2 == NULL) return;
   1.280 +	}
   1.281 +
   1.282 +	memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);
   1.283 +	r->npoints2 = r->npoints;
   1.284 +}
   1.285 +
   1.286 +static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
   1.287 +{
   1.288 +	NSVGedge* e;
   1.289 +
   1.290 +	// Skip horizontal edges
   1.291 +	if (y0 == y1)
   1.292 +		return;
   1.293 +
   1.294 +	if (r->nedges+1 > r->cedges) {
   1.295 +		r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
   1.296 +		r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
   1.297 +		if (r->edges == NULL) return;
   1.298 +	}
   1.299 +
   1.300 +	e = &r->edges[r->nedges];
   1.301 +	r->nedges++;
   1.302 +
   1.303 +	if (y0 < y1) {
   1.304 +		e->x0 = x0;
   1.305 +		e->y0 = y0;
   1.306 +		e->x1 = x1;
   1.307 +		e->y1 = y1;
   1.308 +		e->dir = 1;
   1.309 +	} else {
   1.310 +		e->x0 = x1;
   1.311 +		e->y0 = y1;
   1.312 +		e->x1 = x0;
   1.313 +		e->y1 = y0;
   1.314 +		e->dir = -1;
   1.315 +	}
   1.316 +}
   1.317 +
   1.318 +static float nsvg__normalize(float *x, float* y)
   1.319 +{
   1.320 +	float d = sqrtf((*x)*(*x) + (*y)*(*y));
   1.321 +	if (d > 1e-6f) {
   1.322 +		float id = 1.0f / d;
   1.323 +		*x *= id;
   1.324 +		*y *= id;
   1.325 +	}
   1.326 +	return d;
   1.327 +}
   1.328 +
   1.329 +static float nsvg__absf(float x) { return x < 0 ? -x : x; }
   1.330 +
   1.331 +static void nsvg__flattenCubicBez(NSVGrasterizer* r,
   1.332 +								  float x1, float y1, float x2, float y2,
   1.333 +								  float x3, float y3, float x4, float y4,
   1.334 +								  int level, int type)
   1.335 +{
   1.336 +	float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
   1.337 +	float dx,dy,d2,d3;
   1.338 +
   1.339 +	if (level > 10) return;
   1.340 +
   1.341 +	x12 = (x1+x2)*0.5f;
   1.342 +	y12 = (y1+y2)*0.5f;
   1.343 +	x23 = (x2+x3)*0.5f;
   1.344 +	y23 = (y2+y3)*0.5f;
   1.345 +	x34 = (x3+x4)*0.5f;
   1.346 +	y34 = (y3+y4)*0.5f;
   1.347 +	x123 = (x12+x23)*0.5f;
   1.348 +	y123 = (y12+y23)*0.5f;
   1.349 +
   1.350 +	dx = x4 - x1;
   1.351 +	dy = y4 - y1;
   1.352 +	d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
   1.353 +	d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
   1.354 +
   1.355 +	if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
   1.356 +		nsvg__addPathPoint(r, x4, y4, type);
   1.357 +		return;
   1.358 +	}
   1.359 +
   1.360 +	x234 = (x23+x34)*0.5f;
   1.361 +	y234 = (y23+y34)*0.5f;
   1.362 +	x1234 = (x123+x234)*0.5f;
   1.363 +	y1234 = (y123+y234)*0.5f;
   1.364 +
   1.365 +	nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
   1.366 +	nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
   1.367 +}
   1.368 +
   1.369 +static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)
   1.370 +{
   1.371 +	int i, j;
   1.372 +	NSVGpath* path;
   1.373 +
   1.374 +	for (path = shape->paths; path != NULL; path = path->next) {
   1.375 +		r->npoints = 0;
   1.376 +		// Flatten path
   1.377 +		nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
   1.378 +		for (i = 0; i < path->npts-1; i += 3) {
   1.379 +			float* p = &path->pts[i*2];
   1.380 +			nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);
   1.381 +		}
   1.382 +		// Close path
   1.383 +		nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
   1.384 +		// Build edges
   1.385 +		for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
   1.386 +			nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
   1.387 +	}
   1.388 +}
   1.389 +
   1.390 +enum NSVGpointFlags
   1.391 +{
   1.392 +	NSVG_PT_CORNER = 0x01,
   1.393 +	NSVG_PT_BEVEL = 0x02,
   1.394 +	NSVG_PT_LEFT = 0x04
   1.395 +};
   1.396 +
   1.397 +static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
   1.398 +{
   1.399 +	float w = lineWidth * 0.5f;
   1.400 +	float dx = p1->x - p0->x;
   1.401 +	float dy = p1->y - p0->y;
   1.402 +	float len = nsvg__normalize(&dx, &dy);
   1.403 +	float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
   1.404 +	float dlx = dy, dly = -dx;
   1.405 +	float lx = px - dlx*w, ly = py - dly*w;
   1.406 +	float rx = px + dlx*w, ry = py + dly*w;
   1.407 +	left->x = lx; left->y = ly;
   1.408 +	right->x = rx; right->y = ry;
   1.409 +}
   1.410 +
   1.411 +static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
   1.412 +{
   1.413 +	float w = lineWidth * 0.5f;
   1.414 +	float px = p->x, py = p->y;
   1.415 +	float dlx = dy, dly = -dx;
   1.416 +	float lx = px - dlx*w, ly = py - dly*w;
   1.417 +	float rx = px + dlx*w, ry = py + dly*w;
   1.418 +
   1.419 +	nsvg__addEdge(r, lx, ly, rx, ry);
   1.420 +
   1.421 +	if (connect) {
   1.422 +		nsvg__addEdge(r, left->x, left->y, lx, ly);
   1.423 +		nsvg__addEdge(r, rx, ry, right->x, right->y);
   1.424 +	}
   1.425 +	left->x = lx; left->y = ly;
   1.426 +	right->x = rx; right->y = ry;
   1.427 +}
   1.428 +
   1.429 +static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
   1.430 +{
   1.431 +	float w = lineWidth * 0.5f;
   1.432 +	float px = p->x - dx*w, py = p->y - dy*w;
   1.433 +	float dlx = dy, dly = -dx;
   1.434 +	float lx = px - dlx*w, ly = py - dly*w;
   1.435 +	float rx = px + dlx*w, ry = py + dly*w;
   1.436 +
   1.437 +	nsvg__addEdge(r, lx, ly, rx, ry);
   1.438 +
   1.439 +	if (connect) {
   1.440 +		nsvg__addEdge(r, left->x, left->y, lx, ly);
   1.441 +		nsvg__addEdge(r, rx, ry, right->x, right->y);
   1.442 +	}
   1.443 +	left->x = lx; left->y = ly;
   1.444 +	right->x = rx; right->y = ry;
   1.445 +}
   1.446 +
   1.447 +#ifndef NSVG_PI
   1.448 +#define NSVG_PI (3.14159265358979323846264338327f)
   1.449 +#endif
   1.450 +
   1.451 +static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
   1.452 +{
   1.453 +	int i;
   1.454 +	float w = lineWidth * 0.5f;
   1.455 +	float px = p->x, py = p->y;
   1.456 +	float dlx = dy, dly = -dx;
   1.457 +	float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
   1.458 +
   1.459 +	for (i = 0; i < ncap; i++) {
   1.460 +		float a = (float)i/(float)(ncap-1)*NSVG_PI;
   1.461 +		float ax = cosf(a) * w, ay = sinf(a) * w;
   1.462 +		float x = px - dlx*ax - dx*ay;
   1.463 +		float y = py - dly*ax - dy*ay;
   1.464 +
   1.465 +		if (i > 0)
   1.466 +			nsvg__addEdge(r, prevx, prevy, x, y);
   1.467 +
   1.468 +		prevx = x;
   1.469 +		prevy = y;
   1.470 +
   1.471 +		if (i == 0) {
   1.472 +			lx = x; ly = y;
   1.473 +		} else if (i == ncap-1) {
   1.474 +			rx = x; ry = y;
   1.475 +		}
   1.476 +	}
   1.477 +
   1.478 +	if (connect) {
   1.479 +		nsvg__addEdge(r, left->x, left->y, lx, ly);
   1.480 +		nsvg__addEdge(r, rx, ry, right->x, right->y);
   1.481 +	}
   1.482 +
   1.483 +	left->x = lx; left->y = ly;
   1.484 +	right->x = rx; right->y = ry;
   1.485 +}
   1.486 +
   1.487 +static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
   1.488 +{
   1.489 +	float w = lineWidth * 0.5f;
   1.490 +	float dlx0 = p0->dy, dly0 = -p0->dx;
   1.491 +	float dlx1 = p1->dy, dly1 = -p1->dx;
   1.492 +	float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
   1.493 +	float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
   1.494 +	float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
   1.495 +	float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
   1.496 +
   1.497 +	nsvg__addEdge(r, lx0, ly0, left->x, left->y);
   1.498 +	nsvg__addEdge(r, lx1, ly1, lx0, ly0);
   1.499 +
   1.500 +	nsvg__addEdge(r, right->x, right->y, rx0, ry0);
   1.501 +	nsvg__addEdge(r, rx0, ry0, rx1, ry1);
   1.502 +
   1.503 +	left->x = lx1; left->y = ly1;
   1.504 +	right->x = rx1; right->y = ry1;
   1.505 +}
   1.506 +
   1.507 +static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
   1.508 +{
   1.509 +	float w = lineWidth * 0.5f;
   1.510 +	float dlx0 = p0->dy, dly0 = -p0->dx;
   1.511 +	float dlx1 = p1->dy, dly1 = -p1->dx;
   1.512 +	float lx0, rx0, lx1, rx1;
   1.513 +	float ly0, ry0, ly1, ry1;
   1.514 +
   1.515 +	if (p1->flags & NSVG_PT_LEFT) {
   1.516 +		lx0 = lx1 = p1->x - p1->dmx * w;
   1.517 +		ly0 = ly1 = p1->y - p1->dmy * w;
   1.518 +		nsvg__addEdge(r, lx1, ly1, left->x, left->y);
   1.519 +
   1.520 +		rx0 = p1->x + (dlx0 * w);
   1.521 +		ry0 = p1->y + (dly0 * w);
   1.522 +		rx1 = p1->x + (dlx1 * w);
   1.523 +		ry1 = p1->y + (dly1 * w);
   1.524 +		nsvg__addEdge(r, right->x, right->y, rx0, ry0);
   1.525 +		nsvg__addEdge(r, rx0, ry0, rx1, ry1);
   1.526 +	} else {
   1.527 +		lx0 = p1->x - (dlx0 * w);
   1.528 +		ly0 = p1->y - (dly0 * w);
   1.529 +		lx1 = p1->x - (dlx1 * w);
   1.530 +		ly1 = p1->y - (dly1 * w);
   1.531 +		nsvg__addEdge(r, lx0, ly0, left->x, left->y);
   1.532 +		nsvg__addEdge(r, lx1, ly1, lx0, ly0);
   1.533 +
   1.534 +		rx0 = rx1 = p1->x + p1->dmx * w;
   1.535 +		ry0 = ry1 = p1->y + p1->dmy * w;
   1.536 +		nsvg__addEdge(r, right->x, right->y, rx1, ry1);
   1.537 +	}
   1.538 +
   1.539 +	left->x = lx1; left->y = ly1;
   1.540 +	right->x = rx1; right->y = ry1;
   1.541 +}
   1.542 +
   1.543 +static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
   1.544 +{
   1.545 +	int i, n;
   1.546 +	float w = lineWidth * 0.5f;
   1.547 +	float dlx0 = p0->dy, dly0 = -p0->dx;
   1.548 +	float dlx1 = p1->dy, dly1 = -p1->dx;
   1.549 +	float a0 = atan2f(dly0, dlx0);
   1.550 +	float a1 = atan2f(dly1, dlx1);
   1.551 +	float da = a1 - a0;
   1.552 +	float lx, ly, rx, ry;
   1.553 +
   1.554 +	if (da < NSVG_PI) da += NSVG_PI*2;
   1.555 +	if (da > NSVG_PI) da -= NSVG_PI*2;
   1.556 +
   1.557 +	n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
   1.558 +	if (n < 2) n = 2;
   1.559 +	if (n > ncap) n = ncap;
   1.560 +
   1.561 +	lx = left->x;
   1.562 +	ly = left->y;
   1.563 +	rx = right->x;
   1.564 +	ry = right->y;
   1.565 +
   1.566 +	for (i = 0; i < n; i++) {
   1.567 +		float u = (float)i/(float)(n-1);
   1.568 +		float a = a0 + u*da;
   1.569 +		float ax = cosf(a) * w, ay = sinf(a) * w;
   1.570 +		float lx1 = p1->x - ax, ly1 = p1->y - ay;
   1.571 +		float rx1 = p1->x + ax, ry1 = p1->y + ay;
   1.572 +
   1.573 +		nsvg__addEdge(r, lx1, ly1, lx, ly);
   1.574 +		nsvg__addEdge(r, rx, ry, rx1, ry1);
   1.575 +
   1.576 +		lx = lx1; ly = ly1;
   1.577 +		rx = rx1; ry = ry1;
   1.578 +	}
   1.579 +
   1.580 +	left->x = lx; left->y = ly;
   1.581 +	right->x = rx; right->y = ry;
   1.582 +}
   1.583 +
   1.584 +static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
   1.585 +{
   1.586 +	float w = lineWidth * 0.5f;
   1.587 +	float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
   1.588 +	float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
   1.589 +
   1.590 +	nsvg__addEdge(r, lx, ly, left->x, left->y);
   1.591 +	nsvg__addEdge(r, right->x, right->y, rx, ry);
   1.592 +
   1.593 +	left->x = lx; left->y = ly;
   1.594 +	right->x = rx; right->y = ry;
   1.595 +}
   1.596 +
   1.597 +static int nsvg__curveDivs(float r, float arc, float tol)
   1.598 +{
   1.599 +	float da = acosf(r / (r + tol)) * 2.0f;
   1.600 +	int divs = (int)ceilf(arc / da);
   1.601 +	if (divs < 2) divs = 2;
   1.602 +	return divs;
   1.603 +}
   1.604 +
   1.605 +static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)
   1.606 +{
   1.607 +	int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol);	// Calculate divisions per half circle.
   1.608 +	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};
   1.609 +	NSVGpoint* p0, *p1;
   1.610 +	int j, s, e;
   1.611 +
   1.612 +	// Build stroke edges
   1.613 +	if (closed) {
   1.614 +		// Looping
   1.615 +		p0 = &points[npoints-1];
   1.616 +		p1 = &points[0];
   1.617 +		s = 0;
   1.618 +		e = npoints;
   1.619 +	} else {
   1.620 +		// Add cap
   1.621 +		p0 = &points[0];
   1.622 +		p1 = &points[1];
   1.623 +		s = 1;
   1.624 +		e = npoints-1;
   1.625 +	}
   1.626 +
   1.627 +	if (closed) {
   1.628 +		nsvg__initClosed(&left, &right, p0, p1, lineWidth);
   1.629 +		firstLeft = left;
   1.630 +		firstRight = right;
   1.631 +	} else {
   1.632 +		// Add cap
   1.633 +		float dx = p1->x - p0->x;
   1.634 +		float dy = p1->y - p0->y;
   1.635 +		nsvg__normalize(&dx, &dy);
   1.636 +		if (lineCap == NSVG_CAP_BUTT)
   1.637 +			nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
   1.638 +		else if (lineCap == NSVG_CAP_SQUARE)
   1.639 +			nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
   1.640 +		else if (lineCap == NSVG_CAP_ROUND)
   1.641 +			nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
   1.642 +	}
   1.643 +
   1.644 +	for (j = s; j < e; ++j) {
   1.645 +		if (p1->flags & NSVG_PT_CORNER) {
   1.646 +			if (lineJoin == NSVG_JOIN_ROUND)
   1.647 +				nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
   1.648 +			else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
   1.649 +				nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
   1.650 +			else
   1.651 +				nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
   1.652 +		} else {
   1.653 +			nsvg__straightJoin(r, &left, &right, p1, lineWidth);
   1.654 +		}
   1.655 +		p0 = p1++;
   1.656 +	}
   1.657 +
   1.658 +	if (closed) {
   1.659 +		// Loop it
   1.660 +		nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
   1.661 +		nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
   1.662 +	} else {
   1.663 +		// Add cap
   1.664 +		float dx = p1->x - p0->x;
   1.665 +		float dy = p1->y - p0->y;
   1.666 +		nsvg__normalize(&dx, &dy);
   1.667 +		if (lineCap == NSVG_CAP_BUTT)
   1.668 +			nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
   1.669 +		else if (lineCap == NSVG_CAP_SQUARE)
   1.670 +			nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
   1.671 +		else if (lineCap == NSVG_CAP_ROUND)
   1.672 +			nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
   1.673 +	}
   1.674 +}
   1.675 +
   1.676 +static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)
   1.677 +{
   1.678 +	int i, j;
   1.679 +	NSVGpoint* p0, *p1;
   1.680 +
   1.681 +	p0 = &r->points[r->npoints-1];
   1.682 +	p1 = &r->points[0];
   1.683 +	for (i = 0; i < r->npoints; i++) {
   1.684 +		// Calculate segment direction and length
   1.685 +		p0->dx = p1->x - p0->x;
   1.686 +		p0->dy = p1->y - p0->y;
   1.687 +		p0->len = nsvg__normalize(&p0->dx, &p0->dy);
   1.688 +		// Advance
   1.689 +		p0 = p1++;
   1.690 +	}
   1.691 +
   1.692 +	// calculate joins
   1.693 +	p0 = &r->points[r->npoints-1];
   1.694 +	p1 = &r->points[0];
   1.695 +	for (j = 0; j < r->npoints; j++) {
   1.696 +		float dlx0, dly0, dlx1, dly1, dmr2, cross;
   1.697 +		dlx0 = p0->dy;
   1.698 +		dly0 = -p0->dx;
   1.699 +		dlx1 = p1->dy;
   1.700 +		dly1 = -p1->dx;
   1.701 +		// Calculate extrusions
   1.702 +		p1->dmx = (dlx0 + dlx1) * 0.5f;
   1.703 +		p1->dmy = (dly0 + dly1) * 0.5f;
   1.704 +		dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
   1.705 +		if (dmr2 > 0.000001f) {
   1.706 +			float s2 = 1.0f / dmr2;
   1.707 +			if (s2 > 600.0f) {
   1.708 +				s2 = 600.0f;
   1.709 +			}
   1.710 +			p1->dmx *= s2;
   1.711 +			p1->dmy *= s2;
   1.712 +		}
   1.713 +
   1.714 +		// Clear flags, but keep the corner.
   1.715 +		p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
   1.716 +
   1.717 +		// Keep track of left turns.
   1.718 +		cross = p1->dx * p0->dy - p0->dx * p1->dy;
   1.719 +		if (cross > 0.0f)
   1.720 +			p1->flags |= NSVG_PT_LEFT;
   1.721 +
   1.722 +		// Check to see if the corner needs to be beveled.
   1.723 +		if (p1->flags & NSVG_PT_CORNER) {
   1.724 +			if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
   1.725 +				p1->flags |= NSVG_PT_BEVEL;
   1.726 +			}
   1.727 +		}
   1.728 +
   1.729 +		p0 = p1++;
   1.730 +	}
   1.731 +}
   1.732 +
   1.733 +static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale)
   1.734 +{
   1.735 +	int i, j, closed;
   1.736 +	NSVGpath* path;
   1.737 +	NSVGpoint* p0, *p1;
   1.738 +	float miterLimit = shape->miterLimit;
   1.739 +	int lineJoin = shape->strokeLineJoin;
   1.740 +	int lineCap = shape->strokeLineCap;
   1.741 +	float lineWidth = shape->strokeWidth * scale;
   1.742 +
   1.743 +	for (path = shape->paths; path != NULL; path = path->next) {
   1.744 +		// Flatten path
   1.745 +		r->npoints = 0;
   1.746 +		nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
   1.747 +		for (i = 0; i < path->npts-1; i += 3) {
   1.748 +			float* p = &path->pts[i*2];
   1.749 +			nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER);
   1.750 +		}
   1.751 +		if (r->npoints < 2)
   1.752 +			continue;
   1.753 +
   1.754 +		closed = path->closed;
   1.755 +
   1.756 +		// If the first and last points are the same, remove the last, mark as closed path.
   1.757 +		p0 = &r->points[r->npoints-1];
   1.758 +		p1 = &r->points[0];
   1.759 +		if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
   1.760 +			r->npoints--;
   1.761 +			p0 = &r->points[r->npoints-1];
   1.762 +			closed = 1;
   1.763 +		}
   1.764 +
   1.765 +		if (shape->strokeDashCount > 0) {
   1.766 +			int idash = 0, dashState = 1;
   1.767 +			float totalDist = 0, dashLen, allDashLen, dashOffset;
   1.768 +			NSVGpoint cur;
   1.769 +
   1.770 +			if (closed)
   1.771 +				nsvg__appendPathPoint(r, r->points[0]);
   1.772 +
   1.773 +			// Duplicate points -> points2.
   1.774 +			nsvg__duplicatePoints(r);
   1.775 +
   1.776 +			r->npoints = 0;
   1.777 + 			cur = r->points2[0];
   1.778 +			nsvg__appendPathPoint(r, cur);
   1.779 +
   1.780 +			// Figure out dash offset.
   1.781 +			allDashLen = 0;
   1.782 +			for (j = 0; j < shape->strokeDashCount; j++)
   1.783 +				allDashLen += shape->strokeDashArray[j];
   1.784 +			if (shape->strokeDashCount & 1)
   1.785 +				allDashLen *= 2.0f;
   1.786 +			// Find location inside pattern
   1.787 +			dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
   1.788 +			if (dashOffset < 0.0f)
   1.789 +				dashOffset += allDashLen;
   1.790 +
   1.791 +			while (dashOffset > shape->strokeDashArray[idash]) {
   1.792 +				dashOffset -= shape->strokeDashArray[idash];
   1.793 +				idash = (idash + 1) % shape->strokeDashCount;
   1.794 +			}
   1.795 +			dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;
   1.796 +
   1.797 +			for (j = 1; j < r->npoints2; ) {
   1.798 +				float dx = r->points2[j].x - cur.x;
   1.799 +				float dy = r->points2[j].y - cur.y;
   1.800 +				float dist = sqrtf(dx*dx + dy*dy);
   1.801 +
   1.802 +				if ((totalDist + dist) > dashLen) {
   1.803 +					// Calculate intermediate point
   1.804 +					float d = (dashLen - totalDist) / dist;
   1.805 +					float x = cur.x + dx * d;
   1.806 +					float y = cur.y + dy * d;
   1.807 +					nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
   1.808 +
   1.809 +					// Stroke
   1.810 +					if (r->npoints > 1 && dashState) {
   1.811 +						nsvg__prepareStroke(r, miterLimit, lineJoin);
   1.812 +						nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
   1.813 +					}
   1.814 +					// Advance dash pattern
   1.815 +					dashState = !dashState;
   1.816 +					idash = (idash+1) % shape->strokeDashCount;
   1.817 +					dashLen = shape->strokeDashArray[idash] * scale;
   1.818 +					// Restart
   1.819 +					cur.x = x;
   1.820 +					cur.y = y;
   1.821 +					cur.flags = NSVG_PT_CORNER;
   1.822 +					totalDist = 0.0f;
   1.823 +					r->npoints = 0;
   1.824 +					nsvg__appendPathPoint(r, cur);
   1.825 +				} else {
   1.826 +					totalDist += dist;
   1.827 +					cur = r->points2[j];
   1.828 +					nsvg__appendPathPoint(r, cur);
   1.829 +					j++;
   1.830 +				}
   1.831 +			}
   1.832 +			// Stroke any leftover path
   1.833 +			if (r->npoints > 1 && dashState)
   1.834 +				nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
   1.835 +		} else {
   1.836 +			nsvg__prepareStroke(r, miterLimit, lineJoin);
   1.837 +			nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
   1.838 +		}
   1.839 +	}
   1.840 +}
   1.841 +
   1.842 +static int nsvg__cmpEdge(const void *p, const void *q)
   1.843 +{
   1.844 +	const NSVGedge* a = (const NSVGedge*)p;
   1.845 +	const NSVGedge* b = (const NSVGedge*)q;
   1.846 +
   1.847 +	if (a->y0 < b->y0) return -1;
   1.848 +	if (a->y0 > b->y0) return  1;
   1.849 +	return 0;
   1.850 +}
   1.851 +
   1.852 +
   1.853 +static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
   1.854 +{
   1.855 +	 NSVGactiveEdge* z;
   1.856 +
   1.857 +	if (r->freelist != NULL) {
   1.858 +		// Restore from freelist.
   1.859 +		z = r->freelist;
   1.860 +		r->freelist = z->next;
   1.861 +	} else {
   1.862 +		// Alloc new edge.
   1.863 +		z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
   1.864 +		if (z == NULL) return NULL;
   1.865 +	}
   1.866 +
   1.867 +	float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
   1.868 +//	STBTT_assert(e->y0 <= start_point);
   1.869 +	// round dx down to avoid going too far
   1.870 +	if (dxdy < 0)
   1.871 +		z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
   1.872 +	else
   1.873 +		z->dx = (int)floorf(NSVG__FIX * dxdy);
   1.874 +	z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
   1.875 +//	z->x -= off_x * FIX;
   1.876 +	z->ey = e->y1;
   1.877 +	z->next = 0;
   1.878 +	z->dir = e->dir;
   1.879 +
   1.880 +	return z;
   1.881 +}
   1.882 +
   1.883 +static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
   1.884 +{
   1.885 +	z->next = r->freelist;
   1.886 +	r->freelist = z;
   1.887 +}
   1.888 +
   1.889 +static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)
   1.890 +{
   1.891 +	int i = x0 >> NSVG__FIXSHIFT;
   1.892 +	int j = x1 >> NSVG__FIXSHIFT;
   1.893 +	if (i < *xmin) *xmin = i;
   1.894 +	if (j > *xmax) *xmax = j;
   1.895 +	if (i < len && j >= 0) {
   1.896 +		if (i == j) {
   1.897 +			// x0,x1 are the same pixel, so compute combined coverage
   1.898 +			scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
   1.899 +		} else {
   1.900 +			if (i >= 0) // add antialiasing for x0
   1.901 +				scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
   1.902 +			else
   1.903 +				i = -1; // clip
   1.904 +
   1.905 +			if (j < len) // add antialiasing for x1
   1.906 +				scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
   1.907 +			else
   1.908 +				j = len; // clip
   1.909 +
   1.910 +			for (++i; i < j; ++i) // fill pixels between x0 and x1
   1.911 +				scanline[i] = (unsigned char)(scanline[i] + maxWeight);
   1.912 +		}
   1.913 +	}
   1.914 +}
   1.915 +
   1.916 +// note: this routine clips fills that extend off the edges... ideally this
   1.917 +// wouldn't happen, but it could happen if the truetype glyph bounding boxes
   1.918 +// are wrong, or if the user supplies a too-small bitmap
   1.919 +static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule)
   1.920 +{
   1.921 +	// non-zero winding fill
   1.922 +	int x0 = 0, w = 0;
   1.923 +
   1.924 +	if (fillRule == NSVG_FILLRULE_NONZERO) {
   1.925 +		// Non-zero
   1.926 +		while (e != NULL) {
   1.927 +			if (w == 0) {
   1.928 +				// if we're currently at zero, we need to record the edge start point
   1.929 +				x0 = e->x; w += e->dir;
   1.930 +			} else {
   1.931 +				int x1 = e->x; w += e->dir;
   1.932 +				// if we went to zero, we need to draw
   1.933 +				if (w == 0)
   1.934 +					nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
   1.935 +			}
   1.936 +			e = e->next;
   1.937 +		}
   1.938 +	} else if (fillRule == NSVG_FILLRULE_EVENODD) {
   1.939 +		// Even-odd
   1.940 +		while (e != NULL) {
   1.941 +			if (w == 0) {
   1.942 +				// if we're currently at zero, we need to record the edge start point
   1.943 +				x0 = e->x; w = 1;
   1.944 +			} else {
   1.945 +				int x1 = e->x; w = 0;
   1.946 +				nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
   1.947 +			}
   1.948 +			e = e->next;
   1.949 +		}
   1.950 +	}
   1.951 +}
   1.952 +
   1.953 +static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
   1.954 +
   1.955 +static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
   1.956 +{
   1.957 +	return (r) | (g << 8) | (b << 16) | (a << 24);
   1.958 +}
   1.959 +
   1.960 +static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
   1.961 +{
   1.962 +	int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
   1.963 +	int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
   1.964 +	int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
   1.965 +	int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
   1.966 +	int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
   1.967 +	return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
   1.968 +}
   1.969 +
   1.970 +static unsigned int nsvg__applyOpacity(unsigned int c, float u)
   1.971 +{
   1.972 +	int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
   1.973 +	int r = (c) & 0xff;
   1.974 +	int g = (c>>8) & 0xff;
   1.975 +	int b = (c>>16) & 0xff;
   1.976 +	int a = (((c>>24) & 0xff)*iu) >> 8;
   1.977 +	return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
   1.978 +}
   1.979 +
   1.980 +static inline int nsvg__div255(int x)
   1.981 +{
   1.982 +    return ((x+1) * 257) >> 16;
   1.983 +}
   1.984 +
   1.985 +static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
   1.986 +								float tx, float ty, float scale, NSVGcachedPaint* cache)
   1.987 +{
   1.988 +
   1.989 +	if (cache->type == NSVG_PAINT_COLOR) {
   1.990 +		int i, cr, cg, cb, ca;
   1.991 +		cr = cache->colors[0] & 0xff;
   1.992 +		cg = (cache->colors[0] >> 8) & 0xff;
   1.993 +		cb = (cache->colors[0] >> 16) & 0xff;
   1.994 +		ca = (cache->colors[0] >> 24) & 0xff;
   1.995 +
   1.996 +		for (i = 0; i < count; i++) {
   1.997 +			int r,g,b;
   1.998 +			int a = nsvg__div255((int)cover[0] * ca);
   1.999 +			int ia = 255 - a;
  1.1000 +			// Premultiply
  1.1001 +			r = nsvg__div255(cr * a);
  1.1002 +			g = nsvg__div255(cg * a);
  1.1003 +			b = nsvg__div255(cb * a);
  1.1004 +
  1.1005 +			// Blend over
  1.1006 +			r += nsvg__div255(ia * (int)dst[0]);
  1.1007 +			g += nsvg__div255(ia * (int)dst[1]);
  1.1008 +			b += nsvg__div255(ia * (int)dst[2]);
  1.1009 +			a += nsvg__div255(ia * (int)dst[3]);
  1.1010 +
  1.1011 +			dst[0] = (unsigned char)r;
  1.1012 +			dst[1] = (unsigned char)g;
  1.1013 +			dst[2] = (unsigned char)b;
  1.1014 +			dst[3] = (unsigned char)a;
  1.1015 +
  1.1016 +			cover++;
  1.1017 +			dst += 4;
  1.1018 +		}
  1.1019 +	} else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
  1.1020 +		// TODO: spread modes.
  1.1021 +		// TODO: plenty of opportunities to optimize.
  1.1022 +		float fx, fy, dx, gy;
  1.1023 +		float* t = cache->xform;
  1.1024 +		int i, cr, cg, cb, ca;
  1.1025 +		unsigned int c;
  1.1026 +
  1.1027 +		fx = ((float)x - tx) / scale;
  1.1028 +		fy = ((float)y - ty) / scale;
  1.1029 +		dx = 1.0f / scale;
  1.1030 +
  1.1031 +		for (i = 0; i < count; i++) {
  1.1032 +			int r,g,b,a,ia;
  1.1033 +			gy = fx*t[1] + fy*t[3] + t[5];
  1.1034 +			c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
  1.1035 +			cr = (c) & 0xff;
  1.1036 +			cg = (c >> 8) & 0xff;
  1.1037 +			cb = (c >> 16) & 0xff;
  1.1038 +			ca = (c >> 24) & 0xff;
  1.1039 +
  1.1040 +			a = nsvg__div255((int)cover[0] * ca);
  1.1041 +			ia = 255 - a;
  1.1042 +
  1.1043 +			// Premultiply
  1.1044 +			r = nsvg__div255(cr * a);
  1.1045 +			g = nsvg__div255(cg * a);
  1.1046 +			b = nsvg__div255(cb * a);
  1.1047 +
  1.1048 +			// Blend over
  1.1049 +			r += nsvg__div255(ia * (int)dst[0]);
  1.1050 +			g += nsvg__div255(ia * (int)dst[1]);
  1.1051 +			b += nsvg__div255(ia * (int)dst[2]);
  1.1052 +			a += nsvg__div255(ia * (int)dst[3]);
  1.1053 +
  1.1054 +			dst[0] = (unsigned char)r;
  1.1055 +			dst[1] = (unsigned char)g;
  1.1056 +			dst[2] = (unsigned char)b;
  1.1057 +			dst[3] = (unsigned char)a;
  1.1058 +
  1.1059 +			cover++;
  1.1060 +			dst += 4;
  1.1061 +			fx += dx;
  1.1062 +		}
  1.1063 +	} else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
  1.1064 +		// TODO: spread modes.
  1.1065 +		// TODO: plenty of opportunities to optimize.
  1.1066 +		// TODO: focus (fx,fy)
  1.1067 +		float fx, fy, dx, gx, gy, gd;
  1.1068 +		float* t = cache->xform;
  1.1069 +		int i, cr, cg, cb, ca;
  1.1070 +		unsigned int c;
  1.1071 +
  1.1072 +		fx = ((float)x - tx) / scale;
  1.1073 +		fy = ((float)y - ty) / scale;
  1.1074 +		dx = 1.0f / scale;
  1.1075 +
  1.1076 +		for (i = 0; i < count; i++) {
  1.1077 +			int r,g,b,a,ia;
  1.1078 +			gx = fx*t[0] + fy*t[2] + t[4];
  1.1079 +			gy = fx*t[1] + fy*t[3] + t[5];
  1.1080 +			gd = sqrtf(gx*gx + gy*gy);
  1.1081 +			c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
  1.1082 +			cr = (c) & 0xff;
  1.1083 +			cg = (c >> 8) & 0xff;
  1.1084 +			cb = (c >> 16) & 0xff;
  1.1085 +			ca = (c >> 24) & 0xff;
  1.1086 +
  1.1087 +			a = nsvg__div255((int)cover[0] * ca);
  1.1088 +			ia = 255 - a;
  1.1089 +
  1.1090 +			// Premultiply
  1.1091 +			r = nsvg__div255(cr * a);
  1.1092 +			g = nsvg__div255(cg * a);
  1.1093 +			b = nsvg__div255(cb * a);
  1.1094 +
  1.1095 +			// Blend over
  1.1096 +			r += nsvg__div255(ia * (int)dst[0]);
  1.1097 +			g += nsvg__div255(ia * (int)dst[1]);
  1.1098 +			b += nsvg__div255(ia * (int)dst[2]);
  1.1099 +			a += nsvg__div255(ia * (int)dst[3]);
  1.1100 +
  1.1101 +			dst[0] = (unsigned char)r;
  1.1102 +			dst[1] = (unsigned char)g;
  1.1103 +			dst[2] = (unsigned char)b;
  1.1104 +			dst[3] = (unsigned char)a;
  1.1105 +
  1.1106 +			cover++;
  1.1107 +			dst += 4;
  1.1108 +			fx += dx;
  1.1109 +		}
  1.1110 +	}
  1.1111 +}
  1.1112 +
  1.1113 +static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule)
  1.1114 +{
  1.1115 +	NSVGactiveEdge *active = NULL;
  1.1116 +	int y, s;
  1.1117 +	int e = 0;
  1.1118 +	int maxWeight = (255 / NSVG__SUBSAMPLES);  // weight per vertical scanline
  1.1119 +	int xmin, xmax;
  1.1120 +
  1.1121 +	for (y = 0; y < r->height; y++) {
  1.1122 +		memset(r->scanline, 0, r->width);
  1.1123 +		xmin = r->width;
  1.1124 +		xmax = 0;
  1.1125 +		for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
  1.1126 +			// find center of pixel for this scanline
  1.1127 +			float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
  1.1128 +			NSVGactiveEdge **step = &active;
  1.1129 +
  1.1130 +			// update all active edges;
  1.1131 +			// remove all active edges that terminate before the center of this scanline
  1.1132 +			while (*step) {
  1.1133 +				NSVGactiveEdge *z = *step;
  1.1134 +				if (z->ey <= scany) {
  1.1135 +					*step = z->next; // delete from list
  1.1136 +//					NSVG__assert(z->valid);
  1.1137 +					nsvg__freeActive(r, z);
  1.1138 +				} else {
  1.1139 +					z->x += z->dx; // advance to position for current scanline
  1.1140 +					step = &((*step)->next); // advance through list
  1.1141 +				}
  1.1142 +			}
  1.1143 +
  1.1144 +			// resort the list if needed
  1.1145 +			for (;;) {
  1.1146 +				int changed = 0;
  1.1147 +				step = &active;
  1.1148 +				while (*step && (*step)->next) {
  1.1149 +					if ((*step)->x > (*step)->next->x) {
  1.1150 +						NSVGactiveEdge* t = *step;
  1.1151 +						NSVGactiveEdge* q = t->next;
  1.1152 +						t->next = q->next;
  1.1153 +						q->next = t;
  1.1154 +						*step = q;
  1.1155 +						changed = 1;
  1.1156 +					}
  1.1157 +					step = &(*step)->next;
  1.1158 +				}
  1.1159 +				if (!changed) break;
  1.1160 +			}
  1.1161 +
  1.1162 +			// insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
  1.1163 +			while (e < r->nedges && r->edges[e].y0 <= scany) {
  1.1164 +				if (r->edges[e].y1 > scany) {
  1.1165 +					NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
  1.1166 +					if (z == NULL) break;
  1.1167 +					// find insertion point
  1.1168 +					if (active == NULL) {
  1.1169 +						active = z;
  1.1170 +					} else if (z->x < active->x) {
  1.1171 +						// insert at front
  1.1172 +						z->next = active;
  1.1173 +						active = z;
  1.1174 +					} else {
  1.1175 +						// find thing to insert AFTER
  1.1176 +						NSVGactiveEdge* p = active;
  1.1177 +						while (p->next && p->next->x < z->x)
  1.1178 +							p = p->next;
  1.1179 +						// at this point, p->next->x is NOT < z->x
  1.1180 +						z->next = p->next;
  1.1181 +						p->next = z;
  1.1182 +					}
  1.1183 +				}
  1.1184 +				e++;
  1.1185 +			}
  1.1186 +
  1.1187 +			// now process all active edges in non-zero fashion
  1.1188 +			if (active != NULL)
  1.1189 +				nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
  1.1190 +		}
  1.1191 +		// Blit
  1.1192 +		if (xmin < 0) xmin = 0;
  1.1193 +		if (xmax > r->width-1) xmax = r->width-1;
  1.1194 +		if (xmin <= xmax) {
  1.1195 +			nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache);
  1.1196 +		}
  1.1197 +	}
  1.1198 +
  1.1199 +}
  1.1200 +
  1.1201 +static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
  1.1202 +{
  1.1203 +	int x,y;
  1.1204 +
  1.1205 +	// Unpremultiply
  1.1206 +	for (y = 0; y < h; y++) {
  1.1207 +		unsigned char *row = &image[y*stride];
  1.1208 +		for (x = 0; x < w; x++) {
  1.1209 +			int r = row[0], g = row[1], b = row[2], a = row[3];
  1.1210 +			if (a != 0) {
  1.1211 +				row[0] = (unsigned char)(r*255/a);
  1.1212 +				row[1] = (unsigned char)(g*255/a);
  1.1213 +				row[2] = (unsigned char)(b*255/a);
  1.1214 +			}
  1.1215 +			row += 4;
  1.1216 +		}
  1.1217 +	}
  1.1218 +
  1.1219 +	// Defringe
  1.1220 +	for (y = 0; y < h; y++) {
  1.1221 +		unsigned char *row = &image[y*stride];
  1.1222 +		for (x = 0; x < w; x++) {
  1.1223 +			int r = 0, g = 0, b = 0, a = row[3], n = 0;
  1.1224 +			if (a == 0) {
  1.1225 +				if (x-1 > 0 && row[-1] != 0) {
  1.1226 +					r += row[-4];
  1.1227 +					g += row[-3];
  1.1228 +					b += row[-2];
  1.1229 +					n++;
  1.1230 +				}
  1.1231 +				if (x+1 < w && row[7] != 0) {
  1.1232 +					r += row[4];
  1.1233 +					g += row[5];
  1.1234 +					b += row[6];
  1.1235 +					n++;
  1.1236 +				}
  1.1237 +				if (y-1 > 0 && row[-stride+3] != 0) {
  1.1238 +					r += row[-stride];
  1.1239 +					g += row[-stride+1];
  1.1240 +					b += row[-stride+2];
  1.1241 +					n++;
  1.1242 +				}
  1.1243 +				if (y+1 < h && row[stride+3] != 0) {
  1.1244 +					r += row[stride];
  1.1245 +					g += row[stride+1];
  1.1246 +					b += row[stride+2];
  1.1247 +					n++;
  1.1248 +				}
  1.1249 +				if (n > 0) {
  1.1250 +					row[0] = (unsigned char)(r/n);
  1.1251 +					row[1] = (unsigned char)(g/n);
  1.1252 +					row[2] = (unsigned char)(b/n);
  1.1253 +				}
  1.1254 +			}
  1.1255 +			row += 4;
  1.1256 +		}
  1.1257 +	}
  1.1258 +}
  1.1259 +
  1.1260 +
  1.1261 +static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
  1.1262 +{
  1.1263 +	int i, j;
  1.1264 +	NSVGgradient* grad;
  1.1265 +
  1.1266 +	cache->type = paint->type;
  1.1267 +
  1.1268 +	if (paint->type == NSVG_PAINT_COLOR) {
  1.1269 +		cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
  1.1270 +		return;
  1.1271 +	}
  1.1272 +
  1.1273 +	grad = paint->gradient;
  1.1274 +
  1.1275 +	cache->spread = grad->spread;
  1.1276 +	memcpy(cache->xform, grad->xform, sizeof(float)*6);
  1.1277 +
  1.1278 +	if (grad->nstops == 0) {
  1.1279 +		for (i = 0; i < 256; i++)
  1.1280 +			cache->colors[i] = 0;
  1.1281 +	} if (grad->nstops == 1) {
  1.1282 +		for (i = 0; i < 256; i++)
  1.1283 +			cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
  1.1284 +	} else {
  1.1285 +		unsigned int ca, cb = 0;
  1.1286 +		float ua, ub, du, u;
  1.1287 +		int ia, ib, count;
  1.1288 +
  1.1289 +		ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
  1.1290 +		ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
  1.1291 +		ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
  1.1292 +		ia = (int)(ua * 255.0f);
  1.1293 +		ib = (int)(ub * 255.0f);
  1.1294 +		for (i = 0; i < ia; i++) {
  1.1295 +			cache->colors[i] = ca;
  1.1296 +		}
  1.1297 +
  1.1298 +		for (i = 0; i < grad->nstops-1; i++) {
  1.1299 +			ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
  1.1300 +			cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
  1.1301 +			ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
  1.1302 +			ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
  1.1303 +			ia = (int)(ua * 255.0f);
  1.1304 +			ib = (int)(ub * 255.0f);
  1.1305 +			count = ib - ia;
  1.1306 +			if (count <= 0) continue;
  1.1307 +			u = 0;
  1.1308 +			du = 1.0f / (float)count;
  1.1309 +			for (j = 0; j < count; j++) {
  1.1310 +				cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
  1.1311 +				u += du;
  1.1312 +			}
  1.1313 +		}
  1.1314 +
  1.1315 +		for (i = ib; i < 256; i++)
  1.1316 +			cache->colors[i] = cb;
  1.1317 +	}
  1.1318 +
  1.1319 +}
  1.1320 +
  1.1321 +/*
  1.1322 +static void dumpEdges(NSVGrasterizer* r, const char* name)
  1.1323 +{
  1.1324 +	float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
  1.1325 +	NSVGedge *e = NULL;
  1.1326 +	int i;
  1.1327 +	if (r->nedges == 0) return;
  1.1328 +	FILE* fp = fopen(name, "w");
  1.1329 +	if (fp == NULL) return;
  1.1330 +
  1.1331 +	xmin = xmax = r->edges[0].x0;
  1.1332 +	ymin = ymax = r->edges[0].y0;
  1.1333 +	for (i = 0; i < r->nedges; i++) {
  1.1334 +		e = &r->edges[i];
  1.1335 +		xmin = nsvg__minf(xmin, e->x0);
  1.1336 +		xmin = nsvg__minf(xmin, e->x1);
  1.1337 +		xmax = nsvg__maxf(xmax, e->x0);
  1.1338 +		xmax = nsvg__maxf(xmax, e->x1);
  1.1339 +		ymin = nsvg__minf(ymin, e->y0);
  1.1340 +		ymin = nsvg__minf(ymin, e->y1);
  1.1341 +		ymax = nsvg__maxf(ymax, e->y0);
  1.1342 +		ymax = nsvg__maxf(ymax, e->y1);
  1.1343 +	}
  1.1344 +
  1.1345 +	fprintf(fp, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\">", xmin, ymin, (xmax - xmin), (ymax - ymin));
  1.1346 +
  1.1347 +	for (i = 0; i < r->nedges; i++) {
  1.1348 +		e = &r->edges[i];
  1.1349 +		fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#000;\" />", e->x0,e->y0, e->x1,e->y1);
  1.1350 +	}
  1.1351 +
  1.1352 +	for (i = 0; i < r->npoints; i++) {
  1.1353 +		if (i+1 < r->npoints)
  1.1354 +			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);
  1.1355 +		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");
  1.1356 +	}
  1.1357 +
  1.1358 +	fprintf(fp, "</svg>");
  1.1359 +	fclose(fp);
  1.1360 +}
  1.1361 +*/
  1.1362 +
  1.1363 +void nsvgRasterize(NSVGrasterizer* r,
  1.1364 +				   NSVGimage* image, float tx, float ty, float scale,
  1.1365 +				   unsigned char* dst, int w, int h, int stride)
  1.1366 +{
  1.1367 +	NSVGshape *shape = NULL;
  1.1368 +	NSVGedge *e = NULL;
  1.1369 +	NSVGcachedPaint cache;
  1.1370 +	int i;
  1.1371 +
  1.1372 +	r->bitmap = dst;
  1.1373 +	r->width = w;
  1.1374 +	r->height = h;
  1.1375 +	r->stride = stride;
  1.1376 +
  1.1377 +	if (w > r->cscanline) {
  1.1378 +		r->cscanline = w;
  1.1379 +		r->scanline = (unsigned char*)realloc(r->scanline, w);
  1.1380 +		if (r->scanline == NULL) return;
  1.1381 +	}
  1.1382 +
  1.1383 +	for (i = 0; i < h; i++)
  1.1384 +		memset(&dst[i*stride], 0, w*4);
  1.1385 +
  1.1386 +	for (shape = image->shapes; shape != NULL; shape = shape->next) {
  1.1387 +		if (!(shape->flags & NSVG_FLAGS_VISIBLE))
  1.1388 +			continue;
  1.1389 +
  1.1390 +		if (shape->fill.type != NSVG_PAINT_NONE) {
  1.1391 +			nsvg__resetPool(r);
  1.1392 +			r->freelist = NULL;
  1.1393 +			r->nedges = 0;
  1.1394 +
  1.1395 +			nsvg__flattenShape(r, shape, scale);
  1.1396 +
  1.1397 +			// Scale and translate edges
  1.1398 +			for (i = 0; i < r->nedges; i++) {
  1.1399 +				e = &r->edges[i];
  1.1400 +				e->x0 = tx + e->x0;
  1.1401 +				e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
  1.1402 +				e->x1 = tx + e->x1;
  1.1403 +				e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
  1.1404 +			}
  1.1405 +
  1.1406 +			// Rasterize edges
  1.1407 +			qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
  1.1408 +
  1.1409 +			// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
  1.1410 +			nsvg__initPaint(&cache, &shape->fill, shape->opacity);
  1.1411 +
  1.1412 +			nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
  1.1413 +		}
  1.1414 +		if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
  1.1415 +			nsvg__resetPool(r);
  1.1416 +			r->freelist = NULL;
  1.1417 +			r->nedges = 0;
  1.1418 +
  1.1419 +			nsvg__flattenShapeStroke(r, shape, scale);
  1.1420 +
  1.1421 +//			dumpEdges(r, "edge.svg");
  1.1422 +
  1.1423 +			// Scale and translate edges
  1.1424 +			for (i = 0; i < r->nedges; i++) {
  1.1425 +				e = &r->edges[i];
  1.1426 +				e->x0 = tx + e->x0;
  1.1427 +				e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
  1.1428 +				e->x1 = tx + e->x1;
  1.1429 +				e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
  1.1430 +			}
  1.1431 +
  1.1432 +			// Rasterize edges
  1.1433 +			qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
  1.1434 +
  1.1435 +			// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
  1.1436 +			nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
  1.1437 +
  1.1438 +			nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
  1.1439 +		}
  1.1440 +	}
  1.1441 +
  1.1442 +	nsvg__unpremultiplyAlpha(dst, w, h, stride);
  1.1443 +
  1.1444 +	r->bitmap = NULL;
  1.1445 +	r->width = 0;
  1.1446 +	r->height = 0;
  1.1447 +	r->stride = 0;
  1.1448 +}
  1.1449 +
  1.1450 +#endif