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