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