openEmbroider  0.1
an open source embroidery software
 All Classes Functions Variables
nanosvgrast.h
1 /*
2  * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty. In no event will the authors be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  * claim that you wrote the original software. If you use this software
14  * in a product, an acknowledgment in the product documentation would be
15  * appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  * misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  *
20  * The polygon rasterization is heavily based on stb_truetype rasterizer
21  * by Sean Barrett - http://nothings.org/
22  *
23  */
24 
25 #ifndef NANOSVGRAST_H
26 #define NANOSVGRAST_H
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 typedef struct NSVGrasterizer NSVGrasterizer;
33 
34 /* Example Usage:
35  // Load SVG
36  struct SNVGImage* image = nsvgParseFromFile("test.svg.");
37 
38  // Create rasterizer (can be used to render multiple images).
39  struct NSVGrasterizer* rast = nsvgCreateRasterizer();
40  // Allocate memory for image
41  unsigned char* img = malloc(w*h*4);
42  // Rasterize
43  nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
44 */
45 
46 // Allocated rasterizer context.
47 NSVGrasterizer* nsvgCreateRasterizer();
48 
49 // Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
50 // r - pointer to rasterizer context
51 // image - pointer to image to rasterize
52 // tx,ty - image offset (applied after scaling)
53 // scale - image scale
54 // dst - pointer to destination image data, 4 bytes per pixel (RGBA)
55 // w - width of the image to render
56 // h - height of the image to render
57 // stride - number of bytes per scaleline in the destination buffer
58 void nsvgRasterize(NSVGrasterizer* r,
59  NSVGimage* image, float tx, float ty, float scale,
60  unsigned char* dst, int w, int h, int stride);
61 
62 // Deletes rasterizer context.
63 void nsvgDeleteRasterizer(NSVGrasterizer*);
64 
65 
66 #ifdef __cplusplus
67 };
68 #endif
69 
70 #endif // NANOSVGRAST_H
71 
72 #ifdef NANOSVGRAST_IMPLEMENTATION
73 
74 #include <math.h>
75 
76 #define NSVG__SUBSAMPLES 5
77 #define NSVG__FIXSHIFT 10
78 #define NSVG__FIX (1 << NSVG__FIXSHIFT)
79 #define NSVG__FIXMASK (NSVG__FIX-1)
80 #define NSVG__MEMPAGE_SIZE 1024
81 
82 typedef struct NSVGedge {
83  float x0,y0, x1,y1;
84  int dir;
85  struct NSVGedge* next;
86 } NSVGedge;
87 
88 typedef struct NSVGpoint {
89  float x, y;
90  float dx, dy;
91  float len;
92  float dmx, dmy;
93  unsigned char flags;
94 } NSVGpoint;
95 
96 typedef struct NSVGactiveEdge {
97  int x,dx;
98  float ey;
99  int dir;
100  struct NSVGactiveEdge *next;
101 } NSVGactiveEdge;
102 
103 typedef struct NSVGmemPage {
104  unsigned char mem[NSVG__MEMPAGE_SIZE];
105  int size;
106  struct NSVGmemPage* next;
107 } NSVGmemPage;
108 
109 typedef struct NSVGcachedPaint {
110  char type;
111  char spread;
112  float xform[6];
113  unsigned int colors[256];
114 } NSVGcachedPaint;
115 
116 struct NSVGrasterizer
117 {
118  float px, py;
119 
120  float tessTol;
121  float distTol;
122 
123  NSVGedge* edges;
124  int nedges;
125  int cedges;
126 
127  NSVGpoint* points;
128  int npoints;
129  int cpoints;
130 
131  NSVGactiveEdge* freelist;
132  NSVGmemPage* pages;
133  NSVGmemPage* curpage;
134 
135  unsigned char* scanline;
136  int cscanline;
137 
138  unsigned char* bitmap;
139  int width, height, stride;
140 };
141 
142 NSVGrasterizer* nsvgCreateRasterizer()
143 {
144  NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
145  if (r == NULL) goto error;
146  memset(r, 0, sizeof(NSVGrasterizer));
147 
148  r->tessTol = 0.25f;
149  r->distTol = 0.01f;
150 
151  return r;
152 
153 error:
154  nsvgDeleteRasterizer(r);
155  return NULL;
156 }
157 
158 void nsvgDeleteRasterizer(NSVGrasterizer* r)
159 {
160  NSVGmemPage* p;
161 
162  if (r == NULL) return;
163 
164  p = r->pages;
165  while (p != NULL) {
166  NSVGmemPage* next = p->next;
167  free(p);
168  p = next;
169  }
170 
171  if (r->edges) free(r->edges);
172  if (r->points) free(r->points);
173  if (r->scanline) free(r->scanline);
174 
175  free(r);
176 }
177 
178 static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
179 {
180  NSVGmemPage *newp;
181 
182  // If using existing chain, return the next page in chain
183  if (cur != NULL && cur->next != NULL) {
184  return cur->next;
185  }
186 
187  // Alloc new page
188  newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
189  if (newp == NULL) return NULL;
190  memset(newp, 0, sizeof(NSVGmemPage));
191 
192  // Add to linked list
193  if (cur != NULL)
194  cur->next = newp;
195  else
196  r->pages = newp;
197 
198  return newp;
199 }
200 
201 static void nsvg__resetPool(NSVGrasterizer* r)
202 {
203  NSVGmemPage* p = r->pages;
204  while (p != NULL) {
205  p->size = 0;
206  p = p->next;
207  }
208  r->curpage = r->pages;
209 }
210 
211 static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
212 {
213  unsigned char* buf;
214  if (size > NSVG__MEMPAGE_SIZE) return NULL;
215  if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
216  r->curpage = nsvg__nextPage(r, r->curpage);
217  }
218  buf = &r->curpage->mem[r->curpage->size];
219  r->curpage->size += size;
220  return buf;
221 }
222 
223 static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
224 {
225  float dx = x2 - x1;
226  float dy = y2 - y1;
227  return dx*dx + dy*dy < tol*tol;
228 }
229 
230 static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
231 {
232  NSVGpoint* pt;
233 
234  if (r->npoints > 0) {
235  pt = &r->points[r->npoints-1];
236  if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
237  pt->flags |= flags;
238  return;
239  }
240  }
241 
242  if (r->npoints+1 > r->cpoints) {
243  r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
244  r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
245  if (r->points == NULL) return;
246  }
247 
248  pt = &r->points[r->npoints];
249  pt->x = x;
250  pt->y = y;
251  pt->flags = flags;
252  r->npoints++;
253 }
254 
255 static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
256 {
257  NSVGedge* e;
258 
259  // Skip horizontal edges
260  if (y0 == y1)
261  return;
262 
263  if (r->nedges+1 > r->cedges) {
264  r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
265  r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
266  if (r->edges == NULL) return;
267  }
268 
269  e = &r->edges[r->nedges];
270  r->nedges++;
271 
272  if (y0 < y1) {
273  e->x0 = x0;
274  e->y0 = y0;
275  e->x1 = x1;
276  e->y1 = y1;
277  e->dir = 1;
278  } else {
279  e->x0 = x1;
280  e->y0 = y1;
281  e->x1 = x0;
282  e->y1 = y0;
283  e->dir = -1;
284  }
285 }
286 
287 static float nsvg__normalize(float *x, float* y)
288 {
289  float d = sqrtf((*x)*(*x) + (*y)*(*y));
290  if (d > 1e-6f) {
291  float id = 1.0f / d;
292  *x *= id;
293  *y *= id;
294  }
295  return d;
296 }
297 
298 static float nsvg__absf(float x) { return x < 0 ? -x : x; }
299 
300 static void nsvg__flattenCubicBez(NSVGrasterizer* r,
301  float x1, float y1, float x2, float y2,
302  float x3, float y3, float x4, float y4,
303  int level, int type)
304 {
305  float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
306  float dx,dy,d2,d3;
307 
308  if (level > 10) return;
309 
310  x12 = (x1+x2)*0.5f;
311  y12 = (y1+y2)*0.5f;
312  x23 = (x2+x3)*0.5f;
313  y23 = (y2+y3)*0.5f;
314  x34 = (x3+x4)*0.5f;
315  y34 = (y3+y4)*0.5f;
316  x123 = (x12+x23)*0.5f;
317  y123 = (y12+y23)*0.5f;
318 
319  dx = x4 - x1;
320  dy = y4 - y1;
321  d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
322  d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
323 
324  if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
325  nsvg__addPathPoint(r, x4, y4, type);
326  return;
327  }
328 
329  x234 = (x23+x34)*0.5f;
330  y234 = (y23+y34)*0.5f;
331  x1234 = (x123+x234)*0.5f;
332  y1234 = (y123+y234)*0.5f;
333 
334  nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
335  nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
336 }
337 
338 static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)
339 {
340  int i, j;
341  NSVGpath* path;
342 
343  for (path = shape->paths; path != NULL; path = path->next) {
344  r->npoints = 0;
345  // Flatten path
346  nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
347  for (i = 0; i < path->npts-1; i += 3) {
348  float* p = &path->pts[i*2];
349  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);
350  }
351  // Close path
352  nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
353  // Build edges
354  for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
355  nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
356  }
357 }
358 
359 enum NSVGpointFlags
360 {
361  NSVG_PT_CORNER = 0x01,
362  NSVG_PT_BEVEL = 0x02,
363  NSVG_PT_LEFT = 0x04,
364 };
365 
366 static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
367 {
368  float w = lineWidth * 0.5f;
369  float dx = p1->x - p0->x;
370  float dy = p1->y - p0->y;
371  float len = nsvg__normalize(&dx, &dy);
372  float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
373  float dlx = dy, dly = -dx;
374  float lx = px - dlx*w, ly = py - dly*w;
375  float rx = px + dlx*w, ry = py + dly*w;
376  left->x = lx; left->y = ly;
377  right->x = rx; right->y = ry;
378 }
379 
380 static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
381 {
382  float w = lineWidth * 0.5f;
383  float px = p->x, py = p->y;
384  float dlx = dy, dly = -dx;
385  float lx = px - dlx*w, ly = py - dly*w;
386  float rx = px + dlx*w, ry = py + dly*w;
387 
388  nsvg__addEdge(r, lx, ly, rx, ry);
389 
390  if (connect) {
391  nsvg__addEdge(r, left->x, left->y, lx, ly);
392  nsvg__addEdge(r, rx, ry, right->x, right->y);
393  }
394  left->x = lx; left->y = ly;
395  right->x = rx; right->y = ry;
396 }
397 
398 static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
399 {
400  float w = lineWidth * 0.5f;
401  float px = p->x - dx*w, py = p->y - dy*w;
402  float dlx = dy, dly = -dx;
403  float lx = px - dlx*w, ly = py - dly*w;
404  float rx = px + dlx*w, ry = py + dly*w;
405 
406  nsvg__addEdge(r, lx, ly, rx, ry);
407 
408  if (connect) {
409  nsvg__addEdge(r, left->x, left->y, lx, ly);
410  nsvg__addEdge(r, rx, ry, right->x, right->y);
411  }
412  left->x = lx; left->y = ly;
413  right->x = rx; right->y = ry;
414 }
415 
416 #ifndef NSVG_PI
417 #define NSVG_PI (3.14159265358979323846264338327f)
418 #endif
419 
420 static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
421 {
422  int i;
423  float w = lineWidth * 0.5f;
424  float px = p->x, py = p->y;
425  float dlx = dy, dly = -dx;
426  float lx, ly, rx, ry, prevx, prevy;
427 
428  for (i = 0; i < ncap; i++) {
429  float a = i/(float)(ncap-1)*NSVG_PI;
430  float ax = cosf(a) * w, ay = sinf(a) * w;
431  float x = px - dlx*ax - dx*ay;
432  float y = py - dly*ax - dy*ay;
433 
434  if (i > 0)
435  nsvg__addEdge(r, prevx, prevy, x, y);
436 
437  prevx = x;
438  prevy = y;
439 
440  if (i == 0) {
441  lx = x; ly = y;
442  } else if (i == ncap-1) {
443  rx = x; ry = y;
444  }
445  }
446 
447  if (connect) {
448  nsvg__addEdge(r, left->x, left->y, lx, ly);
449  nsvg__addEdge(r, rx, ry, right->x, right->y);
450  }
451 
452  left->x = lx; left->y = ly;
453  right->x = rx; right->y = ry;
454 }
455 
456 static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
457 {
458  float w = lineWidth * 0.5f;
459  float dlx0 = p0->dy, dly0 = -p0->dx;
460  float dlx1 = p1->dy, dly1 = -p1->dx;
461  float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
462  float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
463  float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
464  float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
465 
466  nsvg__addEdge(r, lx0, ly0, left->x, left->y);
467  nsvg__addEdge(r, lx1, ly1, lx0, ly0);
468 
469  nsvg__addEdge(r, right->x, right->y, rx0, ry0);
470  nsvg__addEdge(r, rx0, ry0, rx1, ry1);
471 
472  left->x = lx1; left->y = ly1;
473  right->x = rx1; right->y = ry1;
474 }
475 
476 static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
477 {
478  float w = lineWidth * 0.5f;
479  float dlx0 = p0->dy, dly0 = -p0->dx;
480  float dlx1 = p1->dy, dly1 = -p1->dx;
481  float lx0, rx0, lx1, rx1;
482  float ly0, ry0, ly1, ry1;
483 
484  if (p1->flags & NSVG_PT_LEFT) {
485  lx0 = lx1 = p1->x - p1->dmx * w;
486  ly0 = ly1 = p1->y - p1->dmy * w;
487  nsvg__addEdge(r, lx1, ly1, left->x, left->y);
488 
489  rx0 = p1->x + (dlx0 * w);
490  ry0 = p1->y + (dly0 * w);
491  rx1 = p1->x + (dlx1 * w);
492  ry1 = p1->y + (dly1 * w);
493  nsvg__addEdge(r, right->x, right->y, rx0, ry0);
494  nsvg__addEdge(r, rx0, ry0, rx1, ry1);
495  } else {
496  lx0 = p1->x - (dlx0 * w);
497  ly0 = p1->y - (dly0 * w);
498  lx1 = p1->x - (dlx1 * w);
499  ly1 = p1->y - (dly1 * w);
500  nsvg__addEdge(r, lx0, ly0, left->x, left->y);
501  nsvg__addEdge(r, lx1, ly1, lx0, ly0);
502 
503  rx0 = rx1 = p1->x + p1->dmx * w;
504  ry0 = ry1 = p1->y + p1->dmy * w;
505  nsvg__addEdge(r, right->x, right->y, rx1, ry1);
506  }
507 
508  left->x = lx1; left->y = ly1;
509  right->x = rx1; right->y = ry1;
510 }
511 
512 static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
513 {
514  int i, n;
515  float w = lineWidth * 0.5f;
516  float dlx0 = p0->dy, dly0 = -p0->dx;
517  float dlx1 = p1->dy, dly1 = -p1->dx;
518  float a0 = atan2f(dly0, dlx0);
519  float a1 = atan2f(dly1, dlx1);
520  float da = a1 - a0;
521  float lx, ly, rx, ry;
522 
523  if (da < NSVG_PI) da += NSVG_PI*2;
524  if (da > NSVG_PI) da -= NSVG_PI*2;
525 
526  n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * ncap);
527  if (n < 2) n = 2;
528  if (n > ncap) n = ncap;
529 
530  lx = left->x;
531  ly = left->y;
532  rx = right->x;
533  ry = right->y;
534 
535  for (i = 0; i < n; i++) {
536  float u = i/(float)(n-1);
537  float a = a0 + u*da;
538  float ax = cosf(a) * w, ay = sinf(a) * w;
539  float lx1 = p1->x - ax, ly1 = p1->y - ay;
540  float rx1 = p1->x + ax, ry1 = p1->y + ay;
541 
542  nsvg__addEdge(r, lx1, ly1, lx, ly);
543  nsvg__addEdge(r, rx, ry, rx1, ry1);
544 
545  lx = lx1; ly = ly1;
546  rx = rx1; ry = ry1;
547  }
548 
549  left->x = lx; left->y = ly;
550  right->x = rx; right->y = ry;
551 }
552 
553 static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
554 {
555  float w = lineWidth * 0.5f;
556  float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
557  float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
558 
559  nsvg__addEdge(r, lx, ly, left->x, left->y);
560  nsvg__addEdge(r, right->x, right->y, rx, ry);
561 
562  left->x = lx; left->y = ly;
563  right->x = rx; right->y = ry;
564 }
565 
566 static int nsvg__curveDivs(float r, float arc, float tol)
567 {
568  float da = acosf(r / (r + tol)) * 2.0f;
569  int divs = (int)ceilf(arc / da);
570  if (divs < 2) divs = 2;
571  return divs;
572 }
573 
574 static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale)
575 {
576  int i, j, closed;
577  int s, e;
578  NSVGpath* path;
579  NSVGpoint* p0, *p1;
580  float miterLimit = 4;
581  int lineJoin = shape->strokeLineJoin;
582  int lineCap = shape->strokeLineCap;
583  float lineWidth = shape->strokeWidth * scale;
584  int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle.
585  NSVGpoint left, right, firstLeft, firstRight;
586 
587  for (path = shape->paths; path != NULL; path = path->next) {
588  r->npoints = 0;
589  // Flatten path
590  nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
591  for (i = 0; i < path->npts-1; i += 3) {
592  float* p = &path->pts[i*2];
593  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);
594  }
595  if (r->npoints < 2)
596  continue;
597 
598  closed = path->closed;
599 
600  // If the first and last points are the same, remove the last, mark as closed path.
601  p0 = &r->points[r->npoints-1];
602  p1 = &r->points[0];
603  if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
604  r->npoints--;
605  p0 = &r->points[r->npoints-1];
606  closed = 1;
607  }
608 
609  for (i = 0; i < r->npoints; i++) {
610  // Calculate segment direction and length
611  p0->dx = p1->x - p0->x;
612  p0->dy = p1->y - p0->y;
613  p0->len = nsvg__normalize(&p0->dx, &p0->dy);
614  // Advance
615  p0 = p1++;
616  }
617 
618  // calculate joins
619  p0 = &r->points[r->npoints-1];
620  p1 = &r->points[0];
621  for (j = 0; j < r->npoints; j++) {
622  float dlx0, dly0, dlx1, dly1, dmr2, cross;
623  dlx0 = p0->dy;
624  dly0 = -p0->dx;
625  dlx1 = p1->dy;
626  dly1 = -p1->dx;
627  // Calculate extrusions
628  p1->dmx = (dlx0 + dlx1) * 0.5f;
629  p1->dmy = (dly0 + dly1) * 0.5f;
630  dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
631  if (dmr2 > 0.000001f) {
632  float s = 1.0f / dmr2;
633  if (s > 600.0f) {
634  s = 600.0f;
635  }
636  p1->dmx *= s;
637  p1->dmy *= s;
638  }
639 
640  // Clear flags, but keep the corner.
641  p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
642 
643  // Keep track of left turns.
644  cross = p1->dx * p0->dy - p0->dx * p1->dy;
645  if (cross > 0.0f)
646  p1->flags |= NSVG_PT_LEFT;
647 
648  // Check to see if the corner needs to be beveled.
649  if (p1->flags & NSVG_PT_CORNER) {
650  if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
651  p1->flags |= NSVG_PT_BEVEL;
652  }
653  }
654 
655  p0 = p1++;
656  }
657 
658  // Build stroke edges
659  if (closed) {
660  // Looping
661  p0 = &r->points[r->npoints-1];
662  p1 = &r->points[0];
663  s = 0;
664  e = r->npoints;
665  } else {
666  // Add cap
667  p0 = &r->points[0];
668  p1 = &r->points[1];
669  s = 1;
670  e = r->npoints-1;
671  }
672 
673  if (closed) {
674  nsvg__initClosed(&left, &right, p0, p1, lineWidth);
675  firstLeft = left;
676  firstRight = right;
677  } else {
678  // Add cap
679  float dx = p1->x - p0->x;
680  float dy = p1->y - p0->y;
681  nsvg__normalize(&dx, &dy);
682  if (lineCap == NSVG_CAP_BUTT)
683  nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
684  else if (lineCap == NSVG_CAP_SQUARE)
685  nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
686  else if (lineCap == NSVG_CAP_ROUND)
687  nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
688  }
689 
690  for (j = s; j < e; ++j) {
691 // if (p1->flags & NSVG_PT_BEVEL) {
692  if (p1->flags & NSVG_PT_CORNER) {
693  if (lineJoin == NSVG_JOIN_ROUND)
694  nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
695  else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
696  nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
697  else
698  nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
699  } else {
700  nsvg__straightJoin(r, &left, &right, p1, lineWidth);
701  }
702  p0 = p1++;
703  }
704 
705  if (closed) {
706  // Loop it
707  nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
708  nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
709  } else {
710  // Add cap
711  float dx = p1->x - p0->x;
712  float dy = p1->y - p0->y;
713  nsvg__normalize(&dx, &dy);
714  if (lineCap == NSVG_CAP_BUTT)
715  nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
716  else if (lineCap == NSVG_CAP_SQUARE)
717  nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
718  else if (lineCap == NSVG_CAP_ROUND)
719  nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
720  }
721  }
722 }
723 
724 static int nsvg__cmpEdge(const void *p, const void *q)
725 {
726  NSVGedge* a = (NSVGedge*)p;
727  NSVGedge* b = (NSVGedge*)q;
728 
729  if (a->y0 < b->y0) return -1;
730  if (a->y0 > b->y0) return 1;
731  return 0;
732 }
733 
734 
735 static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
736 {
737  NSVGactiveEdge* z;
738 
739  if (r->freelist != NULL) {
740  // Restore from freelist.
741  z = r->freelist;
742  r->freelist = z->next;
743  } else {
744  // Alloc new edge.
745  z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
746  if (z == NULL) return NULL;
747  }
748 
749  float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
750 // STBTT_assert(e->y0 <= start_point);
751  // round dx down to avoid going too far
752  if (dxdy < 0)
753  z->dx = -floorf(NSVG__FIX * -dxdy);
754  else
755  z->dx = floorf(NSVG__FIX * dxdy);
756  z->x = floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
757 // z->x -= off_x * FIX;
758  z->ey = e->y1;
759  z->next = 0;
760  z->dir = e->dir;
761 
762  return z;
763 }
764 
765 static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
766 {
767  z->next = r->freelist;
768  r->freelist = z;
769 }
770 
771 // note: this routine clips fills that extend off the edges... ideally this
772 // wouldn't happen, but it could happen if the truetype glyph bounding boxes
773 // are wrong, or if the user supplies a too-small bitmap
774 static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax)
775 {
776  // non-zero winding fill
777  int x0 = 0, w = 0;
778 
779  while (e != NULL) {
780  if (w == 0) {
781  // if we're currently at zero, we need to record the edge start point
782  x0 = e->x; w += e->dir;
783  } else {
784  int x1 = e->x; w += e->dir;
785  // if we went to zero, we need to draw
786  if (w == 0) {
787  int i = x0 >> NSVG__FIXSHIFT;
788  int j = x1 >> NSVG__FIXSHIFT;
789  if (i < *xmin) *xmin = i;
790  if (j > *xmax) *xmax = j;
791  if (i < len && j >= 0) {
792  if (i == j) {
793  // x0,x1 are the same pixel, so compute combined coverage
794  scanline[i] += (unsigned char)((x1 - x0) * maxWeight >> NSVG__FIXSHIFT);
795  } else {
796  if (i >= 0) // add antialiasing for x0
797  scanline[i] += (unsigned char)(((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT);
798  else
799  i = -1; // clip
800 
801  if (j < len) // add antialiasing for x1
802  scanline[j] += (unsigned char)(((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT);
803  else
804  j = len; // clip
805 
806  for (++i; i < j; ++i) // fill pixels between x0 and x1
807  scanline[i] += (unsigned char)maxWeight;
808  }
809  }
810  }
811  }
812  e = e->next;
813  }
814 }
815 
816 static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
817 
818 static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
819 {
820  return (r) | (g << 8) | (b << 16) | (a << 24);
821 }
822 
823 static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
824 {
825  int iu = (float)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
826  int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
827  int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
828  int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
829  int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
830  return nsvg__RGBA(r,g,b,a);
831 }
832 
833 static unsigned int nsvg__applyOpacity(unsigned int c, float u)
834 {
835  int iu = (float)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
836  int r = (c) & 0xff;
837  int g = (c>>8) & 0xff;
838  int b = (c>>16) & 0xff;
839  int a = (((c>>24) & 0xff)*iu) >> 8;
840  return nsvg__RGBA(r,g,b,a);
841 }
842 
843 static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
844  float tx, float ty, float scale, NSVGcachedPaint* cache)
845 {
846 
847  if (cache->type == NSVG_PAINT_COLOR) {
848  int i, cr, cg, cb, ca;
849  cr = cache->colors[0] & 0xff;
850  cg = (cache->colors[0] >> 8) & 0xff;
851  cb = (cache->colors[0] >> 16) & 0xff;
852  ca = (cache->colors[0] >> 24) & 0xff;
853 
854  for (i = 0; i < count; i++) {
855  int r,g,b;
856  int a = ((int)cover[0] * ca) >> 8;
857  int ia = 255 - a;
858  // Premultiply
859  r = (cr * a) >> 8;
860  g = (cg * a) >> 8;
861  b = (cb * a) >> 8;
862 
863  // Blend over
864  r += ((ia * (int)dst[0]) >> 8);
865  g += ((ia * (int)dst[1]) >> 8);
866  b += ((ia * (int)dst[2]) >> 8);
867  a += ((ia * (int)dst[3]) >> 8);
868 
869  dst[0] = (unsigned char)r;
870  dst[1] = (unsigned char)g;
871  dst[2] = (unsigned char)b;
872  dst[3] = (unsigned char)a;
873 
874  cover++;
875  dst += 4;
876  }
877  } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
878  // TODO: spread modes.
879  // TODO: plenty of opportunities to optimize.
880  float fx, fy, dx, gy;
881  float* t = cache->xform;
882  int i, cr, cg, cb, ca;
883  unsigned int c;
884 
885  fx = (x - tx) / scale;
886  fy = (y - ty) / scale;
887  dx = 1.0f / scale;
888 
889  for (i = 0; i < count; i++) {
890  int r,g,b,a,ia;
891  gy = fx*t[1] + fy*t[3] + t[5];
892  c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
893  cr = (c) & 0xff;
894  cg = (c >> 8) & 0xff;
895  cb = (c >> 16) & 0xff;
896  ca = (c >> 24) & 0xff;
897 
898  a = ((int)cover[0] * ca) >> 8;
899  ia = 255 - a;
900 
901  // Premultiply
902  r = (cr * a) >> 8;
903  g = (cg * a) >> 8;
904  b = (cb * a) >> 8;
905 
906  // Blend over
907  r += ((ia * (int)dst[0]) >> 8);
908  g += ((ia * (int)dst[1]) >> 8);
909  b += ((ia * (int)dst[2]) >> 8);
910  a += ((ia * (int)dst[3]) >> 8);
911 
912  dst[0] = (unsigned char)r;
913  dst[1] = (unsigned char)g;
914  dst[2] = (unsigned char)b;
915  dst[3] = (unsigned char)a;
916 
917  cover++;
918  dst += 4;
919  fx += dx;
920  }
921  } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
922  // TODO: spread modes.
923  // TODO: plenty of opportunities to optimize.
924  // TODO: focus (fx,fy)
925  float fx, fy, dx, gx, gy, gd;
926  float* t = cache->xform;
927  int i, cr, cg, cb, ca;
928  unsigned int c;
929 
930  fx = (x - tx) / scale;
931  fy = (y - ty) / scale;
932  dx = 1.0f / scale;
933 
934  for (i = 0; i < count; i++) {
935  int r,g,b,a,ia;
936  gx = fx*t[0] + fy*t[2] + t[4];
937  gy = fx*t[1] + fy*t[3] + t[5];
938  gd = sqrtf(gx*gx + gy*gy);
939  c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
940  cr = (c) & 0xff;
941  cg = (c >> 8) & 0xff;
942  cb = (c >> 16) & 0xff;
943  ca = (c >> 24) & 0xff;
944 
945  a = ((int)cover[0] * ca) >> 8;
946  ia = 255 - a;
947 
948  // Premultiply
949  r = (cr * a) >> 8;
950  g = (cg * a) >> 8;
951  b = (cb * a) >> 8;
952 
953  // Blend over
954  r += ((ia * (int)dst[0]) >> 8);
955  g += ((ia * (int)dst[1]) >> 8);
956  b += ((ia * (int)dst[2]) >> 8);
957  a += ((ia * (int)dst[3]) >> 8);
958 
959  dst[0] = (unsigned char)r;
960  dst[1] = (unsigned char)g;
961  dst[2] = (unsigned char)b;
962  dst[3] = (unsigned char)a;
963 
964  cover++;
965  dst += 4;
966  fx += dx;
967  }
968  }
969 }
970 
971 static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache)
972 {
973  NSVGactiveEdge *active = NULL;
974  int y, s;
975  int e = 0;
976  int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline
977  int xmin, xmax;
978 
979  for (y = 0; y < r->height; y++) {
980  memset(r->scanline, 0, r->width);
981  xmin = r->width;
982  xmax = 0;
983  for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
984  // find center of pixel for this scanline
985  float scany = y*NSVG__SUBSAMPLES + s + 0.5f;
986  NSVGactiveEdge **step = &active;
987 
988  // update all active edges;
989  // remove all active edges that terminate before the center of this scanline
990  while (*step) {
991  NSVGactiveEdge *z = *step;
992  if (z->ey <= scany) {
993  *step = z->next; // delete from list
994 // NSVG__assert(z->valid);
995  nsvg__freeActive(r, z);
996  } else {
997  z->x += z->dx; // advance to position for current scanline
998  step = &((*step)->next); // advance through list
999  }
1000  }
1001 
1002  // resort the list if needed
1003  for (;;) {
1004  int changed = 0;
1005  step = &active;
1006  while (*step && (*step)->next) {
1007  if ((*step)->x > (*step)->next->x) {
1008  NSVGactiveEdge* t = *step;
1009  NSVGactiveEdge* q = t->next;
1010  t->next = q->next;
1011  q->next = t;
1012  *step = q;
1013  changed = 1;
1014  }
1015  step = &(*step)->next;
1016  }
1017  if (!changed) break;
1018  }
1019 
1020  // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
1021  while (e < r->nedges && r->edges[e].y0 <= scany) {
1022  if (r->edges[e].y1 > scany) {
1023  NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
1024  if (z == NULL) break;
1025  // find insertion point
1026  if (active == NULL) {
1027  active = z;
1028  } else if (z->x < active->x) {
1029  // insert at front
1030  z->next = active;
1031  active = z;
1032  } else {
1033  // find thing to insert AFTER
1034  NSVGactiveEdge* p = active;
1035  while (p->next && p->next->x < z->x)
1036  p = p->next;
1037  // at this point, p->next->x is NOT < z->x
1038  z->next = p->next;
1039  p->next = z;
1040  }
1041  }
1042  e++;
1043  }
1044 
1045  // now process all active edges in non-zero fashion
1046  if (active != NULL)
1047  nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax);
1048  }
1049  // Blit
1050  if (xmin < 0) xmin = 0;
1051  if (xmax > r->width-1) xmax = r->width-1;
1052  if (xmin <= xmax) {
1053  nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty,scale,cache);
1054  }
1055  }
1056 
1057 }
1058 
1059 static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
1060 {
1061  int x,y;
1062 
1063  // Unpremultiply
1064  for (y = 0; y < h; y++) {
1065  unsigned char *row = &image[y*stride];
1066  for (x = 0; x < w; x++) {
1067  int r = row[0], g = row[1], b = row[2], a = row[3];
1068  if (a != 0) {
1069  row[0] = (int)(r*255/a);
1070  row[1] = (int)(g*255/a);
1071  row[2] = (int)(b*255/a);
1072  }
1073  row += 4;
1074  }
1075  }
1076 
1077  // Defringe
1078  for (y = 0; y < h; y++) {
1079  unsigned char *row = &image[y*stride];
1080  for (x = 0; x < w; x++) {
1081  int r = 0, g = 0, b = 0, a = row[3], n = 0;
1082  if (a == 0) {
1083  if (x-1 > 0 && row[-1] != 0) {
1084  r += row[-4];
1085  g += row[-3];
1086  b += row[-2];
1087  n++;
1088  }
1089  if (x+1 < w && row[7] != 0) {
1090  r += row[4];
1091  g += row[5];
1092  b += row[6];
1093  n++;
1094  }
1095  if (y-1 > 0 && row[-stride+3] != 0) {
1096  r += row[-stride];
1097  g += row[-stride+1];
1098  b += row[-stride+2];
1099  n++;
1100  }
1101  if (y+1 < h && row[stride+3] != 0) {
1102  r += row[stride];
1103  g += row[stride+1];
1104  b += row[stride+2];
1105  n++;
1106  }
1107  if (n > 0) {
1108  row[0] = r/n;
1109  row[1] = g/n;
1110  row[2] = b/n;
1111  }
1112  }
1113  row += 4;
1114  }
1115  }
1116 }
1117 
1118 
1119 static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
1120 {
1121  int i, j;
1122  NSVGgradient* grad;
1123 
1124  cache->type = paint->type;
1125 
1126  if (paint->type == NSVG_PAINT_COLOR) {
1127  cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
1128  return;
1129  }
1130 
1131  grad = paint->gradient;
1132 
1133  cache->spread = grad->spread;
1134  memcpy(cache->xform, grad->xform, sizeof(float)*6);
1135 
1136  if (grad->nstops == 0) {
1137  for (i = 0; i < 256; i++)
1138  cache->colors[i] = 0;
1139  } if (grad->nstops == 1) {
1140  for (i = 0; i < 256; i++)
1141  cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
1142  } else {
1143  unsigned int ca, cb;
1144  float ua, ub, du, u;
1145  int ia, ib, count;
1146 
1147  ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
1148  ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
1149  ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
1150  ia = ua * 255.0f;
1151  ib = ub * 255.0f;
1152  for (i = 0; i < ia; i++) {
1153  cache->colors[i] = ca;
1154  }
1155 
1156  for (i = 0; i < grad->nstops-1; i++) {
1157  ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
1158  cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
1159  ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
1160  ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
1161  ia = ua * 255.0f;
1162  ib = ub * 255.0f;
1163  count = ib - ia;
1164  if (count <= 0) continue;
1165  u = 0;
1166  du = 1.0f / (float)count;
1167  for (j = 0; j < count; j++) {
1168  cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
1169  u += du;
1170  }
1171  }
1172 
1173  for (i = ib; i < 256; i++)
1174  cache->colors[i] = cb;
1175  }
1176 
1177 }
1178 
1179 /*
1180 static void dumpEdges(NSVGrasterizer* r, const char* name)
1181 {
1182  float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
1183  NSVGedge *e = NULL;
1184  int i;
1185  if (r->nedges == 0) return;
1186  FILE* fp = fopen(name, "w");
1187  if (fp == NULL) return;
1188 
1189  xmin = xmax = r->edges[0].x0;
1190  ymin = ymax = r->edges[0].y0;
1191  for (i = 0; i < r->nedges; i++) {
1192  e = &r->edges[i];
1193  xmin = nsvg__minf(xmin, e->x0);
1194  xmin = nsvg__minf(xmin, e->x1);
1195  xmax = nsvg__maxf(xmax, e->x0);
1196  xmax = nsvg__maxf(xmax, e->x1);
1197  ymin = nsvg__minf(ymin, e->y0);
1198  ymin = nsvg__minf(ymin, e->y1);
1199  ymax = nsvg__maxf(ymax, e->y0);
1200  ymax = nsvg__maxf(ymax, e->y1);
1201  }
1202 
1203  fprintf(fp, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\">", xmin, ymin, (xmax - xmin), (ymax - ymin));
1204 
1205  for (i = 0; i < r->nedges; i++) {
1206  e = &r->edges[i];
1207  fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#000;\" />", e->x0,e->y0, e->x1,e->y1);
1208  }
1209 
1210  for (i = 0; i < r->npoints; i++) {
1211  if (i+1 < r->npoints)
1212  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);
1213  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");
1214  }
1215 
1216  fprintf(fp, "</svg>");
1217  fclose(fp);
1218 }
1219 */
1220 
1221 void nsvgRasterize(NSVGrasterizer* r,
1222  NSVGimage* image, float tx, float ty, float scale,
1223  unsigned char* dst, int w, int h, int stride)
1224 {
1225  NSVGshape *shape = NULL;
1226  NSVGedge *e = NULL;
1227  NSVGcachedPaint cache;
1228  int i;
1229 
1230  r->bitmap = dst;
1231  r->width = w;
1232  r->height = h;
1233  r->stride = stride;
1234 
1235  if (w > r->cscanline) {
1236  r->cscanline = w;
1237  r->scanline = (unsigned char*)realloc(r->scanline, w);
1238  if (r->scanline == NULL) return;
1239  }
1240 
1241  for (i = 0; i < h; i++)
1242  memset(&dst[i*stride], 0, w*4);
1243 
1244  for (shape = image->shapes; shape != NULL; shape = shape->next) {
1245  if (shape->fill.type != NSVG_PAINT_NONE) {
1246  nsvg__resetPool(r);
1247  r->freelist = NULL;
1248  r->nedges = 0;
1249 
1250  nsvg__flattenShape(r, shape, scale);
1251 
1252  // Scale and translate edges
1253  for (i = 0; i < r->nedges; i++) {
1254  e = &r->edges[i];
1255  e->x0 = tx + e->x0;
1256  e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1257  e->x1 = tx + e->x1;
1258  e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1259  }
1260 
1261  // Rasterize edges
1262  qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1263 
1264  // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
1265  nsvg__initPaint(&cache, &shape->fill, shape->opacity);
1266 
1267  nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache);
1268  }
1269  if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
1270  nsvg__resetPool(r);
1271  r->freelist = NULL;
1272  r->nedges = 0;
1273 
1274  nsvg__flattenShapeStroke(r, shape, scale);
1275 
1276 // dumpEdges(r, "edge.svg");
1277 
1278  // Scale and translate edges
1279  for (i = 0; i < r->nedges; i++) {
1280  e = &r->edges[i];
1281  e->x0 = tx + e->x0;
1282  e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1283  e->x1 = tx + e->x1;
1284  e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1285  }
1286 
1287  // Rasterize edges
1288  qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1289 
1290  // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
1291  nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
1292 
1293  nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache);
1294  }
1295  }
1296 
1297  nsvg__unpremultiplyAlpha(dst, w, h, stride);
1298 
1299  r->bitmap = NULL;
1300  r->width = 0;
1301  r->height = 0;
1302  r->stride = 0;
1303 }
1304 
1305 #endif