1 | #include "mupdf/fitz.h" |
2 | #include "svg-imp.h" |
3 | |
4 | #include <string.h> |
5 | #include <math.h> |
6 | |
7 | int svg_is_whitespace_or_comma(int c) |
8 | { |
9 | return (c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA) || (c == ','); |
10 | } |
11 | |
12 | int svg_is_whitespace(int c) |
13 | { |
14 | return (c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA); |
15 | } |
16 | |
17 | int svg_is_alpha(int c) |
18 | { |
19 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); |
20 | } |
21 | |
22 | int svg_is_digit(int c) |
23 | { |
24 | return (c >= '0' && c <= '9') || |
25 | (c == 'e') || (c == 'E') || |
26 | (c == '+') || (c == '-') || (c == '.'); |
27 | } |
28 | |
29 | const char * |
30 | svg_lex_number(float *fp, const char *ss) |
31 | { |
32 | const char *s = ss; |
33 | if (*s == '-') |
34 | ++s; |
35 | while (*s >= '0' && *s <= '9') |
36 | ++s; |
37 | if (*s == '.') { |
38 | ++s; |
39 | while (*s >= '0' && *s <= '9') |
40 | ++s; |
41 | } |
42 | if (*s == 'e' || *s == 'E') { |
43 | ++s; |
44 | if (*s == '+' || *s == '-') |
45 | ++s; |
46 | while (*s >= '0' && *s <= '9') |
47 | ++s; |
48 | } |
49 | *fp = fz_atof(ss); |
50 | return s; |
51 | } |
52 | |
53 | float |
54 | svg_parse_number(const char *str, float min, float max, float inherit) |
55 | { |
56 | float x; |
57 | if (!strcmp(str, "inherit" )) |
58 | return inherit; |
59 | x = fz_atof(str); |
60 | if (x < min) return min; |
61 | if (x > max) return max; |
62 | return x; |
63 | } |
64 | |
65 | /* Return length/coordinate in points */ |
66 | float |
67 | svg_parse_length(const char *str, float percent, float font_size) |
68 | { |
69 | char *end; |
70 | float val; |
71 | |
72 | val = fz_strtof(str, &end); |
73 | if (end == str) |
74 | return 0; /* failed */ |
75 | |
76 | if (!strcmp(end, "px" )) return val; |
77 | |
78 | if (!strcmp(end, "pt" )) return val * 1.0f; |
79 | if (!strcmp(end, "pc" )) return val * 12.0f; |
80 | if (!strcmp(end, "mm" )) return val * 2.83464567f; |
81 | if (!strcmp(end, "cm" )) return val * 28.3464567f; |
82 | if (!strcmp(end, "in" )) return val * 72.0f; |
83 | |
84 | if (!strcmp(end, "em" )) return val * font_size; |
85 | if (!strcmp(end, "ex" )) return val * font_size * 0.5f; |
86 | |
87 | if (!strcmp(end, "%" )) |
88 | return val * percent * 0.01f; |
89 | |
90 | if (end[0] == 0) |
91 | return val; |
92 | |
93 | return 0; |
94 | } |
95 | |
96 | /* Return angle in degrees */ |
97 | float |
98 | svg_parse_angle(const char *str) |
99 | { |
100 | char *end; |
101 | float val; |
102 | |
103 | val = fz_strtof(str, &end); |
104 | if (end == str) |
105 | return 0; /* failed */ |
106 | |
107 | if (!strcmp(end, "deg" )) |
108 | return val; |
109 | |
110 | if (!strcmp(end, "grad" )) |
111 | return val * 0.9f; |
112 | |
113 | if (!strcmp(end, "rad" )) |
114 | return val * FZ_RADIAN; |
115 | |
116 | return val; |
117 | } |
118 | |
119 | /* Coordinate transformations */ |
120 | fz_matrix |
121 | svg_parse_transform(fz_context *ctx, svg_document *doc, const char *str, fz_matrix transform) |
122 | { |
123 | char keyword[20]; |
124 | int keywordlen; |
125 | float args[6]; |
126 | int nargs; |
127 | |
128 | nargs = 0; |
129 | keywordlen = 0; |
130 | |
131 | while (*str) |
132 | { |
133 | while (svg_is_whitespace_or_comma(*str)) |
134 | str ++; |
135 | if (*str == 0) |
136 | break; |
137 | |
138 | /* |
139 | * Parse keyword and opening parenthesis. |
140 | */ |
141 | |
142 | keywordlen = 0; |
143 | while (svg_is_alpha(*str) && keywordlen < sizeof(keyword) - 1) |
144 | keyword[keywordlen++] = *str++; |
145 | keyword[keywordlen] = 0; |
146 | |
147 | if (keywordlen == 0) |
148 | fz_throw(ctx, FZ_ERROR_SYNTAX, "expected keyword in transform attribute" ); |
149 | |
150 | while (svg_is_whitespace(*str)) |
151 | str ++; |
152 | |
153 | if (*str != '(') |
154 | fz_throw(ctx, FZ_ERROR_SYNTAX, "expected opening parenthesis in transform attribute" ); |
155 | str ++; |
156 | |
157 | /* |
158 | * Parse list of numbers until closing parenthesis |
159 | */ |
160 | |
161 | nargs = 0; |
162 | while (*str && *str != ')' && nargs < 6) |
163 | { |
164 | while (svg_is_whitespace_or_comma(*str)) |
165 | str ++; |
166 | if (svg_is_digit(*str)) |
167 | str = svg_lex_number(&args[nargs++], str); |
168 | else |
169 | break; |
170 | } |
171 | |
172 | if (*str != ')') |
173 | fz_throw(ctx, FZ_ERROR_SYNTAX, "expected closing parenthesis in transform attribute" ); |
174 | str ++; |
175 | |
176 | /* |
177 | * Execute the transform. |
178 | */ |
179 | |
180 | if (!strcmp(keyword, "matrix" )) |
181 | { |
182 | if (nargs != 6) |
183 | fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to matrix(): %d" , nargs); |
184 | transform = fz_concat(fz_make_matrix(args[0], args[1], args[2], args[3], args[4], args[5]), transform); |
185 | } |
186 | |
187 | else if (!strcmp(keyword, "translate" )) |
188 | { |
189 | if (nargs != 2) |
190 | fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to translate(): %d" , nargs); |
191 | transform = fz_concat(fz_translate(args[0], args[1]), transform); |
192 | } |
193 | |
194 | else if (!strcmp(keyword, "scale" )) |
195 | { |
196 | if (nargs == 1) |
197 | transform = fz_concat(fz_scale(args[0], args[0]), transform); |
198 | else if (nargs == 2) |
199 | transform = fz_concat(fz_scale(args[0], args[1]), transform); |
200 | else |
201 | fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to scale(): %d" , nargs); |
202 | } |
203 | |
204 | else if (!strcmp(keyword, "rotate" )) |
205 | { |
206 | if (nargs != 1) |
207 | fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to rotate(): %d" , nargs); |
208 | transform = fz_concat(fz_rotate(args[0]), transform); |
209 | } |
210 | |
211 | else if (!strcmp(keyword, "skewX" )) |
212 | { |
213 | if (nargs != 1) |
214 | fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to skewX(): %d" , nargs); |
215 | transform = fz_concat(fz_make_matrix(1, 0, tanf(args[0] * FZ_DEGREE), 1, 0, 0), transform); |
216 | } |
217 | |
218 | else if (!strcmp(keyword, "skewY" )) |
219 | { |
220 | if (nargs != 1) |
221 | fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to skewY(): %d" , nargs); |
222 | transform = fz_concat(fz_make_matrix(1, tanf(args[0] * FZ_DEGREE), 0, 1, 0, 0), transform); |
223 | } |
224 | |
225 | else |
226 | { |
227 | fz_throw(ctx, FZ_ERROR_SYNTAX, "unknown transform function: %s" , keyword); |
228 | } |
229 | } |
230 | |
231 | return transform; |
232 | } |
233 | |