1 /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevpdfd.c,v 1.71 2005/10/12 08:16:50 leonardo Exp $ */
18 /* Path drawing procedures for pdfwrite driver */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gxdevice.h"
23 #include "gxfixed.h"
24 #include "gxistate.h"
25 #include "gxpaint.h"
26 #include "gxcoord.h"
27 #include "gxdevmem.h"
28 #include "gxcolor2.h"
29 #include "gxhldevc.h"
30 #include "gsstate.h"
31 #include "gserrors.h"
32 #include "gsptype2.h"
33 #include "gzpath.h"
34 #include "gzcpath.h"
35 #include "gdevpdfx.h"
36 #include "gdevpdfg.h"
37 #include "gdevpdfo.h"
38 #include "gsutil.h"
39
40 /* ---------------- Drawing ---------------- */
41
42 /* Fill a rectangle. */
43 int
gdev_pdf_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)44 gdev_pdf_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
45 gx_color_index color)
46 {
47 gx_device_pdf *pdev = (gx_device_pdf *) dev;
48 int code;
49
50 /* Make a special check for the initial fill with white, */
51 /* which shouldn't cause the page to be opened. */
52 if (color == pdev->white && !is_in_page(pdev))
53 return 0;
54 code = pdf_open_page(pdev, PDF_IN_STREAM);
55 if (code < 0)
56 return code;
57 /* Make sure we aren't being clipped. */
58 code = pdf_put_clip_path(pdev, NULL);
59 if (code < 0)
60 return code;
61 pdf_set_pure_color(pdev, color, &pdev->saved_fill_color,
62 &pdev->fill_used_process_color,
63 &psdf_set_fill_color_commands);
64 if (!pdev->HaveStrokeColor)
65 pdev->saved_stroke_color = pdev->saved_fill_color;
66 pprintd4(pdev->strm, "%d %d %d %d re f\n", x, y, w, h);
67 return 0;
68 }
69
70 /* ---------------- Path drawing ---------------- */
71
72 /* ------ Vector device implementation ------ */
73
74 private int
pdf_setlinewidth(gx_device_vector * vdev,floatp width)75 pdf_setlinewidth(gx_device_vector * vdev, floatp width)
76 {
77 /* Acrobat Reader doesn't accept negative line widths. */
78 return psdf_setlinewidth(vdev, fabs(width));
79 }
80
81 private int
pdf_can_handle_hl_color(gx_device_vector * vdev,const gs_imager_state * pis,const gx_drawing_color * pdc)82 pdf_can_handle_hl_color(gx_device_vector * vdev, const gs_imager_state * pis,
83 const gx_drawing_color * pdc)
84 {
85 return pis != NULL;
86 }
87
88 private int
pdf_setfillcolor(gx_device_vector * vdev,const gs_imager_state * pis,const gx_drawing_color * pdc)89 pdf_setfillcolor(gx_device_vector * vdev, const gs_imager_state * pis,
90 const gx_drawing_color * pdc)
91 {
92 gx_device_pdf *const pdev = (gx_device_pdf *)vdev;
93 bool hl_color = (*vdev_proc(vdev, can_handle_hl_color)) (vdev, pis, pdc);
94 const gs_imager_state *pis_for_hl_color = (hl_color ? pis : NULL);
95
96 if (!pdev->HaveStrokeColor) {
97 /* opdfread.ps assumes same color for stroking and non-stroking operations. */
98 int code = pdf_set_drawing_color(pdev, pis_for_hl_color, pdc, &pdev->saved_stroke_color,
99 &pdev->stroke_used_process_color,
100 &psdf_set_stroke_color_commands);
101 if (code < 0)
102 return code;
103 }
104 return pdf_set_drawing_color(pdev, pis_for_hl_color, pdc, &pdev->saved_fill_color,
105 &pdev->fill_used_process_color,
106 &psdf_set_fill_color_commands);
107 }
108
109 private int
pdf_setstrokecolor(gx_device_vector * vdev,const gs_imager_state * pis,const gx_drawing_color * pdc)110 pdf_setstrokecolor(gx_device_vector * vdev, const gs_imager_state * pis,
111 const gx_drawing_color * pdc)
112 {
113 gx_device_pdf *const pdev = (gx_device_pdf *)vdev;
114 bool hl_color = (*vdev_proc(vdev, can_handle_hl_color)) (vdev, pis, pdc);
115 const gs_imager_state *pis_for_hl_color = (hl_color ? pis : NULL);
116
117 if (!pdev->HaveStrokeColor) {
118 /* opdfread.ps assumes same color for stroking and non-stroking operations. */
119 int code = pdf_set_drawing_color(pdev, pis_for_hl_color, pdc, &pdev->saved_fill_color,
120 &pdev->fill_used_process_color,
121 &psdf_set_fill_color_commands);
122 if (code < 0)
123 return code;
124 }
125 return pdf_set_drawing_color(pdev, pis_for_hl_color, pdc, &pdev->saved_stroke_color,
126 &pdev->stroke_used_process_color,
127 &psdf_set_stroke_color_commands);
128 }
129
130 private int
pdf_dorect(gx_device_vector * vdev,fixed x0,fixed y0,fixed x1,fixed y1,gx_path_type_t type)131 pdf_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1,
132 gx_path_type_t type)
133 {
134 gx_device_pdf *pdev = (gx_device_pdf *)vdev;
135 fixed xmax = int2fixed(vdev->width), ymax = int2fixed(vdev->height);
136 int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
137 fixed xmin = (pdev->sbstack_depth > bottom ? -xmax : 0);
138 fixed ymin = (pdev->sbstack_depth > bottom ? -ymax : 0);
139
140 /*
141 * If we're doing a stroke operation, expand the checking box by the
142 * stroke width.
143 */
144 if (type & gx_path_type_stroke) {
145 double w = vdev->state.line_params.half_width;
146 double xw = w * (fabs(vdev->state.ctm.xx) + fabs(vdev->state.ctm.yx));
147 int d = float2fixed(xw) + fixed_1;
148
149 xmin -= d;
150 xmax += d;
151 ymin -= d;
152 ymax += d;
153 }
154 if (!(type & gx_path_type_clip) &&
155 (x0 > xmax || x1 < xmin || y0 > ymax || y1 < ymin ||
156 x0 > x1 || y0 > y1)
157 )
158 return 0; /* nothing to fill or stroke */
159 /*
160 * Clamp coordinates to avoid tripping over Acrobat Reader's limit
161 * of 32K on user coordinate values.
162 */
163 if (x0 < xmin)
164 x0 = xmin;
165 if (x1 > xmax)
166 x1 = xmax;
167 if (y0 < ymin)
168 y0 = ymin;
169 if (y1 > ymax)
170 y1 = ymax;
171 return psdf_dorect(vdev, x0, y0, x1, y1, type);
172 }
173
174 private int
pdf_endpath(gx_device_vector * vdev,gx_path_type_t type)175 pdf_endpath(gx_device_vector * vdev, gx_path_type_t type)
176 {
177 return 0; /* always handled by caller */
178 }
179
180 const gx_device_vector_procs pdf_vector_procs = {
181 /* Page management */
182 NULL,
183 /* Imager state */
184 pdf_setlinewidth,
185 psdf_setlinecap,
186 psdf_setlinejoin,
187 psdf_setmiterlimit,
188 psdf_setdash,
189 psdf_setflat,
190 psdf_setlogop,
191 /* Other state */
192 pdf_can_handle_hl_color,
193 pdf_setfillcolor,
194 pdf_setstrokecolor,
195 /* Paths */
196 psdf_dopath,
197 pdf_dorect,
198 psdf_beginpath,
199 psdf_moveto,
200 psdf_lineto,
201 psdf_curveto,
202 psdf_closepath,
203 pdf_endpath
204 };
205
206 /* ------ Utilities ------ */
207
208 /* Store a copy of clipping path. */
209 int
pdf_remember_clip_path(gx_device_pdf * pdev,const gx_clip_path * pcpath)210 pdf_remember_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
211 {
212 /* Used for skipping redundant clip paths. SF bug #624168. */
213 if (pdev->clip_path != 0) {
214 gx_path_free(pdev->clip_path, "pdf clip path");
215 }
216 if (pcpath == 0) {
217 pdev->clip_path = 0;
218 return 0;
219 }
220 pdev->clip_path = gx_path_alloc(pdev->pdf_memory, "pdf clip path");
221 if (pdev->clip_path == 0)
222 return_error(gs_error_VMerror);
223 return gx_cpath_to_path((gx_clip_path *)pcpath, pdev->clip_path);
224 }
225
226 /* Check if same clipping path. */
227 private int
pdf_is_same_clip_path(gx_device_pdf * pdev,const gx_clip_path * pcpath)228 pdf_is_same_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
229 {
230 /* Used for skipping redundant clip paths. SF bug #624168. */
231 gs_cpath_enum cenum;
232 gs_path_enum penum;
233 gs_fixed_point vs0[3], vs1[3];
234 int code, pe_op;
235
236 if ((pdev->clip_path != 0) != (pcpath != 0))
237 return 0;
238 code = gx_path_enum_init(&penum, pdev->clip_path);
239 if (code < 0)
240 return code;
241 code = gx_cpath_enum_init(&cenum, (gx_clip_path *)pcpath);
242 if (code < 0)
243 return code;
244 while ((code = gx_cpath_enum_next(&cenum, vs0)) > 0) {
245 pe_op = gx_path_enum_next(&penum, vs1);
246 if (pe_op < 0)
247 return pe_op;
248 if (pe_op != code)
249 return 0;
250 switch (pe_op) {
251 case gs_pe_curveto:
252 if (vs0[1].x != vs1[1].x || vs0[1].y != vs1[1].y ||
253 vs0[2].x != vs1[2].x || vs0[2].y != vs1[2].y)
254 return 0;
255 case gs_pe_moveto:
256 case gs_pe_lineto:
257 if (vs0[0].x != vs1[0].x || vs0[0].y != vs1[0].y)
258 return 0;
259 }
260 }
261 if (code < 0)
262 return code;
263 code = gx_path_enum_next(&penum, vs1);
264 if (code < 0)
265 return code;
266 return (code == 0);
267 }
268
269 /* Test whether we will need to put the clipping path. */
270 bool
pdf_must_put_clip_path(gx_device_pdf * pdev,const gx_clip_path * pcpath)271 pdf_must_put_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
272 {
273 if (pcpath == NULL) {
274 if (pdev->clip_path_id == pdev->no_clip_path_id)
275 return false;
276 } else {
277 if (pdev->clip_path_id == pcpath->id)
278 return false;
279 if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
280 int2fixed(pdev->width),
281 int2fixed(pdev->height)))
282 if (pdev->clip_path_id == pdev->no_clip_path_id)
283 return false;
284 if (pdf_is_same_clip_path(pdev, pcpath) > 0) {
285 pdev->clip_path_id = pcpath->id;
286 return false;
287 }
288 }
289 return true;
290 }
291
292 /* Put a single element of a clipping path list. */
293 private int
pdf_put_clip_path_list_elem(gx_device_pdf * pdev,gx_cpath_path_list * e,gs_path_enum * cenum,gdev_vector_dopath_state_t * state,gs_fixed_point vs[3])294 pdf_put_clip_path_list_elem(gx_device_pdf * pdev, gx_cpath_path_list *e,
295 gs_path_enum *cenum, gdev_vector_dopath_state_t *state,
296 gs_fixed_point vs[3])
297 { /* This recursive function provides a reverse order of the list elements. */
298 int pe_op;
299
300 if (e->next != NULL) {
301 int code = pdf_put_clip_path_list_elem(pdev, e->next, cenum, state, vs);
302
303 if (code != 0)
304 return code;
305 }
306 gx_path_enum_init(cenum, &e->path);
307 while ((pe_op = gx_path_enum_next(cenum, vs)) > 0)
308 gdev_vector_dopath_segment(state, pe_op, vs);
309 pprints1(pdev->strm, "%s n\n", (e->rule <= 0 ? "W" : "W*"));
310 if (pe_op < 0)
311 return pe_op;
312 return 0;
313 }
314
315 /* Put a clipping path on the output file. */
316 int
pdf_put_clip_path(gx_device_pdf * pdev,const gx_clip_path * pcpath)317 pdf_put_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
318 {
319 int code;
320 stream *s = pdev->strm;
321 gs_id new_id;
322
323 /* Check for no update needed. */
324 if (pcpath == NULL) {
325 if (pdev->clip_path_id == pdev->no_clip_path_id)
326 return 0;
327 new_id = pdev->no_clip_path_id;
328 } else {
329 if (pdev->clip_path_id == pcpath->id)
330 return 0;
331 new_id = pcpath->id;
332 if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
333 int2fixed(pdev->width),
334 int2fixed(pdev->height))
335 ) {
336 if (pdev->clip_path_id == pdev->no_clip_path_id)
337 return 0;
338 new_id = pdev->no_clip_path_id;
339 }
340 code = pdf_is_same_clip_path(pdev, pcpath);
341 if (code < 0)
342 return code;
343 if (code) {
344 pdev->clip_path_id = new_id;
345 return 0;
346 }
347 }
348 /*
349 * The contents must be open already, so the following will only exit
350 * text or string context.
351 */
352 code = pdf_open_contents(pdev, PDF_IN_STREAM);
353 if (code < 0)
354 return code;
355 /* Use Q to unwind the old clipping path. */
356 if (pdev->vgstack_depth > pdev->vgstack_bottom) {
357 code = pdf_restore_viewer_state(pdev, s);
358 if (code < 0)
359 return code;
360 }
361 if (new_id != pdev->no_clip_path_id) {
362 gdev_vector_dopath_state_t state;
363 gs_fixed_point vs[3];
364 int pe_op;
365
366 /* Use q to allow the new clipping path to unwind. */
367 code = pdf_save_viewer_state(pdev, s);
368 if (code < 0)
369 return code;
370 gdev_vector_dopath_init(&state, (gx_device_vector *)pdev,
371 gx_path_type_fill, NULL);
372 if (pcpath->path_list == NULL) {
373 gs_cpath_enum cenum;
374
375 /*
376 * We have to break 'const' here because the clip path
377 * enumeration logic uses some internal mark bits.
378 * This is very unfortunate, but until we can come up with
379 * a better algorithm, it's necessary.
380 */
381 gx_cpath_enum_init(&cenum, (gx_clip_path *) pcpath);
382 while ((pe_op = gx_cpath_enum_next(&cenum, vs)) > 0)
383 gdev_vector_dopath_segment(&state, pe_op, vs);
384 pprints1(s, "%s n\n", (pcpath->rule <= 0 ? "W" : "W*"));
385 if (pe_op < 0)
386 return pe_op;
387 } else {
388 gs_path_enum cenum;
389
390 code = pdf_put_clip_path_list_elem(pdev, pcpath->path_list, &cenum, &state, vs);
391 if (code < 0)
392 return code;
393 }
394 }
395 pdev->clip_path_id = new_id;
396 return pdf_remember_clip_path(pdev,
397 (pdev->clip_path_id == pdev->no_clip_path_id ? NULL : pcpath));
398 }
399
400 /*
401 * Compute the scaling to ensure that user coordinates for a path are within
402 * Acrobat's range. Return true if scaling was needed. In this case, the
403 * CTM will be multiplied by *pscale, and all coordinates will be divided by
404 * *pscale.
405 */
406 private bool
make_rect_scaling(const gx_device_pdf * pdev,const gs_fixed_rect * bbox,floatp prescale,double * pscale)407 make_rect_scaling(const gx_device_pdf *pdev, const gs_fixed_rect *bbox,
408 floatp prescale, double *pscale)
409 {
410 double bmin, bmax;
411
412 bmin = min(bbox->p.x / pdev->scale.x, bbox->p.y / pdev->scale.y) * prescale;
413 bmax = max(bbox->q.x / pdev->scale.x, bbox->q.y / pdev->scale.y) * prescale;
414 if (bmin <= int2fixed(-MAX_USER_COORD) ||
415 bmax > int2fixed(MAX_USER_COORD)
416 ) {
417 /* Rescale the path. */
418 *pscale = max(bmin / int2fixed(-MAX_USER_COORD),
419 bmax / int2fixed(MAX_USER_COORD));
420 return true;
421 } else {
422 *pscale = 1;
423 return false;
424 }
425 }
426
427 /*
428 * Prepare a fill with a color anc a clipping path.
429 * Return 1 if there is nothing to paint.
430 */
431 private int
prepare_fill_with_clip(gx_device_pdf * pdev,const gs_imager_state * pis,gs_fixed_rect * box,bool have_path,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)432 prepare_fill_with_clip(gx_device_pdf *pdev, const gs_imager_state * pis,
433 gs_fixed_rect *box, bool have_path,
434 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
435 {
436 bool new_clip;
437 int code;
438
439 /*
440 * Check for an empty clipping path.
441 */
442 if (pcpath) {
443 gx_cpath_outer_box(pcpath, box);
444 if (box->p.x >= box->q.x || box->p.y >= box->q.y)
445 return 1; /* empty clipping path */
446 }
447 if (gx_dc_is_pure(pdcolor)) {
448 /*
449 * Make a special check for the initial fill with white,
450 * which shouldn't cause the page to be opened.
451 */
452 if (gx_dc_pure_color(pdcolor) == pdev->white &&
453 !is_in_page(pdev) && pdev->sbstack_depth == 0)
454 return 1;
455 }
456 new_clip = pdf_must_put_clip_path(pdev, pcpath);
457 if (have_path || pdev->context == PDF_IN_NONE || new_clip) {
458 if (new_clip)
459 code = pdf_unclip(pdev);
460 else
461 code = pdf_open_page(pdev, PDF_IN_STREAM);
462 if (code < 0)
463 return code;
464 }
465 code = pdf_prepare_fill(pdev, pis);
466 if (code < 0)
467 return code;
468 return pdf_put_clip_path(pdev, pcpath);
469 }
470
471 /* -------------A local image converter device. -----------------------------*/
472
473 public_st_pdf_lcvd_t();
474
475 private int
lcvd_fill_rectangle_shifted(gx_device * dev,int x,int y,int width,int height,gx_color_index color)476 lcvd_fill_rectangle_shifted(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
477 {
478 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
479
480 return cvd->std_fill_rectangle((gx_device *)&cvd->mdev,
481 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, color);
482 }
483 private int
lcvd_fill_rectangle_shifted2(gx_device * dev,int x,int y,int width,int height,gx_color_index color)484 lcvd_fill_rectangle_shifted2(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
485 {
486 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
487 int code;
488
489 code = (*dev_proc(cvd->mask, fill_rectangle))((gx_device *)cvd->mask,
490 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, (gx_color_index)1);
491 if (code < 0)
492 return code;
493 return cvd->std_fill_rectangle((gx_device *)&cvd->mdev,
494 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, color);
495 }
496 private int
lcvd_fill_rectangle_shifted_from_mdev(gx_device * dev,int x,int y,int width,int height,gx_color_index color)497 lcvd_fill_rectangle_shifted_from_mdev(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
498 {
499 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
500
501 return cvd->std_fill_rectangle((gx_device *)&cvd->mdev,
502 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, color);
503 }
504 private void
lcvd_get_clipping_box_from_target(gx_device * dev,gs_fixed_rect * pbox)505 lcvd_get_clipping_box_from_target(gx_device *dev, gs_fixed_rect *pbox)
506 {
507 gx_device_memory *mdev = (gx_device_memory *)dev;
508
509 (*dev_proc(mdev->target, get_clipping_box))(mdev->target, pbox);
510 }
511 private int
lcvd_pattern_manage(gx_device * pdev1,gx_bitmap_id id,gs_pattern1_instance_t * pinst,pattern_manage_t function)512 lcvd_pattern_manage(gx_device *pdev1, gx_bitmap_id id,
513 gs_pattern1_instance_t *pinst, pattern_manage_t function)
514 {
515 if (function == pattern_manage__shading_area)
516 return 1; /* Request shading area. */
517 return 0;
518 }
519 private int
lcvd_close_device_with_writing(gx_device * pdev)520 lcvd_close_device_with_writing(gx_device *pdev)
521 {
522 /* Assuming 'mdev' is being closed before 'mask' - see gx_image3_end_image. */
523 pdf_lcvd_t *cvd = (pdf_lcvd_t *)pdev;
524 int code, code1;
525
526 code = pdf_dump_converted_image(cvd->pdev, cvd);
527 code1 = cvd->std_close_device((gx_device *)&cvd->mdev);
528 return code < 0 ? code : code1;
529 }
530
531 private int
write_image(gx_device_pdf * pdev,gx_device_memory * mdev,gs_matrix * m)532 write_image(gx_device_pdf *pdev, gx_device_memory *mdev, gs_matrix *m)
533 {
534 gs_image_t image;
535 pdf_image_writer writer;
536 const int sourcex = 0;
537 int code;
538
539 if (m != NULL)
540 pdf_put_matrix(pdev, NULL, m, " cm\n");
541 code = pdf_copy_color_data(pdev, mdev->base, sourcex,
542 mdev->raster, gx_no_bitmap_id, 0, 0, mdev->width, mdev->height,
543 &image, &writer, 2);
544 if (code == 1)
545 code = 0; /* Empty image. */
546 else if (code == 0)
547 code = pdf_do_image(pdev, writer.pres, NULL, true);
548 return code;
549 }
550 private int
write_mask(gx_device_pdf * pdev,gx_device_memory * mdev,gs_matrix * m)551 write_mask(gx_device_pdf *pdev, gx_device_memory *mdev, gs_matrix *m)
552 {
553 const int sourcex = 0;
554 gs_id save_clip_id = pdev->clip_path_id;
555 bool save_skip_color = pdev->skip_colors;
556 int code;
557
558 if (m != NULL)
559 pdf_put_matrix(pdev, NULL, m, " cm\n");
560 pdev->clip_path_id = pdev->no_clip_path_id;
561 pdev->skip_colors = true;
562 code = gdev_pdf_copy_mono((gx_device *)pdev, mdev->base, sourcex,
563 mdev->raster, gx_no_bitmap_id, 0, 0, mdev->width, mdev->height,
564 gx_no_color_index, (gx_color_index)0);
565 pdev->clip_path_id = save_clip_id;
566 pdev->skip_colors = save_skip_color;
567 return code;
568 }
569
570 private void
max_subimage_width(int width,byte * base,int x0,long count1,int * x1,long * count)571 max_subimage_width(int width, byte *base, int x0, long count1, int *x1, long *count)
572 {
573 long c = 0, c1 = count1 - 1;
574 int x = x0;
575 byte p = 1; /* The inverse of the previous bit. */
576 byte r; /* The inverse of the current bit. */
577 byte *q = base + (x / 8), m = 0x80 >> (x % 8);
578
579 for (; x < width; x++) {
580 r = !(*q & m);
581 if (p != r) {
582 if (c >= c1) {
583 if (!r)
584 goto ex; /* stop before the upgrade. */
585 }
586 c++;
587 }
588 p = r;
589 m >>= 1;
590 if (!m) {
591 m = 0x80;
592 q++;
593 }
594 }
595 if (p)
596 c++; /* Account the last downgrade. */
597 ex:
598 *count = c;
599 *x1 = x;
600 }
601
602 private void
compute_subimage(int width,int height,int raster,byte * base,int x0,int y0,long MaxClipPathSize,int * x1,int * y1)603 compute_subimage(int width, int height, int raster, byte *base,
604 int x0, int y0, long MaxClipPathSize, int *x1, int *y1)
605 {
606 /* Returns a semiopen range : [x0:x1)*[y0:y1). */
607 if (x0 != 0) {
608 long count;
609
610 /* A partial single scanline. */
611 max_subimage_width(width, base + y0 * raster, x0, MaxClipPathSize / 4, x1, &count);
612 *y1 = y0;
613 } else {
614 int xx, y = y0, yy;
615 long count, count1 = MaxClipPathSize / 4;
616
617 for(; y < height && count1 > 0; ) {
618 max_subimage_width(width, base + y * raster, 0, count1, &xx, &count);
619 if (xx < width) {
620 if (y == y0) {
621 /* Partial single scanline. */
622 *y1 = y + 1;
623 *x1 = xx;
624 return;
625 } else {
626 /* Full lines before this scanline. */
627 break;
628 }
629 }
630 count1 -= count;
631 yy = y + 1;
632 for (; yy < height; yy++)
633 if (memcmp(base + raster * y, base + raster * yy, raster))
634 break;
635 y = yy;
636
637 }
638 *y1 = y;
639 *x1 = width;
640 }
641 }
642
643 private int
image_line_to_clip(gx_device_pdf * pdev,byte * base,int x0,int x1,int y0,int y1,bool started)644 image_line_to_clip(gx_device_pdf *pdev, byte *base, int x0, int x1, int y0, int y1, bool started)
645 { /* returns the number of segments or error code. */
646 int x = x0, xx;
647 byte *q = base + (x / 8), m = 0x80 >> (x % 8);
648 long c = 0;
649
650 for (;;) {
651 /* Look for upgrade : */
652 for (; x < x1; x++) {
653 if (*q & m)
654 break;
655 m >>= 1;
656 if (!m) {
657 m = 0x80;
658 q++;
659 }
660 }
661 if (x == x1)
662 return c;
663 xx = x;
664 /* Look for downgrade : */
665 for (; x < x1; x++) {
666 if (!(*q & m))
667 break;
668 m >>= 1;
669 if (!m) {
670 m = 0x80;
671 q++;
672 }
673 }
674 /* Found the interval [xx:x). */
675 if (!started) {
676 stream_puts(pdev->strm, "n\n");
677 started = true;
678 }
679 pprintld2(pdev->strm, "%ld %ld m ", xx, y0);
680 pprintld2(pdev->strm, "%ld %ld l ", x, y0);
681 pprintld2(pdev->strm, "%ld %ld l ", x, y1);
682 pprintld2(pdev->strm, "%ld %ld l h\n", xx, y1);
683 c += 4;
684 }
685 }
686
687 private int
mask_to_clip(gx_device_pdf * pdev,int width,int height,int raster,byte * base,int x0,int y0,int x1,int y1)688 mask_to_clip(gx_device_pdf *pdev, int width, int height,
689 int raster, byte *base, int x0, int y0, int x1, int y1)
690 {
691 int y, yy, code = 0;
692 bool has_segments = false;
693
694 for (y = y0; y < y1 && code >= 0;) {
695 yy = y + 1;
696 if (x0 == 0) {
697 for (; yy < y1; yy++)
698 if (memcmp(base + raster * y, base + raster * yy, raster))
699 break;
700 }
701 code = image_line_to_clip(pdev, base + raster * y, x0, x1, y, yy, has_segments);
702 if (code > 0)
703 has_segments = true;
704 y = yy;
705 }
706 if (has_segments)
707 stream_puts(pdev->strm, "W n\n");
708 return code < 0 ? code : has_segments ? 1 : 0;
709 }
710
711 private int
write_subimage(gx_device_pdf * pdev,gx_device_memory * mdev,int x,int y,int x1,int y1)712 write_subimage(gx_device_pdf *pdev, gx_device_memory *mdev, int x, int y, int x1, int y1)
713 {
714 gs_image_t image;
715 pdf_image_writer writer;
716 /* expand in 1 pixel to provide a proper color interpolation */
717 int X = max(0, x - 1);
718 int Y = max(0, y - 1);
719 int X1 = min(mdev->width, x1 + 1);
720 int Y1 = min(mdev->height, y1 + 1);
721 int code;
722
723 code = pdf_copy_color_data(pdev, mdev->base + mdev->raster * Y, X,
724 mdev->raster, gx_no_bitmap_id,
725 X, Y, X1 - X, Y1 - Y,
726 &image, &writer, 2);
727 if (code < 0)
728 return code;
729 if (!writer.pres)
730 return 0; /* inline image. */
731 return pdf_do_image(pdev, writer.pres, NULL, true);
732 }
733
734 private int
write_image_with_clip(gx_device_pdf * pdev,pdf_lcvd_t * cvd)735 write_image_with_clip(gx_device_pdf *pdev, pdf_lcvd_t *cvd)
736 {
737 int x = 0, y = 0;
738 int code, code1;
739
740 if (cvd->write_matrix)
741 pdf_put_matrix(pdev, NULL, &cvd->m, " cm\n");
742 for(;;) {
743 int x1, y1;
744
745 compute_subimage(cvd->mask->width, cvd->mask->height,
746 cvd->mask->raster, cvd->mask->base,
747 x, y, max(pdev->MaxClipPathSize, 100), &x1, &y1);
748 code = mask_to_clip(pdev,
749 cvd->mask->width, cvd->mask->height,
750 cvd->mask->raster, cvd->mask->base,
751 x, y, x1, y1);
752 if (code < 0)
753 return code;
754 if (code > 0) {
755 code1 = write_subimage(pdev, &cvd->mdev, x, y, x1, y1);
756 if (code1 < 0)
757 return code1;
758 }
759 if (x1 >= cvd->mdev.width && y1 >= cvd->mdev.height)
760 break;
761 if (code > 0)
762 stream_puts(pdev->strm, "Q q\n");
763 if (x1 == cvd->mask->width) {
764 x = 0;
765 y = y1;
766 } else {
767 x = x1;
768 y = y1;
769 }
770 }
771 return 0;
772 }
773
774 int
pdf_dump_converted_image(gx_device_pdf * pdev,pdf_lcvd_t * cvd)775 pdf_dump_converted_image(gx_device_pdf *pdev, pdf_lcvd_t *cvd)
776 {
777 int code = 0;
778
779 if (!cvd->path_is_empty || cvd->has_background) {
780 if (!cvd->has_background)
781 stream_puts(pdev->strm, "W n\n");
782 code = write_image(pdev, &cvd->mdev, (cvd->write_matrix ? &cvd->m : NULL));
783 cvd->path_is_empty = true;
784 } else if (!cvd->mask_is_empty && pdev->PatternImagemask) {
785 /* Convert to imagemask with a pattern color. */
786 /* See also use_image_as_pattern in gdevpdfi.c . */
787 gs_imager_state s;
788 gs_pattern1_instance_t inst;
789 gs_id id = gs_next_ids(cvd->mdev.memory, 1);
790 cos_value_t v;
791 const pdf_resource_t *pres;
792
793 memset(&s, 0, sizeof(s));
794 s.ctm.xx = cvd->m.xx;
795 s.ctm.xy = cvd->m.xy;
796 s.ctm.yx = cvd->m.yx;
797 s.ctm.yy = cvd->m.yy;
798 s.ctm.tx = cvd->m.tx;
799 s.ctm.ty = cvd->m.ty;
800 memset(&inst, 0, sizeof(inst));
801 inst.saved = (gs_state *)&s; /* HACK : will use s.ctm only. */
802 inst.template.PaintType = 1;
803 inst.template.TilingType = 1;
804 inst.template.BBox.p.x = inst.template.BBox.p.y = 0;
805 inst.template.BBox.q.x = cvd->mdev.width;
806 inst.template.BBox.q.y = cvd->mdev.height;
807 inst.template.XStep = (float)cvd->mdev.width;
808 inst.template.YStep = (float)cvd->mdev.height;
809 code = (*dev_proc(pdev, pattern_manage))((gx_device *)pdev,
810 id, &inst, pattern_manage__start_accum);
811 if (code >= 0) {
812 stream_puts(pdev->strm, "W n\n");
813 code = write_image(pdev, &cvd->mdev, NULL);
814 }
815 pres = pdev->accumulating_substream_resource;
816 if (code >= 0)
817 code = (*dev_proc(pdev, pattern_manage))((gx_device *)pdev,
818 id, &inst, pattern_manage__finish_accum);
819 if (code >= 0)
820 code = (*dev_proc(pdev, pattern_manage))((gx_device *)pdev,
821 id, &inst, pattern_manage__load);
822 if (code >= 0)
823 code = pdf_cs_Pattern_colored(pdev, &v);
824 if (code >= 0) {
825 cos_value_write(&v, pdev);
826 pprintld1(pdev->strm, " cs /R%ld scn ", pdf_resource_id(pres));
827 }
828 if (code >= 0)
829 code = write_mask(pdev, cvd->mask, (cvd->write_matrix ? &cvd->m : NULL));
830 cvd->mask_is_empty = true;
831 } else if (!cvd->mask_is_empty && !pdev->PatternImagemask) {
832 /* Convert to image with a clipping path. */
833 stream_puts(pdev->strm, "q\n");
834 code = write_image_with_clip(pdev, cvd);
835 stream_puts(pdev->strm, "Q\n");
836 }
837 if (code > 0)
838 code = (*dev_proc(&cvd->mdev, fill_rectangle))((gx_device *)&cvd->mdev,
839 0, 0, cvd->mdev.width, cvd->mdev.height, (gx_color_index)0);
840 return code;
841 }
842 private int
lcvd_handle_fill_path_as_shading_coverage(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)843 lcvd_handle_fill_path_as_shading_coverage(gx_device *dev,
844 const gs_imager_state *pis, gx_path *ppath,
845 const gx_fill_params *params,
846 const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
847 {
848 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
849 gx_device_pdf *pdev = (gx_device_pdf *)cvd->mdev.target;
850 int code;
851
852 if (cvd->has_background)
853 return 0;
854 if (gx_path_is_null(ppath)) {
855 /* use the mask. */
856 if (!cvd->path_is_empty) {
857 code = pdf_dump_converted_image(pdev, cvd);
858 if (code < 0)
859 return code;
860 stream_puts(pdev->strm, "Q q\n");
861 dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted2;
862 }
863 if (!cvd->mask_is_clean || !cvd->path_is_empty) {
864 code = (*dev_proc(cvd->mask, fill_rectangle))((gx_device *)cvd->mask,
865 0, 0, cvd->mask->width, cvd->mask->height, (gx_color_index)0);
866 if (code < 0)
867 return code;
868 cvd->mask_is_clean = true;
869 }
870 cvd->path_is_empty = true;
871 cvd->mask_is_empty = false;
872 } else {
873 gs_matrix m;
874
875 gs_make_translation(cvd->path_offset.x, cvd->path_offset.y, &m);
876 /* use the clipping. */
877 if (!cvd->mask_is_empty) {
878 code = pdf_dump_converted_image(pdev, cvd);
879 if (code < 0)
880 return code;
881 stream_puts(pdev->strm, "Q q\n");
882 dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted;
883 cvd->mask_is_empty = true;
884 }
885 code = gdev_vector_dopath((gx_device_vector *)pdev, ppath,
886 gx_path_type_fill | gx_path_type_optimize, &m);
887 if (code < 0)
888 return code;
889 stream_puts(pdev->strm, "h\n");
890 cvd->path_is_empty = false;
891 }
892 return 0;
893 }
894
895 int
pdf_setup_masked_image_converter(gx_device_pdf * pdev,gs_memory_t * mem,const gs_matrix * m,pdf_lcvd_t ** pcvd,bool need_mask,int x,int y,int w,int h,bool write_on_close)896 pdf_setup_masked_image_converter(gx_device_pdf *pdev, gs_memory_t *mem, const gs_matrix *m, pdf_lcvd_t **pcvd,
897 bool need_mask, int x, int y, int w, int h, bool write_on_close)
898 {
899 int code;
900 gx_device_memory *mask = 0;
901 pdf_lcvd_t *cvd = *pcvd;
902
903 if (cvd == NULL) {
904 cvd = gs_alloc_struct(mem, pdf_lcvd_t, &st_pdf_lcvd_t, "pdf_setup_masked_image_converter");
905 if (cvd == NULL)
906 return_error(gs_error_VMerror);
907 *pcvd = cvd;
908 }
909 cvd->pdev = pdev;
910 gs_make_mem_device(&cvd->mdev, gdev_mem_device_for_bits(pdev->color_info.depth),
911 mem, 0, (gx_device *)pdev);
912 cvd->mdev.width = w;
913 cvd->mdev.height = h;
914 cvd->mdev.mapped_x = x;
915 cvd->mdev.mapped_y = y;
916 cvd->mdev.bitmap_memory = mem;
917 cvd->mdev.color_info = pdev->color_info;
918 cvd->path_is_empty = true;
919 cvd->mask_is_empty = true;
920 cvd->mask_is_clean = false;
921 cvd->has_background = false;
922 cvd->mask = 0;
923 cvd->write_matrix = true;
924 code = (*dev_proc(&cvd->mdev, open_device))((gx_device *)&cvd->mdev);
925 if (code < 0)
926 return code;
927 code = (*dev_proc(&cvd->mdev, fill_rectangle))((gx_device *)&cvd->mdev,
928 0, 0, cvd->mdev.width, cvd->mdev.height, (gx_color_index)0);
929 if (code < 0)
930 return code;
931 if (need_mask) {
932 mask = gs_alloc_struct(mem, gx_device_memory, &st_device_memory, "pdf_setup_masked_image_converter");
933 if (mask == NULL)
934 return_error(gs_error_VMerror);
935 cvd->mask = mask;
936 gs_make_mem_mono_device(mask, mem, (gx_device *)pdev);
937 mask->width = cvd->mdev.width;
938 mask->height = cvd->mdev.height;
939 mask->bitmap_memory = mem;
940 code = (*dev_proc(mask, open_device))((gx_device *)mask);
941 if (code < 0)
942 return code;
943 if (write_on_close) {
944 code = (*dev_proc(mask, fill_rectangle))((gx_device *)mask,
945 0, 0, mask->width, mask->height, (gx_color_index)0);
946 if (code < 0)
947 return code;
948 }
949 }
950 cvd->std_fill_rectangle = dev_proc(&cvd->mdev, fill_rectangle);
951 cvd->std_close_device = dev_proc(&cvd->mdev, close_device);
952 if (!write_on_close) {
953 /* Type 3 images will write to the mask directly. */
954 dev_proc(&cvd->mdev, fill_rectangle) = (need_mask ? lcvd_fill_rectangle_shifted2
955 : lcvd_fill_rectangle_shifted);
956 } else
957 dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted_from_mdev;
958 dev_proc(&cvd->mdev, get_clipping_box) = lcvd_get_clipping_box_from_target;
959 dev_proc(&cvd->mdev, pattern_manage) = lcvd_pattern_manage;
960 dev_proc(&cvd->mdev, fill_path) = lcvd_handle_fill_path_as_shading_coverage;
961 cvd->m = *m;
962 if (write_on_close) {
963 cvd->mdev.is_open = true;
964 mask->is_open = true;
965 dev_proc(&cvd->mdev, close_device) = lcvd_close_device_with_writing;
966 }
967 return 0;
968 }
969
970 void
pdf_remove_masked_image_converter(gx_device_pdf * pdev,pdf_lcvd_t * cvd,bool need_mask)971 pdf_remove_masked_image_converter(gx_device_pdf *pdev, pdf_lcvd_t *cvd, bool need_mask)
972 {
973 (*dev_proc(&cvd->mdev, close_device))((gx_device *)&cvd->mdev);
974 if (cvd->mask) {
975 (*dev_proc(cvd->mask, close_device))((gx_device *)cvd->mask);
976 gs_free_object(cvd->mask->memory, cvd->mask, "pdf_remove_masked_image_converter");
977 }
978 }
979
980 private int
path_scale(gx_path * path,double scalex,double scaley)981 path_scale(gx_path *path, double scalex, double scaley)
982 {
983 segment *pseg = (segment *)path->first_subpath;
984
985 for (;pseg != NULL; pseg = pseg->next) {
986 pseg->pt.x = (fixed)floor(pseg->pt.x * scalex + 0.5);
987 pseg->pt.y = (fixed)floor(pseg->pt.y * scaley + 0.5);
988 if (pseg->type == s_curve) {
989 curve_segment *s = (curve_segment *)pseg;
990
991 s->p1.x = (fixed)floor(s->p1.x * scalex + 0.5);
992 s->p1.y = (fixed)floor(s->p1.y * scaley + 0.5);
993 s->p2.x = (fixed)floor(s->p2.x * scalex + 0.5);
994 s->p2.y = (fixed)floor(s->p2.y * scaley + 0.5);
995 }
996 }
997 path->position.x = (fixed)floor(path->position.x * scalex + 0.5);
998 path->position.y = (fixed)floor(path->position.y * scaley + 0.5);
999 return 0;
1000 }
1001
1002 /* ------ Driver procedures ------ */
1003
1004 /* Fill a path. */
1005 int
gdev_pdf_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)1006 gdev_pdf_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
1007 const gx_fill_params * params,
1008 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1009 {
1010 gx_device_pdf *pdev = (gx_device_pdf *) dev;
1011 int code;
1012 /*
1013 * HACK: we fill an empty path in order to set the clipping path
1014 * and the color for writing text. If it weren't for this, we
1015 * could detect and skip empty paths before putting out the clip
1016 * path or the color. We also clip with an empty path in order
1017 * to advance currentpoint for show operations without actually
1018 * drawing anything.
1019 */
1020 bool have_path;
1021 gs_fixed_rect box = {{0, 0}, {0, 0}};
1022
1023 have_path = !gx_path_is_void(ppath);
1024 if (!have_path && !pdev->vg_initial_set) {
1025 /* See lib/gs_pdfwr.ps about "initial graphic state". */
1026 pdf_prepare_initial_viewer_state(pdev, pis);
1027 pdf_reset_graphics(pdev);
1028 return 0;
1029 }
1030
1031 code = prepare_fill_with_clip(pdev, pis, &box, have_path, pdcolor, pcpath);
1032 if (code == gs_error_rangecheck) {
1033 /* Fallback to the default implermentation for handling
1034 a transparency with CompatibilityLevel<=1.3 . */
1035 return gx_default_fill_path((gx_device *)pdev, pis, ppath, params, pdcolor, pcpath);
1036 }
1037 if (code < 0)
1038 return code;
1039 if (code == 1)
1040 return 0; /* Nothing to paint. */
1041 code = pdf_setfillcolor((gx_device_vector *)pdev, pis, pdcolor);
1042 if (code == gs_error_rangecheck) {
1043 const bool convert_to_image = (pdev->CompatibilityLevel <= 1.2 &&
1044 gx_dc_is_pattern2_color(pdcolor));
1045
1046 if (!convert_to_image) {
1047 /* Fallback to the default implermentation for handling
1048 a shading with CompatibilityLevel<=1.2 . */
1049 return gx_default_fill_path(dev, pis, ppath, params, pdcolor, pcpath);
1050 } else {
1051 /* Convert a shading into a bitmap
1052 with CompatibilityLevel<=1.2 . */
1053 pdf_lcvd_t cvd, *pcvd = &cvd;
1054 int sx, sy;
1055 gs_fixed_rect bbox, bbox1;
1056 bool need_mask = gx_dc_pattern2_can_overlap(pdcolor);
1057 gs_matrix m, save_ctm = ctm_only(pis), ms, msi, mm;
1058 gs_int_point rect_size;
1059 /* double scalex = 1.9, scaley = 1.4; debug purpose only. */
1060 double scale, scalex = 1.0, scaley = 1.0;
1061 gx_drawing_color dc = *pdcolor;
1062 gs_pattern2_instance_t pi = *(gs_pattern2_instance_t *)dc.ccolor.pattern;
1063 gs_state *pgs = gs_state_copy(pi.saved, gs_state_memory(pi.saved));
1064
1065 if (pgs == NULL)
1066 return_error(gs_error_VMerror);
1067 dc.ccolor.pattern = (gs_pattern_instance_t *)π
1068 pi.saved = pgs;
1069 code = gx_path_bbox(ppath, &bbox);
1070 if (code < 0)
1071 return code;
1072 rect_intersect(bbox, box);
1073 code = gx_dc_pattern2_get_bbox(pdcolor, &bbox1);
1074 if (code < 0)
1075 return code;
1076 if (code)
1077 rect_intersect(bbox, bbox1);
1078 if (bbox.p.x >= bbox.q.x || bbox.p.y >= bbox.q.y)
1079 return 0;
1080 sx = fixed2int(bbox.p.x);
1081 sy = fixed2int(bbox.p.y);
1082 gs_make_identity(&m);
1083 rect_size.x = fixed2int(bbox.q.x + fixed_half) - sx;
1084 rect_size.y = fixed2int(bbox.q.y + fixed_half) - sy;
1085 if (rect_size.x == 0 || rect_size.y == 0)
1086 return 0;
1087 m.tx = (float)sx;
1088 m.ty = (float)sy;
1089 cvd.path_offset.x = sx;
1090 cvd.path_offset.y = sy;
1091 scale = (double)rect_size.x * rect_size.y * pdev->color_info.num_components /
1092 pdev->MaxShadingBitmapSize;
1093 if (scale > 1) {
1094 /* This section (together with the call to 'path_scale' below)
1095 sets up a downscaling when converting the shading into bitmap.
1096 We used floating point numbers to debug it, but in production
1097 we prefer to deal only with integers being powers of 2
1098 in order to avoid possible distorsions when scaling paths.
1099 */
1100 scalex = ceil(sqrt(scale));
1101 scalex = scaley = 1 << ilog2((int)scalex);
1102 if (scalex * scaley < scale)
1103 scalex *= 2;
1104 if (scalex * scaley < scale)
1105 scaley *= 2;
1106 rect_size.x = (int)floor(rect_size.x / scalex + 0.5);
1107 rect_size.y = (int)floor(rect_size.y / scaley + 0.5);
1108 gs_make_scaling(1.0 / scalex, 1.0 / scaley, &ms);
1109 gs_make_scaling(scalex, scaley, &msi);
1110 gs_matrix_multiply(&msi, &m, &m);
1111 gs_matrix_multiply(&ctm_only(pis), &ms, &mm);
1112 gs_setmatrix((gs_state *)pis, &mm);
1113 gs_matrix_multiply(&ctm_only((gs_imager_state *)pgs), &ms, &mm);
1114 gs_setmatrix((gs_state *)pgs, &mm);
1115 sx = fixed2int(bbox.p.x / (int)scalex);
1116 sy = fixed2int(bbox.p.y / (int)scaley);
1117 cvd.path_offset.x = sx; /* m.tx / scalex */
1118 cvd.path_offset.y = sy;
1119 }
1120 code = pdf_setup_masked_image_converter(pdev, pdev->memory, &m, &pcvd, need_mask, sx, sy,
1121 rect_size.x, rect_size.y, false);
1122 pcvd->has_background = gx_dc_pattern2_has_background(pdcolor);
1123 stream_puts(pdev->strm, "q\n");
1124 if (code >= 0) {
1125 code = gdev_vector_dopath((gx_device_vector *)pdev, ppath,
1126 gx_path_type_clip, NULL);
1127 if (code >= 0)
1128 stream_puts(pdev->strm, "W n\n");
1129 }
1130 pdf_put_matrix(pdev, NULL, &cvd.m, " cm q\n");
1131 cvd.write_matrix = false;
1132 if (code >= 0) {
1133 /* See gx_default_fill_path. */
1134 gx_clip_path cpath_intersection;
1135 gx_path path_intersection, path1, *p = &path_intersection;
1136
1137 gx_path_init_local(&path_intersection, pdev->memory);
1138 gx_path_init_local(&path1, pdev->memory);
1139 gx_cpath_init_local_shared(&cpath_intersection, pcpath, pdev->memory);
1140 if ((code = gx_cpath_intersect(&cpath_intersection, ppath, params->rule, (gs_imager_state *)pis)) >= 0)
1141 code = gx_cpath_to_path(&cpath_intersection, &path_intersection);
1142 if (code >= 0 && scale > 1) {
1143 code = gx_path_copy(&path_intersection, &path1);
1144 if (code > 0) {
1145 p = &path1;
1146 code = path_scale(&path1, scalex, scaley);
1147 }
1148 }
1149 if (code >= 0)
1150 code = gx_dc_pattern2_fill_path(&dc, p, NULL, (gx_device *)&cvd.mdev);
1151 gx_path_free(&path_intersection, "gdev_pdf_fill_path");
1152 gx_path_free(&path1, "gdev_pdf_fill_path");
1153 gx_cpath_free(&cpath_intersection, "gdev_pdf_fill_path");
1154 }
1155 if (code >= 0) {
1156 code = pdf_dump_converted_image(pdev, &cvd);
1157 }
1158 stream_puts(pdev->strm, "Q Q\n");
1159 pdf_remove_masked_image_converter(pdev, &cvd, need_mask);
1160 gs_setmatrix((gs_state *)pis, &save_ctm);
1161 gs_state_free(pgs);
1162 return code;
1163 }
1164 }
1165 if (code < 0)
1166 return code;
1167 if (have_path) {
1168 stream *s = pdev->strm;
1169 double scale;
1170 gs_matrix smat;
1171 gs_matrix *psmat = NULL;
1172 gs_fixed_rect box1;
1173
1174 code = gx_path_bbox(ppath, &box1);
1175 if (code < 0)
1176 return code;
1177 if (pcpath) {
1178 rect_intersect(box1, box);
1179 if (box1.p.x > box1.q.x || box1.p.y > box1.q.y)
1180 return 0; /* outside the clipping path */
1181 }
1182 if (params->flatness != pdev->state.flatness) {
1183 pprintg1(s, "%g i\n", params->flatness);
1184 pdev->state.flatness = params->flatness;
1185 }
1186 if (make_rect_scaling(pdev, &box1, 1.0, &scale)) {
1187 gs_make_scaling(pdev->scale.x * scale, pdev->scale.y * scale,
1188 &smat);
1189 pdf_put_matrix(pdev, "q ", &smat, "cm\n");
1190 psmat = &smat;
1191 }
1192 gdev_vector_dopath((gx_device_vector *)pdev, ppath,
1193 gx_path_type_fill | gx_path_type_optimize,
1194 psmat);
1195 stream_puts(s, (params->rule < 0 ? "f\n" : "f*\n"));
1196 if (psmat)
1197 stream_puts(s, "Q\n");
1198 }
1199 return 0;
1200 }
1201
1202 /* Stroke a path. */
1203 int
gdev_pdf_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)1204 gdev_pdf_stroke_path(gx_device * dev, const gs_imager_state * pis,
1205 gx_path * ppath, const gx_stroke_params * params,
1206 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1207 {
1208 gx_device_pdf *pdev = (gx_device_pdf *) dev;
1209 stream *s;
1210 int code;
1211 double scale, path_scale;
1212 bool set_ctm;
1213 gs_matrix mat;
1214 double prescale = 1;
1215 gs_fixed_rect bbox;
1216
1217 if (gx_path_is_void(ppath))
1218 return 0; /* won't mark the page */
1219 if (pdf_must_put_clip_path(pdev, pcpath))
1220 code = pdf_unclip(pdev);
1221 else
1222 code = pdf_open_page(pdev, PDF_IN_STREAM);
1223 if (code < 0)
1224 return code;
1225 code = pdf_prepare_stroke(pdev, pis);
1226 if (code == gs_error_rangecheck) {
1227 /* Fallback to the default implermentation for handling
1228 a transparency with CompatibilityLevel<=1.3 . */
1229 return gx_default_stroke_path((gx_device *)dev, pis, ppath, params, pdcolor, pcpath);
1230 }
1231 if (code < 0)
1232 return code;
1233 code = pdf_put_clip_path(pdev, pcpath);
1234 if (code < 0)
1235 return code;
1236 /*
1237 * If the CTM is not uniform, stroke width depends on angle.
1238 * We'd like to avoid resetting the CTM, so we check for uniform
1239 * CTMs explicitly. Note that in PDF, unlike PostScript, it is
1240 * the CTM at the time of the stroke operation, not the CTM at
1241 * the time the path was constructed, that is used for transforming
1242 * the points of the path; so if we have to reset the CTM, we must
1243 * do it before constructing the path, and inverse-transform all
1244 * the coordinates.
1245 */
1246 set_ctm = (bool)gdev_vector_stroke_scaling((gx_device_vector *)pdev,
1247 pis, &scale, &mat);
1248 if (set_ctm && (pis->ctm.xx == 0) + (pis->ctm.xy == 0) +
1249 (pis->ctm.yx == 0) + (pis->ctm.yy == 0) >= 3) {
1250 /* Acrobat Reader 5 and Adobe Reader 6 issues
1251 the "Wrong operand type" error with such matrices.
1252 Besides that, we found that Acrobat Reader 4, Acrobat Reader 5
1253 and Adobe Reader 6 all store the current path in user space
1254 and apply CTM in the time of stroking - See the bug 687901.
1255 Therefore a precise conversion of Postscript to PDF isn't possible in this case.
1256 Adobe viewers render a line with a constant width instead. */
1257 set_ctm = false;
1258 scale = fabs(pis->ctm.xx + pis->ctm.xy + pis->ctm.yx + pis->ctm.yy) /* Using the non-zero coeff. */
1259 / sqrt(2); /* Empirically from Adobe. */
1260 }
1261 if (set_ctm) {
1262 /*
1263 * We want a scaling factor that will bring the largest reasonable
1264 * user coordinate within bounds. We choose a factor based on the
1265 * minor axis of the transformation. Thanks to Raph Levien for
1266 * the following formula.
1267 */
1268 double a = mat.xx, b = mat.xy, c = mat.yx, d = mat.yy;
1269 double u = fabs(a * d - b * c);
1270 double v = a * a + b * b + c * c + d * d;
1271 double minor = (sqrt(v + 2 * u) - sqrt(v - 2 * u)) * 0.5;
1272
1273 prescale = (minor == 0 || minor > 1 ? 1 : 1 / minor);
1274 }
1275 gx_path_bbox(ppath, &bbox);
1276 {
1277 /* Check whether a painting appears inside the clipping box.
1278 Doing so after writing the clipping path due to /SP pdfmark
1279 uses a special hack with painting outside the clipping box
1280 for synchronizing the clipping path (see lib/gs_pdfwr.ps).
1281 That hack appeared because there is no way to pass
1282 the imager state through gdev_pdf_put_params,
1283 which pdfmark is implemented with.
1284 */
1285 gs_fixed_rect clip_box, stroke_bbox = bbox;
1286 gs_point d0, d1;
1287 gs_fixed_point p0, p1;
1288 fixed bbox_expansion_x, bbox_expansion_y;
1289
1290 gs_distance_transform(pis->line_params.half_width, 0, &ctm_only(pis), &d0);
1291 gs_distance_transform(0, pis->line_params.half_width, &ctm_only(pis), &d1);
1292 p0.x = float2fixed(any_abs(d0.x));
1293 p0.y = float2fixed(any_abs(d0.y));
1294 p1.x = float2fixed(any_abs(d1.x));
1295 p1.y = float2fixed(any_abs(d1.y));
1296 bbox_expansion_x = max(p0.x, p1.x) + fixed_1 * 2;
1297 bbox_expansion_y = max(p0.y, p1.y) + fixed_1 * 2;
1298 stroke_bbox.p.x -= bbox_expansion_x;
1299 stroke_bbox.p.y -= bbox_expansion_y;
1300 stroke_bbox.q.x += bbox_expansion_x;
1301 stroke_bbox.q.y += bbox_expansion_y;
1302 gx_cpath_outer_box(pcpath, &clip_box);
1303 rect_intersect(stroke_bbox, clip_box);
1304 if (stroke_bbox.q.x < stroke_bbox.p.x || stroke_bbox.q.y < stroke_bbox.p.y)
1305 return 0;
1306 }
1307 if (make_rect_scaling(pdev, &bbox, prescale, &path_scale)) {
1308 scale /= path_scale;
1309 if (set_ctm)
1310 gs_matrix_scale(&mat, path_scale, path_scale, &mat);
1311 else {
1312 gs_make_scaling(path_scale, path_scale, &mat);
1313 set_ctm = true;
1314 }
1315 }
1316 code = gdev_vector_prepare_stroke((gx_device_vector *)pdev, pis, params,
1317 pdcolor, scale);
1318 if (code < 0)
1319 return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
1320 pcpath);
1321 if (!pdev->HaveStrokeColor)
1322 pdev->saved_fill_color = pdev->saved_stroke_color;
1323 if (set_ctm)
1324 pdf_put_matrix(pdev, "q ", &mat, "cm\n");
1325 code = gdev_vector_dopath((gx_device_vector *)pdev, ppath,
1326 gx_path_type_stroke | gx_path_type_optimize,
1327 (set_ctm ? &mat : (const gs_matrix *)0));
1328 if (code < 0)
1329 return code;
1330 s = pdev->strm;
1331 stream_puts(s, (code ? "s" : "S"));
1332 stream_puts(s, (set_ctm ? " Q\n" : "\n"));
1333 return 0;
1334 }
1335
1336 /*
1337 The fill_rectangle_hl_color device method.
1338 See gxdevcli.h about return codes.
1339 */
1340 int
gdev_pdf_fill_rectangle_hl_color(gx_device * dev,const gs_fixed_rect * rect,const gs_imager_state * pis,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)1341 gdev_pdf_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
1342 const gs_imager_state *pis, const gx_drawing_color *pdcolor,
1343 const gx_clip_path *pcpath)
1344 {
1345 int code;
1346 gs_fixed_rect box1 = *rect, box = {{0, 0}, {0, 0}};
1347 gx_device_pdf *pdev = (gx_device_pdf *) dev;
1348 double scale;
1349 gs_matrix smat;
1350 gs_matrix *psmat = NULL;
1351 const bool convert_to_image = (pdev->CompatibilityLevel <= 1.2 &&
1352 gx_dc_is_pattern2_color(pdcolor));
1353
1354 if (rect->p.x == rect->q.x)
1355 return 0;
1356 if (!convert_to_image) {
1357 code = prepare_fill_with_clip(pdev, pis, &box, true, pdcolor, pcpath);
1358 if (code < 0)
1359 return code;
1360 if (code == 1)
1361 return 0; /* Nothing to paint. */
1362 code = pdf_setfillcolor((gx_device_vector *)pdev, pis, pdcolor);
1363 if (code < 0)
1364 return code;
1365 if (pcpath)
1366 rect_intersect(box1, box);
1367 if (box1.p.x > box1.q.x || box1.p.y > box1.q.y)
1368 return 0; /* outside the clipping path */
1369 if (make_rect_scaling(pdev, &box1, 1.0, &scale)) {
1370 gs_make_scaling(pdev->scale.x * scale, pdev->scale.y * scale, &smat);
1371 pdf_put_matrix(pdev, "q ", &smat, "cm\n");
1372 psmat = &smat;
1373 }
1374 pprintg4(pdev->strm, "%g %g %g %g re f\n",
1375 fixed2float(box1.p.x) * scale, fixed2float(box1.p.y) * scale,
1376 fixed2float(box1.q.x - box1.p.x) * scale, fixed2float(box1.q.y - box1.p.y) * scale);
1377 if (psmat)
1378 stream_puts(pdev->strm, "Q\n");
1379 return 0;
1380 } else {
1381 gx_fill_params params;
1382 gx_path path;
1383
1384 params.rule = 1; /* Not important because the path is a rectange. */
1385 params.adjust.x = params.adjust.y = 0;
1386 params.flatness = pis->flatness;
1387 params.fill_zero_width = false;
1388 gx_path_init_local(&path, pis->memory);
1389 gx_path_add_rectangle(&path, rect->p.x, rect->p.y, rect->q.x, rect->q.y);
1390 code = gdev_pdf_fill_path(dev, pis, &path, ¶ms, pdcolor, pcpath);
1391 gx_path_free(&path, "gdev_pdf_fill_rectangle_hl_color");
1392 return code;
1393
1394 }
1395 }
1396
1397