Bug Summary

File:svgtiny.c
Warning:line 1182, column 42
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name svgtiny.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-libsvgtiny -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D _BSD_SOURCE -D _DEFAULT_SOURCE -I /var/lib/jenkins/workspace/scan-build-libsvgtiny/include/ -I /var/lib/jenkins/workspace/scan-build-libsvgtiny/src -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wwrite-strings -Wno-error -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-libsvgtiny -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-libsvgtiny/clangScanBuildReports/2024-03-19-085417-578713-1 -x c src/svgtiny.c
1/*
2 * This file is part of Libsvgtiny
3 * Licensed under the MIT License,
4 * http://opensource.org/licenses/mit-license.php
5 * Copyright 2008-2009 James Bursa <james@semichrome.net>
6 * Copyright 2012 Daniel Silverstone <dsilvers@netsurf-browser.org>
7 */
8
9#include <assert.h>
10#include <math.h>
11#include <setjmp.h>
12#include <stdbool.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include <dom/dom.h>
18#include <dom/bindings/xml/xmlparser.h>
19
20#include "svgtiny.h"
21#include "svgtiny_internal.h"
22
23/* Source file generated by `gperf`. */
24#include "autogenerated_colors.c"
25
26#define TAU6.28318530717958647692 6.28318530717958647692
27
28#ifndef M_PI3.14159265358979323846
29#define M_PI3.14159265358979323846 3.14159265358979323846
30#endif
31
32#ifndef M_PI_21.57079632679489661923
33#define M_PI_21.57079632679489661923 1.57079632679489661923
34#endif
35
36#define KAPPA0.5522847498 0.5522847498
37
38#define degToRad(angleInDegrees)((angleInDegrees) * 3.14159265358979323846 / 180.0) ((angleInDegrees) * M_PI3.14159265358979323846 / 180.0)
39#define radToDeg(angleInRadians)((angleInRadians) * 180.0 / 3.14159265358979323846) ((angleInRadians) * 180.0 / M_PI3.14159265358979323846)
40
41static svgtiny_code svgtiny_parse_svg(dom_element *svg,
42 struct svgtiny_parse_state state);
43static svgtiny_code svgtiny_parse_path(dom_element *path,
44 struct svgtiny_parse_state state);
45static svgtiny_code svgtiny_parse_rect(dom_element *rect,
46 struct svgtiny_parse_state state);
47static svgtiny_code svgtiny_parse_circle(dom_element *circle,
48 struct svgtiny_parse_state state);
49static svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
50 struct svgtiny_parse_state state);
51static svgtiny_code svgtiny_parse_line(dom_element *line,
52 struct svgtiny_parse_state state);
53static svgtiny_code svgtiny_parse_poly(dom_element *poly,
54 struct svgtiny_parse_state state, bool_Bool polygon);
55static svgtiny_code svgtiny_parse_text(dom_element *text,
56 struct svgtiny_parse_state state);
57static void svgtiny_parse_position_attributes(dom_element *node,
58 const struct svgtiny_parse_state state,
59 float *x, float *y, float *width, float *height);
60static void svgtiny_parse_paint_attributes(dom_element *node,
61 struct svgtiny_parse_state *state);
62static void svgtiny_parse_font_attributes(dom_element *node,
63 struct svgtiny_parse_state *state);
64static void svgtiny_parse_transform_attributes(dom_element *node,
65 struct svgtiny_parse_state *state);
66static svgtiny_code svgtiny_add_path(float *p, unsigned int n,
67 struct svgtiny_parse_state *state);
68static void _svgtiny_parse_color(const char *s, svgtiny_colour *c,
69 struct svgtiny_parse_state_gradient *grad,
70 struct svgtiny_parse_state *state);
71
72/**
73 * rotate midpoint vector
74 */
75static void
76rotate_midpoint_vector(float ax, float ay,
77 float bx, float by,
78 double radangle,
79 double *x_out, double *y_out)
80{
81 double dx2; /* midpoint x coordinate */
82 double dy2; /* midpoint y coordinate */
83 double cosangle; /* cosine of rotation angle */
84 double sinangle; /* sine of rotation angle */
85
86 /* compute the sin and cos of the angle */
87 cosangle = cos(radangle);
88 sinangle = sin(radangle);
89
90 /* compute the midpoint between start and end points */
91 dx2 = (ax - bx) / 2.0;
92 dy2 = (ay - by) / 2.0;
93
94 /* rotate vector to remove angle */
95 *x_out = ((cosangle * dx2) + (sinangle * dy2));
96 *y_out = ((-sinangle * dx2) + (cosangle * dy2));
97}
98
99
100/**
101 * ensure the arc radii are large enough and scale as appropriate
102 *
103 * the radii need to be large enough if they are not they must be
104 * adjusted. This allows for elimination of differences between
105 * implementations especialy with rounding.
106 */
107static void
108ensure_radii_scale(double x1_sq, double y1_sq,
109 float *rx, float *ry,
110 double *rx_sq, double *ry_sq)
111{
112 double radiisum;
113 double radiiscale;
114
115 /* set radii square values */
116 (*rx_sq) = (*rx) * (*rx);
117 (*ry_sq) = (*ry) * (*ry);
118
119 radiisum = (x1_sq / (*rx_sq)) + (y1_sq / (*ry_sq));
120 if (radiisum > 0.99999) {
121 /* need to scale radii */
122 radiiscale = sqrt(radiisum) * 1.00001;
123 *rx = (float)(radiiscale * (*rx));
124 *ry = (float)(radiiscale * (*ry));
125 /* update squares too */
126 (*rx_sq) = (*rx) * (*rx);
127 (*ry_sq) = (*ry) * (*ry);
128 }
129}
130
131
132/**
133 * compute the transformed centre point
134 */
135static void
136compute_transformed_centre_point(double sign, float rx, float ry,
137 double rx_sq, double ry_sq,
138 double x1, double y1,
139 double x1_sq, double y1_sq,
140 double *cx1, double *cy1)
141{
142 double sq;
143 double coef;
144 sq = ((rx_sq * ry_sq) - (rx_sq * y1_sq) - (ry_sq * x1_sq)) /
145 ((rx_sq * y1_sq) + (ry_sq * x1_sq));
146 sq = (sq < 0) ? 0 : sq;
147
148 coef = (sign * sqrt(sq));
149
150 *cx1 = coef * ((rx * y1) / ry);
151 *cy1 = coef * -((ry * x1) / rx);
152}
153
154
155/**
156 * compute untransformed centre point
157 *
158 * \param ax The first point x coordinate
159 * \param ay The first point y coordinate
160 * \param bx The second point x coordinate
161 * \param ay The second point y coordinate
162 */
163static void
164compute_centre_point(float ax, float ay,
165 float bx, float by,
166 double cx1, double cy1,
167 double radangle,
168 double *x_out, double *y_out)
169{
170 double sx2;
171 double sy2;
172 double cosangle; /* cosine of rotation angle */
173 double sinangle; /* sine of rotation angle */
174
175 /* compute the sin and cos of the angle */
176 cosangle = cos(radangle);
177 sinangle = sin(radangle);
178
179 sx2 = (ax + bx) / 2.0;
180 sy2 = (ay + by) / 2.0;
181
182 *x_out = sx2 + (cosangle * cx1 - sinangle * cy1);
183 *y_out = sy2 + (sinangle * cx1 + cosangle * cy1);
184}
185
186
187/**
188 * compute the angle start and extent
189 */
190static void
191compute_angle_start_extent(float rx, float ry,
192 double x1, double y1,
193 double cx1, double cy1,
194 double *start, double *extent)
195{
196 double sign;
197 double ux;
198 double uy;
199 double vx;
200 double vy;
201 double p, n;
202 double actmp;
203
204 /*
205 * Angle betwen two vectors is +/- acos( u.v / len(u) * len(v))
206 * Where:
207 * '.' is the dot product.
208 * +/- is calculated from the sign of the cross product (u x v)
209 */
210
211 ux = (x1 - cx1) / rx;
212 uy = (y1 - cy1) / ry;
213 vx = (-x1 - cx1) / rx;
214 vy = (-y1 - cy1) / ry;
215
216 /* compute the start angle */
217 /* The angle between (ux, uy) and the 0 angle */
218
219 /* len(u) * len(1,0) == len(u) */
220 n = sqrt((ux * ux) + (uy * uy));
221 /* u.v == (ux,uy).(1,0) == (1 * ux) + (0 * uy) == ux */
222 p = ux;
223 /* u x v == (1 * uy - ux * 0) == uy */
224 sign = (uy < 0) ? -1.0 : 1.0;
225 /* (p >= n) so safe */
226 *start = sign * acos(p / n);
227
228 /* compute the extent angle */
229 n = sqrt(((ux * ux) + (uy * uy)) * ((vx * vx) + (vy * vy)));
230 p = (ux * vx) + (uy * vy);
231 sign = ((ux * vy) - (uy * vx) < 0) ? -1.0f : 1.0f;
232
233 /* arc cos must operate between -1 and 1 */
234 actmp = p / n;
235 if (actmp < -1.0) {
236 *extent = sign * M_PI3.14159265358979323846;
237 } else if (actmp > 1.0) {
238 *extent = 0;
239 } else {
240 *extent = sign * acos(actmp);
241 }
242}
243
244
245/**
246 * converts a circle centered unit circle arc to a series of bezier curves
247 *
248 * Each bezier is stored as six values of three pairs of coordinates
249 *
250 * The beziers are stored without their start point as that is assumed
251 * to be the preceding elements end point.
252 *
253 * \param start The start angle of the arc (in radians)
254 * \param extent The size of the arc (in radians)
255 * \param bzpt The array to store the bezier values in
256 * \return The number of bezier segments output (max 4)
257 */
258static int
259circle_arc_to_bezier(double start, double extent, double *bzpt)
260{
261 int bzsegments;
262 double increment;
263 double controllen;
264 int pos = 0;
265 int segment;
266 double angle;
267 double dx, dy;
268
269 bzsegments = (int) ceil(fabs(extent) / M_PI_21.57079632679489661923);
270 increment = extent / bzsegments;
271 controllen = 4.0 / 3.0 * sin(increment / 2.0) / (1.0 + cos(increment / 2.0));
272
273 for (segment = 0; segment < bzsegments; segment++) {
274 /* first control point */
275 angle = start + (segment * increment);
276 dx = cos(angle);
277 dy = sin(angle);
278 bzpt[pos++] = dx - controllen * dy;
279 bzpt[pos++] = dy + controllen * dx;
280 /* second control point */
281 angle+=increment;
282 dx = cos(angle);
283 dy = sin(angle);
284 bzpt[pos++] = dx + controllen * dy;
285 bzpt[pos++] = dy - controllen * dx;
286 /* endpoint */
287 bzpt[pos++] = dx;
288 bzpt[pos++] = dy;
289
290 }
291 return bzsegments;
292}
293
294
295/**
296 * transform coordinate list
297 *
298 * perform a scale, rotate and translate on list of coordinates
299 *
300 * scale(rx,ry)
301 * rotate(an)
302 * translate (cx, cy)
303 *
304 * homogeneous transforms
305 *
306 * scaling
307 * | rx 0 0 |
308 * S = | 0 ry 0 |
309 * | 0 0 1 |
310 *
311 * rotate
312 * | cos(an) -sin(an) 0 |
313 * R = | sin(an) cos(an) 0 |
314 * | 0 0 1 |
315 *
316 * {{cos(a), -sin(a) 0}, {sin(a), cos(a),0}, {0,0,1}}
317 *
318 * translate
319 * | 1 0 cx |
320 * T = | 0 1 cy |
321 * | 0 0 1 |
322 *
323 * note order is significat here and the combined matrix is
324 * M = T.R.S
325 *
326 * | cos(an) -sin(an) cx |
327 * T.R = | sin(an) cos(an) cy |
328 * | 0 0 1 |
329 *
330 * | rx * cos(an) ry * -sin(an) cx |
331 * T.R.S = | rx * sin(an) ry * cos(an) cy |
332 * | 0 0 1 |
333 *
334 * {{Cos[a], -Sin[a], c}, {Sin[a], Cos[a], d}, {0, 0, 1}} . {{r, 0, 0}, {0, s, 0}, {0, 0, 1}}
335 *
336 * Each point
337 * | x1 |
338 * P = | y1 |
339 * | 1 |
340 *
341 * output
342 * | x2 |
343 * | y2 | = M . P
344 * | 1 |
345 *
346 * x2 = cx + (rx * x1 * cos(a)) + (ry * y1 * -1 * sin(a))
347 * y2 = cy + (ry * y1 * cos(a)) + (rx * x1 * sin(a))
348 *
349 *
350 * \param rx X scaling to apply
351 * \param ry Y scaling to apply
352 * \param radangle rotation to apply (in radians)
353 * \param cx X translation to apply
354 * \param cy Y translation to apply
355 * \param points The size of the bzpoints array
356 * \param bzpoints an array of x,y values to apply the transform to
357 */
358static void
359scale_rotate_translate_points(double rx, double ry,
360 double radangle,
361 double cx, double cy,
362 int pntsize,
363 double *points)
364{
365 int pnt;
366 double cosangle; /* cosine of rotation angle */
367 double sinangle; /* sine of rotation angle */
368 double rxcosangle, rxsinangle, rycosangle, rynsinangle;
369 double x2,y2;
370
371 /* compute the sin and cos of the angle */
372 cosangle = cos(radangle);
373 sinangle = sin(radangle);
374
375 rxcosangle = rx * cosangle;
376 rxsinangle = rx * sinangle;
377 rycosangle = ry * cosangle;
378 rynsinangle = ry * -1 * sinangle;
379
380 for (pnt = 0; pnt < pntsize; pnt+=2) {
381 x2 = cx + (points[pnt] * rxcosangle) + (points[pnt + 1] * rynsinangle);
382 y2 = cy + (points[pnt + 1] * rycosangle) + (points[pnt] * rxsinangle);
383 points[pnt] = x2;
384 points[pnt + 1] = y2;
385 }
386}
387
388
389/**
390 * convert an svg path arc to a bezier curve
391 *
392 * This function perfoms a transform on the nine arc parameters
393 * (coordinate pairs for start and end together with the radii of the
394 * elipse, the rotation angle and which of the four arcs to draw)
395 * which generates the parameters (coordinate pairs for start,
396 * end and their control points) for a set of up to four bezier curves.
397 *
398 * Obviously the start and end coordinates are not altered between
399 * representations so the aim is to calculate the coordinate pairs for
400 * the bezier control points.
401 *
402 * \param bzpoints the array to fill with bezier curves
403 * \return the number of bezier segments generated or -1 for a line
404 */
405static int
406svgarc_to_bezier(float start_x,
407 float start_y,
408 float end_x,
409 float end_y,
410 float rx,
411 float ry,
412 float angle,
413 bool_Bool largearc,
414 bool_Bool sweep,
415 double *bzpoints)
416{
417 double radangle; /* normalised elipsis rotation angle in radians */
418 double rx_sq; /* x radius squared */
419 double ry_sq; /* y radius squared */
420 double x1, y1; /* rotated midpoint vector */
421 double x1_sq, y1_sq; /* x1 vector squared */
422 double cx1,cy1; /* transformed circle center */
423 double cx,cy; /* circle center */
424 double start, extent;
425 int bzsegments;
426
427 if ((start_x == end_x) && (start_y == end_y)) {
428 /*
429 * if the start and end coordinates are the same the
430 * svg spec says this is equivalent to having no segment
431 * at all
432 */
433 return 0;
434 }
435
436 if ((rx == 0) || (ry == 0)) {
437 /*
438 * if either radii is zero the specified behaviour is a line
439 */
440 return -1;
441 }
442
443 /* obtain the absolute values of the radii */
444 rx = fabsf(rx);
445 ry = fabsf(ry);
446
447 /* convert normalised angle to radians */
448 radangle = degToRad(fmod(angle, 360.0))((fmod(angle, 360.0)) * 3.14159265358979323846 / 180.0);
449
450 /* step 1 */
451 /* x1,x2 is the midpoint vector rotated to remove the arc angle */
452 rotate_midpoint_vector(start_x, start_y, end_x, end_y, radangle, &x1, &y1);
453
454 /* step 2 */
455 /* get squared x1 values */
456 x1_sq = x1 * x1;
457 y1_sq = y1 * y1;
458
459 /* ensure radii are correctly scaled */
460 ensure_radii_scale(x1_sq, y1_sq, &rx, &ry, &rx_sq, &ry_sq);
461
462 /* compute the transformed centre point */
463 compute_transformed_centre_point(largearc == sweep?-1:1,
464 rx, ry,
465 rx_sq, ry_sq,
466 x1, y1,
467 x1_sq, y1_sq,
468 &cx1, &cy1);
469
470 /* step 3 */
471 /* get the untransformed centre point */
472 compute_centre_point(start_x, start_y,
473 end_x, end_y,
474 cx1, cy1,
475 radangle,
476 &cx, &cy);
477
478 /* step 4 */
479 /* compute anglestart and extent */
480 compute_angle_start_extent(rx,ry,
481 x1,y1,
482 cx1, cy1,
483 &start, &extent);
484
485 /* extent of 0 is a straight line */
486 if (extent == 0) {
487 return -1;
488 }
489
490 /* take account of sweep */
491 if (!sweep && extent > 0) {
492 extent -= TAU6.28318530717958647692;
493 } else if (sweep && extent < 0) {
494 extent += TAU6.28318530717958647692;
495 }
496
497 /* normalise start and extent */
498 extent = fmod(extent, TAU6.28318530717958647692);
499 start = fmod(start, TAU6.28318530717958647692);
500
501 /* convert the arc to unit circle bezier curves */
502 bzsegments = circle_arc_to_bezier(start, extent, bzpoints);
503
504 /* transform the bezier curves */
505 scale_rotate_translate_points(rx, ry,
506 radangle,
507 cx, cy,
508 bzsegments * 6,
509 bzpoints);
510
511 return bzsegments;
512}
513
514
515/**
516 * Call this to ref the strings in a gradient state.
517 */
518static void svgtiny_grad_string_ref(struct svgtiny_parse_state_gradient *grad)
519{
520 if (grad->gradient_x1 != NULL((void*)0)) {
521 dom_string_ref(grad->gradient_x1);
522 }
523 if (grad->gradient_y1 != NULL((void*)0)) {
524 dom_string_ref(grad->gradient_y1);
525 }
526 if (grad->gradient_x2 != NULL((void*)0)) {
527 dom_string_ref(grad->gradient_x2);
528 }
529 if (grad->gradient_y2 != NULL((void*)0)) {
530 dom_string_ref(grad->gradient_y2);
531 }
532}
533
534/**
535 * Call this to clean up the strings in a gradient state.
536 */
537static void svgtiny_grad_string_cleanup(
538 struct svgtiny_parse_state_gradient *grad)
539{
540 if (grad->gradient_x1 != NULL((void*)0)) {
541 dom_string_unref(grad->gradient_x1);
542 grad->gradient_x1 = NULL((void*)0);
543 }
544 if (grad->gradient_y1 != NULL((void*)0)) {
545 dom_string_unref(grad->gradient_y1);
546 grad->gradient_y1 = NULL((void*)0);
547 }
548 if (grad->gradient_x2 != NULL((void*)0)) {
549 dom_string_unref(grad->gradient_x2);
550 grad->gradient_x2 = NULL((void*)0);
551 }
552 if (grad->gradient_y2 != NULL((void*)0)) {
553 dom_string_unref(grad->gradient_y2);
554 grad->gradient_y2 = NULL((void*)0);
555 }
556}
557
558/**
559 * Set the local externally-stored parts of a parse state.
560 * Call this in functions that made a new state on the stack.
561 * Doesn't make own copy of global state, such as the interned string list.
562 */
563static void svgtiny_setup_state_local(struct svgtiny_parse_state *state)
564{
565 svgtiny_grad_string_ref(&(state->fill_grad));
566 svgtiny_grad_string_ref(&(state->stroke_grad));
567}
568
569/**
570 * Cleanup the local externally-stored parts of a parse state.
571 * Call this in functions that made a new state on the stack.
572 * Doesn't cleanup global state, such as the interned string list.
573 */
574static void svgtiny_cleanup_state_local(struct svgtiny_parse_state *state)
575{
576 svgtiny_grad_string_cleanup(&(state->fill_grad));
577 svgtiny_grad_string_cleanup(&(state->stroke_grad));
578}
579
580
581/**
582 * Create a new svgtiny_diagram structure.
583 */
584
585struct svgtiny_diagram *svgtiny_create(void)
586{
587 struct svgtiny_diagram *diagram;
588
589 diagram = calloc(sizeof(*diagram), 1);
590 if (!diagram)
591 return 0;
592
593 return diagram;
594 free(diagram);
595 return NULL((void*)0);
596}
597
598static void ignore_msg(uint32_t severity, void *ctx, const char *msg, ...)
599{
600 UNUSED(severity)((void) (severity));
601 UNUSED(ctx)((void) (ctx));
602 UNUSED(msg)((void) (msg));
603}
604
605/**
606 * Parse a block of memory into a svgtiny_diagram.
607 */
608
609svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram,
610 const char *buffer, size_t size, const char *url,
611 int viewport_width, int viewport_height)
612{
613 dom_document *document;
614 dom_exception exc;
615 dom_xml_parser *parser;
616 dom_xml_error err;
617 dom_element *svg;
618 dom_string *svg_name;
619 lwc_string *svg_name_lwc;
620 struct svgtiny_parse_state state;
621 float x, y, width, height;
622 svgtiny_code code;
623
624 assert(diagram)((diagram) ? (void) (0) : __assert_fail ("diagram", "src/svgtiny.c"
, 624, __extension__ __PRETTY_FUNCTION__))
;
625 assert(buffer)((buffer) ? (void) (0) : __assert_fail ("buffer", "src/svgtiny.c"
, 625, __extension__ __PRETTY_FUNCTION__))
;
626 assert(url)((url) ? (void) (0) : __assert_fail ("url", "src/svgtiny.c", 626
, __extension__ __PRETTY_FUNCTION__))
;
627
628 UNUSED(url)((void) (url));
629
630 parser = dom_xml_parser_create(NULL((void*)0), NULL((void*)0),
631 ignore_msg, NULL((void*)0), &document);
632
633 if (parser == NULL((void*)0))
634 return svgtiny_LIBDOM_ERROR;
635
636 err = dom_xml_parser_parse_chunk(parser, (uint8_t *)buffer, size);
637 if (err != DOM_XML_OK) {
638 dom_node_unref(document)dom_node_unref((dom_node *) (document));
639 dom_xml_parser_destroy(parser);
640 return svgtiny_LIBDOM_ERROR;
641 }
642
643 err = dom_xml_parser_completed(parser);
644 if (err != DOM_XML_OK) {
645 dom_node_unref(document)dom_node_unref((dom_node *) (document));
646 dom_xml_parser_destroy(parser);
647 return svgtiny_LIBDOM_ERROR;
648 }
649
650 /* We're done parsing, drop the parser.
651 * We now own the document entirely.
652 */
653 dom_xml_parser_destroy(parser);
654
655 /* find root <svg> element */
656 exc = dom_document_get_document_element(document, &svg)dom_document_get_document_element((dom_document *) (document)
, (struct dom_element **) (&svg))
;
657 if (exc != DOM_NO_ERR) {
658 dom_node_unref(document)dom_node_unref((dom_node *) (document));
659 return svgtiny_LIBDOM_ERROR;
660 }
661 if (svg == NULL((void*)0)) {
662 /* no root svg element */
663 dom_node_unref(document)dom_node_unref((dom_node *) (document));
664 return svgtiny_SVG_ERROR;
665 }
666
667 exc = dom_node_get_node_name(svg, &svg_name)dom_node_get_node_name((dom_node *) (svg), (&svg_name));
668 if (exc != DOM_NO_ERR) {
669 dom_node_unref(svg)dom_node_unref((dom_node *) (svg));
670 dom_node_unref(document)dom_node_unref((dom_node *) (document));
671 return svgtiny_LIBDOM_ERROR;
672 }
673 if (lwc_intern_string("svg", 3 /* SLEN("svg") */,
674 &svg_name_lwc) != lwc_error_ok) {
675 dom_string_unref(svg_name);
676 dom_node_unref(svg)dom_node_unref((dom_node *) (svg));
677 dom_node_unref(document)dom_node_unref((dom_node *) (document));
678 return svgtiny_LIBDOM_ERROR;
679 }
680 if (!dom_string_caseless_lwc_isequal(svg_name, svg_name_lwc)) {
681 lwc_string_unref(svg_name_lwc){ lwc_string *__lwc_s = (svg_name_lwc); ((__lwc_s != ((void*)
0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/svgtiny.c"
, 681, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
682 dom_string_unref(svg_name);
683 dom_node_unref(svg)dom_node_unref((dom_node *) (svg));
684 dom_node_unref(document)dom_node_unref((dom_node *) (document));
685 return svgtiny_NOT_SVG;
686 }
687
688 lwc_string_unref(svg_name_lwc){ lwc_string *__lwc_s = (svg_name_lwc); ((__lwc_s != ((void*)
0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "src/svgtiny.c"
, 688, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
689 dom_string_unref(svg_name);
690
691 /* get graphic dimensions */
692 memset(&state, 0, sizeof(state));
693 state.diagram = diagram;
694 state.document = document;
695 state.viewport_width = viewport_width;
696 state.viewport_height = viewport_height;
697
698#define SVGTINY_STRING_ACTION2(s,n) \
699 if (dom_string_create_interned((const uint8_t *) #n, \
700 strlen(#n), &state.interned_##s) \
701 != DOM_NO_ERR) { \
702 code = svgtiny_LIBDOM_ERROR; \
703 goto cleanup; \
704 }
705#include "svgtiny_strings.h"
706#undef SVGTINY_STRING_ACTION2
707
708 svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height);
709 diagram->width = width;
710 diagram->height = height;
711
712 /* set up parsing state */
713 state.viewport_width = width;
714 state.viewport_height = height;
715 state.ctm.a = 1; /*(float) viewport_width / (float) width;*/
716 state.ctm.b = 0;
717 state.ctm.c = 0;
718 state.ctm.d = 1; /*(float) viewport_height / (float) height;*/
719 state.ctm.e = 0; /*x;*/
720 state.ctm.f = 0; /*y;*/
721 /*state.style = css_base_style;
722 state.style.font_size.value.length.value = option_font_size * 0.1;*/
723 state.fill = 0x000000;
724 state.stroke = svgtiny_TRANSPARENT0x1000000;
725 state.stroke_width = 1;
726
727 /* parse tree */
728 code = svgtiny_parse_svg(svg, state);
729
730 dom_node_unref(svg)dom_node_unref((dom_node *) (svg));
731 dom_node_unref(document)dom_node_unref((dom_node *) (document));
732
733cleanup:
734 svgtiny_cleanup_state_local(&state);
735#define SVGTINY_STRING_ACTION2(s,n) \
736 if (state.interned_##s != NULL((void*)0)) \
737 dom_string_unref(state.interned_##s);
738#include "svgtiny_strings.h"
739#undef SVGTINY_STRING_ACTION2
740 return code;
741}
742
743
744/**
745 * Parse a <svg> or <g> element node.
746 */
747
748svgtiny_code svgtiny_parse_svg(dom_element *svg,
749 struct svgtiny_parse_state state)
750{
751 float x, y, width, height;
752 dom_string *view_box;
753 dom_element *child;
754 dom_exception exc;
755
756 svgtiny_setup_state_local(&state);
757
758 svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height);
759 svgtiny_parse_paint_attributes(svg, &state);
760 svgtiny_parse_font_attributes(svg, &state);
761
762 exc = dom_element_get_attribute(svg, state.interned_viewBox,dom_element_get_attribute( (dom_element *) (svg), (state.interned_viewBox
), (&view_box))
763 &view_box)dom_element_get_attribute( (dom_element *) (svg), (state.interned_viewBox
), (&view_box))
;
764 if (exc != DOM_NO_ERR) {
765 svgtiny_cleanup_state_local(&state);
766 return svgtiny_LIBDOM_ERROR;
767 }
768
769 if (view_box) {
770 char *s = strndup(dom_string_data(view_box),
771 dom_string_byte_length(view_box));
772 float min_x, min_y, vwidth, vheight;
773 if (sscanf(s, "%f,%f,%f,%f",
774 &min_x, &min_y, &vwidth, &vheight) == 4 ||
775 sscanf(s, "%f %f %f %f",
776 &min_x, &min_y, &vwidth, &vheight) == 4) {
777 state.ctm.a = (float) state.viewport_width / vwidth;
778 state.ctm.d = (float) state.viewport_height / vheight;
779 state.ctm.e += -min_x * state.ctm.a;
780 state.ctm.f += -min_y * state.ctm.d;
781 }
782 free(s);
783 dom_string_unref(view_box);
784 }
785
786 svgtiny_parse_transform_attributes(svg, &state);
787
788 exc = dom_node_get_first_child(svg, (dom_node **) (void *) &child)dom_node_get_first_child( (dom_node *) (svg), (dom_node **) (
(dom_node **) (void *) &child))
;
789 if (exc != DOM_NO_ERR) {
790 svgtiny_cleanup_state_local(&state);
791 return svgtiny_LIBDOM_ERROR;
792 }
793 while (child != NULL((void*)0)) {
794 dom_element *next;
795 dom_node_type nodetype;
796 svgtiny_code code = svgtiny_OK;
797
798 exc = dom_node_get_node_type(child, &nodetype)dom_node_get_node_type( (dom_node *) (child), (dom_node_type *
) (&nodetype))
;
799 if (exc != DOM_NO_ERR) {
800 dom_node_unref(child)dom_node_unref((dom_node *) (child));
801 return svgtiny_LIBDOM_ERROR;
802 }
803 if (nodetype == DOM_ELEMENT_NODE) {
804 dom_string *nodename;
805 exc = dom_node_get_node_name(child, &nodename)dom_node_get_node_name((dom_node *) (child), (&nodename));
806 if (exc != DOM_NO_ERR) {
807 dom_node_unref(child)dom_node_unref((dom_node *) (child));
808 svgtiny_cleanup_state_local(&state);
809 return svgtiny_LIBDOM_ERROR;
810 }
811 if (dom_string_caseless_isequal(state.interned_svg,
812 nodename))
813 code = svgtiny_parse_svg(child, state);
814 else if (dom_string_caseless_isequal(state.interned_g,
815 nodename))
816 code = svgtiny_parse_svg(child, state);
817 else if (dom_string_caseless_isequal(state.interned_a,
818 nodename))
819 code = svgtiny_parse_svg(child, state);
820 else if (dom_string_caseless_isequal(state.interned_path,
821 nodename))
822 code = svgtiny_parse_path(child, state);
823 else if (dom_string_caseless_isequal(state.interned_rect,
824 nodename))
825 code = svgtiny_parse_rect(child, state);
826 else if (dom_string_caseless_isequal(state.interned_circle,
827 nodename))
828 code = svgtiny_parse_circle(child, state);
829 else if (dom_string_caseless_isequal(state.interned_ellipse,
830 nodename))
831 code = svgtiny_parse_ellipse(child, state);
832 else if (dom_string_caseless_isequal(state.interned_line,
833 nodename))
834 code = svgtiny_parse_line(child, state);
835 else if (dom_string_caseless_isequal(state.interned_polyline,
836 nodename))
837 code = svgtiny_parse_poly(child, state, false0);
838 else if (dom_string_caseless_isequal(state.interned_polygon,
839 nodename))
840 code = svgtiny_parse_poly(child, state, true1);
841 else if (dom_string_caseless_isequal(state.interned_text,
842 nodename))
843 code = svgtiny_parse_text(child, state);
844 dom_string_unref(nodename);
845 }
846 if (code != svgtiny_OK) {
847 dom_node_unref(child)dom_node_unref((dom_node *) (child));
848 svgtiny_cleanup_state_local(&state);
849 return code;
850 }
851 exc = dom_node_get_next_sibling(child,dom_node_get_next_sibling( (dom_node *) (child), (dom_node **
) ((dom_node **) (void *) &next))
852 (dom_node **) (void *) &next)dom_node_get_next_sibling( (dom_node *) (child), (dom_node **
) ((dom_node **) (void *) &next))
;
853 dom_node_unref(child)dom_node_unref((dom_node *) (child));
854 if (exc != DOM_NO_ERR) {
855 svgtiny_cleanup_state_local(&state);
856 return svgtiny_LIBDOM_ERROR;
857 }
858 child = next;
859 }
860
861 svgtiny_cleanup_state_local(&state);
862 return svgtiny_OK;
863}
864
865
866
867/**
868 * Parse a <path> element node.
869 *
870 * http://www.w3.org/TR/SVG11/paths#PathElement
871 */
872
873svgtiny_code svgtiny_parse_path(dom_element *path,
874 struct svgtiny_parse_state state)
875{
876 svgtiny_code err;
877 dom_string *path_d_str;
878 dom_exception exc;
879 char *s, *path_d;
880 float *p; /* path elemets */
881 unsigned int palloc; /* number of path elements allocated */
882 unsigned int i;
883 float last_x = 0, last_y = 0;
884 float last_cubic_x = 0, last_cubic_y = 0;
885 float last_quad_x = 0, last_quad_y = 0;
886 float subpath_first_x = 0, subpath_first_y = 0;
887
888 svgtiny_setup_state_local(&state);
889
890 svgtiny_parse_paint_attributes(path, &state);
891 svgtiny_parse_transform_attributes(path, &state);
892
893 /* read d attribute */
894 exc = dom_element_get_attribute(path, state.interned_d, &path_d_str)dom_element_get_attribute( (dom_element *) (path), (state.interned_d
), (&path_d_str))
;
895 if (exc != DOM_NO_ERR) {
1
Assuming 'exc' is equal to DOM_NO_ERR
2
Taking false branch
896 state.diagram->error_line = -1; /* path->line; */
897 state.diagram->error_message = "path: error retrieving d attribute";
898 svgtiny_cleanup_state_local(&state);
899 return svgtiny_SVG_ERROR;
900 }
901
902 if (path_d_str == NULL((void*)0)) {
3
Assuming 'path_d_str' is not equal to NULL
4
Taking false branch
903 state.diagram->error_line = -1; /* path->line; */
904 state.diagram->error_message = "path: missing d attribute";
905 svgtiny_cleanup_state_local(&state);
906 return svgtiny_SVG_ERROR;
907 }
908
909 /* empty path is permitted it just disables the path */
910 palloc = dom_string_byte_length(path_d_str);
911 if (palloc == 0) {
5
Assuming 'palloc' is not equal to 0
6
Taking false branch
912 dom_string_unref(path_d_str);
913 svgtiny_cleanup_state_local(&state);
914 return svgtiny_OK;
915 }
916
917 /* local copy of the path data allowing in-place modification */
918 s = path_d = strndup(dom_string_data(path_d_str), palloc);
919 dom_string_unref(path_d_str);
920 if (s == NULL((void*)0)) {
7
Assuming 's' is not equal to NULL
8
Taking false branch
921 svgtiny_cleanup_state_local(&state);
922 return svgtiny_OUT_OF_MEMORY;
923 }
924
925 /* ensure path element allocation is sensibly bounded */
926 if (palloc < 8) {
9
Assuming 'palloc' is >= 8
10
Taking false branch
927 palloc = 8;
928 } else if (palloc > 64) {
11
Assuming 'palloc' is <= 64
12
Taking false branch
929 palloc = palloc / 2;
930 }
931
932 /* allocate initial space for path elements */
933 p = malloc(sizeof p[0] * palloc);
13
Storing uninitialized value
934 if (p == NULL((void*)0)) {
14
Assuming 'p' is not equal to NULL
15
Taking false branch
935 free(path_d);
936 svgtiny_cleanup_state_local(&state);
937 return svgtiny_OUT_OF_MEMORY;
938 }
939
940 /* parse d and build path */
941 for (i = 0; s[i]; i++)
16
Loop condition is true. Entering loop body
19
Loop condition is false. Execution continues on line 944
942 if (s[i] == ',')
17
Assuming the condition is false
18
Taking false branch
943 s[i] = ' ';
944 i = 0;
945 while (*s) {
20
Loop condition is true. Entering loop body
946 char command[2];
947 int plot_command;
948 float x, y, x1, y1, x2, y2, rx, ry, rotation, large_arc, sweep;
949 int n;
950
951 /* Ensure there is sufficient space for path elements */
952#define ALLOC_PATH_ELEMENTS(NUM_ELEMENTS)do { if ((palloc - i) < NUM_ELEMENTS) { float *tp; palloc =
(palloc * 2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc
); if (tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
\
953 do { \
954 if ((palloc - i) < NUM_ELEMENTS) { \
955 float *tp; \
956 palloc = (palloc * 2) + (palloc / 2); \
957 tp = realloc(p, sizeof p[0] * palloc); \
958 if (tp == NULL((void*)0)) { \
959 free(p); \
960 free(path_d); \
961 svgtiny_cleanup_state_local(&state); \
962 return svgtiny_OUT_OF_MEMORY; \
963 } \
964 p = tp; \
965 } \
966 } while(0)
967
968
969 /* moveto (M, m), lineto (L, l) (2 arguments) */
970 if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) {
21
Assuming the condition is false
22
Taking false branch
971 /*LOG(("moveto or lineto"));*/
972 if (*command == 'M' || *command == 'm')
973 plot_command = svgtiny_PATH_MOVE;
974 else
975 plot_command = svgtiny_PATH_LINE;
976 do {
977 ALLOC_PATH_ELEMENTS(3)do { if ((palloc - i) < 3) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
978 p[i++] = plot_command;
979 if ('a' <= *command) {
980 x += last_x;
981 y += last_y;
982 }
983 if (plot_command == svgtiny_PATH_MOVE) {
984 subpath_first_x = x;
985 subpath_first_y = y;
986 }
987 p[i++] = last_cubic_x = last_quad_x = last_x
988 = x;
989 p[i++] = last_cubic_y = last_quad_y = last_y
990 = y;
991 s += n;
992 plot_command = svgtiny_PATH_LINE;
993 } while (sscanf(s, "%f %f %n", &x, &y, &n) == 2);
994
995 /* closepath (Z, z) (no arguments) */
996 } else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) {
23
Assuming the condition is false
24
Taking false branch
997 /*LOG(("closepath"));*/
998 ALLOC_PATH_ELEMENTS(1)do { if ((palloc - i) < 1) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
999
1000 p[i++] = svgtiny_PATH_CLOSE;
1001 s += n;
1002 last_cubic_x = last_quad_x = last_x = subpath_first_x;
1003 last_cubic_y = last_quad_y = last_y = subpath_first_y;
1004
1005 /* horizontal lineto (H, h) (1 argument) */
1006 } else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) {
25
Assuming the condition is false
26
Taking false branch
1007 /*LOG(("horizontal lineto"));*/
1008 do {
1009 ALLOC_PATH_ELEMENTS(3)do { if ((palloc - i) < 3) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
1010
1011 p[i++] = svgtiny_PATH_LINE;
1012 if (*command == 'h')
1013 x += last_x;
1014 p[i++] = last_cubic_x = last_quad_x = last_x
1015 = x;
1016 p[i++] = last_cubic_y = last_quad_y = last_y;
1017 s += n;
1018 } while (sscanf(s, "%f %n", &x, &n) == 1);
1019
1020 /* vertical lineto (V, v) (1 argument) */
1021 } else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) {
27
Assuming the condition is false
28
Taking false branch
1022 /*LOG(("vertical lineto"));*/
1023 do {
1024 ALLOC_PATH_ELEMENTS(3)do { if ((palloc - i) < 3) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
1025
1026 p[i++] = svgtiny_PATH_LINE;
1027 if (*command == 'v')
1028 y += last_y;
1029 p[i++] = last_cubic_x = last_quad_x = last_x;
1030 p[i++] = last_cubic_y = last_quad_y = last_y
1031 = y;
1032 s += n;
1033 } while (sscanf(s, "%f %n", &y, &n) == 1);
1034
1035 /* curveto (C, c) (6 arguments) */
1036 } else if (sscanf(s, " %1[Cc] %f %f %f %f %f %f %n", command,
29
Assuming the condition is false
30
Taking false branch
1037 &x1, &y1, &x2, &y2, &x, &y, &n) == 7) {
1038 /*LOG(("curveto"));*/
1039 do {
1040 ALLOC_PATH_ELEMENTS(7)do { if ((palloc - i) < 7) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
1041
1042 p[i++] = svgtiny_PATH_BEZIER;
1043 if (*command == 'c') {
1044 x1 += last_x;
1045 y1 += last_y;
1046 x2 += last_x;
1047 y2 += last_y;
1048 x += last_x;
1049 y += last_y;
1050 }
1051 p[i++] = x1;
1052 p[i++] = y1;
1053 p[i++] = last_cubic_x = x2;
1054 p[i++] = last_cubic_y = y2;
1055 p[i++] = last_quad_x = last_x = x;
1056 p[i++] = last_quad_y = last_y = y;
1057 s += n;
1058 } while (sscanf(s, "%f %f %f %f %f %f %n",
1059 &x1, &y1, &x2, &y2, &x, &y, &n) == 6);
1060
1061 /* shorthand/smooth curveto (S, s) (4 arguments) */
1062 } else if (sscanf(s, " %1[Ss] %f %f %f %f %n", command,
31
Assuming the condition is false
32
Taking false branch
1063 &x2, &y2, &x, &y, &n) == 5) {
1064 /*LOG(("shorthand/smooth curveto"));*/
1065 do {
1066 ALLOC_PATH_ELEMENTS(7)do { if ((palloc - i) < 7) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
1067
1068 p[i++] = svgtiny_PATH_BEZIER;
1069 x1 = last_x + (last_x - last_cubic_x);
1070 y1 = last_y + (last_y - last_cubic_y);
1071 if (*command == 's') {
1072 x2 += last_x;
1073 y2 += last_y;
1074 x += last_x;
1075 y += last_y;
1076 }
1077 p[i++] = x1;
1078 p[i++] = y1;
1079 p[i++] = last_cubic_x = x2;
1080 p[i++] = last_cubic_y = y2;
1081 p[i++] = last_quad_x = last_x = x;
1082 p[i++] = last_quad_y = last_y = y;
1083 s += n;
1084 } while (sscanf(s, "%f %f %f %f %n",
1085 &x2, &y2, &x, &y, &n) == 4);
1086
1087 /* quadratic Bezier curveto (Q, q) (4 arguments) */
1088 } else if (sscanf(s, " %1[Qq] %f %f %f %f %n", command,
33
Assuming the condition is false
34
Taking false branch
1089 &x1, &y1, &x, &y, &n) == 5) {
1090 /*LOG(("quadratic Bezier curveto"));*/
1091 do {
1092 ALLOC_PATH_ELEMENTS(7)do { if ((palloc - i) < 7) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
1093
1094 p[i++] = svgtiny_PATH_BEZIER;
1095 last_quad_x = x1;
1096 last_quad_y = y1;
1097 if (*command == 'q') {
1098 x1 += last_x;
1099 y1 += last_y;
1100 x += last_x;
1101 y += last_y;
1102 }
1103 p[i++] = 1./3 * last_x + 2./3 * x1;
1104 p[i++] = 1./3 * last_y + 2./3 * y1;
1105 p[i++] = 2./3 * x1 + 1./3 * x;
1106 p[i++] = 2./3 * y1 + 1./3 * y;
1107 p[i++] = last_cubic_x = last_x = x;
1108 p[i++] = last_cubic_y = last_y = y;
1109 s += n;
1110 } while (sscanf(s, "%f %f %f %f %n",
1111 &x1, &y1, &x, &y, &n) == 4);
1112
1113 /* shorthand/smooth quadratic Bezier curveto (T, t)
1114 (2 arguments) */
1115 } else if (sscanf(s, " %1[Tt] %f %f %n", command,
35
Assuming the condition is false
36
Taking false branch
1116 &x, &y, &n) == 3) {
1117 /*LOG(("shorthand/smooth quadratic Bezier curveto"));*/
1118 do {
1119 ALLOC_PATH_ELEMENTS(7)do { if ((palloc - i) < 7) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
1120
1121 p[i++] = svgtiny_PATH_BEZIER;
1122 x1 = last_x + (last_x - last_quad_x);
1123 y1 = last_y + (last_y - last_quad_y);
1124 last_quad_x = x1;
1125 last_quad_y = y1;
1126 if (*command == 't') {
1127 x1 += last_x;
1128 y1 += last_y;
1129 x += last_x;
1130 y += last_y;
1131 }
1132 p[i++] = 1./3 * last_x + 2./3 * x1;
1133 p[i++] = 1./3 * last_y + 2./3 * y1;
1134 p[i++] = 2./3 * x1 + 1./3 * x;
1135 p[i++] = 2./3 * y1 + 1./3 * y;
1136 p[i++] = last_cubic_x = last_x = x;
1137 p[i++] = last_cubic_y = last_y = y;
1138 s += n;
1139 } while (sscanf(s, "%f %f %n",
1140 &x, &y, &n) == 2);
1141
1142 /* elliptical arc (A, a) (7 arguments) */
1143 } else if (sscanf(s, " %1[Aa] %f %f %f %f %f %f %f %n", command,
37
Assuming the condition is true
38
Taking true branch
1144 &rx, &ry, &rotation, &large_arc, &sweep,
1145 &x, &y, &n) == 8) {
1146 do {
1147 int bzsegments;
1148 double bzpoints[6*4]; /* allow for up to four bezier segments per arc */
1149
1150 if (*command == 'a') {
39
Assuming the condition is false
40
Taking false branch
1151 x += last_x;
1152 y += last_y;
1153 }
1154
1155 bzsegments = svgarc_to_bezier(last_x, last_y,
1156 x, y,
1157 rx, ry,
1158 rotation,
1159 large_arc,
1160 sweep,
1161 bzpoints);
1162 if (bzsegments == -1) {
41
Assuming the condition is false
42
Taking false branch
1163 /* draw a line */
1164 ALLOC_PATH_ELEMENTS(3)do { if ((palloc - i) < 3) { float *tp; palloc = (palloc *
2) + (palloc / 2); tp = realloc(p, sizeof p[0] * palloc); if
(tp == ((void*)0)) { free(p); free(path_d); svgtiny_cleanup_state_local
(&state); return svgtiny_OUT_OF_MEMORY; } p = tp; } } while
(0)
;
1165 p[i++] = svgtiny_PATH_LINE;
1166 p[i++] = x;
1167 p[i++] = y;
1168 } else if (bzsegments
42.1
'bzsegments' is <= 0
> 0) {
43
Taking false branch
1169 int bzpnt;
1170 ALLOC_PATH_ELEMENTS((unsigned int)bzsegments * 7)do { if ((palloc - i) < (unsigned int)bzsegments * 7) { float
*tp; palloc = (palloc * 2) + (palloc / 2); tp = realloc(p, sizeof
p[0] * palloc); if (tp == ((void*)0)) { free(p); free(path_d
); svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY
; } p = tp; } } while(0)
;
1171 for (bzpnt = 0;bzpnt < (bzsegments * 6); bzpnt+=6) {
1172 p[i++] = svgtiny_PATH_BEZIER;
1173 p[i++] = bzpoints[bzpnt];
1174 p[i++] = bzpoints[bzpnt+1];
1175 p[i++] = bzpoints[bzpnt+2];
1176 p[i++] = bzpoints[bzpnt+3];
1177 p[i++] = bzpoints[bzpnt+4];
1178 p[i++] = bzpoints[bzpnt+5];
1179 }
1180 }
1181 if (bzsegments != 0) {
44
Assuming 'bzsegments' is not equal to 0
45
Taking true branch
1182 last_cubic_x = last_quad_x = last_x = p[i-2];
46
Assigned value is garbage or undefined
1183 last_cubic_y = last_quad_y = last_y = p[i-1];
1184 }
1185
1186
1187 s += n;
1188 } while (sscanf(s, "%f %f %f %f %f %f %f %n",
1189 &rx, &ry, &rotation, &large_arc, &sweep,
1190 &x, &y, &n) == 7);
1191
1192 } else {
1193 /* fprintf(stderr, "parse failed at \"%s\"\n", s); */
1194 break;
1195 }
1196 }
1197
1198 free(path_d);
1199
1200 if (i <= 4) {
1201 /* no real segments in path */
1202 free(p);
1203 svgtiny_cleanup_state_local(&state);
1204 return svgtiny_OK;
1205 }
1206
1207 /* resize path element array to not be over allocated */
1208 if (palloc != i) {
1209 float *tp;
1210
1211 /* try the resize, if it fails just continue to use the old
1212 * allocation
1213 */
1214 tp = realloc(p, sizeof p[0] * i);
1215 if (tp != NULL((void*)0)) {
1216 p = tp;
1217 }
1218 }
1219
1220 err = svgtiny_add_path(p, i, &state);
1221
1222 svgtiny_cleanup_state_local(&state);
1223
1224 return err;
1225}
1226
1227
1228/**
1229 * Parse a <rect> element node.
1230 *
1231 * http://www.w3.org/TR/SVG11/shapes#RectElement
1232 */
1233
1234svgtiny_code svgtiny_parse_rect(dom_element *rect,
1235 struct svgtiny_parse_state state)
1236{
1237 svgtiny_code err;
1238 float x, y, width, height;
1239 float *p;
1240
1241 svgtiny_setup_state_local(&state);
1242
1243 svgtiny_parse_position_attributes(rect, state,
1244 &x, &y, &width, &height);
1245 svgtiny_parse_paint_attributes(rect, &state);
1246 svgtiny_parse_transform_attributes(rect, &state);
1247
1248 p = malloc(13 * sizeof p[0]);
1249 if (!p) {
1250 svgtiny_cleanup_state_local(&state);
1251 return svgtiny_OUT_OF_MEMORY;
1252 }
1253
1254 p[0] = svgtiny_PATH_MOVE;
1255 p[1] = x;
1256 p[2] = y;
1257 p[3] = svgtiny_PATH_LINE;
1258 p[4] = x + width;
1259 p[5] = y;
1260 p[6] = svgtiny_PATH_LINE;
1261 p[7] = x + width;
1262 p[8] = y + height;
1263 p[9] = svgtiny_PATH_LINE;
1264 p[10] = x;
1265 p[11] = y + height;
1266 p[12] = svgtiny_PATH_CLOSE;
1267
1268 err = svgtiny_add_path(p, 13, &state);
1269
1270 svgtiny_cleanup_state_local(&state);
1271
1272 return err;
1273}
1274
1275
1276/**
1277 * Parse a <circle> element node.
1278 */
1279
1280svgtiny_code svgtiny_parse_circle(dom_element *circle,
1281 struct svgtiny_parse_state state)
1282{
1283 svgtiny_code err;
1284 float x = 0, y = 0, r = -1;
1285 float *p;
1286 dom_string *attr;
1287 dom_exception exc;
1288
1289 svgtiny_setup_state_local(&state);
1290
1291 exc = dom_element_get_attribute(circle, state.interned_cx, &attr)dom_element_get_attribute( (dom_element *) (circle), (state.interned_cx
), (&attr))
;
1292 if (exc != DOM_NO_ERR) {
1293 svgtiny_cleanup_state_local(&state);
1294 return svgtiny_LIBDOM_ERROR;
1295 }
1296 if (attr != NULL((void*)0)) {
1297 x = svgtiny_parse_length(attr, state.viewport_width, state);
1298 }
1299 dom_string_unref(attr);
1300
1301 exc = dom_element_get_attribute(circle, state.interned_cy, &attr)dom_element_get_attribute( (dom_element *) (circle), (state.interned_cy
), (&attr))
;
1302 if (exc != DOM_NO_ERR) {
1303 svgtiny_cleanup_state_local(&state);
1304 return svgtiny_LIBDOM_ERROR;
1305 }
1306 if (attr != NULL((void*)0)) {
1307 y = svgtiny_parse_length(attr, state.viewport_height, state);
1308 }
1309 dom_string_unref(attr);
1310
1311 exc = dom_element_get_attribute(circle, state.interned_r, &attr)dom_element_get_attribute( (dom_element *) (circle), (state.interned_r
), (&attr))
;
1312 if (exc != DOM_NO_ERR) {
1313 svgtiny_cleanup_state_local(&state);
1314 return svgtiny_LIBDOM_ERROR;
1315 }
1316 if (attr != NULL((void*)0)) {
1317 r = svgtiny_parse_length(attr, state.viewport_width, state);
1318 }
1319 dom_string_unref(attr);
1320
1321 svgtiny_parse_paint_attributes(circle, &state);
1322 svgtiny_parse_transform_attributes(circle, &state);
1323
1324 if (r < 0) {
1325 state.diagram->error_line = -1; /* circle->line; */
1326 state.diagram->error_message = "circle: r missing or negative";
1327 svgtiny_cleanup_state_local(&state);
1328 return svgtiny_SVG_ERROR;
1329 }
1330 if (r == 0) {
1331 svgtiny_cleanup_state_local(&state);
1332 return svgtiny_OK;
1333 }
1334
1335 p = malloc(32 * sizeof p[0]);
1336 if (!p) {
1337 svgtiny_cleanup_state_local(&state);
1338 return svgtiny_OUT_OF_MEMORY;
1339 }
1340
1341 p[0] = svgtiny_PATH_MOVE;
1342 p[1] = x + r;
1343 p[2] = y;
1344 p[3] = svgtiny_PATH_BEZIER;
1345 p[4] = x + r;
1346 p[5] = y + r * KAPPA0.5522847498;
1347 p[6] = x + r * KAPPA0.5522847498;
1348 p[7] = y + r;
1349 p[8] = x;
1350 p[9] = y + r;
1351 p[10] = svgtiny_PATH_BEZIER;
1352 p[11] = x - r * KAPPA0.5522847498;
1353 p[12] = y + r;
1354 p[13] = x - r;
1355 p[14] = y + r * KAPPA0.5522847498;
1356 p[15] = x - r;
1357 p[16] = y;
1358 p[17] = svgtiny_PATH_BEZIER;
1359 p[18] = x - r;
1360 p[19] = y - r * KAPPA0.5522847498;
1361 p[20] = x - r * KAPPA0.5522847498;
1362 p[21] = y - r;
1363 p[22] = x;
1364 p[23] = y - r;
1365 p[24] = svgtiny_PATH_BEZIER;
1366 p[25] = x + r * KAPPA0.5522847498;
1367 p[26] = y - r;
1368 p[27] = x + r;
1369 p[28] = y - r * KAPPA0.5522847498;
1370 p[29] = x + r;
1371 p[30] = y;
1372 p[31] = svgtiny_PATH_CLOSE;
1373
1374 err = svgtiny_add_path(p, 32, &state);
1375
1376 svgtiny_cleanup_state_local(&state);
1377
1378 return err;
1379}
1380
1381
1382/**
1383 * Parse an <ellipse> element node.
1384 */
1385
1386svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
1387 struct svgtiny_parse_state state)
1388{
1389 svgtiny_code err;
1390 float x = 0, y = 0, rx = -1, ry = -1;
1391 float *p;
1392 dom_string *attr;
1393 dom_exception exc;
1394
1395 svgtiny_setup_state_local(&state);
1396
1397 exc = dom_element_get_attribute(ellipse, state.interned_cx, &attr)dom_element_get_attribute( (dom_element *) (ellipse), (state.
interned_cx), (&attr))
;
1398 if (exc != DOM_NO_ERR) {
1399 svgtiny_cleanup_state_local(&state);
1400 return svgtiny_LIBDOM_ERROR;
1401 }
1402 if (attr != NULL((void*)0)) {
1403 x = svgtiny_parse_length(attr, state.viewport_width, state);
1404 }
1405 dom_string_unref(attr);
1406
1407 exc = dom_element_get_attribute(ellipse, state.interned_cy, &attr)dom_element_get_attribute( (dom_element *) (ellipse), (state.
interned_cy), (&attr))
;
1408 if (exc != DOM_NO_ERR) {
1409 svgtiny_cleanup_state_local(&state);
1410 return svgtiny_LIBDOM_ERROR;
1411 }
1412 if (attr != NULL((void*)0)) {
1413 y = svgtiny_parse_length(attr, state.viewport_height, state);
1414 }
1415 dom_string_unref(attr);
1416
1417 exc = dom_element_get_attribute(ellipse, state.interned_rx, &attr)dom_element_get_attribute( (dom_element *) (ellipse), (state.
interned_rx), (&attr))
;
1418 if (exc != DOM_NO_ERR) {
1419 svgtiny_cleanup_state_local(&state);
1420 return svgtiny_LIBDOM_ERROR;
1421 }
1422 if (attr != NULL((void*)0)) {
1423 rx = svgtiny_parse_length(attr, state.viewport_width, state);
1424 }
1425 dom_string_unref(attr);
1426
1427 exc = dom_element_get_attribute(ellipse, state.interned_ry, &attr)dom_element_get_attribute( (dom_element *) (ellipse), (state.
interned_ry), (&attr))
;
1428 if (exc != DOM_NO_ERR) {
1429 svgtiny_cleanup_state_local(&state);
1430 return svgtiny_LIBDOM_ERROR;
1431 }
1432 if (attr != NULL((void*)0)) {
1433 ry = svgtiny_parse_length(attr, state.viewport_width, state);
1434 }
1435 dom_string_unref(attr);
1436
1437 svgtiny_parse_paint_attributes(ellipse, &state);
1438 svgtiny_parse_transform_attributes(ellipse, &state);
1439
1440 if (rx < 0 || ry < 0) {
1441 state.diagram->error_line = -1; /* ellipse->line; */
1442 state.diagram->error_message = "ellipse: rx or ry missing "
1443 "or negative";
1444 svgtiny_cleanup_state_local(&state);
1445 return svgtiny_SVG_ERROR;
1446 }
1447 if (rx == 0 || ry == 0) {
1448 svgtiny_cleanup_state_local(&state);
1449 return svgtiny_OK;
1450 }
1451
1452 p = malloc(32 * sizeof p[0]);
1453 if (!p) {
1454 svgtiny_cleanup_state_local(&state);
1455 return svgtiny_OUT_OF_MEMORY;
1456 }
1457
1458 p[0] = svgtiny_PATH_MOVE;
1459 p[1] = x + rx;
1460 p[2] = y;
1461 p[3] = svgtiny_PATH_BEZIER;
1462 p[4] = x + rx;
1463 p[5] = y + ry * KAPPA0.5522847498;
1464 p[6] = x + rx * KAPPA0.5522847498;
1465 p[7] = y + ry;
1466 p[8] = x;
1467 p[9] = y + ry;
1468 p[10] = svgtiny_PATH_BEZIER;
1469 p[11] = x - rx * KAPPA0.5522847498;
1470 p[12] = y + ry;
1471 p[13] = x - rx;
1472 p[14] = y + ry * KAPPA0.5522847498;
1473 p[15] = x - rx;
1474 p[16] = y;
1475 p[17] = svgtiny_PATH_BEZIER;
1476 p[18] = x - rx;
1477 p[19] = y - ry * KAPPA0.5522847498;
1478 p[20] = x - rx * KAPPA0.5522847498;
1479 p[21] = y - ry;
1480 p[22] = x;
1481 p[23] = y - ry;
1482 p[24] = svgtiny_PATH_BEZIER;
1483 p[25] = x + rx * KAPPA0.5522847498;
1484 p[26] = y - ry;
1485 p[27] = x + rx;
1486 p[28] = y - ry * KAPPA0.5522847498;
1487 p[29] = x + rx;
1488 p[30] = y;
1489 p[31] = svgtiny_PATH_CLOSE;
1490
1491 err = svgtiny_add_path(p, 32, &state);
1492
1493 svgtiny_cleanup_state_local(&state);
1494
1495 return err;
1496}
1497
1498
1499/**
1500 * Parse a <line> element node.
1501 */
1502
1503svgtiny_code svgtiny_parse_line(dom_element *line,
1504 struct svgtiny_parse_state state)
1505{
1506 svgtiny_code err;
1507 float x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1508 float *p;
1509 dom_string *attr;
1510 dom_exception exc;
1511
1512 svgtiny_setup_state_local(&state);
1513
1514 exc = dom_element_get_attribute(line, state.interned_x1, &attr)dom_element_get_attribute( (dom_element *) (line), (state.interned_x1
), (&attr))
;
1515 if (exc != DOM_NO_ERR) {
1516 svgtiny_cleanup_state_local(&state);
1517 return svgtiny_LIBDOM_ERROR;
1518 }
1519 if (attr != NULL((void*)0)) {
1520 x1 = svgtiny_parse_length(attr, state.viewport_width, state);
1521 }
1522 dom_string_unref(attr);
1523
1524 exc = dom_element_get_attribute(line, state.interned_y1, &attr)dom_element_get_attribute( (dom_element *) (line), (state.interned_y1
), (&attr))
;
1525 if (exc != DOM_NO_ERR) {
1526 svgtiny_cleanup_state_local(&state);
1527 return svgtiny_LIBDOM_ERROR;
1528 }
1529 if (attr != NULL((void*)0)) {
1530 y1 = svgtiny_parse_length(attr, state.viewport_height, state);
1531 }
1532 dom_string_unref(attr);
1533
1534 exc = dom_element_get_attribute(line, state.interned_x2, &attr)dom_element_get_attribute( (dom_element *) (line), (state.interned_x2
), (&attr))
;
1535 if (exc != DOM_NO_ERR) {
1536 svgtiny_cleanup_state_local(&state);
1537 return svgtiny_LIBDOM_ERROR;
1538 }
1539 if (attr != NULL((void*)0)) {
1540 x2 = svgtiny_parse_length(attr, state.viewport_width, state);
1541 }
1542 dom_string_unref(attr);
1543
1544 exc = dom_element_get_attribute(line, state.interned_y2, &attr)dom_element_get_attribute( (dom_element *) (line), (state.interned_y2
), (&attr))
;
1545 if (exc != DOM_NO_ERR) {
1546 svgtiny_cleanup_state_local(&state);
1547 return svgtiny_LIBDOM_ERROR;
1548 }
1549 if (attr != NULL((void*)0)) {
1550 y2 = svgtiny_parse_length(attr, state.viewport_height, state);
1551 }
1552 dom_string_unref(attr);
1553
1554 svgtiny_parse_paint_attributes(line, &state);
1555 svgtiny_parse_transform_attributes(line, &state);
1556
1557 p = malloc(7 * sizeof p[0]);
1558 if (!p) {
1559 svgtiny_cleanup_state_local(&state);
1560 return svgtiny_OUT_OF_MEMORY;
1561 }
1562
1563 p[0] = svgtiny_PATH_MOVE;
1564 p[1] = x1;
1565 p[2] = y1;
1566 p[3] = svgtiny_PATH_LINE;
1567 p[4] = x2;
1568 p[5] = y2;
1569 p[6] = svgtiny_PATH_CLOSE;
1570
1571 err = svgtiny_add_path(p, 7, &state);
1572
1573 svgtiny_cleanup_state_local(&state);
1574
1575 return err;
1576}
1577
1578
1579/**
1580 * Parse a <polyline> or <polygon> element node.
1581 *
1582 * http://www.w3.org/TR/SVG11/shapes#PolylineElement
1583 * http://www.w3.org/TR/SVG11/shapes#PolygonElement
1584 */
1585
1586svgtiny_code svgtiny_parse_poly(dom_element *poly,
1587 struct svgtiny_parse_state state, bool_Bool polygon)
1588{
1589 svgtiny_code err;
1590 dom_string *points_str;
1591 dom_exception exc;
1592 char *s, *points;
1593 float *p;
1594 unsigned int i;
1595
1596 svgtiny_setup_state_local(&state);
1597
1598 svgtiny_parse_paint_attributes(poly, &state);
1599 svgtiny_parse_transform_attributes(poly, &state);
1600
1601 exc = dom_element_get_attribute(poly, state.interned_points,dom_element_get_attribute( (dom_element *) (poly), (state.interned_points
), (&points_str))
1602 &points_str)dom_element_get_attribute( (dom_element *) (poly), (state.interned_points
), (&points_str))
;
1603 if (exc != DOM_NO_ERR) {
1604 svgtiny_cleanup_state_local(&state);
1605 return svgtiny_LIBDOM_ERROR;
1606 }
1607
1608 if (points_str == NULL((void*)0)) {
1609 state.diagram->error_line = -1; /* poly->line; */
1610 state.diagram->error_message =
1611 "polyline/polygon: missing points attribute";
1612 svgtiny_cleanup_state_local(&state);
1613 return svgtiny_SVG_ERROR;
1614 }
1615
1616 s = points = strndup(dom_string_data(points_str),
1617 dom_string_byte_length(points_str));
1618 dom_string_unref(points_str);
1619 /* read points attribute */
1620 if (s == NULL((void*)0)) {
1621 svgtiny_cleanup_state_local(&state);
1622 return svgtiny_OUT_OF_MEMORY;
1623 }
1624 /* allocate space for path: it will never have more elements than s */
1625 p = malloc(sizeof p[0] * strlen(s));
1626 if (!p) {
1627 free(points);
1628 svgtiny_cleanup_state_local(&state);
1629 return svgtiny_OUT_OF_MEMORY;
1630 }
1631
1632 /* parse s and build path */
1633 for (i = 0; s[i]; i++)
1634 if (s[i] == ',')
1635 s[i] = ' ';
1636 i = 0;
1637 while (*s) {
1638 float x, y;
1639 int n;
1640
1641 if (sscanf(s, "%f %f %n", &x, &y, &n) == 2) {
1642 if (i == 0)
1643 p[i++] = svgtiny_PATH_MOVE;
1644 else
1645 p[i++] = svgtiny_PATH_LINE;
1646 p[i++] = x;
1647 p[i++] = y;
1648 s += n;
1649 } else {
1650 break;
1651 }
1652 }
1653 if (polygon)
1654 p[i++] = svgtiny_PATH_CLOSE;
1655
1656 free(points);
1657
1658 err = svgtiny_add_path(p, i, &state);
1659
1660 svgtiny_cleanup_state_local(&state);
1661
1662 return err;
1663}
1664
1665
1666/**
1667 * Parse a <text> or <tspan> element node.
1668 */
1669
1670svgtiny_code svgtiny_parse_text(dom_element *text,
1671 struct svgtiny_parse_state state)
1672{
1673 float x, y, width, height;
1674 float px, py;
1675 dom_node *child;
1676 dom_exception exc;
1677
1678 svgtiny_setup_state_local(&state);
1679
1680 svgtiny_parse_position_attributes(text, state,
1681 &x, &y, &width, &height);
1682 svgtiny_parse_font_attributes(text, &state);
1683 svgtiny_parse_transform_attributes(text, &state);
1684
1685 px = state.ctm.a * x + state.ctm.c * y + state.ctm.e;
1686 py = state.ctm.b * x + state.ctm.d * y + state.ctm.f;
1687/* state.ctm.e = px - state.origin_x; */
1688/* state.ctm.f = py - state.origin_y; */
1689
1690 /*struct css_style style = state.style;
1691 style.font_size.value.length.value *= state.ctm.a;*/
1692
1693 exc = dom_node_get_first_child(text, &child)dom_node_get_first_child( (dom_node *) (text), (dom_node **) (
&child))
;
1694 if (exc != DOM_NO_ERR) {
1695 return svgtiny_LIBDOM_ERROR;
1696 svgtiny_cleanup_state_local(&state);
1697 }
1698 while (child != NULL((void*)0)) {
1699 dom_node *next;
1700 dom_node_type nodetype;
1701 svgtiny_code code = svgtiny_OK;
1702
1703 exc = dom_node_get_node_type(child, &nodetype)dom_node_get_node_type( (dom_node *) (child), (dom_node_type *
) (&nodetype))
;
1704 if (exc != DOM_NO_ERR) {
1705 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1706 svgtiny_cleanup_state_local(&state);
1707 return svgtiny_LIBDOM_ERROR;
1708 }
1709 if (nodetype == DOM_ELEMENT_NODE) {
1710 dom_string *nodename;
1711 exc = dom_node_get_node_name(child, &nodename)dom_node_get_node_name((dom_node *) (child), (&nodename));
1712 if (exc != DOM_NO_ERR) {
1713 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1714 svgtiny_cleanup_state_local(&state);
1715 return svgtiny_LIBDOM_ERROR;
1716 }
1717 if (dom_string_caseless_isequal(nodename,
1718 state.interned_tspan))
1719 code = svgtiny_parse_text((dom_element *)child,
1720 state);
1721 dom_string_unref(nodename);
1722 } else if (nodetype == DOM_TEXT_NODE) {
1723 struct svgtiny_shape *shape = svgtiny_add_shape(&state);
1724 dom_string *content;
1725 if (shape == NULL((void*)0)) {
1726 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1727 svgtiny_cleanup_state_local(&state);
1728 return svgtiny_OUT_OF_MEMORY;
1729 }
1730 exc = dom_text_get_whole_text(child, &content)dom_text_get_whole_text((dom_text *) (child), (&content));
1731 if (exc != DOM_NO_ERR) {
1732 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1733 svgtiny_cleanup_state_local(&state);
1734 return svgtiny_LIBDOM_ERROR;
1735 }
1736 if (content != NULL((void*)0)) {
1737 shape->text = strndup(dom_string_data(content),
1738 dom_string_byte_length(content));
1739 dom_string_unref(content);
1740 } else {
1741 shape->text = strdup("");
1742 }
1743 shape->text_x = px;
1744 shape->text_y = py;
1745 state.diagram->shape_count++;
1746 }
1747
1748 if (code != svgtiny_OK) {
1749 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1750 svgtiny_cleanup_state_local(&state);
1751 return code;
1752 }
1753 exc = dom_node_get_next_sibling(child, &next)dom_node_get_next_sibling( (dom_node *) (child), (dom_node **
) (&next))
;
1754 dom_node_unref(child)dom_node_unref((dom_node *) (child));
1755 if (exc != DOM_NO_ERR) {
1756 svgtiny_cleanup_state_local(&state);
1757 return svgtiny_LIBDOM_ERROR;
1758 }
1759 child = next;
1760 }
1761
1762 svgtiny_cleanup_state_local(&state);
1763
1764 return svgtiny_OK;
1765}
1766
1767
1768/**
1769 * Parse x, y, width, and height attributes, if present.
1770 */
1771
1772void svgtiny_parse_position_attributes(dom_element *node,
1773 const struct svgtiny_parse_state state,
1774 float *x, float *y, float *width, float *height)
1775{
1776 dom_string *attr;
1777 dom_exception exc;
1778
1779 *x = 0;
1780 *y = 0;
1781 *width = state.viewport_width;
1782 *height = state.viewport_height;
1783
1784 exc = dom_element_get_attribute(node, state.interned_x, &attr)dom_element_get_attribute( (dom_element *) (node), (state.interned_x
), (&attr))
;
1785 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1786 *x = svgtiny_parse_length(attr, state.viewport_width, state);
1787 dom_string_unref(attr);
1788 }
1789
1790 exc = dom_element_get_attribute(node, state.interned_y, &attr)dom_element_get_attribute( (dom_element *) (node), (state.interned_y
), (&attr))
;
1791 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1792 *y = svgtiny_parse_length(attr, state.viewport_height, state);
1793 dom_string_unref(attr);
1794 }
1795
1796 exc = dom_element_get_attribute(node, state.interned_width, &attr)dom_element_get_attribute( (dom_element *) (node), (state.interned_width
), (&attr))
;
1797 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1798 *width = svgtiny_parse_length(attr, state.viewport_width,
1799 state);
1800 dom_string_unref(attr);
1801 }
1802
1803 exc = dom_element_get_attribute(node, state.interned_height, &attr)dom_element_get_attribute( (dom_element *) (node), (state.interned_height
), (&attr))
;
1804 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1805 *height = svgtiny_parse_length(attr, state.viewport_height,
1806 state);
1807 dom_string_unref(attr);
1808 }
1809}
1810
1811
1812/**
1813 * Parse a length as a number of pixels.
1814 */
1815
1816static float _svgtiny_parse_length(const char *s, int viewport_size,
1817 const struct svgtiny_parse_state state)
1818{
1819 int num_length = strspn(s, "0123456789+-.");
1820 const char *unit = s + num_length;
1821 float n = atof((const char *) s);
1822 float font_size = 20; /*css_len2px(&state.style.font_size.value.length, 0);*/
1823
1824 UNUSED(state)((void) (state));
1825
1826 if (unit[0] == 0) {
1827 return n;
1828 } else if (unit[0] == '%') {
1829 return n / 100.0 * viewport_size;
1830 } else if (unit[0] == 'e' && unit[1] == 'm') {
1831 return n * font_size;
1832 } else if (unit[0] == 'e' && unit[1] == 'x') {
1833 return n / 2.0 * font_size;
1834 } else if (unit[0] == 'p' && unit[1] == 'x') {
1835 return n;
1836 } else if (unit[0] == 'p' && unit[1] == 't') {
1837 return n * 1.25;
1838 } else if (unit[0] == 'p' && unit[1] == 'c') {
1839 return n * 15.0;
1840 } else if (unit[0] == 'm' && unit[1] == 'm') {
1841 return n * 3.543307;
1842 } else if (unit[0] == 'c' && unit[1] == 'm') {
1843 return n * 35.43307;
1844 } else if (unit[0] == 'i' && unit[1] == 'n') {
1845 return n * 90;
1846 }
1847
1848 return 0;
1849}
1850
1851float svgtiny_parse_length(dom_string *s, int viewport_size,
1852 const struct svgtiny_parse_state state)
1853{
1854 char *ss = strndup(dom_string_data(s), dom_string_byte_length(s));
1855 float ret = _svgtiny_parse_length(ss, viewport_size, state);
1856 free(ss);
1857 return ret;
1858}
1859
1860/**
1861 * Parse paint attributes, if present.
1862 */
1863
1864void svgtiny_parse_paint_attributes(dom_element *node,
1865 struct svgtiny_parse_state *state)
1866{
1867 dom_string *attr;
1868 dom_exception exc;
1869
1870 exc = dom_element_get_attribute(node, state->interned_fill, &attr)dom_element_get_attribute( (dom_element *) (node), (state->
interned_fill), (&attr))
;
1871 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1872 svgtiny_parse_color(attr, &state->fill, &state->fill_grad, state);
1873 dom_string_unref(attr);
1874 }
1875
1876 exc = dom_element_get_attribute(node, state->interned_stroke, &attr)dom_element_get_attribute( (dom_element *) (node), (state->
interned_stroke), (&attr))
;
1877 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1878 svgtiny_parse_color(attr, &state->stroke, &state->stroke_grad, state);
1879 dom_string_unref(attr);
1880 }
1881
1882 exc = dom_element_get_attribute(node, state->interned_stroke_width, &attr)dom_element_get_attribute( (dom_element *) (node), (state->
interned_stroke_width), (&attr))
;
1883 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1884 state->stroke_width = svgtiny_parse_length(attr,
1885 state->viewport_width, *state);
1886 dom_string_unref(attr);
1887 }
1888
1889 exc = dom_element_get_attribute(node, state->interned_style, &attr)dom_element_get_attribute( (dom_element *) (node), (state->
interned_style), (&attr))
;
1890 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
1891 char *style = strndup(dom_string_data(attr),
1892 dom_string_byte_length(attr));
1893 const char *s;
1894 char *value;
1895 if ((s = strstr(style, "fill:"))) {
1896 s += 5;
1897 while (*s == ' ')
1898 s++;
1899 value = strndup(s, strcspn(s, "; "));
1900 _svgtiny_parse_color(value, &state->fill, &state->fill_grad, state);
1901 free(value);
1902 }
1903 if ((s = strstr(style, "stroke:"))) {
1904 s += 7;
1905 while (*s == ' ')
1906 s++;
1907 value = strndup(s, strcspn(s, "; "));
1908 _svgtiny_parse_color(value, &state->stroke, &state->stroke_grad, state);
1909 free(value);
1910 }
1911 if ((s = strstr(style, "stroke-width:"))) {
1912 s += 13;
1913 while (*s == ' ')
1914 s++;
1915 value = strndup(s, strcspn(s, "; "));
1916 state->stroke_width = _svgtiny_parse_length(value,
1917 state->viewport_width, *state);
1918 free(value);
1919 }
1920 free(style);
1921 dom_string_unref(attr);
1922 }
1923}
1924
1925
1926/**
1927 * Parse a colour.
1928 */
1929
1930static void _svgtiny_parse_color(const char *s, svgtiny_colour *c,
1931 struct svgtiny_parse_state_gradient *grad,
1932 struct svgtiny_parse_state *state)
1933{
1934 unsigned int r, g, b;
1935 float rf, gf, bf;
1936 size_t len = strlen(s);
1937 char *id = 0, *rparen;
1938
1939 if (len == 4 && s[0] == '#') {
1940 if (sscanf(s + 1, "%1x%1x%1x", &r, &g, &b) == 3)
1941 *c = svgtiny_RGB(r | r << 4, g | g << 4, b | b << 4)((r | r << 4) << 16 | (g | g << 4) <<
8 | (b | b << 4))
;
1942
1943 } else if (len == 7 && s[0] == '#') {
1944 if (sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3)
1945 *c = svgtiny_RGB(r, g, b)((r) << 16 | (g) << 8 | (b));
1946
1947 } else if (10 <= len && s[0] == 'r' && s[1] == 'g' && s[2] == 'b' &&
1948 s[3] == '(' && s[len - 1] == ')') {
1949 if (sscanf(s + 4, "%u,%u,%u", &r, &g, &b) == 3)
1950 *c = svgtiny_RGB(r, g, b)((r) << 16 | (g) << 8 | (b));
1951 else if (sscanf(s + 4, "%f%%,%f%%,%f%%", &rf, &gf, &bf) == 3) {
1952 b = bf * 255 / 100;
1953 g = gf * 255 / 100;
1954 r = rf * 255 / 100;
1955 *c = svgtiny_RGB(r, g, b)((r) << 16 | (g) << 8 | (b));
1956 }
1957
1958 } else if (len == 4 && strcmp(s, "none") == 0) {
1959 *c = svgtiny_TRANSPARENT0x1000000;
1960
1961 } else if (5 < len && s[0] == 'u' && s[1] == 'r' && s[2] == 'l' &&
1962 s[3] == '(') {
1963 if (grad == NULL((void*)0)) {
1964 *c = svgtiny_RGB(0, 0, 0)((0) << 16 | (0) << 8 | (0));
1965 } else if (s[4] == '#') {
1966 id = strdup(s + 5);
1967 if (!id)
1968 return;
1969 rparen = strchr(id, ')');
1970 if (rparen)
1971 *rparen = 0;
1972 svgtiny_find_gradient(id, grad, state);
1973 free(id);
1974 if (grad->linear_gradient_stop_count == 0)
1975 *c = svgtiny_TRANSPARENT0x1000000;
1976 else if (grad->linear_gradient_stop_count == 1)
1977 *c = grad->gradient_stop[0].color;
1978 else
1979 *c = svgtiny_LINEAR_GRADIENT0x2000000;
1980 }
1981
1982 } else {
1983 const struct svgtiny_named_color *named_color;
1984 named_color = svgtiny_color_lookup(s, strlen(s));
1985 if (named_color)
1986 *c = named_color->color;
1987 }
1988}
1989
1990void svgtiny_parse_color(dom_string *s, svgtiny_colour *c,
1991 struct svgtiny_parse_state_gradient *grad,
1992 struct svgtiny_parse_state *state)
1993{
1994 dom_string_ref(s);
1995 _svgtiny_parse_color(dom_string_data(s), c, grad, state);
1996 dom_string_unref(s);
1997}
1998
1999/**
2000 * Parse font attributes, if present.
2001 */
2002
2003void svgtiny_parse_font_attributes(dom_element *node,
2004 struct svgtiny_parse_state *state)
2005{
2006 /* TODO: Implement this, it never used to be */
2007 UNUSED(node)((void) (node));
2008 UNUSED(state)((void) (state));
2009#ifdef WRITTEN_THIS_PROPERLY
2010 const xmlAttr *attr;
2011
2012 UNUSED(state)((void) (state));
2013
2014 for (attr = node->properties; attr; attr = attr->next) {
2015 if (strcmp((const char *) attr->name, "font-size") == 0) {
2016 /*if (css_parse_length(
2017 (const char *) attr->children->content,
2018 &state->style.font_size.value.length,
2019 true, true)) {
2020 state->style.font_size.size =
2021 CSS_FONT_SIZE_LENGTH;
2022 }*/
2023 }
2024 }
2025#endif
2026}
2027
2028
2029/**
2030 * Parse transform attributes, if present.
2031 *
2032 * http://www.w3.org/TR/SVG11/coords#TransformAttribute
2033 */
2034
2035void svgtiny_parse_transform_attributes(dom_element *node,
2036 struct svgtiny_parse_state *state)
2037{
2038 char *transform;
2039 dom_string *attr;
2040 dom_exception exc;
2041
2042 exc = dom_element_get_attribute(node, state->interned_transform,dom_element_get_attribute( (dom_element *) (node), (state->
interned_transform), (&attr))
2043 &attr)dom_element_get_attribute( (dom_element *) (node), (state->
interned_transform), (&attr))
;
2044 if (exc == DOM_NO_ERR && attr != NULL((void*)0)) {
2045 transform = strndup(dom_string_data(attr),
2046 dom_string_byte_length(attr));
2047 svgtiny_parse_transform(transform, &state->ctm.a, &state->ctm.b,
2048 &state->ctm.c, &state->ctm.d,
2049 &state->ctm.e, &state->ctm.f);
2050 free(transform);
2051 dom_string_unref(attr);
2052 }
2053}
2054
2055
2056/**
2057 * Parse a transform string.
2058 */
2059
2060void svgtiny_parse_transform(char *s, float *ma, float *mb,
2061 float *mc, float *md, float *me, float *mf)
2062{
2063 float a, b, c, d, e, f;
2064 float za, zb, zc, zd, ze, zf;
2065 float angle, x, y;
2066 int n;
2067 unsigned int i;
2068
2069 for (i = 0; s[i]; i++)
2070 if (s[i] == ',')
2071 s[i] = ' ';
2072
2073 while (*s) {
2074 a = d = 1;
2075 b = c = 0;
2076 e = f = 0;
2077 n = 0;
2078 if ((sscanf(s, " matrix (%f %f %f %f %f %f ) %n",
2079 &a, &b, &c, &d, &e, &f, &n) == 6) && (n > 0))
2080 ;
2081 else if ((sscanf(s, " translate (%f %f ) %n",
2082 &e, &f, &n) == 2) && (n > 0))
2083 ;
2084 else if ((sscanf(s, " translate (%f ) %n",
2085 &e, &n) == 1) && (n > 0))
2086 ;
2087 else if ((sscanf(s, " scale (%f %f ) %n",
2088 &a, &d, &n) == 2) && (n > 0))
2089 ;
2090 else if ((sscanf(s, " scale (%f ) %n",
2091 &a, &n) == 1) && (n > 0))
2092 d = a;
2093 else if ((sscanf(s, " rotate (%f %f %f ) %n",
2094 &angle, &x, &y, &n) == 3) && (n > 0)) {
2095 angle = angle / 180 * M_PI3.14159265358979323846;
2096 a = cos(angle);
2097 b = sin(angle);
2098 c = -sin(angle);
2099 d = cos(angle);
2100 e = -x * cos(angle) + y * sin(angle) + x;
2101 f = -x * sin(angle) - y * cos(angle) + y;
2102 } else if ((sscanf(s, " rotate (%f ) %n",
2103 &angle, &n) == 1) && (n > 0)) {
2104 angle = angle / 180 * M_PI3.14159265358979323846;
2105 a = cos(angle);
2106 b = sin(angle);
2107 c = -sin(angle);
2108 d = cos(angle);
2109 } else if ((sscanf(s, " skewX (%f ) %n",
2110 &angle, &n) == 1) && (n > 0)) {
2111 angle = angle / 180 * M_PI3.14159265358979323846;
2112 c = tan(angle);
2113 } else if ((sscanf(s, " skewY (%f ) %n",
2114 &angle, &n) == 1) && (n > 0)) {
2115 angle = angle / 180 * M_PI3.14159265358979323846;
2116 b = tan(angle);
2117 } else
2118 break;
2119 za = *ma * a + *mc * b;
2120 zb = *mb * a + *md * b;
2121 zc = *ma * c + *mc * d;
2122 zd = *mb * c + *md * d;
2123 ze = *ma * e + *mc * f + *me;
2124 zf = *mb * e + *md * f + *mf;
2125 *ma = za;
2126 *mb = zb;
2127 *mc = zc;
2128 *md = zd;
2129 *me = ze;
2130 *mf = zf;
2131 s += n;
2132 }
2133}
2134
2135
2136/**
2137 * Add a path to the svgtiny_diagram.
2138 */
2139
2140svgtiny_code svgtiny_add_path(float *p, unsigned int n,
2141 struct svgtiny_parse_state *state)
2142{
2143 struct svgtiny_shape *shape;
2144
2145 if (state->fill == svgtiny_LINEAR_GRADIENT0x2000000)
2146 return svgtiny_add_path_linear_gradient(p, n, state);
2147
2148 svgtiny_transform_path(p, n, state);
2149
2150 shape = svgtiny_add_shape(state);
2151 if (!shape) {
2152 free(p);
2153 return svgtiny_OUT_OF_MEMORY;
2154 }
2155 shape->path = p;
2156 shape->path_length = n;
2157 state->diagram->shape_count++;
2158
2159 return svgtiny_OK;
2160}
2161
2162
2163/**
2164 * Add a svgtiny_shape to the svgtiny_diagram.
2165 */
2166
2167struct svgtiny_shape *svgtiny_add_shape(struct svgtiny_parse_state *state)
2168{
2169 struct svgtiny_shape *shape = realloc(state->diagram->shape,
2170 (state->diagram->shape_count + 1) *
2171 sizeof (state->diagram->shape[0]));
2172 if (!shape)
2173 return 0;
2174 state->diagram->shape = shape;
2175
2176 shape += state->diagram->shape_count;
2177 shape->path = 0;
2178 shape->path_length = 0;
2179 shape->text = 0;
2180 shape->fill = state->fill;
2181 shape->stroke = state->stroke;
2182 shape->stroke_width = lroundf((float) state->stroke_width *
2183 (state->ctm.a + state->ctm.d) / 2.0);
2184 if (0 < state->stroke_width && shape->stroke_width == 0)
2185 shape->stroke_width = 1;
2186
2187 return shape;
2188}
2189
2190
2191/**
2192 * Apply the current transformation matrix to a path.
2193 */
2194
2195void svgtiny_transform_path(float *p, unsigned int n,
2196 struct svgtiny_parse_state *state)
2197{
2198 unsigned int j;
2199
2200 for (j = 0; j != n; ) {
2201 unsigned int points = 0;
2202 unsigned int k;
2203 switch ((int) p[j]) {
2204 case svgtiny_PATH_MOVE:
2205 case svgtiny_PATH_LINE:
2206 points = 1;
2207 break;
2208 case svgtiny_PATH_CLOSE:
2209 points = 0;
2210 break;
2211 case svgtiny_PATH_BEZIER:
2212 points = 3;
2213 break;
2214 default:
2215 assert(0)((0) ? (void) (0) : __assert_fail ("0", "src/svgtiny.c", 2215
, __extension__ __PRETTY_FUNCTION__))
;
2216 }
2217 j++;
2218 for (k = 0; k != points; k++) {
2219 float x0 = p[j], y0 = p[j + 1];
2220 float x = state->ctm.a * x0 + state->ctm.c * y0 +
2221 state->ctm.e;
2222 float y = state->ctm.b * x0 + state->ctm.d * y0 +
2223 state->ctm.f;
2224 p[j] = x;
2225 p[j + 1] = y;
2226 j += 2;
2227 }
2228 }
2229}
2230
2231
2232/**
2233 * Free all memory used by a diagram.
2234 */
2235
2236void svgtiny_free(struct svgtiny_diagram *svg)
2237{
2238 unsigned int i;
2239 assert(svg)((svg) ? (void) (0) : __assert_fail ("svg", "src/svgtiny.c", 2239
, __extension__ __PRETTY_FUNCTION__))
;
2240
2241 for (i = 0; i != svg->shape_count; i++) {
2242 free(svg->shape[i].path);
2243 free(svg->shape[i].text);
2244 }
2245
2246 free(svg->shape);
2247
2248 free(svg);
2249}
2250
2251#ifndef HAVE_STRNDUP
2252char *svgtiny_strndup(const char *s, size_t n)
2253{
2254 size_t len;
2255 char *s2;
2256
2257 for (len = 0; len != n && s[len]; len++)
2258 continue;
2259
2260 s2 = malloc(len + 1);
2261 if (s2 == NULL((void*)0))
2262 return NULL((void*)0);
2263
2264 memcpy(s2, s, len);
2265 s2[len] = '\0';
2266
2267 return s2;
2268}
2269#endif