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 *)&pi;
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, &params, 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