1 /* Copyright (C) 2001-2012 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., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* Path drawing procedures for pdfwrite driver */
18 #include "math_.h"
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gxdevice.h"
22 #include "gxfixed.h"
23 #include "gxistate.h"
24 #include "gxpaint.h"
25 #include "gxcoord.h"
26 #include "gxdevmem.h"
27 #include "gxcolor2.h"
28 #include "gxhldevc.h"
29 #include "gsstate.h"
30 #include "gxstate.h"
31 #include "gserrors.h"
32 #include "gsptype2.h"
33 #include "gsshade.h"
34 #include "gzpath.h"
35 #include "gzcpath.h"
36 #include "gdevpdfx.h"
37 #include "gdevpdfg.h"
38 #include "gdevpdfo.h"
39 #include "gsutil.h"
40 #include "gdevpdtf.h"
41 #include "gdevpdts.h"
42 #include "gxdevsop.h"
43
44 /* ---------------- Drawing ---------------- */
45
46 /* Fill a rectangle. */
47 int
gdev_pdf_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)48 gdev_pdf_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
49 gx_color_index color)
50 {
51 gx_device_pdf *pdev = (gx_device_pdf *) dev;
52 int code;
53
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 static 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 static 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 static 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 static 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 static 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(32766), ymax = int2fixed(32766);
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 static 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 static 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 /* Both clip paths are empty, so the same */
239 if (pdev->clip_path == 0)
240 return 1;
241 code = gx_path_enum_init(&penum, pdev->clip_path);
242 if (code < 0)
243 return code;
244 code = gx_cpath_enum_init(&cenum, (gx_clip_path *)pcpath);
245 if (code < 0)
246 return code;
247 /* This flags a warning in Coverity, uninitialised variable cenum.first_visit */
248 /* This is because gx_cpath_enum_init doesn't initialise first_visit, but the */
249 /* variable can be used in enum_next. However, this is not truly used this */
250 /* way. The enum_init sets the 'state' to 'scan', and the first thing that happens */
251 /* in enum_next when state is 'scan' is to set first_visit. */
252 while ((code = gx_cpath_enum_next(&cenum, vs0)) > 0) {
253 pe_op = gx_path_enum_next(&penum, vs1);
254 if (pe_op < 0)
255 return pe_op;
256 if (pe_op != code)
257 return 0;
258 switch (pe_op) {
259 case gs_pe_curveto:
260 if (vs0[1].x != vs1[1].x || vs0[1].y != vs1[1].y ||
261 vs0[2].x != vs1[2].x || vs0[2].y != vs1[2].y)
262 return 0;
263 case gs_pe_moveto:
264 case gs_pe_lineto:
265 case gs_pe_gapto:
266 if (vs0[0].x != vs1[0].x || vs0[0].y != vs1[0].y)
267 return 0;
268 }
269 }
270 if (code < 0)
271 return code;
272 code = gx_path_enum_next(&penum, vs1);
273 if (code < 0)
274 return code;
275 return (code == 0);
276 }
277
278 /* Test whether we will need to put the clipping path. */
279 bool
pdf_must_put_clip_path(gx_device_pdf * pdev,const gx_clip_path * pcpath)280 pdf_must_put_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
281 {
282 if (pcpath == NULL) {
283 if (pdev->clip_path_id == pdev->no_clip_path_id)
284 return false;
285 } else {
286 if (pdev->clip_path_id == pcpath->id)
287 return false;
288 if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
289 int2fixed(pdev->width),
290 int2fixed(pdev->height)))
291 if (pdev->clip_path_id == pdev->no_clip_path_id)
292 return false;
293 if (pdf_is_same_clip_path(pdev, pcpath) > 0) {
294 pdev->clip_path_id = pcpath->id;
295 return false;
296 }
297 }
298 return true;
299 }
300
301 /* Put a single element of a clipping path list. */
302 static 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])303 pdf_put_clip_path_list_elem(gx_device_pdf * pdev, gx_cpath_path_list *e,
304 gs_path_enum *cenum, gdev_vector_dopath_state_t *state,
305 gs_fixed_point vs[3])
306 { /* This recursive function provides a reverse order of the list elements. */
307 int pe_op;
308
309 if (e->next != NULL) {
310 int code = pdf_put_clip_path_list_elem(pdev, e->next, cenum, state, vs);
311
312 if (code != 0)
313 return code;
314 }
315 gx_path_enum_init(cenum, &e->path);
316 while ((pe_op = gx_path_enum_next(cenum, vs)) > 0)
317 gdev_vector_dopath_segment(state, pe_op, vs);
318 pprints1(pdev->strm, "%s n\n", (e->rule <= 0 ? "W" : "W*"));
319 if (pe_op < 0)
320 return pe_op;
321 return 0;
322 }
323
324 /* Put a clipping path on the output file. */
325 int
pdf_put_clip_path(gx_device_pdf * pdev,const gx_clip_path * pcpath)326 pdf_put_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
327 {
328 int code;
329 stream *s = pdev->strm;
330 gs_id new_id;
331
332 /* Check for no update needed. */
333 if (pcpath == NULL) {
334 if (pdev->clip_path_id == pdev->no_clip_path_id)
335 return 0;
336 new_id = pdev->no_clip_path_id;
337 } else {
338 if (pdev->clip_path_id == pcpath->id)
339 return 0;
340 new_id = pcpath->id;
341 if (gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
342 int2fixed(pdev->width),
343 int2fixed(pdev->height))
344 ) {
345 if (pdev->clip_path_id == pdev->no_clip_path_id)
346 return 0;
347 new_id = pdev->no_clip_path_id;
348 }
349 code = pdf_is_same_clip_path(pdev, pcpath);
350 if (code < 0)
351 return code;
352 if (code) {
353 pdev->clip_path_id = new_id;
354 return 0;
355 }
356 }
357 /*
358 * The contents must be open already, so the following will only exit
359 * text or string context.
360 */
361 code = pdf_open_contents(pdev, PDF_IN_STREAM);
362 if (code < 0)
363 return code;
364 /* Use Q to unwind the old clipping path. */
365 if (pdev->vgstack_depth > pdev->vgstack_bottom) {
366 code = pdf_restore_viewer_state(pdev, s);
367 if (code < 0)
368 return code;
369 }
370 if (new_id != pdev->no_clip_path_id) {
371 const gs_fixed_rect *rect = cpath_is_rectangle(pcpath);
372
373 /* Use q to allow the new clipping path to unwind. */
374 code = pdf_save_viewer_state(pdev, s);
375 if (code < 0)
376 return code;
377 if (rect != NULL) {
378 /* Use unrounded coordinates. */
379 pprintg4(s, "%g %g %g %g re",
380 fixed2float(rect->p.x), fixed2float(rect->p.y),
381 fixed2float(rect->q.x - rect->p.x),
382 fixed2float(rect->q.y - rect->p.y));
383 pprints1(s, " %s n\n", (pcpath->rule <= 0 ? "W" : "W*"));
384 } else {
385 gdev_vector_dopath_state_t state;
386 gs_fixed_point vs[3];
387 int pe_op;
388
389 gdev_vector_dopath_init(&state, (gx_device_vector *)pdev,
390 gx_path_type_fill, NULL);
391 if (pcpath->path_list == NULL) {
392 /*
393 * We think this should be never executed.
394 * This obsolete branch writes a clip path intersection
395 * as a set of rectangles computed by
396 * gx_cpath_intersect_path_slow.
397 * Those rectangles use coordinates rounded to pixels,
398 * therefore the precision may be unsatisfactory -
399 * see Bug 688407.
400 */
401 gs_cpath_enum cenum;
402
403 /*
404 * We have to break 'const' here because the clip path
405 * enumeration logic uses some internal mark bits.
406 * This is very unfortunate, but until we can come up with
407 * a better algorithm, it's necessary.
408 */
409 gx_cpath_enum_init(&cenum, (gx_clip_path *) pcpath);
410 while ((pe_op = gx_cpath_enum_next(&cenum, vs)) > 0)
411 gdev_vector_dopath_segment(&state, pe_op, vs);
412 pprints1(s, "%s n\n", (pcpath->rule <= 0 ? "W" : "W*"));
413 if (pe_op < 0)
414 return pe_op;
415 } else {
416 gs_path_enum cenum;
417
418 code = pdf_put_clip_path_list_elem(pdev, pcpath->path_list, &cenum, &state, vs);
419 if (code < 0)
420 return code;
421 }
422 }
423 }
424 pdev->clip_path_id = new_id;
425 return pdf_remember_clip_path(pdev,
426 (pdev->clip_path_id == pdev->no_clip_path_id ? NULL : pcpath));
427 }
428
429 /*
430 * Compute the scaling to ensure that user coordinates for a path are within
431 * Acrobat's range. Return true if scaling was needed. In this case, the
432 * CTM will be multiplied by *pscale, and all coordinates will be divided by
433 * *pscale.
434 */
435 static bool
make_rect_scaling(const gx_device_pdf * pdev,const gs_fixed_rect * bbox,floatp prescale,double * pscale)436 make_rect_scaling(const gx_device_pdf *pdev, const gs_fixed_rect *bbox,
437 floatp prescale, double *pscale)
438 {
439 double bmin, bmax;
440
441 bmin = min(bbox->p.x / pdev->scale.x, bbox->p.y / pdev->scale.y) * prescale;
442 bmax = max(bbox->q.x / pdev->scale.x, bbox->q.y / pdev->scale.y) * prescale;
443 if (bmin <= int2fixed(-MAX_USER_COORD) ||
444 bmax > int2fixed(MAX_USER_COORD)
445 ) {
446 /* Rescale the path. */
447 *pscale = max(bmin / int2fixed(-MAX_USER_COORD),
448 bmax / int2fixed(MAX_USER_COORD));
449 return true;
450 } else {
451 *pscale = 1;
452 return false;
453 }
454 }
455
456 /*
457 * Prepare a fill with a color anc a clipping path.
458 * Return 1 if there is nothing to paint.
459 * Changes *box to the clipping box.
460 */
461 static 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)462 prepare_fill_with_clip(gx_device_pdf *pdev, const gs_imager_state * pis,
463 gs_fixed_rect *box, bool have_path,
464 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
465 {
466 bool new_clip;
467 int code;
468
469 /*
470 * Check for an empty clipping path.
471 */
472 if (pcpath) {
473 gs_fixed_rect cbox;
474
475 gx_cpath_outer_box(pcpath, &cbox);
476 if (cbox.p.x >= cbox.q.x || cbox.p.y >= cbox.q.y)
477 return 1; /* empty clipping path */
478 *box = cbox;
479 }
480 new_clip = pdf_must_put_clip_path(pdev, pcpath);
481 if (have_path || pdev->context == PDF_IN_NONE || new_clip) {
482 if (new_clip)
483 code = pdf_unclip(pdev);
484 else
485 code = pdf_open_page(pdev, PDF_IN_STREAM);
486 if (code < 0)
487 return code;
488 }
489 code = pdf_prepare_fill(pdev, pis);
490 if (code < 0)
491 return code;
492 return pdf_put_clip_path(pdev, pcpath);
493 }
494
495 /* -------------A local image converter device. -----------------------------*/
496
497 public_st_pdf_lcvd_t();
498
499 static int
lcvd_copy_color_shifted(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)500 lcvd_copy_color_shifted(gx_device * dev,
501 const byte * base, int sourcex, int sraster, gx_bitmap_id id,
502 int x, int y, int w, int h)
503 {
504 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
505
506 return cvd->std_copy_color((gx_device *)&cvd->mdev, base, sourcex, sraster, id,
507 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, w, h);
508 }
509
510 static int
lcvd_fill_rectangle_shifted(gx_device * dev,int x,int y,int width,int height,gx_color_index color)511 lcvd_fill_rectangle_shifted(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
512 {
513 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
514
515 return cvd->std_fill_rectangle((gx_device *)&cvd->mdev,
516 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, color);
517 }
518 static int
lcvd_fill_rectangle_shifted2(gx_device * dev,int x,int y,int width,int height,gx_color_index color)519 lcvd_fill_rectangle_shifted2(gx_device *dev, int x, int y, int width, int height, gx_color_index color)
520 {
521 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
522 int code;
523
524 code = (*dev_proc(cvd->mask, fill_rectangle))((gx_device *)cvd->mask,
525 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, (gx_color_index)1);
526 if (code < 0)
527 return code;
528 return cvd->std_fill_rectangle((gx_device *)&cvd->mdev,
529 x - cvd->mdev.mapped_x, y - cvd->mdev.mapped_y, width, height, color);
530 }
531 static void
lcvd_get_clipping_box_shifted_from_mdev(gx_device * dev,gs_fixed_rect * pbox)532 lcvd_get_clipping_box_shifted_from_mdev(gx_device *dev, gs_fixed_rect *pbox)
533 {
534 fixed ofs;
535 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
536
537 cvd->std_get_clipping_box((gx_device *)&cvd->mdev, pbox);
538 ofs = int2fixed(cvd->mdev.mapped_x);
539 pbox->p.x += ofs;
540 pbox->q.x += ofs;
541 ofs = int2fixed(cvd->mdev.mapped_y);
542 pbox->p.y += ofs;
543 pbox->q.y += ofs;
544 }
545 static int
lcvd_dev_spec_op(gx_device * pdev1,int dev_spec_op,void * data,int size)546 lcvd_dev_spec_op(gx_device *pdev1, int dev_spec_op,
547 void *data, int size)
548 {
549 switch (dev_spec_op) {
550 case gxdso_pattern_shading_area:
551 return 1; /* Request shading area. */
552 case gxdso_pattern_can_accum:
553 case gxdso_pattern_start_accum:
554 case gxdso_pattern_finish_accum:
555 case gxdso_pattern_load:
556 case gxdso_pattern_is_cpath_accum:
557 case gxdso_pattern_shfill_doesnt_need_path:
558 case gxdso_pattern_handles_clip_path:
559 return 0;
560 }
561 return gx_default_dev_spec_op(pdev1, dev_spec_op, data, size);
562 }
563 static int
lcvd_close_device_with_writing(gx_device * pdev)564 lcvd_close_device_with_writing(gx_device *pdev)
565 {
566 /* Assuming 'mdev' is being closed before 'mask' - see gx_image3_end_image. */
567 pdf_lcvd_t *cvd = (pdf_lcvd_t *)pdev;
568 int code, code1;
569
570 code = pdf_dump_converted_image(cvd->pdev, cvd);
571 code1 = cvd->std_close_device((gx_device *)&cvd->mdev);
572 return code < 0 ? code : code1;
573 }
574
575 static int
write_image(gx_device_pdf * pdev,gx_device_memory * mdev,gs_matrix * m)576 write_image(gx_device_pdf *pdev, gx_device_memory *mdev, gs_matrix *m)
577 {
578 gs_image_t image;
579 pdf_image_writer writer;
580 const int sourcex = 0;
581 int code;
582
583 if (m != NULL)
584 pdf_put_matrix(pdev, NULL, m, " cm\n");
585 code = pdf_copy_color_data(pdev, mdev->base, sourcex,
586 mdev->raster, gx_no_bitmap_id, 0, 0, mdev->width, mdev->height,
587 &image, &writer, 2);
588 if (code == 1)
589 code = 0; /* Empty image. */
590 else if (code == 0)
591 code = pdf_do_image(pdev, writer.pres, NULL, true);
592 return code;
593 }
594 static int
write_mask(gx_device_pdf * pdev,gx_device_memory * mdev,gs_matrix * m)595 write_mask(gx_device_pdf *pdev, gx_device_memory *mdev, gs_matrix *m)
596 {
597 const int sourcex = 0;
598 gs_id save_clip_id = pdev->clip_path_id;
599 bool save_skip_color = pdev->skip_colors;
600 int code;
601
602 if (m != NULL)
603 pdf_put_matrix(pdev, NULL, m, " cm\n");
604 pdev->clip_path_id = pdev->no_clip_path_id;
605 pdev->skip_colors = true;
606 code = gdev_pdf_copy_mono((gx_device *)pdev, mdev->base, sourcex,
607 mdev->raster, gx_no_bitmap_id, 0, 0, mdev->width, mdev->height,
608 gx_no_color_index, (gx_color_index)0);
609 pdev->clip_path_id = save_clip_id;
610 pdev->skip_colors = save_skip_color;
611 return code;
612 }
613
614 static void
max_subimage_width(int width,byte * base,int x0,long count1,int * x1,long * count)615 max_subimage_width(int width, byte *base, int x0, long count1, int *x1, long *count)
616 {
617 long c = 0, c1 = count1 - 1;
618 int x = x0;
619 byte p = 1; /* The inverse of the previous bit. */
620 byte r; /* The inverse of the current bit. */
621 byte *q = base + (x / 8), m = 0x80 >> (x % 8);
622
623 for (; x < width; x++) {
624 r = !(*q & m);
625 if (p != r) {
626 if (c >= c1) {
627 if (!r)
628 goto ex; /* stop before the upgrade. */
629 }
630 c++;
631 }
632 p = r;
633 m >>= 1;
634 if (!m) {
635 m = 0x80;
636 q++;
637 }
638 }
639 if (p)
640 c++; /* Account the last downgrade. */
641 ex:
642 *count = c;
643 *x1 = x;
644 }
645
646 static void
compute_subimage(int width,int height,int raster,byte * base,int x0,int y0,long MaxClipPathSize,int * x1,int * y1)647 compute_subimage(int width, int height, int raster, byte *base,
648 int x0, int y0, long MaxClipPathSize, int *x1, int *y1)
649 {
650 /* Returns a semiopen range : [x0:x1)*[y0:y1). */
651 if (x0 != 0) {
652 long count;
653
654 /* A partial single scanline. */
655 max_subimage_width(width, base + y0 * raster, x0, MaxClipPathSize / 4, x1, &count);
656 *y1 = y0;
657 } else {
658 int xx, y = y0, yy;
659 long count, count1 = MaxClipPathSize / 4;
660
661 for(; y < height && count1 > 0; ) {
662 max_subimage_width(width, base + y * raster, 0, count1, &xx, &count);
663 if (xx < width) {
664 if (y == y0) {
665 /* Partial single scanline. */
666 *y1 = y + 1;
667 *x1 = xx;
668 return;
669 } else {
670 /* Full lines before this scanline. */
671 break;
672 }
673 }
674 count1 -= count;
675 yy = y + 1;
676 for (; yy < height; yy++)
677 if (memcmp(base + raster * y, base + raster * yy, raster))
678 break;
679 y = yy;
680
681 }
682 *y1 = y;
683 *x1 = width;
684 }
685 }
686
687 static int
image_line_to_clip(gx_device_pdf * pdev,byte * base,int x0,int x1,int y0,int y1,bool started)688 image_line_to_clip(gx_device_pdf *pdev, byte *base, int x0, int x1, int y0, int y1, bool started)
689 { /* returns the number of segments or error code. */
690 int x = x0, xx;
691 byte *q = base + (x / 8), m = 0x80 >> (x % 8);
692 long c = 0;
693
694 for (;;) {
695 /* Look for upgrade : */
696 for (; x < x1; x++) {
697 if (*q & m)
698 break;
699 m >>= 1;
700 if (!m) {
701 m = 0x80;
702 q++;
703 }
704 }
705 if (x == x1)
706 return c;
707 xx = x;
708 /* Look for downgrade : */
709 for (; x < x1; x++) {
710 if (!(*q & m))
711 break;
712 m >>= 1;
713 if (!m) {
714 m = 0x80;
715 q++;
716 }
717 }
718 /* Found the interval [xx:x). */
719 if (!started) {
720 stream_puts(pdev->strm, "n\n");
721 started = true;
722 }
723 pprintld2(pdev->strm, "%ld %ld m ", xx, y0);
724 pprintld2(pdev->strm, "%ld %ld l ", x, y0);
725 pprintld2(pdev->strm, "%ld %ld l ", x, y1);
726 pprintld2(pdev->strm, "%ld %ld l h\n", xx, y1);
727 c += 4;
728 }
729 return c;
730 }
731
732 static int
mask_to_clip(gx_device_pdf * pdev,int width,int height,int raster,byte * base,int x0,int y0,int x1,int y1)733 mask_to_clip(gx_device_pdf *pdev, int width, int height,
734 int raster, byte *base, int x0, int y0, int x1, int y1)
735 {
736 int y, yy, code = 0;
737 bool has_segments = false;
738
739 for (y = y0; y < y1 && code >= 0;) {
740 yy = y + 1;
741 if (x0 == 0) {
742 for (; yy < y1; yy++)
743 if (memcmp(base + raster * y, base + raster * yy, raster))
744 break;
745 }
746 code = image_line_to_clip(pdev, base + raster * y, x0, x1, y, yy, has_segments);
747 if (code > 0)
748 has_segments = true;
749 y = yy;
750 }
751 if (has_segments)
752 stream_puts(pdev->strm, "W n\n");
753 return code < 0 ? code : has_segments ? 1 : 0;
754 }
755
756 static int
write_subimage(gx_device_pdf * pdev,gx_device_memory * mdev,int x,int y,int x1,int y1)757 write_subimage(gx_device_pdf *pdev, gx_device_memory *mdev, int x, int y, int x1, int y1)
758 {
759 gs_image_t image;
760 pdf_image_writer writer;
761 /* expand in 1 pixel to provide a proper color interpolation */
762 int X = max(0, x - 1);
763 int Y = max(0, y - 1);
764 int X1 = min(mdev->width, x1 + 1);
765 int Y1 = min(mdev->height, y1 + 1);
766 int code;
767
768 code = pdf_copy_color_data(pdev, mdev->base + mdev->raster * Y, X,
769 mdev->raster, gx_no_bitmap_id,
770 X, Y, X1 - X, Y1 - Y,
771 &image, &writer, 2);
772 if (code < 0)
773 return code;
774 if (!writer.pres)
775 return 0; /* inline image. */
776 return pdf_do_image(pdev, writer.pres, NULL, true);
777 }
778
779 static int
write_image_with_clip(gx_device_pdf * pdev,pdf_lcvd_t * cvd)780 write_image_with_clip(gx_device_pdf *pdev, pdf_lcvd_t *cvd)
781 {
782 int x = 0, y = 0;
783 int code, code1;
784
785 if (cvd->write_matrix)
786 pdf_put_matrix(pdev, NULL, &cvd->m, " cm q\n");
787 for(;;) {
788 int x1, y1;
789
790 compute_subimage(cvd->mask->width, cvd->mask->height,
791 cvd->mask->raster, cvd->mask->base,
792 x, y, max(pdev->MaxClipPathSize, 100), &x1, &y1);
793 code = mask_to_clip(pdev,
794 cvd->mask->width, cvd->mask->height,
795 cvd->mask->raster, cvd->mask->base,
796 x, y, x1, y1);
797 if (code < 0)
798 return code;
799 if (code > 0) {
800 code1 = write_subimage(pdev, &cvd->mdev, x, y, x1, y1);
801 if (code1 < 0)
802 return code1;
803 }
804 if (x1 >= cvd->mdev.width && y1 >= cvd->mdev.height)
805 break;
806 if (code > 0)
807 stream_puts(pdev->strm, "Q q\n");
808 if (x1 == cvd->mask->width) {
809 x = 0;
810 y = y1;
811 } else {
812 x = x1;
813 y = y1;
814 }
815 }
816 if (cvd->write_matrix)
817 stream_puts(pdev->strm, "Q\n");
818 return 0;
819 }
820
821 int
pdf_dump_converted_image(gx_device_pdf * pdev,pdf_lcvd_t * cvd)822 pdf_dump_converted_image(gx_device_pdf *pdev, pdf_lcvd_t *cvd)
823 {
824 int code = 0;
825
826 if (!cvd->path_is_empty || cvd->has_background) {
827 if (!cvd->has_background)
828 stream_puts(pdev->strm, "W n\n");
829 code = write_image(pdev, &cvd->mdev, (cvd->write_matrix ? &cvd->m : NULL));
830 cvd->path_is_empty = true;
831 } else if (!cvd->mask_is_empty && pdev->PatternImagemask) {
832 /* Convert to imagemask with a pattern color. */
833 /* See also use_image_as_pattern in gdevpdfi.c . */
834 gs_imager_state s;
835 gs_pattern1_instance_t inst;
836 gs_id id = gs_next_ids(cvd->mdev.memory, 1);
837 cos_value_t v;
838 const pdf_resource_t *pres;
839
840 memset(&s, 0, sizeof(s));
841 s.ctm.xx = cvd->m.xx;
842 s.ctm.xy = cvd->m.xy;
843 s.ctm.yx = cvd->m.yx;
844 s.ctm.yy = cvd->m.yy;
845 s.ctm.tx = cvd->m.tx;
846 s.ctm.ty = cvd->m.ty;
847 memset(&inst, 0, sizeof(inst));
848 inst.saved = (gs_state *)&s; /* HACK : will use s.ctm only. */
849 inst.templat.PaintType = 1;
850 inst.templat.TilingType = 1;
851 inst.templat.BBox.p.x = inst.templat.BBox.p.y = 0;
852 inst.templat.BBox.q.x = cvd->mdev.width;
853 inst.templat.BBox.q.y = cvd->mdev.height;
854 inst.templat.XStep = (float)cvd->mdev.width;
855 inst.templat.YStep = (float)cvd->mdev.height;
856 code = (*dev_proc(pdev, dev_spec_op))((gx_device *)pdev,
857 gxdso_pattern_start_accum, &inst, id);
858 if (code >= 0) {
859 stream_puts(pdev->strm, "W n\n");
860 code = write_image(pdev, &cvd->mdev, NULL);
861 }
862 pres = pdev->accumulating_substream_resource;
863 if (code >= 0)
864 code = (*dev_proc(pdev, dev_spec_op))((gx_device *)pdev,
865 gxdso_pattern_finish_accum, &inst, id);
866 if (code >= 0)
867 code = (*dev_proc(pdev, dev_spec_op))((gx_device *)pdev,
868 gxdso_pattern_load, &inst, id);
869 if (code >= 0)
870 code = pdf_cs_Pattern_colored(pdev, &v);
871 if (code >= 0) {
872 cos_value_write(&v, pdev);
873 pprintld1(pdev->strm, " cs /R%ld scn ", pdf_resource_id(pres));
874 }
875 if (code >= 0)
876 code = write_mask(pdev, cvd->mask, (cvd->write_matrix ? &cvd->m : NULL));
877 cvd->mask_is_empty = true;
878 } else if (!cvd->mask_is_empty && !pdev->PatternImagemask) {
879 /* Convert to image with a clipping path. */
880 stream_puts(pdev->strm, "q\n");
881 code = write_image_with_clip(pdev, cvd);
882 stream_puts(pdev->strm, "Q\n");
883 }
884 if (code > 0)
885 code = (*dev_proc(&cvd->mdev, fill_rectangle))((gx_device *)&cvd->mdev,
886 0, 0, cvd->mdev.width, cvd->mdev.height, (gx_color_index)0);
887 return code;
888 }
889 static 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)890 lcvd_handle_fill_path_as_shading_coverage(gx_device *dev,
891 const gs_imager_state *pis, gx_path *ppath,
892 const gx_fill_params *params,
893 const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
894 {
895 pdf_lcvd_t *cvd = (pdf_lcvd_t *)dev;
896 gx_device_pdf *pdev = (gx_device_pdf *)cvd->mdev.target;
897 int code;
898
899 if (cvd->has_background)
900 return 0;
901 if (gx_path_is_null(ppath)) {
902 /* use the mask. */
903 if (!cvd->path_is_empty) {
904 code = pdf_dump_converted_image(pdev, cvd);
905 if (code < 0)
906 return code;
907 stream_puts(pdev->strm, "Q q\n");
908 dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted2;
909 }
910 if (!cvd->mask_is_clean || !cvd->path_is_empty) {
911 code = (*dev_proc(cvd->mask, fill_rectangle))((gx_device *)cvd->mask,
912 0, 0, cvd->mask->width, cvd->mask->height, (gx_color_index)0);
913 if (code < 0)
914 return code;
915 cvd->mask_is_clean = true;
916 }
917 cvd->path_is_empty = true;
918 cvd->mask_is_empty = false;
919 } else {
920 gs_matrix m;
921
922 gs_make_translation(cvd->path_offset.x, cvd->path_offset.y, &m);
923 /* use the clipping. */
924 if (!cvd->mask_is_empty) {
925 code = pdf_dump_converted_image(pdev, cvd);
926 if (code < 0)
927 return code;
928 stream_puts(pdev->strm, "Q q\n");
929 dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted;
930 cvd->mask_is_empty = true;
931 }
932 code = gdev_vector_dopath((gx_device_vector *)pdev, ppath,
933 gx_path_type_fill | gx_path_type_optimize, &m);
934 if (code < 0)
935 return code;
936 stream_puts(pdev->strm, "h\n");
937 cvd->path_is_empty = false;
938 }
939 return 0;
940 }
941
942 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)943 pdf_setup_masked_image_converter(gx_device_pdf *pdev, gs_memory_t *mem, const gs_matrix *m, pdf_lcvd_t **pcvd,
944 bool need_mask, int x, int y, int w, int h, bool write_on_close)
945 {
946 int code;
947 gx_device_memory *mask = 0;
948 pdf_lcvd_t *cvd = *pcvd;
949
950 if (cvd == NULL) {
951 cvd = gs_alloc_struct(mem, pdf_lcvd_t, &st_pdf_lcvd_t, "pdf_setup_masked_image_converter");
952 if (cvd == NULL)
953 return_error(gs_error_VMerror);
954 *pcvd = cvd;
955 }
956 cvd->pdev = pdev;
957 gs_make_mem_device(&cvd->mdev, gdev_mem_device_for_bits(pdev->color_info.depth),
958 mem, 0, (gx_device *)pdev);
959 cvd->mdev.width = w;
960 cvd->mdev.height = h;
961 cvd->mdev.mapped_x = x;
962 cvd->mdev.mapped_y = y;
963 cvd->mdev.bitmap_memory = mem;
964 cvd->mdev.color_info = pdev->color_info;
965 cvd->path_is_empty = true;
966 cvd->mask_is_empty = true;
967 cvd->mask_is_clean = false;
968 cvd->has_background = false;
969 cvd->mask = 0;
970 cvd->write_matrix = true;
971 code = (*dev_proc(&cvd->mdev, open_device))((gx_device *)&cvd->mdev);
972 if (code < 0)
973 return code;
974 code = (*dev_proc(&cvd->mdev, fill_rectangle))((gx_device *)&cvd->mdev,
975 0, 0, cvd->mdev.width, cvd->mdev.height, (gx_color_index)0);
976 if (code < 0)
977 return code;
978 if (need_mask) {
979 mask = gs_alloc_struct(mem, gx_device_memory, &st_device_memory, "pdf_setup_masked_image_converter");
980 if (mask == NULL)
981 return_error(gs_error_VMerror);
982 cvd->mask = mask;
983 gs_make_mem_mono_device(mask, mem, (gx_device *)pdev);
984 mask->width = cvd->mdev.width;
985 mask->height = cvd->mdev.height;
986 mask->bitmap_memory = mem;
987 code = (*dev_proc(mask, open_device))((gx_device *)mask);
988 if (code < 0)
989 return code;
990 if (write_on_close) {
991 code = (*dev_proc(mask, fill_rectangle))((gx_device *)mask,
992 0, 0, mask->width, mask->height, (gx_color_index)0);
993 if (code < 0)
994 return code;
995 }
996 }
997 cvd->std_copy_color = dev_proc(&cvd->mdev, copy_color);
998 cvd->std_fill_rectangle = dev_proc(&cvd->mdev, fill_rectangle);
999 cvd->std_close_device = dev_proc(&cvd->mdev, close_device);
1000 cvd->std_get_clipping_box = dev_proc(&cvd->mdev, get_clipping_box);
1001 if (!write_on_close) {
1002 /* Type 3 images will write to the mask directly. */
1003 dev_proc(&cvd->mdev, fill_rectangle) = (need_mask ? lcvd_fill_rectangle_shifted2
1004 : lcvd_fill_rectangle_shifted);
1005 dev_proc(&cvd->mdev, get_clipping_box) = lcvd_get_clipping_box_shifted_from_mdev;
1006 } else {
1007 dev_proc(&cvd->mdev, fill_rectangle) = lcvd_fill_rectangle_shifted;
1008 dev_proc(&cvd->mdev, get_clipping_box) = lcvd_get_clipping_box_shifted_from_mdev;
1009 }
1010 dev_proc(&cvd->mdev, copy_color) = lcvd_copy_color_shifted;
1011 dev_proc(&cvd->mdev, dev_spec_op) = lcvd_dev_spec_op;
1012 dev_proc(&cvd->mdev, fill_path) = lcvd_handle_fill_path_as_shading_coverage;
1013 cvd->m = *m;
1014 if (write_on_close) {
1015 cvd->mdev.is_open = true;
1016 if (mask)
1017 mask->is_open = true;
1018 dev_proc(&cvd->mdev, close_device) = lcvd_close_device_with_writing;
1019 }
1020 return 0;
1021 }
1022
1023 void
pdf_remove_masked_image_converter(gx_device_pdf * pdev,pdf_lcvd_t * cvd,bool need_mask)1024 pdf_remove_masked_image_converter(gx_device_pdf *pdev, pdf_lcvd_t *cvd, bool need_mask)
1025 {
1026 (*dev_proc(&cvd->mdev, close_device))((gx_device *)&cvd->mdev);
1027 if (cvd->mask) {
1028 (*dev_proc(cvd->mask, close_device))((gx_device *)cvd->mask);
1029 gs_free_object(cvd->mask->memory, cvd->mask, "pdf_remove_masked_image_converter");
1030 }
1031 }
1032
1033 /* ------ Driver procedures ------ */
1034
1035 /* Fill a path. */
1036 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)1037 gdev_pdf_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
1038 const gx_fill_params * params,
1039 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1040 {
1041 gx_device_pdf *pdev = (gx_device_pdf *) dev;
1042 int code;
1043 /*
1044 * HACK: we fill an empty path in order to set the clipping path
1045 * and the color for writing text. If it weren't for this, we
1046 * could detect and skip empty paths before putting out the clip
1047 * path or the color. We also clip with an empty path in order
1048 * to advance currentpoint for show operations without actually
1049 * drawing anything.
1050 */
1051 bool have_path;
1052 gs_fixed_rect box = {{0, 0}, {0, 0}}, box1;
1053
1054 have_path = !gx_path_is_void(ppath);
1055 if (!have_path && !pdev->vg_initial_set) {
1056 /* See lib/gs_pdfwr.ps about "initial graphic state". */
1057 pdf_prepare_initial_viewer_state(pdev, pis);
1058 pdf_reset_graphics(pdev);
1059 return 0;
1060 }
1061 if (have_path) {
1062 code = gx_path_bbox(ppath, &box);
1063 if (code < 0)
1064 return code;
1065 }
1066 box1 = box;
1067
1068 code = prepare_fill_with_clip(pdev, pis, &box, have_path, pdcolor, pcpath);
1069 if (code == gs_error_rangecheck) {
1070 /* Fallback to the default implermentation for handling
1071 a transparency with CompatibilityLevel<=1.3 . */
1072 return gx_default_fill_path((gx_device *)pdev, pis, ppath, params, pdcolor, pcpath);
1073 }
1074 if (code < 0)
1075 return code;
1076 if (code == 1)
1077 return 0; /* Nothing to paint. */
1078 if (!have_path)
1079 return 0;
1080 code = pdf_setfillcolor((gx_device_vector *)pdev, pis, pdcolor);
1081 if (code == gs_error_rangecheck) {
1082 const bool convert_to_image = (pdev->CompatibilityLevel <= 1.2 &&
1083 gx_dc_is_pattern2_color(pdcolor));
1084
1085 if (!convert_to_image) {
1086 /* Fallback to the default implermentation for handling
1087 a shading with CompatibilityLevel<=1.2 . */
1088 return gx_default_fill_path(dev, pis, ppath, params, pdcolor, pcpath);
1089 } else {
1090 /* Convert a shading into a bitmap
1091 with CompatibilityLevel<=1.2 . */
1092 pdf_lcvd_t cvd, *pcvd = &cvd;
1093 int sx, sy;
1094 gs_fixed_rect bbox, bbox1;
1095 bool need_mask = gx_dc_pattern2_can_overlap(pdcolor);
1096 gs_matrix m, save_ctm = ctm_only(pis), ms, msi, mm;
1097 gs_int_point rect_size;
1098 /* double scalex = 1.9, scaley = 1.4; debug purpose only. */
1099 double scale, scalex, scaley;
1100 int log2_scale_x = 0, log2_scale_y = 0;
1101 gx_drawing_color dc = *pdcolor;
1102 gs_pattern2_instance_t pi = *(gs_pattern2_instance_t *)dc.ccolor.pattern;
1103 gs_state *pgs = gs_state_copy(pi.saved, gs_state_memory(pi.saved));
1104
1105 if (pgs == NULL)
1106 return_error(gs_error_VMerror);
1107 dc.ccolor.pattern = (gs_pattern_instance_t *)π
1108 pi.saved = pgs;
1109 code = gx_path_bbox(ppath, &bbox);
1110 if (code < 0)
1111 return code;
1112 rect_intersect(bbox, box);
1113 code = gx_dc_pattern2_get_bbox(pdcolor, &bbox1);
1114 if (code < 0)
1115 return code;
1116 if (code)
1117 rect_intersect(bbox, bbox1);
1118 if (bbox.p.x >= bbox.q.x || bbox.p.y >= bbox.q.y)
1119 return 0;
1120 sx = fixed2int(bbox.p.x);
1121 sy = fixed2int(bbox.p.y);
1122 gs_make_identity(&m);
1123 rect_size.x = fixed2int(bbox.q.x + fixed_half) - sx;
1124 rect_size.y = fixed2int(bbox.q.y + fixed_half) - sy;
1125 if (rect_size.x == 0 || rect_size.y == 0)
1126 return 0;
1127 m.tx = (float)sx;
1128 m.ty = (float)sy;
1129 cvd.path_offset.x = sx;
1130 cvd.path_offset.y = sy;
1131 scale = (double)rect_size.x * rect_size.y * pdev->color_info.num_components /
1132 pdev->MaxShadingBitmapSize;
1133 if (scale > 1) {
1134 /* This section (together with the call to 'path_scale' below)
1135 sets up a downscaling when converting the shading into bitmap.
1136 We used floating point numbers to debug it, but in production
1137 we prefer to deal only with integers being powers of 2
1138 in order to avoid possible distorsions when scaling paths.
1139 */
1140 log2_scale_x = log2_scale_y = ilog2((int)ceil(sqrt(scale)));
1141 if ((double)(1 << log2_scale_x) * (1 << log2_scale_y) < scale)
1142 log2_scale_y++;
1143 if ((double)(1 << log2_scale_x) * (1 << log2_scale_y) < scale)
1144 log2_scale_x++;
1145 scalex = (double)(1 << log2_scale_x);
1146 scaley = (double)(1 << log2_scale_y);
1147 rect_size.x = (int)floor(rect_size.x / scalex + 0.5);
1148 rect_size.y = (int)floor(rect_size.y / scaley + 0.5);
1149 gs_make_scaling(1.0 / scalex, 1.0 / scaley, &ms);
1150 gs_make_scaling(scalex, scaley, &msi);
1151 gs_matrix_multiply(&msi, &m, &m);
1152 gs_matrix_multiply(&ctm_only(pis), &ms, &mm);
1153 gs_setmatrix((gs_state *)pis, &mm);
1154 gs_matrix_multiply(&ctm_only((gs_imager_state *)pgs), &ms, &mm);
1155 gs_setmatrix((gs_state *)pgs, &mm);
1156 sx = fixed2int(bbox.p.x / (int)scalex);
1157 sy = fixed2int(bbox.p.y / (int)scaley);
1158 cvd.path_offset.x = sx; /* m.tx / scalex */
1159 cvd.path_offset.y = sy;
1160 }
1161 code = pdf_setup_masked_image_converter(pdev, pdev->memory, &m, &pcvd, need_mask, sx, sy,
1162 rect_size.x, rect_size.y, false);
1163 pcvd->has_background = gx_dc_pattern2_has_background(pdcolor);
1164 stream_puts(pdev->strm, "q\n");
1165 if (code >= 0) {
1166 code = gdev_vector_dopath((gx_device_vector *)pdev, ppath,
1167 gx_path_type_clip, NULL);
1168 if (code >= 0)
1169 stream_puts(pdev->strm, (params->rule < 0 ? "W n\n" : "W* n\n"));
1170 }
1171 pdf_put_matrix(pdev, NULL, &cvd.m, " cm q\n");
1172 cvd.write_matrix = false;
1173 if (code >= 0)
1174 code = gs_shading_do_fill_rectangle(pi.templat.Shading,
1175 NULL, (gx_device *)&cvd.mdev, (gs_imager_state *)pgs, !pi.shfill);
1176 if (code >= 0)
1177 code = pdf_dump_converted_image(pdev, &cvd);
1178 stream_puts(pdev->strm, "Q Q\n");
1179 pdf_remove_masked_image_converter(pdev, &cvd, need_mask);
1180 gs_setmatrix((gs_state *)pis, &save_ctm);
1181 gs_state_free(pgs);
1182 return code;
1183 }
1184 }
1185 if (code < 0)
1186 return code;
1187 {
1188 stream *s = pdev->strm;
1189 double scale;
1190 gs_matrix smat;
1191 gs_matrix *psmat = NULL;
1192
1193 if (pcpath) {
1194 rect_intersect(box1, box);
1195 if (box1.p.x > box1.q.x || box1.p.y > box1.q.y)
1196 return 0; /* outside the clipping path */
1197 }
1198 if (params->flatness != pdev->state.flatness) {
1199 pprintg1(s, "%g i\n", params->flatness);
1200 pdev->state.flatness = params->flatness;
1201 }
1202 if (make_rect_scaling(pdev, &box1, 1.0, &scale)) {
1203 gs_make_scaling(pdev->scale.x * scale, pdev->scale.y * scale,
1204 &smat);
1205 pdf_put_matrix(pdev, "q ", &smat, "cm\n");
1206 psmat = &smat;
1207 }
1208 gdev_vector_dopath((gx_device_vector *)pdev, ppath,
1209 gx_path_type_fill | gx_path_type_optimize,
1210 psmat);
1211 stream_puts(s, (params->rule < 0 ? "f\n" : "f*\n"));
1212 if (psmat)
1213 stream_puts(s, "Q\n");
1214 }
1215 return 0;
1216 }
1217
1218 /* Stroke a path. */
1219 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)1220 gdev_pdf_stroke_path(gx_device * dev, const gs_imager_state * pis,
1221 gx_path * ppath, const gx_stroke_params * params,
1222 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1223 {
1224 gx_device_pdf *pdev = (gx_device_pdf *) dev;
1225 stream *s;
1226 int code;
1227 double scale, path_scale;
1228 bool set_ctm;
1229 gs_matrix mat;
1230 double prescale = 1;
1231 gs_fixed_rect bbox;
1232
1233 if (gx_path_is_void(ppath))
1234 return 0; /* won't mark the page */
1235 if (pdf_must_put_clip_path(pdev, pcpath))
1236 code = pdf_unclip(pdev);
1237 else if ((pdev->last_charpath_op & TEXT_DO_FALSE_CHARPATH) && ppath->current_subpath &&
1238 (ppath->last_charpath_segment == ppath->current_subpath->last) && !pdev->ForOPDFRead) {
1239 bool hl_color = pdf_can_handle_hl_color((gx_device_vector *)pdev, pis, pdcolor);
1240 const gs_imager_state *pis_for_hl_color = (hl_color ? pis : NULL);
1241
1242 if (pdf_modify_text_render_mode(pdev->text->text_state, 1)) {
1243 /* Set the colour for the stroke */
1244 code = pdf_reset_color(pdev, pis_for_hl_color, pdcolor, &pdev->saved_stroke_color,
1245 &pdev->stroke_used_process_color, &psdf_set_stroke_color_commands);
1246 if (code == 0) {
1247 s = pdev->strm;
1248 /* Text is emitted scaled so that the CTM is an identity matrix, the line width
1249 * needs to be scaled to match otherwise we will get the default, or the current
1250 * width scaled by the CTM before the text, either of which would be wrong.
1251 */
1252 scale = 72 / pdev->HWResolution[0];
1253 scale *= pis->ctm.xx;
1254 pprintg1(s, "%g w\n", (pis->line_params.half_width * 2) * (float)scale);
1255 /* Some trickery here. We have altered the colour, text render mode and linewidth,
1256 * we don't want those to persist. By switching to a stream context we will flush the
1257 * pending text. This has the beneficial side effect of executing a grestore. So
1258 * everything works out neatly.
1259 */
1260 code = pdf_open_page(pdev, PDF_IN_STREAM);
1261 return(code);
1262 }
1263 }
1264 /* Can only get here if any of the above steps fail, in which case we proceed to
1265 * emit the charpath as a normal path, and stroke it.
1266 */
1267 code = pdf_open_page(pdev, PDF_IN_STREAM);
1268 } else
1269 code = pdf_open_page(pdev, PDF_IN_STREAM);
1270 if (code < 0)
1271 return code;
1272 code = pdf_prepare_stroke(pdev, pis);
1273 if (code == gs_error_rangecheck) {
1274 /* Fallback to the default implermentation for handling
1275 a transparency with CompatibilityLevel<=1.3 . */
1276 return gx_default_stroke_path((gx_device *)dev, pis, ppath, params, pdcolor, pcpath);
1277 }
1278 if (code < 0)
1279 return code;
1280 code = pdf_put_clip_path(pdev, pcpath);
1281 if (code < 0)
1282 return code;
1283 /*
1284 * If the CTM is not uniform, stroke width depends on angle.
1285 * We'd like to avoid resetting the CTM, so we check for uniform
1286 * CTMs explicitly. Note that in PDF, unlike PostScript, it is
1287 * the CTM at the time of the stroke operation, not the CTM at
1288 * the time the path was constructed, that is used for transforming
1289 * the points of the path; so if we have to reset the CTM, we must
1290 * do it before constructing the path, and inverse-transform all
1291 * the coordinates.
1292 */
1293 set_ctm = (bool)gdev_vector_stroke_scaling((gx_device_vector *)pdev,
1294 pis, &scale, &mat);
1295 if (set_ctm && ((pis->ctm.xx == 0 && pis->ctm.xy == 0) ||
1296 (pis->ctm.yx == 0 && pis->ctm.yy == 0))) {
1297 /* Acrobat Reader 5 and Adobe Reader 6 issues
1298 the "Wrong operand type" error with matrices, which have 3 zero coefs.
1299 Besides that, we found that Acrobat Reader 4, Acrobat Reader 5
1300 and Adobe Reader 6 all store the current path in user space
1301 and apply CTM in the time of stroking - See the bug 687901.
1302 Therefore a precise conversion of Postscript to PDF isn't possible in this case.
1303 Adobe viewers render a line with a constant width instead.
1304 At last, with set_ctm == true we need the inverse matrix in
1305 gdev_vector_dopath. Therefore we exclude projection matrices
1306 (see bug 688363). */
1307 set_ctm = false;
1308 scale = fabs(pis->ctm.xx + pis->ctm.xy + pis->ctm.yx + pis->ctm.yy) /* Using the non-zero coeff. */
1309 / sqrt(2); /* Empirically from Adobe. */
1310 }
1311 if (set_ctm) {
1312 /*
1313 * We want a scaling factor that will bring the largest reasonable
1314 * user coordinate within bounds. We choose a factor based on the
1315 * minor axis of the transformation. Thanks to Raph Levien for
1316 * the following formula.
1317 */
1318 double a = mat.xx, b = mat.xy, c = mat.yx, d = mat.yy;
1319 double u = fabs(a * d - b * c);
1320 double v = a * a + b * b + c * c + d * d;
1321 double minor = (sqrt(v + 2 * u) - sqrt(v - 2 * u)) * 0.5;
1322
1323 prescale = (minor == 0 || minor > 1 ? 1 : 1 / minor);
1324 }
1325 gx_path_bbox(ppath, &bbox);
1326 {
1327 /* Check whether a painting appears inside the clipping box.
1328 Doing so after writing the clipping path due to /SP pdfmark
1329 uses a special hack with painting outside the clipping box
1330 for synchronizing the clipping path (see lib/gs_pdfwr.ps).
1331 That hack appeared because there is no way to pass
1332 the imager state through gdev_pdf_put_params,
1333 which pdfmark is implemented with.
1334 */
1335 gs_fixed_rect clip_box, stroke_bbox = bbox;
1336 gs_point d0, d1;
1337 gs_fixed_point p0, p1;
1338 fixed bbox_expansion_x, bbox_expansion_y;
1339
1340 gs_distance_transform(pis->line_params.half_width, 0, &ctm_only(pis), &d0);
1341 gs_distance_transform(0, pis->line_params.half_width, &ctm_only(pis), &d1);
1342 p0.x = float2fixed(any_abs(d0.x));
1343 p0.y = float2fixed(any_abs(d0.y));
1344 p1.x = float2fixed(any_abs(d1.x));
1345 p1.y = float2fixed(any_abs(d1.y));
1346 bbox_expansion_x = max(p0.x, p1.x) + fixed_1 * 2;
1347 bbox_expansion_y = max(p0.y, p1.y) + fixed_1 * 2;
1348 stroke_bbox.p.x -= bbox_expansion_x;
1349 stroke_bbox.p.y -= bbox_expansion_y;
1350 stroke_bbox.q.x += bbox_expansion_x;
1351 stroke_bbox.q.y += bbox_expansion_y;
1352 gx_cpath_outer_box(pcpath, &clip_box);
1353 rect_intersect(stroke_bbox, clip_box);
1354 if (stroke_bbox.q.x < stroke_bbox.p.x || stroke_bbox.q.y < stroke_bbox.p.y)
1355 return 0;
1356 }
1357 if (make_rect_scaling(pdev, &bbox, prescale, &path_scale)) {
1358 scale /= path_scale;
1359 if (set_ctm)
1360 gs_matrix_scale(&mat, path_scale, path_scale, &mat);
1361 else {
1362 gs_make_scaling(path_scale, path_scale, &mat);
1363 set_ctm = true;
1364 }
1365 }
1366 code = gdev_vector_prepare_stroke((gx_device_vector *)pdev, pis, params,
1367 pdcolor, scale);
1368 if (code < 0)
1369 return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
1370 pcpath);
1371 if (!pdev->HaveStrokeColor)
1372 pdev->saved_fill_color = pdev->saved_stroke_color;
1373 if (set_ctm)
1374 pdf_put_matrix(pdev, "q ", &mat, "cm\n");
1375 code = gdev_vector_dopath((gx_device_vector *)pdev, ppath,
1376 gx_path_type_stroke | gx_path_type_optimize,
1377 (set_ctm ? &mat : (const gs_matrix *)0));
1378 if (code < 0)
1379 return code;
1380 s = pdev->strm;
1381 stream_puts(s, (code ? "s" : "S"));
1382 stream_puts(s, (set_ctm ? " Q\n" : "\n"));
1383 return 0;
1384 }
1385
1386 /*
1387 The fill_rectangle_hl_color device method.
1388 See gxdevcli.h about return codes.
1389 */
1390 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)1391 gdev_pdf_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
1392 const gs_imager_state *pis, const gx_drawing_color *pdcolor,
1393 const gx_clip_path *pcpath)
1394 {
1395 int code;
1396 gs_fixed_rect box1 = *rect, box = box1;
1397 gx_device_pdf *pdev = (gx_device_pdf *) dev;
1398 double scale;
1399 gs_matrix smat;
1400 gs_matrix *psmat = NULL;
1401 const bool convert_to_image = (pdev->CompatibilityLevel <= 1.2 &&
1402 gx_dc_is_pattern2_color(pdcolor));
1403
1404 if (rect->p.x == rect->q.x)
1405 return 0;
1406 if (!convert_to_image) {
1407 code = prepare_fill_with_clip(pdev, pis, &box, true, pdcolor, pcpath);
1408 if (code < 0)
1409 return code;
1410 if (code == 1)
1411 return 0; /* Nothing to paint. */
1412 code = pdf_setfillcolor((gx_device_vector *)pdev, pis, pdcolor);
1413 if (code < 0)
1414 return code;
1415 if (pcpath)
1416 rect_intersect(box1, box);
1417 if (box1.p.x > box1.q.x || box1.p.y > box1.q.y)
1418 return 0; /* outside the clipping path */
1419 if (make_rect_scaling(pdev, &box1, 1.0, &scale)) {
1420 gs_make_scaling(pdev->scale.x * scale, pdev->scale.y * scale, &smat);
1421 pdf_put_matrix(pdev, "q ", &smat, "cm\n");
1422 psmat = &smat;
1423 }
1424 pprintg4(pdev->strm, "%g %g %g %g re f\n",
1425 fixed2float(box1.p.x) / scale, fixed2float(box1.p.y) / scale,
1426 fixed2float(box1.q.x - box1.p.x) / scale, fixed2float(box1.q.y - box1.p.y) / scale);
1427 if (psmat)
1428 stream_puts(pdev->strm, "Q\n");
1429 return 0;
1430 } else {
1431 gx_fill_params params;
1432 gx_path path;
1433
1434 params.rule = 1; /* Not important because the path is a rectange. */
1435 params.adjust.x = params.adjust.y = 0;
1436 params.flatness = pis->flatness;
1437 gx_path_init_local(&path, pis->memory);
1438 code = gx_path_add_rectangle(&path, rect->p.x, rect->p.y, rect->q.x, rect->q.y);
1439 if (code < 0)
1440 return code;
1441 code = gdev_pdf_fill_path(dev, pis, &path, ¶ms, pdcolor, pcpath);
1442 if (code < 0)
1443 return code;
1444 gx_path_free(&path, "gdev_pdf_fill_rectangle_hl_color");
1445 return code;
1446
1447 }
1448 }
1449
1450 int
gdev_pdf_fillpage(gx_device * dev,gs_imager_state * pis,gx_device_color * pdevc)1451 gdev_pdf_fillpage(gx_device *dev, gs_imager_state * pis, gx_device_color *pdevc)
1452 {
1453 gx_device_pdf *pdev = (gx_device_pdf *) dev;
1454 int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
1455
1456 if (gx_dc_pure_color(pdevc) == pdev->white && !is_in_page(pdev) && pdev->sbstack_depth <= bottom) {
1457 /* PDF doesn't need to erase the page if its plain white */
1458 return 0;
1459 }
1460 else
1461 return gx_default_fillpage(dev, pis, pdevc);
1462 }
1463