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