/src/ghostpdl/pdf/pdf_path.c
Line | Count | Source |
1 | | /* Copyright (C) 2018-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 | | /* Path operations for the PDF interpreter */ |
17 | | |
18 | | #include "pdf_int.h" |
19 | | #include "pdf_font_types.h" |
20 | | #include "pdf_gstate.h" |
21 | | #include "pdf_path.h" |
22 | | #include "pdf_stack.h" |
23 | | #include "pdf_trans.h" |
24 | | #include "gstypes.h" |
25 | | #include "pdf_optcontent.h" |
26 | | #include "gspath.h" /* For gs_moveto() and friends */ |
27 | | #include "gspaint.h" /* For gs_fill() and friends */ |
28 | | #include "gxdevsop.h" /* For special ops */ |
29 | | |
30 | | typedef enum path_segment_e { |
31 | | pdfi_moveto_seg, |
32 | | pdfi_lineto_seg, |
33 | | pdfi_curveto_seg, |
34 | | pdfi_re_seg, |
35 | | pdfi_v_curveto_seg, |
36 | | pdfi_y_curveto_seg, |
37 | | pdfi_closepath_seg |
38 | | } pdfi_path_segment; |
39 | | |
40 | | static int StorePathSegment(pdf_context *ctx, pdfi_path_segment segment, double *pts) |
41 | 27.2M | { |
42 | 27.2M | int size = 0; |
43 | | |
44 | 27.2M | switch (segment) |
45 | 27.2M | { |
46 | 5.07M | case pdfi_moveto_seg: |
47 | 15.2M | case pdfi_lineto_seg: |
48 | 15.2M | size = 2; |
49 | 15.2M | break; |
50 | 2.77M | case pdfi_re_seg: |
51 | 2.90M | case pdfi_v_curveto_seg: |
52 | 3.03M | case pdfi_y_curveto_seg: |
53 | 3.03M | size = 4; |
54 | 3.03M | break; |
55 | 8.38M | case pdfi_curveto_seg: |
56 | 8.38M | size = 6; |
57 | 8.38M | break; |
58 | 579k | case pdfi_closepath_seg: |
59 | 579k | break; |
60 | 0 | default: |
61 | 0 | return_error(gs_error_undefined); |
62 | 0 | break; |
63 | 27.2M | } |
64 | 27.2M | if (ctx->PathSegments == NULL) { |
65 | 5.77M | ctx->PathSegments = (char *)gs_alloc_bytes(ctx->memory, 1024, "StorePathSegment"); |
66 | 5.77M | if (ctx->PathSegments == NULL) |
67 | 0 | return_error(gs_error_VMerror); |
68 | 5.77M | ctx->PathSegmentsCurrent = ctx->PathSegments; |
69 | 5.77M | ctx->PathSegmentsTop = ctx->PathSegments + 1024; |
70 | 5.77M | } |
71 | 27.2M | if (ctx->PathSegmentsCurrent == ctx->PathSegmentsTop) { |
72 | 1.78k | char *new_accumulator = NULL; |
73 | 1.78k | uint64_t old_size; |
74 | | |
75 | 1.78k | old_size = ctx->PathSegmentsCurrent - ctx->PathSegments; |
76 | 1.78k | new_accumulator = (char *)gs_alloc_bytes(ctx->memory, old_size + 1024, "StorePathSegment"); |
77 | 1.78k | if (new_accumulator == NULL) |
78 | 0 | return_error(gs_error_VMerror); |
79 | 1.78k | memcpy(new_accumulator, ctx->PathSegments, old_size); |
80 | 1.78k | ctx->PathSegmentsCurrent = new_accumulator + old_size; |
81 | 1.78k | gs_free_object(ctx->memory, ctx->PathSegments, "StorePathSegment"); |
82 | 1.78k | ctx->PathSegments = new_accumulator; |
83 | 1.78k | ctx->PathSegmentsTop = ctx->PathSegments + old_size + 1024; |
84 | 1.78k | } |
85 | | |
86 | 27.2M | if (ctx->PathPts == NULL) { |
87 | 5.77M | ctx->PathPts = (double *)gs_alloc_bytes(ctx->memory, 4096, "StorePathSegment"); |
88 | 5.77M | if (ctx->PathPts == NULL) |
89 | 0 | return_error(gs_error_VMerror); |
90 | 5.77M | ctx->PathPtsCurrent = ctx->PathPts; |
91 | 5.77M | ctx->PathPtsTop = ctx->PathPts + (4096 / sizeof(double)); |
92 | 5.77M | } |
93 | 27.2M | if (ctx->PathPtsCurrent + size > ctx->PathPtsTop) { |
94 | 26.7k | double *new_accumulator = NULL; |
95 | 26.7k | uint64_t old_size; |
96 | | |
97 | 26.7k | old_size = (char *)ctx->PathPtsCurrent - (char *)ctx->PathPts; |
98 | 26.7k | new_accumulator = (double *)gs_alloc_bytes(ctx->memory, old_size + 4096, "StorePathSegment"); |
99 | 26.7k | if (new_accumulator == NULL) |
100 | 0 | return_error(gs_error_VMerror); |
101 | 26.7k | memcpy(new_accumulator, ctx->PathPts, old_size); |
102 | 26.7k | ctx->PathPtsCurrent = new_accumulator + (old_size / sizeof(double)); |
103 | 26.7k | gs_free_object(ctx->memory, ctx->PathPts, "StorePathSegment"); |
104 | 26.7k | ctx->PathPts = new_accumulator; |
105 | 26.7k | ctx->PathPtsTop = ctx->PathPts + ((old_size + 4096) / sizeof(double)); |
106 | 26.7k | } |
107 | | |
108 | 27.2M | *(ctx->PathSegmentsCurrent++) = (char)segment; |
109 | 27.2M | switch (segment) |
110 | 27.2M | { |
111 | 5.07M | case pdfi_moveto_seg: |
112 | 15.2M | case pdfi_lineto_seg: |
113 | 15.2M | memcpy(ctx->PathPtsCurrent, pts, 2 * sizeof(double)); |
114 | 15.2M | ctx->PathPtsCurrent += 2; |
115 | 15.2M | break; |
116 | 2.77M | case pdfi_re_seg: |
117 | 2.90M | case pdfi_v_curveto_seg: |
118 | 3.03M | case pdfi_y_curveto_seg: |
119 | 3.03M | memcpy(ctx->PathPtsCurrent, pts, 4 * sizeof(double)); |
120 | 3.03M | ctx->PathPtsCurrent += 4; |
121 | 3.03M | break; |
122 | 8.38M | case pdfi_curveto_seg: |
123 | 8.38M | memcpy(ctx->PathPtsCurrent, pts, 6 * sizeof(double)); |
124 | 8.38M | ctx->PathPtsCurrent += 6; |
125 | 8.38M | break; |
126 | 579k | case pdfi_closepath_seg: |
127 | 579k | break; |
128 | 27.2M | } |
129 | 27.2M | return 0; |
130 | 27.2M | } |
131 | | |
132 | | static int ApplyStoredPath(pdf_context *ctx) |
133 | 6.19M | { |
134 | 6.19M | int code = 0; |
135 | 6.19M | char *op = NULL; |
136 | 6.19M | double *dpts = NULL; |
137 | 6.19M | double *current; |
138 | | |
139 | 6.19M | if (ctx->PathSegments == NULL) |
140 | 530k | return 0; |
141 | | |
142 | 5.66M | if (ctx->PathPts == NULL) { |
143 | 0 | code = gs_note_error(gs_error_unknownerror); |
144 | 0 | goto error; |
145 | 0 | } |
146 | | |
147 | 5.66M | if (ctx->pgs->current_point_valid) { |
148 | 139k | code = gs_newpath(ctx->pgs); |
149 | 139k | if (code < 0) |
150 | 0 | goto error; |
151 | 139k | } |
152 | | |
153 | 5.66M | op = ctx->PathSegments; |
154 | 5.66M | dpts = ctx->PathPts; |
155 | 5.66M | current = dpts; /* Stop stupid compilers complaining. */ |
156 | | |
157 | 31.5M | while (op < ctx->PathSegmentsCurrent) { |
158 | 26.0M | if (dpts > ctx->PathPtsCurrent) { |
159 | 0 | code = gs_note_error(gs_error_unknownerror); |
160 | 0 | goto error; |
161 | 0 | } |
162 | | |
163 | 26.0M | switch(*op++) { |
164 | 4.78M | case pdfi_moveto_seg: |
165 | 4.78M | code = gs_moveto(ctx->pgs, dpts[0], dpts[1]); |
166 | 4.78M | current = dpts; |
167 | 4.78M | dpts+= 2; |
168 | 4.78M | break; |
169 | 9.56M | case pdfi_lineto_seg: |
170 | 9.56M | code = gs_lineto(ctx->pgs, dpts[0], dpts[1]); |
171 | 9.56M | current = dpts; |
172 | 9.56M | dpts+= 2; |
173 | 9.56M | break; |
174 | 2.70M | case pdfi_re_seg: |
175 | 2.70M | code = gs_moveto(ctx->pgs, dpts[0], dpts[1]); |
176 | 2.70M | if (code >= 0) { |
177 | 2.70M | code = gs_rlineto(ctx->pgs, dpts[2], 0); |
178 | 2.70M | if (code >= 0) { |
179 | 2.70M | code = gs_rlineto(ctx->pgs, 0, dpts[3]); |
180 | 2.70M | if (code >= 0) { |
181 | 2.70M | code = gs_rlineto(ctx->pgs, -dpts[2], 0); |
182 | 2.70M | if (code >= 0) |
183 | 2.70M | code = gs_closepath(ctx->pgs); |
184 | 2.70M | } |
185 | 2.70M | } |
186 | 2.70M | } |
187 | 2.70M | current = dpts; |
188 | 2.70M | dpts+= 4; |
189 | 2.70M | break; |
190 | 122k | case pdfi_v_curveto_seg: |
191 | 122k | code = gs_curveto(ctx->pgs, current[0], current[1], dpts[0], dpts[1], dpts[2], dpts[3]); |
192 | 122k | current = dpts + 2; |
193 | 122k | dpts+= 4; |
194 | 122k | break; |
195 | 129k | case pdfi_y_curveto_seg: |
196 | 129k | code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[2], dpts[3]); |
197 | 129k | current = dpts + 2; |
198 | 129k | dpts+= 4; |
199 | 129k | break; |
200 | 8.24M | case pdfi_curveto_seg: |
201 | 8.24M | code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[4], dpts[5]); |
202 | 8.24M | current = dpts + 4; |
203 | 8.24M | dpts+= 6; |
204 | 8.24M | break; |
205 | 532k | case pdfi_closepath_seg: |
206 | 532k | code = gs_closepath(ctx->pgs); |
207 | 532k | break; |
208 | 0 | default: |
209 | 0 | code = gs_note_error(gs_error_rangecheck); |
210 | 0 | break; |
211 | 26.0M | } |
212 | 26.0M | if (code < 0) |
213 | 184k | break; |
214 | 26.0M | } |
215 | | |
216 | 5.66M | error: |
217 | 5.66M | gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath"); |
218 | 5.66M | ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL; |
219 | 5.66M | gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath"); |
220 | 5.66M | ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL; |
221 | 5.66M | return code; |
222 | 5.66M | } |
223 | | |
224 | | int pdfi_moveto (pdf_context *ctx) |
225 | 5.94M | { |
226 | 5.94M | int code; |
227 | 5.94M | double xy[2]; |
228 | | |
229 | 5.94M | if (ctx->text.BlockDepth != 0) { |
230 | 25.6k | if (ctx->text.TextClip) { |
231 | 3 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
232 | | |
233 | 3 | ctx->text.TextClip = false; |
234 | 3 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
235 | 3 | } |
236 | 25.6k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL); |
237 | 25.6k | if (code < 0) |
238 | 0 | return code; |
239 | 25.6k | } |
240 | | |
241 | 5.94M | code = pdfi_destack_reals(ctx, xy, 2); |
242 | 5.94M | if (code < 0) |
243 | 876k | return code; |
244 | | |
245 | 5.07M | return StorePathSegment(ctx, pdfi_moveto_seg, (double *)&xy); |
246 | 5.94M | } |
247 | | |
248 | | int pdfi_lineto (pdf_context *ctx) |
249 | 10.7M | { |
250 | 10.7M | int code; |
251 | 10.7M | double xy[2]; |
252 | | |
253 | 10.7M | if (ctx->text.BlockDepth != 0) { |
254 | 8.64k | ctx->text.BlockDepth = 0; |
255 | 8.64k | if (ctx->text.TextClip) { |
256 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
257 | |
|
258 | 0 | ctx->text.TextClip = false; |
259 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
260 | 0 | } |
261 | 8.64k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_lineto", NULL); |
262 | 8.64k | if (code < 0) |
263 | 0 | return code; |
264 | 8.64k | } |
265 | | |
266 | 10.7M | code = pdfi_destack_reals(ctx, xy, 2); |
267 | 10.7M | if (code < 0) |
268 | 607k | return code; |
269 | | |
270 | 10.1M | return StorePathSegment(ctx, pdfi_lineto_seg, (double *)&xy); |
271 | 10.7M | } |
272 | | |
273 | | static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill) |
274 | 2.31M | { |
275 | 2.31M | int code=0, code1; |
276 | 2.31M | pdfi_trans_state_t state; |
277 | | |
278 | 2.31M | if (ctx->text.BlockDepth != 0) { |
279 | 15.3k | ctx->text.BlockDepth = 0; |
280 | 15.3k | if (ctx->text.TextClip) { |
281 | 1 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
282 | | |
283 | 1 | ctx->text.TextClip = false; |
284 | 1 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
285 | 1 | } |
286 | 15.3k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_fill_inner", NULL); |
287 | 15.3k | if (code < 0) |
288 | 0 | return code; |
289 | 15.3k | } |
290 | | |
291 | 2.31M | if (pdfi_oc_is_off(ctx)) |
292 | 59.8k | goto exit; |
293 | | |
294 | 2.25M | code = ApplyStoredPath(ctx); |
295 | 2.25M | if (code < 0) |
296 | 12.8k | return code; |
297 | | |
298 | 2.23M | code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Fill); |
299 | 2.23M | if (code == 0) { |
300 | | /* If we don't gsave/grestore round the fill, then the file |
301 | | * /tests_private/pdf/sumatra/954_-_dashed_lines_hardly_visible.pdf renders |
302 | | * incorrectly. However we must not gsave/grestore round the trans_setup |
303 | | * trans_teardown, because that might set pgs->soft_mask_id and if we restore |
304 | | * back to a point where that is not set then pdfwrite doesn't work properly. |
305 | | */ |
306 | 2.23M | code = pdfi_gsave(ctx); |
307 | 2.23M | if (code < 0) goto exit; |
308 | | |
309 | 2.23M | if (use_eofill) |
310 | 65.7k | code = gs_eofill(ctx->pgs); |
311 | 2.17M | else |
312 | 2.17M | code = gs_fill(ctx->pgs); |
313 | 2.23M | code1 = pdfi_grestore(ctx); |
314 | 2.23M | if (code == 0) code = code1; |
315 | | |
316 | 2.23M | code1 = pdfi_trans_teardown(ctx, &state); |
317 | 2.23M | if (code == 0) code = code1; |
318 | 2.23M | } |
319 | | |
320 | 2.29M | exit: |
321 | 2.29M | code1 = pdfi_newpath(ctx); |
322 | 2.29M | if (code == 0) code = code1; |
323 | | |
324 | 2.29M | return code; |
325 | 2.23M | } |
326 | | |
327 | | int pdfi_fill(pdf_context *ctx) |
328 | 2.24M | { |
329 | 2.24M | return pdfi_fill_inner(ctx, false); |
330 | 2.24M | } |
331 | | |
332 | | int pdfi_eofill(pdf_context *ctx) |
333 | 69.4k | { |
334 | 69.4k | return pdfi_fill_inner(ctx, true); |
335 | 69.4k | } |
336 | | |
337 | | int pdfi_stroke(pdf_context *ctx) |
338 | 3.27M | { |
339 | 3.27M | int code=0, code1; |
340 | 3.27M | pdfi_trans_state_t state; |
341 | | |
342 | 3.27M | if (ctx->text.BlockDepth != 0) { |
343 | 19.1k | ctx->text.BlockDepth = 0; |
344 | 19.1k | if (ctx->text.TextClip) { |
345 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
346 | |
|
347 | 0 | ctx->text.TextClip = false; |
348 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
349 | 0 | } |
350 | 19.1k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_stroke", NULL); |
351 | 19.1k | if (code < 0) |
352 | 0 | return code; |
353 | 19.1k | } |
354 | | |
355 | 3.27M | if (pdfi_oc_is_off(ctx)) |
356 | 46 | goto exit; |
357 | | |
358 | 3.27M | code = ApplyStoredPath(ctx); |
359 | 3.27M | if (code < 0) |
360 | 144k | return code; |
361 | | |
362 | 3.12M | gs_swapcolors_quick(ctx->pgs); |
363 | 3.12M | code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Stroke); |
364 | 3.12M | if (code == 0) { |
365 | 3.12M | code = pdfi_gsave(ctx); |
366 | 3.12M | if (code < 0) goto exit; |
367 | | |
368 | 3.12M | code = gs_stroke(ctx->pgs); |
369 | | |
370 | 3.12M | code1 = pdfi_grestore(ctx); |
371 | 3.12M | if (code == 0) code = code1; |
372 | | |
373 | 3.12M | code1 = pdfi_trans_teardown(ctx, &state); |
374 | 3.12M | if (code == 0) code = code1; |
375 | 3.12M | } |
376 | 3.12M | gs_swapcolors_quick(ctx->pgs); |
377 | | |
378 | 3.12M | exit: |
379 | 3.12M | code1 = pdfi_newpath(ctx); |
380 | 3.12M | if (code == 0) code = code1; |
381 | | |
382 | 3.12M | return code; |
383 | 3.12M | } |
384 | | |
385 | | int pdfi_closepath_stroke(pdf_context *ctx) |
386 | 82.7k | { |
387 | 82.7k | int code; |
388 | | |
389 | 82.7k | if (ctx->text.BlockDepth != 0) { |
390 | 2.71k | ctx->text.BlockDepth = 0; |
391 | 2.71k | if (ctx->text.TextClip) { |
392 | 2 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
393 | | |
394 | 2 | ctx->text.TextClip = false; |
395 | 2 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
396 | 2 | } |
397 | 2.71k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath_stroke", NULL); |
398 | 2.71k | if (code < 0) |
399 | 0 | return code; |
400 | 2.71k | } |
401 | | |
402 | 82.7k | code = StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
403 | 82.7k | if (code < 0) |
404 | 0 | return code; |
405 | | |
406 | 82.7k | return pdfi_stroke(ctx); |
407 | 82.7k | } |
408 | | |
409 | | int pdfi_curveto(pdf_context *ctx) |
410 | 8.73M | { |
411 | 8.73M | int code; |
412 | 8.73M | double Values[6]; |
413 | | |
414 | 8.73M | code = pdfi_destack_reals(ctx, Values, 6); |
415 | 8.73M | if (code < 0) |
416 | 346k | return code; |
417 | | |
418 | 8.38M | if (ctx->text.BlockDepth != 0) { |
419 | 265 | ctx->text.BlockDepth = 0; |
420 | 265 | if (ctx->text.TextClip) { |
421 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
422 | |
|
423 | 0 | ctx->text.TextClip = false; |
424 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
425 | 0 | } |
426 | 265 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_curveto", NULL); |
427 | 265 | if (code < 0) |
428 | 0 | return code; |
429 | 265 | } |
430 | | |
431 | 8.38M | return StorePathSegment(ctx, pdfi_curveto_seg, (double *)&Values); |
432 | 8.38M | } |
433 | | |
434 | | int pdfi_v_curveto(pdf_context *ctx) |
435 | 129k | { |
436 | 129k | int code; |
437 | 129k | double Values[4]; |
438 | | |
439 | 129k | code = pdfi_destack_reals(ctx, Values, 4); |
440 | 129k | if (code < 0) |
441 | 6.59k | return code; |
442 | | |
443 | 123k | if (ctx->text.BlockDepth != 0) { |
444 | 22 | ctx->text.BlockDepth = 0; |
445 | 22 | if (ctx->text.TextClip) { |
446 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
447 | |
|
448 | 0 | ctx->text.TextClip = false; |
449 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
450 | 0 | } |
451 | 22 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_v_curveto", NULL); |
452 | 22 | if (code < 0) |
453 | 0 | return code; |
454 | 22 | } |
455 | | |
456 | 123k | return StorePathSegment(ctx, pdfi_v_curveto_seg, (double *)&Values); |
457 | 123k | } |
458 | | |
459 | | int pdfi_y_curveto(pdf_context *ctx) |
460 | 146k | { |
461 | 146k | int code; |
462 | 146k | double Values[4]; |
463 | | |
464 | 146k | code = pdfi_destack_reals(ctx, Values, 4); |
465 | 146k | if (code < 0) |
466 | 16.9k | return code; |
467 | | |
468 | 129k | if (ctx->text.BlockDepth != 0) { |
469 | 25 | ctx->text.BlockDepth = 0; |
470 | 25 | if (ctx->text.TextClip) { |
471 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
472 | |
|
473 | 0 | ctx->text.TextClip = false; |
474 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
475 | 0 | } |
476 | 25 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_y_curveto", NULL); |
477 | 25 | if (code < 0) |
478 | 0 | return code; |
479 | 25 | } |
480 | | |
481 | 129k | return StorePathSegment(ctx, pdfi_y_curveto_seg, (double *)&Values); |
482 | 129k | } |
483 | | |
484 | | int pdfi_closepath(pdf_context *ctx) |
485 | 479k | { |
486 | 479k | int code; |
487 | | |
488 | 479k | if (ctx->text.BlockDepth != 0) { |
489 | 761 | ctx->text.BlockDepth = 0; |
490 | 761 | if (ctx->text.TextClip) { |
491 | 6 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
492 | | |
493 | 6 | ctx->text.TextClip = false; |
494 | 6 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
495 | 6 | } |
496 | 761 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath", NULL); |
497 | 761 | if (code < 0) |
498 | 0 | return code; |
499 | 761 | } |
500 | | |
501 | 479k | return StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
502 | 479k | } |
503 | | |
504 | | int pdfi_newpath(pdf_context *ctx) |
505 | 6.66M | { |
506 | 6.66M | int code = 0, code1; |
507 | | |
508 | | /* This code is to deal with the wacky W and W* operators */ |
509 | 6.66M | if (ctx->clip_active) { |
510 | 645k | if (ctx->PathSegments != NULL) { |
511 | 603k | code = ApplyStoredPath(ctx); |
512 | 603k | if (code < 0) |
513 | 24.8k | return code; |
514 | 603k | } |
515 | 620k | if (ctx->pgs->current_point_valid) { |
516 | 575k | if (ctx->do_eoclip) |
517 | 63.4k | code = gs_eoclip(ctx->pgs); |
518 | 511k | else |
519 | 511k | code = gs_clip(ctx->pgs); |
520 | 575k | } |
521 | 620k | } |
522 | 6.63M | ctx->clip_active = false; |
523 | | |
524 | 6.63M | if (ctx->PathSegments != NULL){ |
525 | 97.1k | gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath"); |
526 | 97.1k | ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL; |
527 | 97.1k | gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath"); |
528 | 97.1k | ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL; |
529 | 97.1k | } |
530 | | |
531 | 6.63M | code1 = gs_newpath(ctx->pgs); |
532 | 6.63M | if (code == 0) code = code1; |
533 | | |
534 | 6.63M | if (ctx->text.BlockDepth != 0) { |
535 | 4.48k | ctx->text.BlockDepth = 0; |
536 | 4.48k | if (ctx->text.TextClip) { |
537 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
538 | |
|
539 | 0 | ctx->text.TextClip = false; |
540 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
541 | 0 | } |
542 | 4.48k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_newpath", NULL); |
543 | 4.48k | if (code < 0) |
544 | 0 | return code; |
545 | 4.48k | } |
546 | | |
547 | 6.63M | return code; |
548 | 6.63M | } |
549 | | |
550 | | int pdfi_b(pdf_context *ctx) |
551 | 16.9k | { |
552 | 16.9k | int code; |
553 | | |
554 | 16.9k | if (ctx->text.BlockDepth != 0) { |
555 | 493 | ctx->text.BlockDepth = 0; |
556 | 493 | if (ctx->text.TextClip) { |
557 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
558 | |
|
559 | 0 | ctx->text.TextClip = false; |
560 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
561 | 0 | } |
562 | 493 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b", NULL); |
563 | 493 | if (code < 0) |
564 | 0 | return code; |
565 | 493 | } |
566 | | |
567 | 16.9k | code = StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
568 | 16.9k | if (code < 0) |
569 | 0 | return code; |
570 | | |
571 | 16.9k | return pdfi_B(ctx); |
572 | 16.9k | } |
573 | | |
574 | | int pdfi_b_star(pdf_context *ctx) |
575 | 623 | { |
576 | 623 | int code; |
577 | | |
578 | 623 | if (ctx->text.BlockDepth != 0) { |
579 | 0 | ctx->text.BlockDepth = 0; |
580 | 0 | if (ctx->text.TextClip) { |
581 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
582 | |
|
583 | 0 | ctx->text.TextClip = false; |
584 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
585 | 0 | } |
586 | 0 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b_star", NULL); |
587 | 0 | if (code < 0) |
588 | 0 | return code; |
589 | 0 | } |
590 | | |
591 | 623 | code = StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
592 | 623 | if (code < 0) |
593 | 0 | return code; |
594 | | |
595 | 623 | return pdfi_B_star(ctx); |
596 | 623 | } |
597 | | |
598 | | /* common code for B and B* */ |
599 | | static int pdfi_B_inner(pdf_context *ctx, bool use_eofill) |
600 | 69.9k | { |
601 | 69.9k | int code=0, code1=0; |
602 | 69.9k | pdfi_trans_state_t state; |
603 | | |
604 | 69.9k | if (ctx->text.BlockDepth != 0) { |
605 | 4.50k | ctx->text.BlockDepth = 0; |
606 | 4.50k | if (ctx->text.TextClip) { |
607 | 12 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
608 | | |
609 | 12 | ctx->text.TextClip = false; |
610 | 12 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
611 | 12 | } |
612 | 4.50k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_inner", NULL); |
613 | 4.50k | if (code < 0) |
614 | 0 | goto exit; |
615 | 4.50k | } |
616 | | |
617 | 69.9k | if (pdfi_oc_is_off(ctx)) |
618 | 10 | goto exit; |
619 | | |
620 | 69.9k | code = ApplyStoredPath(ctx); |
621 | 69.9k | if (code < 0) |
622 | 2.36k | return code; |
623 | | |
624 | 67.5k | code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_FillStroke); |
625 | 67.5k | if (code == 0) { |
626 | 67.5k | code = pdfi_gsave(ctx); |
627 | 67.5k | if (code < 0) goto exit; |
628 | | |
629 | 67.5k | if (use_eofill) |
630 | 2.51k | code = gs_eofillstroke(ctx->pgs, &code1); |
631 | 65.0k | else |
632 | 65.0k | code = gs_fillstroke(ctx->pgs, &code1); |
633 | | |
634 | 67.5k | code1 = pdfi_grestore(ctx); |
635 | 67.5k | if (code == 0) code = code1; |
636 | | |
637 | 67.5k | code1 = pdfi_trans_teardown(ctx, &state); |
638 | 67.5k | if (code >= 0) code = code1; |
639 | 67.5k | } |
640 | | |
641 | 67.5k | exit: |
642 | 67.5k | code1 = pdfi_newpath(ctx); |
643 | 67.5k | if (code == 0) code = code1; |
644 | | |
645 | 67.5k | return code; |
646 | 67.5k | } |
647 | | |
648 | | int pdfi_B(pdf_context *ctx) |
649 | 67.2k | { |
650 | 67.2k | return pdfi_B_inner(ctx, false); |
651 | 67.2k | } |
652 | | |
653 | | int pdfi_B_star(pdf_context *ctx) |
654 | 2.68k | { |
655 | 2.68k | return pdfi_B_inner(ctx, true); |
656 | 2.68k | } |
657 | | |
658 | | int pdfi_clip(pdf_context *ctx) |
659 | 0 | { |
660 | 0 | int code = gs_clip(ctx->pgs); |
661 | |
|
662 | 0 | if (ctx->text.BlockDepth != 0) { |
663 | 0 | ctx->text.BlockDepth = 0; |
664 | 0 | if (ctx->text.TextClip) { |
665 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
666 | |
|
667 | 0 | ctx->text.TextClip = false; |
668 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
669 | 0 | } |
670 | 0 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_clip", NULL); |
671 | 0 | if (code < 0) |
672 | 0 | return code; |
673 | 0 | } |
674 | | |
675 | 0 | return code; |
676 | 0 | } |
677 | | |
678 | | int pdfi_eoclip(pdf_context *ctx) |
679 | 0 | { |
680 | 0 | int code = gs_eoclip(ctx->pgs); |
681 | |
|
682 | 0 | if (ctx->text.BlockDepth != 0) { |
683 | 0 | ctx->text.BlockDepth = 0; |
684 | 0 | if (ctx->text.TextClip) { |
685 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
686 | |
|
687 | 0 | ctx->text.TextClip = false; |
688 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
689 | 0 | } |
690 | 0 | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_eoclip", NULL); |
691 | 0 | if (code < 0) |
692 | 0 | return code; |
693 | 0 | } |
694 | | |
695 | 0 | return code; |
696 | 0 | } |
697 | | |
698 | | int pdfi_rectpath(pdf_context *ctx) |
699 | 2.95M | { |
700 | 2.95M | int code; |
701 | 2.95M | double Values[4]; |
702 | | |
703 | 2.95M | code = pdfi_destack_reals(ctx, Values, 4); |
704 | 2.95M | if (code < 0) |
705 | 172k | return code; |
706 | | |
707 | 2.77M | if (ctx->text.BlockDepth != 0) { |
708 | 84.1k | ctx->text.BlockDepth = 0; |
709 | 84.1k | if (ctx->text.TextClip) { |
710 | 0 | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
711 | |
|
712 | 0 | ctx->text.TextClip = false; |
713 | 0 | (void)dev_proc(dev, dev_spec_op)(dev, gxdso_hilevel_text_clip, (void *)0, 1); |
714 | 0 | } |
715 | 84.1k | code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_OPINVALIDINTEXT, "pdfi_rectpath", NULL); |
716 | 84.1k | if (code < 0) |
717 | 0 | return code; |
718 | 84.1k | } |
719 | | |
720 | 2.77M | return StorePathSegment(ctx, pdfi_re_seg, (double *)&Values); |
721 | 2.77M | } |