/src/ghostpdl/devices/vector/gdevpsfx.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Convert Type 1 Charstrings to Type 2 */ |
18 | | #include "math_.h" |
19 | | #include "memory_.h" |
20 | | #include "gx.h" |
21 | | #include "gserrors.h" |
22 | | #include "gxfixed.h" |
23 | | #include "gxmatrix.h" /* for gsfont.h */ |
24 | | #include "gxfont.h" |
25 | | #include "gxfont1.h" |
26 | | #include "gxtype1.h" |
27 | | #include "stream.h" |
28 | | #include "gdevpsf.h" |
29 | | #include "gxgstate.h" |
30 | | |
31 | | /* ------ Type 1 Charstring parsing ------ */ |
32 | | |
33 | | /* |
34 | | * The parsing code handles numbers on its own; it reports callsubr and |
35 | | * return operators to the caller, but also executes them. |
36 | | * |
37 | | * Only the following elements of the Type 1 state are used: |
38 | | * ostack, os_count, ipstack, ips_count |
39 | | */ |
40 | | |
41 | 22.9M | #define CE_OFFSET 32 /* offset for extended opcodes */ |
42 | | |
43 | | typedef struct { |
44 | | fixed v0, v1; /* coordinates */ |
45 | | ushort index; /* sequential index of hint */ |
46 | | } cv_stem_hint; |
47 | | typedef struct { |
48 | | int count; |
49 | | int current; /* cache cursor for search */ |
50 | | /* |
51 | | * For dotsection and Type 1 Charstring hint replacement, |
52 | | * we store active hints at the bottom of the table, and |
53 | | * replaced hints at the top. |
54 | | */ |
55 | | int replaced_count; /* # of replaced hints at top */ |
56 | | cv_stem_hint data[max_total_stem_hints]; |
57 | | } cv_stem_hint_table; |
58 | | |
59 | | /* Skip over the initial bytes in a Charstring, if any. */ |
60 | | static void |
61 | | skip_iv(gs_type1_state *pcis) |
62 | 8.41M | { |
63 | 8.41M | int skip = pcis->pfont->data.lenIV; |
64 | 8.41M | ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1]; |
65 | 8.41M | const byte *cip = ipsp->cs_data.bits.data; |
66 | 8.41M | crypt_state state = crypt_charstring_seed; |
67 | | |
68 | 42.0M | for (; skip > 0; ++cip, --skip) |
69 | 33.6M | decrypt_skip_next(*cip, state); |
70 | 8.41M | ipsp->ip = cip; |
71 | 8.41M | ipsp->dstate = state; |
72 | 8.41M | } |
73 | | |
74 | | /* |
75 | | * Set up for parsing a Type 1 Charstring. |
76 | | * |
77 | | * Only uses the following elements of *pfont: |
78 | | * data.lenIV |
79 | | */ |
80 | | static void |
81 | | type1_next_init(gs_type1_state *pcis, const gs_glyph_data_t *pgd, |
82 | | gs_font_type1 *pfont) |
83 | 4.33M | { |
84 | 4.33M | gs_type1_interp_init(pcis, NULL, NULL, NULL, NULL, false, 0, pfont); |
85 | 4.33M | pcis->flex_count = flex_max; |
86 | 4.33M | pcis->ipstack[0].cs_data = *pgd; |
87 | 4.33M | skip_iv(pcis); |
88 | 4.33M | } |
89 | | |
90 | | /* Clear the Type 1 operand stack. */ |
91 | | static inline void |
92 | | type1_clear(gs_type1_state *pcis) |
93 | 81.0M | { |
94 | 81.0M | pcis->os_count = 0; |
95 | 81.0M | } |
96 | | |
97 | | /* Execute a callsubr. */ |
98 | | static int |
99 | | type1_callsubr(gs_type1_state *pcis, int index) |
100 | 4.07M | { |
101 | 4.07M | gs_font_type1 *pfont = pcis->pfont; |
102 | 4.07M | ip_state_t *ipsp1 = &pcis->ipstack[pcis->ips_count]; |
103 | 4.07M | int code = pfont->data.procs.subr_data(pfont, index, false, |
104 | 4.07M | &ipsp1->cs_data); |
105 | | |
106 | 4.07M | if (code < 0) |
107 | 5 | return_error(code); |
108 | 4.07M | pcis->ips_count++; |
109 | 4.07M | skip_iv(pcis); |
110 | 4.07M | return code; |
111 | 4.07M | } |
112 | | |
113 | | /* Add 1 or 3 stem hints. */ |
114 | | static int |
115 | | type1_stem1(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv, |
116 | | fixed lsb, byte *active_hints) |
117 | 20.6M | { |
118 | 20.6M | fixed v0 = pv[0] + lsb, v1 = v0 + pv[1]; |
119 | 20.6M | cv_stem_hint *bot = &psht->data[0]; |
120 | 20.6M | cv_stem_hint *orig_top = bot + psht->count; |
121 | 20.6M | cv_stem_hint *top = orig_top; |
122 | | |
123 | 20.6M | if (psht->count >= max_total_stem_hints) |
124 | 0 | return_error(gs_error_limitcheck); |
125 | 31.7M | while (top > bot && |
126 | 27.7M | (v0 < top[-1].v0 || (v0 == top[-1].v0 && v1 < top[-1].v1)) |
127 | 20.6M | ) { |
128 | 11.0M | *top = top[-1]; |
129 | 11.0M | top--; |
130 | 11.0M | } |
131 | 20.6M | if (top > bot && v0 == top[-1].v0 && v1 == top[-1].v1) { |
132 | | /* Duplicate hint, don't add it. */ |
133 | 12.9M | memmove(top, top + 1, (char *)orig_top - (char *)top); |
134 | 12.9M | if (active_hints) { |
135 | 10.3M | uint index = top[-1].index; |
136 | | |
137 | 10.3M | active_hints[index >> 3] |= 0x80 >> (index & 7); |
138 | 10.3M | } |
139 | 12.9M | return 0; |
140 | 12.9M | } |
141 | 7.72M | top->v0 = v0; |
142 | 7.72M | top->v1 = v1; |
143 | 7.72M | psht->count++; |
144 | 7.72M | return 0; |
145 | 20.6M | } |
146 | | static int |
147 | | type1_stem3(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv3, |
148 | | fixed lsb, byte *active_hints) |
149 | 11.9k | { |
150 | 11.9k | int code = 0; |
151 | 11.9k | if (type1_stem1(pcis, psht, pv3, lsb, active_hints) < 0) |
152 | 0 | return code; |
153 | 11.9k | if (type1_stem1(pcis, psht, pv3 + 2, lsb, active_hints) < 0) |
154 | 0 | return code; |
155 | 11.9k | if (type1_stem1(pcis, psht, pv3 + 4, lsb, active_hints) < 0) |
156 | 0 | return code; |
157 | 11.9k | return 0; |
158 | 11.9k | } |
159 | | |
160 | | /* |
161 | | * Get the next operator from a Type 1 Charstring. This procedure handles |
162 | | * numbers, div, blend, pop, and callsubr/return. |
163 | | */ |
164 | | static int |
165 | | type1_next(gs_type1_state *pcis) |
166 | 92.3M | { |
167 | 92.3M | ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1]; |
168 | 92.3M | const byte *cip, *cipe; |
169 | 92.3M | crypt_state state; |
170 | 92.3M | #define CLEAR (csp = pcis->ostack - 1) |
171 | 92.3M | fixed *csp = (&pcis->ostack[pcis->os_count]) - 1; |
172 | 92.3M | const bool encrypted = pcis->pfont->data.lenIV >= 0; |
173 | 92.3M | int c, code, num_results, c0; |
174 | | |
175 | 100M | load: |
176 | 100M | cip = ipsp->ip; |
177 | 100M | cipe = ipsp->cs_data.bits.data + ipsp->cs_data.bits.size; |
178 | 100M | state = ipsp->dstate; |
179 | 335M | for (;;) { |
180 | 335M | if (cip >= cipe) |
181 | | /* We used to treat buffer overrun as a simple invalid font, now we assume that |
182 | | * there is an implicit endchar, so we return a particular error for later |
183 | | * interception. Returning an error allows any other code to continue as before. |
184 | | * Part of bug #693170 where the fonts are invalid (no endchar on some glyphs). |
185 | | */ |
186 | 439 | return_error(gs_error_unknownerror); |
187 | 335M | c0 = *cip++; |
188 | 335M | charstring_next(c0, state, c, encrypted); |
189 | 335M | if (c >= c_num1) { |
190 | | /* This is a number, decode it and push it on the stack. */ |
191 | 232M | if (c < c_pos2_0) { /* 1-byte number */ |
192 | 179M | decode_push_num1(csp, pcis->ostack, c); |
193 | 179M | } else if (c < cx_num4) { /* 2-byte number */ |
194 | 53.1M | decode_push_num2(csp, pcis->ostack, c, cip, state, encrypted); |
195 | 53.1M | } else if (c == cx_num4) { /* 4-byte number */ |
196 | 60.2k | long lw; |
197 | | |
198 | 60.2k | decode_num4(lw, cip, state, encrypted); |
199 | 60.2k | CS_CHECK_PUSH(csp, pcis->ostack); |
200 | 60.2k | *++csp = int2fixed(lw); |
201 | 60.2k | if (lw != fixed2long(*csp)) { |
202 | | /* |
203 | | * The integer was too large to handle in fixed point. |
204 | | * Handle this case specially. |
205 | | */ |
206 | 13 | code = gs_type1_check_float(&state, encrypted, &cip, csp, lw); |
207 | 13 | if (code < 0) |
208 | 13 | return code; |
209 | 13 | } |
210 | 60.2k | } else /* not possible */ |
211 | 0 | return_error(gs_error_invalidfont); |
212 | 232M | continue; |
213 | 232M | } |
214 | | #ifdef DEBUG |
215 | | if (gs_debug_c('1')) { |
216 | | const fixed *p; |
217 | | |
218 | | for (p = pcis->ostack; p <= csp; ++p) |
219 | | dmprintf1(pcis->pgs->memory, " %g", fixed2float(*p)); |
220 | | if (c == cx_escape) { |
221 | | crypt_state cstate = state; |
222 | | int cn; |
223 | | |
224 | | charstring_next(*cip, cstate, cn, encrypted); |
225 | | dmprintf1(pcis->pgs->memory, " [*%d]\n", cn); |
226 | | } else |
227 | | dmprintf1(pcis->pgs->memory, " [%d]\n", c); |
228 | | } |
229 | | #endif |
230 | 102M | switch ((char_command) c) { |
231 | 90.3M | default: |
232 | 90.3M | break; |
233 | 90.3M | case c_undef0: |
234 | 24 | case c_undef2: |
235 | 38 | case c_undef17: |
236 | 38 | return_error(gs_error_invalidfont); |
237 | 4.07M | case c_callsubr: |
238 | 4.07M | if (csp + 1 - &pcis->ostack[0] < 1) |
239 | 3 | return_error(gs_error_invalidfont); |
240 | 4.07M | code = type1_callsubr(pcis, fixed2int_var(*csp) + |
241 | 4.07M | pcis->pfont->data.subroutineNumberBias); |
242 | 4.07M | if (code < 0) |
243 | 5 | return_error(code); |
244 | 4.07M | ipsp->ip = cip, ipsp->dstate = state; |
245 | 4.07M | --csp; |
246 | 4.07M | ++ipsp; |
247 | 4.07M | goto load; |
248 | 4.07M | case c_return: |
249 | 4.07M | if (pcis->ips_count > 1) { |
250 | 4.07M | gs_glyph_data_free(&ipsp->cs_data, "type1_next"); |
251 | 4.07M | pcis->ips_count--; |
252 | 4.07M | --ipsp; |
253 | 4.07M | } else |
254 | 13 | return_error(gs_error_invalidfont); |
255 | 4.07M | goto load; |
256 | 4.07M | case c_undoc15: |
257 | | /* See gstype1.h for information on this opcode. */ |
258 | 61 | CLEAR; |
259 | 61 | continue; |
260 | 4.04M | case cx_escape: |
261 | 4.04M | charstring_next(*cip, state, c, encrypted); |
262 | 4.04M | ++cip; |
263 | 4.04M | switch ((char1_extended_command) c) { |
264 | 15.6k | default: |
265 | 15.6k | c += CE_OFFSET; |
266 | 15.6k | break; |
267 | 45.8k | case ce1_div: |
268 | 45.8k | if (csp + 1 - &pcis->ostack[0] < 1) |
269 | 0 | return_error(gs_error_invalidfont); |
270 | 45.8k | csp[-1] = float2fixed((double)csp[-1] / (double)*csp); |
271 | 45.8k | --csp; |
272 | 45.8k | continue; |
273 | 0 | case ce1_undoc15: /* see gstype1.h */ |
274 | 0 | CLEAR; |
275 | 0 | continue; |
276 | 2.00M | case ce1_callothersubr: |
277 | 2.00M | if (csp + 1 - &pcis->ostack[0] < 2) |
278 | 0 | return_error(gs_error_invalidfont); |
279 | 2.00M | switch (fixed2int_var(*csp)) { |
280 | 3.57k | case 0: |
281 | 3.57k | pcis->ignore_pops = 2; |
282 | 3.57k | break; /* pass to caller */ |
283 | 1.97M | case 3: |
284 | 1.97M | pcis->ignore_pops = 1; |
285 | 1.97M | break; /* pass to caller */ |
286 | 0 | case 14: |
287 | 0 | num_results = 1; goto blend; |
288 | 0 | case 15: |
289 | 0 | num_results = 2; goto blend; |
290 | 0 | case 16: |
291 | 0 | num_results = 3; goto blend; |
292 | 0 | case 17: |
293 | 0 | num_results = 4; goto blend; |
294 | 0 | case 18: |
295 | 0 | num_results = 6; |
296 | 0 | blend: |
297 | 0 | CS_CHECK_POP(csp, pcis->ostack); |
298 | 0 | if (!CS_CHECK_CSTACK_BOUNDS(&csp[-1 - fixed2int_var(csp[-1])], pcis->ostack)) |
299 | 0 | return_error(gs_error_invalidfont); |
300 | | |
301 | 0 | code = gs_type1_blend(pcis, csp, num_results); |
302 | 0 | if (code < 0) |
303 | 0 | return code; |
304 | 0 | csp -= code; |
305 | 0 | continue; |
306 | 28.5k | default: |
307 | 28.5k | break; /* pass to caller */ |
308 | 2.00M | } |
309 | 2.00M | break; |
310 | 2.00M | case ce1_pop: |
311 | 1.97M | if (pcis->ignore_pops != 0) { |
312 | 1.97M | pcis->ignore_pops--; |
313 | 1.97M | continue; |
314 | 1.97M | } |
315 | 4.04M | return_error(gs_error_rangecheck); |
316 | 4.04M | } |
317 | 2.02M | break; |
318 | 102M | } |
319 | 92.3M | break; |
320 | 102M | } |
321 | 92.3M | ipsp->ip = cip, ipsp->dstate = state; |
322 | 92.3M | pcis->ips_count = ipsp + 1 - &pcis->ipstack[0]; |
323 | 92.3M | pcis->os_count = csp + 1 - &pcis->ostack[0]; |
324 | 92.3M | return c; |
325 | 100M | } |
326 | | |
327 | | /* ------ Output ------ */ |
328 | | |
329 | | /* Put 2 or 4 bytes on a stream (big-endian). */ |
330 | | static void |
331 | | sputc2(stream *s, int i) |
332 | 24.7M | { |
333 | 24.7M | sputc(s, (byte)(i >> 8)); |
334 | 24.7M | sputc(s, (byte)i); |
335 | 24.7M | } |
336 | | static void |
337 | | sputc4(stream *s, int i) |
338 | 22.8k | { |
339 | 22.8k | sputc2(s, i >> 16); |
340 | 22.8k | sputc2(s, i); |
341 | 22.8k | } |
342 | | |
343 | | /* Put a Type 2 operator on a stream. */ |
344 | | static void |
345 | | type2_put_op(stream *s, int op) |
346 | 22.9M | { |
347 | 22.9M | if (op >= CE_OFFSET) { |
348 | 1.78k | spputc(s, cx_escape); |
349 | 1.78k | spputc(s, (byte)(op - CE_OFFSET)); |
350 | 1.78k | } else |
351 | 22.9M | sputc(s, (byte)op); |
352 | 22.9M | } |
353 | | |
354 | | /* Put a Type 2 number on a stream. */ |
355 | | static void |
356 | | type2_put_int(stream *s, int i) |
357 | 103M | { |
358 | 103M | if (i >= -107 && i <= 107) |
359 | 78.6M | sputc(s, (byte)(i + 139)); |
360 | 24.6M | else if (i <= 1131 && i >= 0) |
361 | 16.8M | sputc2(s, (c_pos2_0 << 8) + i - 108); |
362 | 7.77M | else if (i >= -1131 && i < 0) |
363 | 7.76M | sputc2(s, (c_neg2_0 << 8) - i - 108); |
364 | 8.02k | else if (i >= -32768 && i <= 32767) { |
365 | 8.02k | spputc(s, c2_shortint); |
366 | 8.02k | sputc2(s, i); |
367 | 8.02k | } else { |
368 | | /* |
369 | | * We can't represent this number directly: compute it. |
370 | | * (This can be done much more efficiently in particular cases; |
371 | | * we'll do this if it ever seems worthwhile.) |
372 | | */ |
373 | 0 | type2_put_int(s, i >> 10); |
374 | 0 | type2_put_int(s, 1024); |
375 | 0 | type2_put_op(s, CE_OFFSET + ce2_mul); |
376 | 0 | type2_put_int(s, i & 1023); |
377 | 0 | type2_put_op(s, CE_OFFSET + ce2_add); |
378 | 0 | } |
379 | 103M | } |
380 | | |
381 | | /* Put a fixed value on a stream. */ |
382 | | static void |
383 | | type2_put_fixed(stream *s, fixed v) |
384 | 103M | { |
385 | 103M | if (fixed_is_int(v)) |
386 | 103M | type2_put_int(s, fixed2int_var(v)); |
387 | 22.8k | else if (v >= int2fixed(-32768) && v < int2fixed(32768)) { |
388 | | /* We can represent this as a 16:16 number. */ |
389 | 22.8k | spputc(s, cx_num4); |
390 | 22.8k | sputc4(s, v << (16 - _fixed_shift)); |
391 | 22.8k | } else { |
392 | 0 | type2_put_int(s, fixed2int_var(v)); |
393 | 0 | type2_put_fixed(s, fixed_fraction(v)); |
394 | 0 | type2_put_op(s, CE_OFFSET + ce2_add); |
395 | 0 | } |
396 | 103M | } |
397 | | |
398 | | /* Put a stem hint table on a stream. */ |
399 | | static void |
400 | | type2_put_stems(stream *s, int os_count, const cv_stem_hint_table *psht, int op) |
401 | 3.64M | { |
402 | 3.64M | fixed prev = 0; |
403 | 3.64M | int pushed = os_count; |
404 | 3.64M | int i; |
405 | | |
406 | 11.3M | for (i = 0; i < psht->count; ++i, pushed += 2) { |
407 | 7.72M | fixed v0 = psht->data[i].v0; |
408 | 7.72M | fixed v1 = psht->data[i].v1; |
409 | | |
410 | 7.72M | if (pushed > ostack_size - 2) { |
411 | 0 | type2_put_op(s, op); |
412 | 0 | pushed = 0; |
413 | 0 | } |
414 | 7.72M | type2_put_fixed(s, v0 - prev); |
415 | 7.72M | type2_put_fixed(s, v1 - v0); |
416 | 7.72M | prev = v1; |
417 | 7.72M | } |
418 | 3.64M | type2_put_op(s, op); |
419 | 3.64M | } |
420 | | |
421 | | /* Put out a hintmask command. */ |
422 | | static void |
423 | | type2_put_hintmask(stream *s, const byte *mask, uint size) |
424 | 1.48M | { |
425 | 1.48M | uint ignore; |
426 | | |
427 | 1.48M | type2_put_op(s, c2_hintmask); |
428 | 1.48M | sputs(s, mask, size, &ignore); |
429 | 1.48M | } |
430 | | |
431 | | /* ------ Main program ------ */ |
432 | | |
433 | | /* |
434 | | * Convert a Type 1 Charstring to (unencrypted) Type 2. |
435 | | * For simplicity, we expand all Subrs in-line. |
436 | | * We still need to optimize the output using these patterns: |
437 | | * (vhcurveto hvcurveto)* (vhcurveto hrcurveto | vrcurveto) => |
438 | | * vhcurveto |
439 | | * (hvcurveto vhcurveto)* (hvcurveto vrcurveto | hrcurveto) => |
440 | | * hvcurveto |
441 | | */ |
442 | 23.7M | #define MAX_STACK ostack_size |
443 | | int |
444 | | psf_convert_type1_to_type2(stream *s, const gs_glyph_data_t *pgd, |
445 | | gs_font_type1 *pfont) |
446 | 2.16M | { |
447 | 2.16M | gs_type1_state cis; |
448 | 2.16M | cv_stem_hint_table hstem_hints; /* horizontal stem hints */ |
449 | 2.16M | cv_stem_hint_table vstem_hints; /* vertical stem hints */ |
450 | 2.16M | bool first = true; |
451 | 2.16M | bool need_moveto = true; |
452 | 2.16M | bool replace_hints = false; |
453 | 2.16M | bool hints_changed = false; |
454 | 2.16M | bool width_on_stack = false; |
455 | 2.16M | enum { |
456 | 2.16M | dotsection_in = 0, |
457 | 2.16M | dotsection_out = -1 |
458 | 2.16M | } dotsection_flag = dotsection_out; |
459 | 2.16M | byte active_hints[(max_total_stem_hints + 7) / 8]; |
460 | 2.16M | byte dot_save_hints[(max_total_stem_hints + 7) / 8]; |
461 | 2.16M | uint hintmask_size; |
462 | 2.16M | #define HINTS_CHANGED()\ |
463 | 11.3M | BEGIN\ |
464 | 11.3M | hints_changed = replace_hints;\ |
465 | 11.3M | if (hints_changed)\ |
466 | 11.3M | CHECK_OP(); /* see below */\ |
467 | 11.3M | END |
468 | 2.16M | #define CHECK_HINTS_CHANGED()\ |
469 | 18.4M | BEGIN\ |
470 | 18.4M | if (hints_changed) {\ |
471 | 1.48M | type2_put_hintmask(s, active_hints, hintmask_size);\ |
472 | 1.48M | hints_changed = false;\ |
473 | 1.48M | }\ |
474 | 18.4M | END |
475 | | /* |
476 | | * In order to combine Type 1 operators, we usually delay writing |
477 | | * out operators (but not their operands). We must keep track of |
478 | | * the stack depth so we don't exceed it when combining operators. |
479 | | */ |
480 | 2.16M | int depth; /* of operands on stack */ |
481 | 2.16M | int prev_op; /* operator to write, -1 if none */ |
482 | 2.16M | int code = 0; |
483 | 2.16M | #define CLEAR_OP()\ |
484 | 17.8M | (depth = 0, prev_op = -1) |
485 | 2.16M | #define CHECK_OP()\ |
486 | 32.6M | BEGIN\ |
487 | 32.6M | if (prev_op >= 0) {\ |
488 | 15.6M | type2_put_op(s, prev_op);\ |
489 | 15.6M | CLEAR_OP();\ |
490 | 15.6M | }\ |
491 | 32.6M | END |
492 | 2.16M | fixed mx0 = 0, my0 = 0; /* See ce1_setcurrentpoint. */ |
493 | | |
494 | | /* Really this is to silence Coverity, but it makes sense and we do it a lot so no penatly */ |
495 | 2.16M | memset(active_hints, 0, (max_total_stem_hints + 7) / 8); |
496 | | |
497 | | /* In case we do not get an sbw or hsbw op */ |
498 | 2.16M | cis.lsb.x = cis.lsb.y = cis.width.x = cis.width.y = fixed_0; |
499 | | |
500 | | /* |
501 | | * Do a first pass to collect hints. Note that we must also process |
502 | | * [h]sbw, because the hint coordinates are relative to the lsb. |
503 | | */ |
504 | 2.16M | hstem_hints.count = hstem_hints.replaced_count = hstem_hints.current = 0; |
505 | 2.16M | vstem_hints.count = vstem_hints.replaced_count = vstem_hints.current = 0; |
506 | 2.16M | type1_next_init(&cis, pgd, pfont); |
507 | 46.1M | for (;;) { |
508 | 46.1M | int c = type1_next(&cis); |
509 | 46.1M | fixed *csp = (&cis.ostack[cis.os_count]) - 1; |
510 | | |
511 | 46.1M | switch (c) { |
512 | 30.5M | default: |
513 | | /* We used to treat buffer overrun as a simple invalid font, now we assume that |
514 | | * there is an implicit endchar, this is handled by looking for a specific error. |
515 | | * Part of bug #693170 where the fonts are invalid (no endchar on some glyphs). |
516 | | */ |
517 | 30.5M | if (c == gs_error_unknownerror) |
518 | 223 | break; |
519 | 30.5M | if (c < 0) |
520 | 72 | return c; |
521 | 30.5M | type1_clear(&cis); |
522 | 30.5M | continue; |
523 | 2.16M | case c1_hsbw: |
524 | 2.16M | if (cis.os_count < 2) |
525 | 4 | return_error(gs_error_invalidfont); |
526 | 2.16M | gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0); |
527 | 2.16M | goto clear; |
528 | 6.10M | case cx_hstem: |
529 | 6.10M | if (cis.os_count < 2) |
530 | 2 | return_error(gs_error_invalidfont); |
531 | 6.10M | code = type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, NULL); |
532 | 6.10M | if (code < 0) |
533 | 0 | return code; |
534 | 6.10M | goto clear; |
535 | 6.10M | case cx_vstem: |
536 | 4.20M | if (cis.os_count < 2) |
537 | 2 | return_error(gs_error_invalidfont); |
538 | 4.20M | code = type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, NULL); |
539 | 4.20M | if (code < 0) |
540 | 0 | return code; |
541 | 4.20M | goto clear; |
542 | 4.20M | case CE_OFFSET + ce1_sbw: |
543 | 0 | if (cis.os_count < 4) |
544 | 0 | return_error(gs_error_invalidfont); |
545 | 0 | gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1], |
546 | 0 | cis.ostack[2], cis.ostack[3]); |
547 | 0 | goto clear; |
548 | 5.96k | case CE_OFFSET + ce1_vstem3: |
549 | 5.96k | if (cis.os_count < 6) |
550 | 0 | return_error(gs_error_invalidfont); |
551 | 5.96k | code = type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, NULL); |
552 | 5.96k | if (code < 0) |
553 | 0 | return code; |
554 | 5.96k | goto clear; |
555 | 5.96k | case CE_OFFSET + ce1_hstem3: |
556 | 9 | if (cis.os_count < 6) |
557 | 0 | return_error(gs_error_invalidfont); |
558 | 9 | code = type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, NULL); |
559 | 9 | if (code < 0) |
560 | 0 | return code; |
561 | 12.4M | clear: |
562 | 12.4M | type1_clear(&cis); |
563 | 12.4M | continue; |
564 | 1.00M | case ce1_callothersubr: |
565 | 1.00M | if (cis.os_count < 2) |
566 | 1 | return_error(gs_error_invalidfont); |
567 | 1.00M | if (*csp == int2fixed(3)) |
568 | 986k | replace_hints = true; |
569 | 1.00M | if (fixed2int(csp[-1]) < 0) |
570 | 5 | return_error(gs_error_invalidfont); |
571 | 1.00M | if (cis.os_count < 2 + fixed2int(csp[-1])) |
572 | 4 | return_error(gs_error_invalidfont); |
573 | 1.00M | if (*csp == int2fixed(12) || *csp == int2fixed(13)) |
574 | 0 | cis.os_count -= fixed2int(csp[-1]); |
575 | 1.00M | cis.os_count -= 2; |
576 | 1.00M | continue; |
577 | 90 | case CE_OFFSET + ce1_dotsection: |
578 | 90 | replace_hints = true; |
579 | 90 | continue; |
580 | 0 | case CE_OFFSET + ce1_seac: |
581 | 0 | if (cis.os_count < 5) |
582 | 0 | return_error(gs_error_invalidfont); |
583 | 2.16M | case cx_endchar: |
584 | 2.16M | break; |
585 | 46.1M | } |
586 | 2.16M | break; |
587 | 46.1M | } |
588 | | /* |
589 | | * Number the hints for hintmask. We must do this even if we never |
590 | | * replace hints, because type1_stem# uses the index to set bits in |
591 | | * active_hints. |
592 | | */ |
593 | 2.16M | { |
594 | 2.16M | int i; |
595 | | |
596 | 6.96M | for (i = 0; i < hstem_hints.count; ++i) |
597 | 4.79M | hstem_hints.data[i].index = i; |
598 | 5.10M | for (i = 0; i < vstem_hints.count; ++i) |
599 | 2.93M | vstem_hints.data[i].index = i + hstem_hints.count; |
600 | 2.16M | } |
601 | 2.16M | if (replace_hints) { |
602 | 495k | hintmask_size = |
603 | 495k | (hstem_hints.count + vstem_hints.count + 7) / 8; |
604 | 495k | if (hintmask_size > (max_total_stem_hints + 7) / 8) |
605 | 0 | return_error(gs_error_invalidfont); |
606 | 495k | memset(active_hints, 0, hintmask_size); |
607 | 495k | } else |
608 | 1.67M | hintmask_size = 0; |
609 | | |
610 | | /* Do a second pass to write the result. */ |
611 | 2.16M | type1_next_init(&cis, pgd, pfont); |
612 | 2.16M | CLEAR_OP(); |
613 | 46.1M | for (;;) { |
614 | 46.1M | int c = type1_next(&cis); |
615 | 46.1M | fixed *csp = (&cis.ostack[cis.os_count]) - 1; |
616 | 46.1M | #define POP(n)\ |
617 | 46.1M | (csp -= (n), cis.os_count -= (n)) |
618 | 46.1M | int i; |
619 | 46.1M | fixed mx, my; |
620 | | |
621 | 46.1M | if (need_moveto && ((c >= cx_rlineto && c <= cx_rrcurveto) || |
622 | 14.9M | c == cx_vhcurveto || c == cx_hvcurveto)) |
623 | 45 | { |
624 | 45 | mx = my = 0; |
625 | 45 | need_moveto = false; |
626 | 45 | CHECK_OP(); |
627 | 45 | if (first) { |
628 | 9 | if (width_on_stack) { |
629 | 9 | if (cis.os_count < 1) |
630 | 0 | return_error(gs_error_invalidfont); |
631 | 9 | type2_put_fixed(s, *csp); /* width */ |
632 | | /* We need to move all the stored numeric values up by |
633 | | * one in the stack, eliminating the width, so that later |
634 | | * processing when we handle the drswing operator emits the correct |
635 | | * values. This is different to the 'move' case below. |
636 | | */ |
637 | 9 | cis.os_count--; |
638 | 54 | for (i = 0; i < cis.os_count; ++i) |
639 | 45 | cis.ostack[i] = cis.ostack[i+1]; |
640 | 9 | } |
641 | 9 | mx += cis.lsb.x + mx0, my += cis.lsb.y + my0; |
642 | 9 | first = false; |
643 | 9 | } |
644 | 45 | CHECK_HINTS_CHANGED(); |
645 | 45 | if (mx == 0) { |
646 | 36 | type2_put_fixed(s, my); |
647 | 36 | depth = 1, prev_op = cx_vmoveto; |
648 | 36 | } else if (my == 0) { |
649 | 9 | type2_put_fixed(s, mx); |
650 | 9 | depth = 1, prev_op = cx_hmoveto; |
651 | 9 | } else { |
652 | 0 | type2_put_fixed(s, mx); |
653 | 0 | type2_put_fixed(s, my); |
654 | 0 | depth = 2, prev_op = cx_rmoveto; |
655 | 0 | } |
656 | 45 | } |
657 | | |
658 | 46.1M | switch (c) { |
659 | 448 | default: |
660 | | /* We used to treat buffer overrun as a simple invalid font, now we assume that |
661 | | * there is an implicit endchar, this is handled by looking for a specific error. |
662 | | * Part of bug #693170 where the fonts are invalid (no endchar on some glyphs). |
663 | | */ |
664 | 448 | if (c == gs_error_unknownerror) { |
665 | 216 | type2_put_op(s, cx_endchar); |
666 | 216 | return 0; |
667 | 216 | } |
668 | 232 | if (c < 0) |
669 | 0 | return c; |
670 | 232 | if (c >= CE_OFFSET) |
671 | 2 | return_error(gs_error_rangecheck); |
672 | | /* The Type 1 use of all other operators is the same in Type 2. */ |
673 | 12.8M | copy: |
674 | 12.8M | CHECK_OP(); |
675 | 12.8M | CHECK_HINTS_CHANGED(); |
676 | 24.8M | put: |
677 | 105M | for (i = 0; i < cis.os_count; ++i) |
678 | 80.4M | type2_put_fixed(s, cis.ostack[i]); |
679 | 24.8M | depth += cis.os_count; |
680 | 24.8M | prev_op = c; |
681 | 24.8M | type1_clear(&cis); |
682 | 24.8M | continue; |
683 | 6.10M | case cx_hstem: |
684 | 6.10M | if (cis.os_count < 2) |
685 | 0 | return_error(gs_error_invalidfont); |
686 | 6.10M | code = type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, active_hints); |
687 | 6.10M | if (code < 0) |
688 | 0 | return code; |
689 | 10.3M | hint: |
690 | 10.3M | HINTS_CHANGED(); |
691 | 10.3M | type1_clear(&cis); |
692 | 10.3M | continue; |
693 | 4.20M | case cx_vstem: |
694 | 4.20M | if (cis.os_count < 2) |
695 | 0 | return_error(gs_error_invalidfont); |
696 | 4.20M | code = type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, active_hints); |
697 | 4.20M | if (code < 0) |
698 | 0 | return code; |
699 | 4.20M | goto hint; |
700 | 4.20M | case CE_OFFSET + ce1_vstem3: |
701 | 5.95k | if (cis.os_count < 6) |
702 | 0 | return_error(gs_error_invalidfont); |
703 | 5.95k | code = type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, active_hints); |
704 | 5.95k | if (code < 0) |
705 | 0 | return code; |
706 | 5.95k | goto hint; |
707 | 5.95k | case CE_OFFSET + ce1_hstem3: |
708 | 9 | if (cis.os_count < 6) |
709 | 0 | return_error(gs_error_invalidfont); |
710 | 9 | code = type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, active_hints); |
711 | 9 | if (code < 0) |
712 | 0 | return code; |
713 | 9 | goto hint; |
714 | 90 | case CE_OFFSET + ce1_dotsection: |
715 | 90 | if (dotsection_flag == dotsection_out) { |
716 | 54 | memcpy(dot_save_hints, active_hints, hintmask_size); |
717 | 54 | memset(active_hints, 0, hintmask_size); |
718 | 54 | dotsection_flag = dotsection_in; |
719 | 54 | } else { |
720 | 36 | memcpy(active_hints, dot_save_hints, hintmask_size); |
721 | 36 | dotsection_flag = dotsection_out; |
722 | 36 | } |
723 | 90 | HINTS_CHANGED(); |
724 | 90 | continue; |
725 | 2.82M | case c1_closepath: |
726 | 2.82M | need_moveto = true; |
727 | 2.82M | continue; |
728 | 1.78k | case CE_OFFSET + ce1_setcurrentpoint: |
729 | 1.78k | if (first) { |
730 | 0 | if (cis.os_count < 2) |
731 | 0 | return_error(gs_error_invalidfont); |
732 | | |
733 | | /* A workaround for fonts which use ce1_setcurrentpoint |
734 | | in an illegal way for shifting a path. |
735 | | See t1_hinter__setcurrentpoint for more information. */ |
736 | 0 | mx0 = csp[-1], my0 = *csp; |
737 | 0 | } |
738 | 1.78k | continue; |
739 | 485k | case cx_vmoveto: |
740 | 485k | if (cis.os_count < 1) |
741 | 0 | return_error(gs_error_invalidfont); |
742 | 485k | mx = 0, my = *csp; |
743 | 485k | POP(1); goto move; |
744 | 138k | case cx_hmoveto: |
745 | 138k | if (cis.os_count < 1) |
746 | 1 | return_error(gs_error_invalidfont); |
747 | 138k | mx = *csp, my = 0; |
748 | 138k | POP(1); goto move; |
749 | 2.21M | case cx_rmoveto: |
750 | 2.21M | if (cis.os_count < 2) |
751 | 0 | return_error(gs_error_invalidfont); |
752 | 2.21M | mx = csp[-1], my = *csp; |
753 | 2.21M | POP(2); |
754 | 2.84M | move: |
755 | 2.84M | need_moveto = false; |
756 | 2.84M | CHECK_OP(); |
757 | 2.84M | if (first) { |
758 | 2.01M | if (cis.os_count) |
759 | 13.8k | type2_put_fixed(s, *csp); /* width */ |
760 | 2.01M | mx += cis.lsb.x + mx0, my += cis.lsb.y + my0; |
761 | 2.01M | first = false; |
762 | 2.01M | } |
763 | 2.84M | if (cis.flex_count != flex_max) { |
764 | | /* We're accumulating points for a flex. */ |
765 | 12.5k | if (type1_next(&cis) != ce1_callothersubr) |
766 | 0 | return_error(gs_error_rangecheck); |
767 | 12.5k | csp = &cis.ostack[cis.os_count - 1]; |
768 | 12.5k | if (*csp != int2fixed(2) || csp[-1] != fixed_0) |
769 | 0 | return_error(gs_error_rangecheck); |
770 | 12.5k | cis.flex_count++; |
771 | 12.5k | csp[-1] = mx, *csp = my; |
772 | 12.5k | continue; |
773 | 12.5k | } |
774 | 2.84M | CHECK_HINTS_CHANGED(); |
775 | 2.82M | if (mx == 0) { |
776 | 205k | type2_put_fixed(s, my); |
777 | 205k | depth = 1, prev_op = cx_vmoveto; |
778 | 2.62M | } else if (my == 0) { |
779 | 190k | type2_put_fixed(s, mx); |
780 | 190k | depth = 1, prev_op = cx_hmoveto; |
781 | 2.43M | } else { |
782 | 2.43M | type2_put_fixed(s, mx); |
783 | 2.43M | type2_put_fixed(s, my); |
784 | 2.43M | depth = 2, prev_op = cx_rmoveto; |
785 | 2.43M | } |
786 | 2.82M | type1_clear(&cis); |
787 | 2.82M | continue; |
788 | 2.16M | case c1_hsbw: |
789 | 2.16M | if (cis.os_count < 2) |
790 | 0 | return_error(gs_error_invalidfont); |
791 | 2.16M | gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0); |
792 | | /* |
793 | | * Leave the l.s.b. on the operand stack for the initial hint, |
794 | | * moveto, or endchar command. |
795 | | */ |
796 | 2.16M | cis.ostack[0] = cis.ostack[1]; |
797 | 2.16M | sbw: |
798 | | /* cff_write_Private doesn't write defaultWidthX |
799 | | when called with the Type 1 font, |
800 | | so the reader will assume |
801 | | defaultWidthX = defaultWidthX_DEFAULT |
802 | | Use the latter here. |
803 | | */ |
804 | 2.16M | if (cis.ostack[0] == default_defaultWidthX) |
805 | 3.52k | cis.os_count = 0; |
806 | 2.16M | else { |
807 | 2.16M | cis.ostack[0] -= default_defaultWidthX; |
808 | 2.16M | cis.os_count = 1; |
809 | 2.16M | width_on_stack = true; |
810 | 2.16M | } |
811 | 2.16M | if (hstem_hints.count) { |
812 | 1.97M | if (cis.os_count) |
813 | 1.97M | type2_put_fixed(s, cis.ostack[0]); |
814 | 1.97M | type2_put_stems(s, cis.os_count, &hstem_hints, |
815 | 1.97M | (replace_hints ? c2_hstemhm : cx_hstem)); |
816 | 1.97M | cis.os_count = 0; |
817 | 1.97M | width_on_stack = false; |
818 | 1.97M | } |
819 | 2.16M | if (vstem_hints.count) { |
820 | 1.66M | if (cis.os_count) |
821 | 18.1k | type2_put_fixed(s, cis.ostack[0]); |
822 | 1.66M | type2_put_stems(s, cis.os_count, &vstem_hints, |
823 | 1.66M | (replace_hints ? c2_vstemhm : cx_vstem)); |
824 | 1.66M | cis.os_count = 0; |
825 | 1.66M | width_on_stack = false; |
826 | 1.66M | } |
827 | 2.16M | continue; |
828 | 0 | case CE_OFFSET + ce1_seac: |
829 | 0 | if (cis.os_count < 5) |
830 | 0 | return_error(gs_error_invalidfont); |
831 | | /* |
832 | | * It is an undocumented feature of the Type 2 CharString |
833 | | * format that endchar + 4 or 5 operands is equivalent to |
834 | | * seac with an implicit asb operand + endchar with 0 or 1 |
835 | | * operands. Remove the asb argument from the stack, but |
836 | | * adjust the adx argument to compensate for the fact that |
837 | | * Type 2 CharStrings don't have any concept of l.s.b. |
838 | | */ |
839 | 0 | csp[-3] += cis.lsb.x - csp[-4]; |
840 | 0 | memmove(csp - 4, csp - 3, sizeof(*csp) * 4); |
841 | 0 | POP(1); |
842 | | /* (falls through) */ |
843 | 2.16M | case cx_endchar: |
844 | 2.16M | CHECK_OP(); |
845 | 2.32M | for (i = 0; i < cis.os_count; ++i) |
846 | 154k | type2_put_fixed(s, cis.ostack[i]); |
847 | 2.16M | type2_put_op(s, cx_endchar); |
848 | 2.16M | return 0; |
849 | 0 | case CE_OFFSET + ce1_sbw: |
850 | 0 | if (cis.os_count < 4) |
851 | 0 | return_error(gs_error_invalidfont); |
852 | 0 | gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1], |
853 | 0 | cis.ostack[2], cis.ostack[3]); |
854 | 0 | cis.ostack[0] = cis.ostack[2]; |
855 | 0 | goto sbw; |
856 | 989k | case ce1_callothersubr: |
857 | 989k | if (cis.os_count < 2) |
858 | 0 | return_error(gs_error_invalidfont); |
859 | 989k | CHECK_OP(); |
860 | 989k | switch (fixed2int_var(*csp)) { |
861 | 0 | default: |
862 | 0 | return_error(gs_error_rangecheck); |
863 | 1.78k | case 0: |
864 | | /* |
865 | | * The operand stack contains: delta to reference point, |
866 | | * 6 deltas for the two curves, fd, final point, 3, 0. |
867 | | */ |
868 | 1.78k | csp[-18] += csp[-16], csp[-17] += csp[-15]; |
869 | 1.78k | memmove(csp - 16, csp - 14, sizeof(*csp) * 11); |
870 | 1.78k | cis.os_count -= 6, csp -= 6; |
871 | | /* |
872 | | * We could optimize by using [h]flex[1], |
873 | | * but it isn't worth the trouble. |
874 | | */ |
875 | 1.78k | c = CE_OFFSET + ce2_flex; |
876 | 1.78k | cis.flex_count = flex_max; /* not inside flex */ |
877 | 1.78k | cis.ignore_pops = 2; |
878 | 1.78k | goto copy; |
879 | 1.78k | case 1: |
880 | 1.78k | cis.flex_count = 0; |
881 | 1.78k | cis.os_count -= 2; |
882 | 1.78k | continue; |
883 | | /*case 2:*/ /* detected in *moveto */ |
884 | 986k | case 3: |
885 | 986k | memset(active_hints, 0, hintmask_size); |
886 | 986k | HINTS_CHANGED(); |
887 | 986k | cis.ignore_pops = 1; |
888 | 986k | cis.os_count -= 2; |
889 | 986k | continue; |
890 | 0 | case 12: |
891 | 0 | case 13: |
892 | | /* Counter control is not implemented. */ |
893 | 0 | if (fixed2int(csp[-1]) < 0) |
894 | 0 | return_error(gs_error_invalidfont); |
895 | 0 | if (cis.os_count < 2 + fixed2int(csp[-1])) |
896 | 0 | return_error(gs_error_invalidfont); |
897 | 0 | cis.os_count -= 2 + fixed2int(csp[-1]); |
898 | 0 | continue; |
899 | 989k | } |
900 | | /* |
901 | | * The remaining cases are strictly for optimization. |
902 | | */ |
903 | 2.45M | case cx_rlineto: |
904 | 2.45M | if (cis.os_count < 2) |
905 | 2 | return_error(gs_error_invalidfont); |
906 | 2.45M | if (depth > MAX_STACK - 2) |
907 | 983 | goto copy; |
908 | 2.45M | switch (prev_op) { |
909 | 563k | case cx_rlineto: /* rlineto+ => rlineto */ |
910 | 563k | goto put; |
911 | 268k | case cx_rrcurveto: /* rrcurveto+ rlineto => rcurveline */ |
912 | 268k | c = c2_rcurveline; |
913 | 268k | goto put; |
914 | 1.62M | default: |
915 | 1.62M | goto copy; |
916 | 2.45M | } |
917 | 4.84M | case cx_hlineto: /* hlineto (vlineto hlineto)* [vlineto] => hlineto */ |
918 | 4.84M | if (cis.os_count < 1) |
919 | 0 | return_error(gs_error_invalidfont); |
920 | 4.84M | if (depth > MAX_STACK - 1 || |
921 | 4.84M | prev_op != (depth & 1 ? cx_vlineto : cx_hlineto)) |
922 | 2.50M | goto copy; |
923 | 2.33M | c = prev_op; |
924 | 2.33M | goto put; |
925 | 4.47M | case cx_vlineto: /* vlineto (hlineto vlineto)* [hlineto] => vlineto */ |
926 | 4.47M | if (cis.os_count < 1) |
927 | 0 | return_error(gs_error_invalidfont); |
928 | 4.47M | if (depth > MAX_STACK - 1 || |
929 | 4.47M | prev_op != (depth & 1 ? cx_hlineto : cx_vlineto)) |
930 | 2.17M | goto copy; |
931 | 2.29M | c = prev_op; |
932 | 2.29M | goto put; |
933 | 2.55M | case cx_hvcurveto: /* hvcurveto (vhcurveto hvcurveto)* => hvcurveto */ |
934 | | /* (vhcurveto hvcurveto)+ => vhcurveto */ |
935 | 2.55M | if (cis.os_count < 4) |
936 | 1 | return_error(gs_error_invalidfont); |
937 | | /* |
938 | | * We have to check (depth & 1) because the last curve might |
939 | | * have 5 parameters rather than 4 (see rrcurveto below). |
940 | | */ |
941 | 2.55M | if ((depth & 1) || depth > MAX_STACK - 4 || |
942 | 2.23M | prev_op != (depth & 4 ? cx_vhcurveto : cx_hvcurveto)) |
943 | 1.75M | goto copy; |
944 | 796k | c = prev_op; |
945 | 796k | goto put; |
946 | 2.69M | case cx_vhcurveto: /* vhcurveto (hvcurveto vhcurveto)* => vhcurveto */ |
947 | | /* (hvcurveto vhcurveto)+ => hvcurveto */ |
948 | 2.69M | if (cis.os_count < 4) |
949 | 0 | return_error(gs_error_invalidfont); |
950 | | /* See above re the (depth & 1) check. */ |
951 | 2.69M | if ((depth & 1) || depth > MAX_STACK - 4 || |
952 | 2.26M | prev_op != (depth & 4 ? cx_hvcurveto : cx_vhcurveto)) |
953 | 1.24M | goto copy; |
954 | 1.44M | c = prev_op; |
955 | 1.44M | goto put; |
956 | 7.84M | case cx_rrcurveto: |
957 | 7.84M | if (cis.os_count < 6) |
958 | 1 | return_error(gs_error_invalidfont); |
959 | 7.84M | if (depth == 0) { |
960 | 404k | if (csp[-1] == 0) { |
961 | | /* A|0 B C D 0 F rrcurveto => [A] B C D F vvcurveto */ |
962 | 75.9k | c = c2_vvcurveto; |
963 | 75.9k | csp[-1] = csp[0]; |
964 | 75.9k | if (csp[-5] == 0) { |
965 | 9 | memmove(csp - 5, csp - 4, sizeof(*csp) * 4); |
966 | 9 | POP(2); |
967 | 9 | } else |
968 | 75.9k | POP(1); |
969 | 329k | } else if (*csp == 0) { |
970 | | /* A B|0 C D E 0 rrcurveto => [B] A C D E hhcurveto */ |
971 | 171k | c = c2_hhcurveto; |
972 | 171k | if (csp[-4] == 0) { |
973 | 110 | memmove(csp - 4, csp - 3, sizeof(*csp) * 3); |
974 | 110 | POP(2); |
975 | 171k | } else { |
976 | 171k | *csp = csp[-5], csp[-5] = csp[-4], csp[-4] = *csp; |
977 | 171k | POP(1); |
978 | 171k | } |
979 | 171k | } |
980 | | /* |
981 | | * We could also optimize: |
982 | | * 0 B C D E F|0 rrcurveto => B C D E [F] vhcurveto |
983 | | * A 0 C D E|0 F rrcurveto => A C D F [E] hvcurveto |
984 | | * but this gets in the way of subsequent optimization |
985 | | * of multiple rrcurvetos, so we don't do it. |
986 | | */ |
987 | 404k | goto copy; |
988 | 404k | } |
989 | 7.43M | if (depth > MAX_STACK - 6) |
990 | 3.57k | goto copy; |
991 | 7.43M | switch (prev_op) { |
992 | 71.8k | case c2_hhcurveto: /* hrcurveto (x1 0 x2 y2 x3 0 rrcurveto)* => */ |
993 | | /* hhcurveto */ |
994 | 71.8k | if (csp[-4] == 0 && *csp == 0) { |
995 | 0 | memmove(csp - 4, csp - 3, sizeof(*csp) * 3); |
996 | 0 | c = prev_op; |
997 | 0 | POP(2); |
998 | 0 | goto put; |
999 | 0 | } |
1000 | 71.8k | goto copy; |
1001 | 71.8k | case c2_vvcurveto: /* rvcurveto (0 y1 x2 y2 0 y3 rrcurveto)* => */ |
1002 | | /* vvcurveto */ |
1003 | 28.9k | if (csp[-5] == 0 && csp[-1] == 0) { |
1004 | 0 | memmove(csp - 5, csp - 4, sizeof(*csp) * 3); |
1005 | 0 | csp[-2] = *csp; |
1006 | 0 | c = prev_op; |
1007 | 0 | POP(2); |
1008 | 0 | goto put; |
1009 | 0 | } |
1010 | 28.9k | goto copy; |
1011 | 1.10M | case cx_hvcurveto: |
1012 | 1.10M | if (depth & 1) |
1013 | 286k | goto copy; |
1014 | 817k | if (!(depth & 4)) |
1015 | 399k | goto hrc; |
1016 | 512k | vrc: /* (vhcurveto hvcurveto)+ vrcurveto => vhcurveto */ |
1017 | | /* hvcurveto (vhcurveto hvcurveto)* vrcurveto => hvcurveto */ |
1018 | 512k | if (csp[-5] != 0) |
1019 | 2.80k | goto copy; |
1020 | 510k | memmove(csp - 5, csp - 4, sizeof(*csp) * 5); |
1021 | 510k | c = prev_op; |
1022 | 510k | POP(1); |
1023 | 510k | goto put; |
1024 | 1.14M | case cx_vhcurveto: |
1025 | 1.14M | if (depth & 1) |
1026 | 365k | goto copy; |
1027 | 781k | if (!(depth & 4)) |
1028 | 95.2k | goto vrc; |
1029 | 1.08M | hrc: /* (hvcurveto vhcurveto)+ hrcurveto => hvcurveto */ |
1030 | | /* vhcurveto (hvcurveto vhcurveto)* hrcurveto => vhcurveto */ |
1031 | 1.08M | if (csp[-4] != 0) |
1032 | 8.88k | goto copy; |
1033 | | /* A 0 C D E F => A C D F E */ |
1034 | 1.07M | memmove(csp - 4, csp - 3, sizeof(*csp) * 2); |
1035 | 1.07M | csp[-2] = *csp; |
1036 | 1.07M | c = prev_op; |
1037 | 1.07M | POP(1); |
1038 | 1.07M | goto put; |
1039 | 445k | case cx_rlineto: /* rlineto+ rrcurveto => rlinecurve */ |
1040 | 445k | c = c2_rlinecurve; |
1041 | 445k | goto put; |
1042 | 2.28M | case cx_rrcurveto: /* rrcurveto+ => rrcurveto */ |
1043 | 2.28M | goto put; |
1044 | 2.35M | default: |
1045 | 2.35M | goto copy; |
1046 | 7.43M | } |
1047 | 46.1M | } |
1048 | 46.1M | } |
1049 | 2.16M | } |