/src/ghostpdl/pdf/pdf_path.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2018-2023 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 | | |
29 | | typedef enum path_segment_e { |
30 | | pdfi_moveto_seg, |
31 | | pdfi_lineto_seg, |
32 | | pdfi_curveto_seg, |
33 | | pdfi_re_seg, |
34 | | pdfi_v_curveto_seg, |
35 | | pdfi_y_curveto_seg, |
36 | | pdfi_closepath_seg |
37 | | } pdfi_path_segment; |
38 | | |
39 | | static int StorePathSegment(pdf_context *ctx, pdfi_path_segment segment, double *pts) |
40 | 27.8M | { |
41 | 27.8M | int size = 0; |
42 | | |
43 | 27.8M | switch (segment) |
44 | 27.8M | { |
45 | 5.63M | case pdfi_moveto_seg: |
46 | 16.6M | case pdfi_lineto_seg: |
47 | 16.6M | size = 2; |
48 | 16.6M | break; |
49 | 3.33M | case pdfi_re_seg: |
50 | 3.41M | case pdfi_v_curveto_seg: |
51 | 3.49M | case pdfi_y_curveto_seg: |
52 | 3.49M | size = 4; |
53 | 3.49M | break; |
54 | 6.82M | case pdfi_curveto_seg: |
55 | 6.82M | size = 6; |
56 | 6.82M | break; |
57 | 897k | case pdfi_closepath_seg: |
58 | 897k | break; |
59 | 0 | default: |
60 | 0 | return_error(gs_error_undefined); |
61 | 0 | break; |
62 | 27.8M | } |
63 | 27.8M | if (ctx->PathSegments == NULL) { |
64 | 6.46M | ctx->PathSegments = (char *)gs_alloc_bytes(ctx->memory, 1024, "StorePathSegment"); |
65 | 6.46M | if (ctx->PathSegments == NULL) |
66 | 0 | return_error(gs_error_VMerror); |
67 | 6.46M | ctx->PathSegmentsCurrent = ctx->PathSegments; |
68 | 6.46M | ctx->PathSegmentsTop = ctx->PathSegments + 1024; |
69 | 6.46M | } |
70 | 27.8M | if (ctx->PathSegmentsCurrent == ctx->PathSegmentsTop) { |
71 | 3.11k | char *new_accumulator = NULL; |
72 | 3.11k | uint64_t old_size; |
73 | | |
74 | 3.11k | old_size = ctx->PathSegmentsCurrent - ctx->PathSegments; |
75 | 3.11k | new_accumulator = (char *)gs_alloc_bytes(ctx->memory, old_size + 1024, "StorePathSegment"); |
76 | 3.11k | if (new_accumulator == NULL) |
77 | 0 | return_error(gs_error_VMerror); |
78 | 3.11k | memcpy(new_accumulator, ctx->PathSegments, old_size); |
79 | 3.11k | ctx->PathSegmentsCurrent = new_accumulator + old_size; |
80 | 3.11k | gs_free_object(ctx->memory, ctx->PathSegments, "StorePathSegment"); |
81 | 3.11k | ctx->PathSegments = new_accumulator; |
82 | 3.11k | ctx->PathSegmentsTop = ctx->PathSegments + old_size + 1024; |
83 | 3.11k | } |
84 | | |
85 | 27.8M | if (ctx->PathPts == NULL) { |
86 | 6.46M | ctx->PathPts = (double *)gs_alloc_bytes(ctx->memory, 4096, "StorePathSegment"); |
87 | 6.46M | if (ctx->PathPts == NULL) |
88 | 0 | return_error(gs_error_VMerror); |
89 | 6.46M | ctx->PathPtsCurrent = ctx->PathPts; |
90 | 6.46M | ctx->PathPtsTop = ctx->PathPts + (4096 / sizeof(double)); |
91 | 6.46M | } |
92 | 27.8M | if (ctx->PathPtsCurrent + size > ctx->PathPtsTop) { |
93 | 32.1k | double *new_accumulator = NULL; |
94 | 32.1k | uint64_t old_size; |
95 | | |
96 | 32.1k | old_size = (char *)ctx->PathPtsCurrent - (char *)ctx->PathPts; |
97 | 32.1k | new_accumulator = (double *)gs_alloc_bytes(ctx->memory, old_size + 4096, "StorePathSegment"); |
98 | 32.1k | if (new_accumulator == NULL) |
99 | 0 | return_error(gs_error_VMerror); |
100 | 32.1k | memcpy(new_accumulator, ctx->PathPts, old_size); |
101 | 32.1k | ctx->PathPtsCurrent = new_accumulator + (old_size / sizeof(double)); |
102 | 32.1k | gs_free_object(ctx->memory, ctx->PathPts, "StorePathSegment"); |
103 | 32.1k | ctx->PathPts = new_accumulator; |
104 | 32.1k | ctx->PathPtsTop = ctx->PathPts + ((old_size + 4096) / sizeof(double)); |
105 | 32.1k | } |
106 | | |
107 | 27.8M | *(ctx->PathSegmentsCurrent++) = (char)segment; |
108 | 27.8M | switch (segment) |
109 | 27.8M | { |
110 | 5.63M | case pdfi_moveto_seg: |
111 | 16.6M | case pdfi_lineto_seg: |
112 | 16.6M | memcpy(ctx->PathPtsCurrent, pts, 2 * sizeof(double)); |
113 | 16.6M | ctx->PathPtsCurrent += 2; |
114 | 16.6M | break; |
115 | 3.33M | case pdfi_re_seg: |
116 | 3.41M | case pdfi_v_curveto_seg: |
117 | 3.49M | case pdfi_y_curveto_seg: |
118 | 3.49M | memcpy(ctx->PathPtsCurrent, pts, 4 * sizeof(double)); |
119 | 3.49M | ctx->PathPtsCurrent += 4; |
120 | 3.49M | break; |
121 | 6.82M | case pdfi_curveto_seg: |
122 | 6.82M | memcpy(ctx->PathPtsCurrent, pts, 6 * sizeof(double)); |
123 | 6.82M | ctx->PathPtsCurrent += 6; |
124 | 6.82M | break; |
125 | 897k | case pdfi_closepath_seg: |
126 | 897k | break; |
127 | 27.8M | } |
128 | 27.8M | return 0; |
129 | 27.8M | } |
130 | | |
131 | | static int ApplyStoredPath(pdf_context *ctx) |
132 | 6.83M | { |
133 | 6.83M | int code = 0; |
134 | 6.83M | char *op = NULL; |
135 | 6.83M | double *dpts = NULL; |
136 | 6.83M | double *current; |
137 | | |
138 | 6.83M | if (ctx->PathSegments == NULL) |
139 | 478k | return 0; |
140 | | |
141 | 6.35M | if (ctx->PathPts == NULL) { |
142 | 0 | code = gs_note_error(gs_error_unknownerror); |
143 | 0 | goto error; |
144 | 0 | } |
145 | | |
146 | 6.35M | if (ctx->pgs->current_point_valid) { |
147 | 22.0k | code = gs_newpath(ctx->pgs); |
148 | 22.0k | if (code < 0) |
149 | 0 | goto error; |
150 | 22.0k | } |
151 | | |
152 | 6.35M | op = ctx->PathSegments; |
153 | 6.35M | dpts = ctx->PathPts; |
154 | 6.35M | current = dpts; /* Stop stupid compilers complaining. */ |
155 | | |
156 | 32.2M | while (op < ctx->PathSegmentsCurrent) { |
157 | 26.1M | if (dpts > ctx->PathPtsCurrent) { |
158 | 0 | code = gs_note_error(gs_error_unknownerror); |
159 | 0 | goto error; |
160 | 0 | } |
161 | | |
162 | 26.1M | switch(*op++) { |
163 | 5.31M | case pdfi_moveto_seg: |
164 | 5.31M | code = gs_moveto(ctx->pgs, dpts[0], dpts[1]); |
165 | 5.31M | current = dpts; |
166 | 5.31M | dpts+= 2; |
167 | 5.31M | break; |
168 | 10.1M | case pdfi_lineto_seg: |
169 | 10.1M | code = gs_lineto(ctx->pgs, dpts[0], dpts[1]); |
170 | 10.1M | current = dpts; |
171 | 10.1M | dpts+= 2; |
172 | 10.1M | break; |
173 | 3.25M | case pdfi_re_seg: |
174 | 3.25M | code = gs_moveto(ctx->pgs, dpts[0], dpts[1]); |
175 | 3.25M | if (code >= 0) { |
176 | 3.25M | code = gs_rlineto(ctx->pgs, dpts[2], 0); |
177 | 3.25M | if (code >= 0) { |
178 | 3.25M | code = gs_rlineto(ctx->pgs, 0, dpts[3]); |
179 | 3.25M | if (code >= 0) { |
180 | 3.25M | code = gs_rlineto(ctx->pgs, -dpts[2], 0); |
181 | 3.25M | if (code >= 0) |
182 | 3.25M | code = gs_closepath(ctx->pgs); |
183 | 3.25M | } |
184 | 3.25M | } |
185 | 3.25M | } |
186 | 3.25M | current = dpts; |
187 | 3.25M | dpts+= 4; |
188 | 3.25M | break; |
189 | 79.8k | case pdfi_v_curveto_seg: |
190 | 79.8k | code = gs_curveto(ctx->pgs, current[0], current[1], dpts[0], dpts[1], dpts[2], dpts[3]); |
191 | 79.8k | current = dpts + 2; |
192 | 79.8k | dpts+= 4; |
193 | 79.8k | break; |
194 | 84.6k | case pdfi_y_curveto_seg: |
195 | 84.6k | code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[2], dpts[3]); |
196 | 84.6k | current = dpts + 2; |
197 | 84.6k | dpts+= 4; |
198 | 84.6k | break; |
199 | 6.40M | case pdfi_curveto_seg: |
200 | 6.40M | code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[4], dpts[5]); |
201 | 6.40M | current = dpts + 4; |
202 | 6.40M | dpts+= 6; |
203 | 6.40M | break; |
204 | 824k | case pdfi_closepath_seg: |
205 | 824k | code = gs_closepath(ctx->pgs); |
206 | 824k | break; |
207 | 0 | default: |
208 | 0 | code = gs_note_error(gs_error_rangecheck); |
209 | 0 | break; |
210 | 26.1M | } |
211 | 26.1M | if (code < 0) |
212 | 207k | break; |
213 | 26.1M | } |
214 | | |
215 | 6.35M | error: |
216 | 6.35M | gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath"); |
217 | 6.35M | ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL; |
218 | 6.35M | gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath"); |
219 | 6.35M | ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL; |
220 | 6.35M | return code; |
221 | 6.35M | } |
222 | | |
223 | | int pdfi_moveto (pdf_context *ctx) |
224 | 6.43M | { |
225 | 6.43M | int code; |
226 | 6.43M | double xy[2]; |
227 | | |
228 | 6.43M | if (ctx->text.BlockDepth != 0) |
229 | 255k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL); |
230 | | |
231 | 6.43M | code = pdfi_destack_reals(ctx, xy, 2); |
232 | 6.43M | if (code < 0) |
233 | 796k | return code; |
234 | | |
235 | 5.63M | return StorePathSegment(ctx, pdfi_moveto_seg, (double *)&xy); |
236 | 6.43M | } |
237 | | |
238 | | int pdfi_lineto (pdf_context *ctx) |
239 | 11.6M | { |
240 | 11.6M | int code; |
241 | 11.6M | double xy[2]; |
242 | | |
243 | 11.6M | if (ctx->text.BlockDepth != 0) |
244 | 281k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_lineto", NULL); |
245 | | |
246 | 11.6M | code = pdfi_destack_reals(ctx, xy, 2); |
247 | 11.6M | if (code < 0) |
248 | 652k | return code; |
249 | | |
250 | 11.0M | return StorePathSegment(ctx, pdfi_lineto_seg, (double *)&xy); |
251 | 11.6M | } |
252 | | |
253 | | static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill) |
254 | 2.21M | { |
255 | 2.21M | int code=0, code1; |
256 | 2.21M | pdfi_trans_state_t state; |
257 | | |
258 | 2.21M | if (ctx->text.BlockDepth != 0) |
259 | 145k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_fill_inner", NULL); |
260 | | |
261 | 2.21M | if (pdfi_oc_is_off(ctx)) |
262 | 64.1k | goto exit; |
263 | | |
264 | 2.15M | code = ApplyStoredPath(ctx); |
265 | 2.15M | if (code < 0) |
266 | 13.5k | return code; |
267 | | |
268 | 2.13M | code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Fill); |
269 | 2.13M | if (code == 0) { |
270 | | /* If we don't gsave/grestore round the fill, then the file |
271 | | * /tests_private/pdf/sumatra/954_-_dashed_lines_hardly_visible.pdf renders |
272 | | * incorrectly. However we must not gsave/grestore round the trans_setup |
273 | | * trans_teardown, because that might set pgs->soft_mask_id and if we restore |
274 | | * back to a point where that is not set then pdfwrite doesn't work properly. |
275 | | */ |
276 | 2.13M | code = pdfi_gsave(ctx); |
277 | 2.13M | if (code < 0) goto exit; |
278 | | |
279 | 2.13M | if (use_eofill) |
280 | 72.9k | code = gs_eofill(ctx->pgs); |
281 | 2.06M | else |
282 | 2.06M | code = gs_fill(ctx->pgs); |
283 | 2.13M | code1 = pdfi_grestore(ctx); |
284 | 2.13M | if (code == 0) code = code1; |
285 | | |
286 | 2.13M | code1 = pdfi_trans_teardown(ctx, &state); |
287 | 2.13M | if (code == 0) code = code1; |
288 | 2.13M | } |
289 | | |
290 | 2.20M | exit: |
291 | 2.20M | code1 = pdfi_newpath(ctx); |
292 | 2.20M | if (code == 0) code = code1; |
293 | | |
294 | 2.20M | return code; |
295 | 2.13M | } |
296 | | |
297 | | int pdfi_fill(pdf_context *ctx) |
298 | 2.14M | { |
299 | 2.14M | return pdfi_fill_inner(ctx, false); |
300 | 2.14M | } |
301 | | |
302 | | int pdfi_eofill(pdf_context *ctx) |
303 | 75.9k | { |
304 | 75.9k | return pdfi_fill_inner(ctx, true); |
305 | 75.9k | } |
306 | | |
307 | | int pdfi_stroke(pdf_context *ctx) |
308 | 3.76M | { |
309 | 3.76M | int code=0, code1; |
310 | 3.76M | pdfi_trans_state_t state; |
311 | | |
312 | 3.76M | if (ctx->text.BlockDepth != 0) |
313 | 266k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_stroke", NULL); |
314 | | |
315 | 3.76M | if (pdfi_oc_is_off(ctx)) |
316 | 67 | goto exit; |
317 | | |
318 | 3.76M | code = ApplyStoredPath(ctx); |
319 | 3.76M | if (code < 0) |
320 | 145k | return code; |
321 | | |
322 | 3.61M | gs_swapcolors_quick(ctx->pgs); |
323 | 3.61M | code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Stroke); |
324 | 3.61M | if (code == 0) { |
325 | 3.61M | code = pdfi_gsave(ctx); |
326 | 3.61M | if (code < 0) goto exit; |
327 | | |
328 | 3.61M | code = gs_stroke(ctx->pgs); |
329 | | |
330 | 3.61M | code1 = pdfi_grestore(ctx); |
331 | 3.61M | if (code == 0) code = code1; |
332 | | |
333 | 3.61M | code1 = pdfi_trans_teardown(ctx, &state); |
334 | 3.61M | if (code == 0) code = code1; |
335 | 3.61M | } |
336 | 3.61M | gs_swapcolors_quick(ctx->pgs); |
337 | | |
338 | 3.61M | exit: |
339 | 3.61M | code1 = pdfi_newpath(ctx); |
340 | 3.61M | if (code == 0) code = code1; |
341 | | |
342 | 3.61M | return code; |
343 | 3.61M | } |
344 | | |
345 | | int pdfi_closepath_stroke(pdf_context *ctx) |
346 | 82.8k | { |
347 | 82.8k | int code; |
348 | | |
349 | 82.8k | if (ctx->text.BlockDepth != 0) |
350 | 29.3k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath_stroke", NULL); |
351 | | |
352 | 82.8k | code = StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
353 | 82.8k | if (code < 0) |
354 | 0 | return code; |
355 | | |
356 | 82.8k | return pdfi_stroke(ctx); |
357 | 82.8k | } |
358 | | |
359 | | int pdfi_curveto(pdf_context *ctx) |
360 | 7.24M | { |
361 | 7.24M | int code; |
362 | 7.24M | double Values[6]; |
363 | | |
364 | 7.24M | code = pdfi_destack_reals(ctx, Values, 6); |
365 | 7.24M | if (code < 0) |
366 | 422k | return code; |
367 | | |
368 | 6.82M | if (ctx->text.BlockDepth != 0) |
369 | 13.2k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_curveto", NULL); |
370 | | |
371 | 6.82M | return StorePathSegment(ctx, pdfi_curveto_seg, (double *)&Values); |
372 | 7.24M | } |
373 | | |
374 | | int pdfi_v_curveto(pdf_context *ctx) |
375 | 85.8k | { |
376 | 85.8k | int code; |
377 | 85.8k | double Values[4]; |
378 | | |
379 | 85.8k | code = pdfi_destack_reals(ctx, Values, 4); |
380 | 85.8k | if (code < 0) |
381 | 5.83k | return code; |
382 | | |
383 | 80.0k | if (ctx->text.BlockDepth != 0) |
384 | 55 | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_v_curveto", NULL); |
385 | | |
386 | 80.0k | return StorePathSegment(ctx, pdfi_v_curveto_seg, (double *)&Values); |
387 | 85.8k | } |
388 | | |
389 | | int pdfi_y_curveto(pdf_context *ctx) |
390 | 106k | { |
391 | 106k | int code; |
392 | 106k | double Values[4]; |
393 | | |
394 | 106k | code = pdfi_destack_reals(ctx, Values, 4); |
395 | 106k | if (code < 0) |
396 | 21.6k | return code; |
397 | | |
398 | 85.0k | if (ctx->text.BlockDepth != 0) |
399 | 59 | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_y_curveto", NULL); |
400 | | |
401 | 85.0k | return StorePathSegment(ctx, pdfi_y_curveto_seg, (double *)&Values); |
402 | 106k | } |
403 | | |
404 | | int pdfi_closepath(pdf_context *ctx) |
405 | 800k | { |
406 | 800k | if (ctx->text.BlockDepth != 0) |
407 | 56.8k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath", NULL); |
408 | | |
409 | 800k | return StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
410 | 800k | } |
411 | | |
412 | | int pdfi_newpath(pdf_context *ctx) |
413 | 7.33M | { |
414 | 7.33M | int code = 0, code1; |
415 | | |
416 | | /* This code is to deal with the wacky W and W* operators */ |
417 | 7.33M | if (ctx->clip_active) { |
418 | 909k | if (ctx->PathSegments != NULL) { |
419 | 855k | code = ApplyStoredPath(ctx); |
420 | 855k | if (code < 0) |
421 | 46.7k | return code; |
422 | 855k | } |
423 | 863k | if (ctx->pgs->current_point_valid) { |
424 | 805k | if (ctx->do_eoclip) |
425 | 57.7k | code = gs_eoclip(ctx->pgs); |
426 | 747k | else |
427 | 747k | code = gs_clip(ctx->pgs); |
428 | 805k | } |
429 | 863k | } |
430 | 7.28M | ctx->clip_active = false; |
431 | | |
432 | 7.28M | if (ctx->PathSegments != NULL){ |
433 | 102k | gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath"); |
434 | 102k | ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL; |
435 | 102k | gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath"); |
436 | 102k | ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL; |
437 | 102k | } |
438 | | |
439 | 7.28M | code1 = gs_newpath(ctx->pgs); |
440 | 7.28M | if (code == 0) code = code1; |
441 | | |
442 | 7.28M | if (ctx->text.BlockDepth != 0) |
443 | 480k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_newpath", NULL); |
444 | | |
445 | 7.28M | return code; |
446 | 7.33M | } |
447 | | |
448 | | int pdfi_b(pdf_context *ctx) |
449 | 13.9k | { |
450 | 13.9k | int code; |
451 | | |
452 | 13.9k | if (ctx->text.BlockDepth != 0) |
453 | 8.29k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b", NULL); |
454 | | |
455 | 13.9k | code = StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
456 | 13.9k | if (code < 0) |
457 | 0 | return code; |
458 | | |
459 | 13.9k | return pdfi_B(ctx); |
460 | 13.9k | } |
461 | | |
462 | | int pdfi_b_star(pdf_context *ctx) |
463 | 447 | { |
464 | 447 | int code; |
465 | | |
466 | 447 | if (ctx->text.BlockDepth != 0) |
467 | 2 | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b_star", NULL); |
468 | | |
469 | 447 | code = StorePathSegment(ctx, pdfi_closepath_seg, NULL); |
470 | 447 | if (code < 0) |
471 | 0 | return code; |
472 | | |
473 | 447 | return pdfi_B_star(ctx); |
474 | 447 | } |
475 | | |
476 | | /* common code for B and B* */ |
477 | | static int pdfi_B_inner(pdf_context *ctx, bool use_eofill) |
478 | 61.3k | { |
479 | 61.3k | int code=0, code1=0; |
480 | 61.3k | pdfi_trans_state_t state; |
481 | | |
482 | 61.3k | if (ctx->text.BlockDepth != 0) |
483 | 30.9k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_inner", NULL); |
484 | | |
485 | 61.3k | if (pdfi_oc_is_off(ctx)) |
486 | 4 | goto exit; |
487 | | |
488 | 61.3k | code = ApplyStoredPath(ctx); |
489 | 61.3k | if (code < 0) |
490 | 2.06k | return code; |
491 | | |
492 | 59.2k | code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_FillStroke); |
493 | 59.2k | if (code == 0) { |
494 | 59.2k | code = pdfi_gsave(ctx); |
495 | 59.2k | if (code < 0) goto exit; |
496 | | |
497 | 59.2k | if (use_eofill) |
498 | 2.07k | code = gs_eofillstroke(ctx->pgs, &code1); |
499 | 57.1k | else |
500 | 57.1k | code = gs_fillstroke(ctx->pgs, &code1); |
501 | | |
502 | 59.2k | code1 = pdfi_grestore(ctx); |
503 | 59.2k | if (code == 0) code = code1; |
504 | | |
505 | 59.2k | code1 = pdfi_trans_teardown(ctx, &state); |
506 | 59.2k | if (code >= 0) code = code1; |
507 | 59.2k | } |
508 | | |
509 | 59.2k | exit: |
510 | 59.2k | code1 = pdfi_newpath(ctx); |
511 | 59.2k | if (code == 0) code = code1; |
512 | | |
513 | 59.2k | return code; |
514 | 59.2k | } |
515 | | |
516 | | int pdfi_B(pdf_context *ctx) |
517 | 59.1k | { |
518 | 59.1k | return pdfi_B_inner(ctx, false); |
519 | 59.1k | } |
520 | | |
521 | | int pdfi_B_star(pdf_context *ctx) |
522 | 2.19k | { |
523 | 2.19k | return pdfi_B_inner(ctx, true); |
524 | 2.19k | } |
525 | | |
526 | | int pdfi_clip(pdf_context *ctx) |
527 | 0 | { |
528 | 0 | int code = gs_clip(ctx->pgs); |
529 | |
|
530 | 0 | if (ctx->text.BlockDepth != 0) |
531 | 0 | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_B_clip", NULL); |
532 | |
|
533 | 0 | return code; |
534 | 0 | } |
535 | | |
536 | | int pdfi_eoclip(pdf_context *ctx) |
537 | 0 | { |
538 | 0 | int code = gs_eoclip(ctx->pgs); |
539 | |
|
540 | 0 | if (ctx->text.BlockDepth != 0) |
541 | 0 | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_eoclip", NULL); |
542 | |
|
543 | 0 | return code; |
544 | 0 | } |
545 | | |
546 | | int pdfi_rectpath(pdf_context *ctx) |
547 | 3.50M | { |
548 | 3.50M | int code; |
549 | 3.50M | double Values[4]; |
550 | | |
551 | 3.50M | code = pdfi_destack_reals(ctx, Values, 4); |
552 | 3.50M | if (code < 0) |
553 | 175k | return code; |
554 | | |
555 | 3.33M | if (ctx->text.BlockDepth != 0) |
556 | 172k | pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_rectpath", NULL); |
557 | | |
558 | 3.33M | return StorePathSegment(ctx, pdfi_re_seg, (double *)&Values); |
559 | 3.50M | } |