1 /* Copyright (C) 2001-2006 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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gxp1fill.c 9931 2009-08-04 01:32:50Z henrys $ */
15 /* PatternType 1 filling algorithms */
16 #include "string_.h"
17 #include "math_.h"
18 #include "gx.h"
19 #include "gserrors.h"
20 #include "gsrop.h"
21 #include "gsmatrix.h"
22 #include "gxcspace.h"		/* for gscolor2.h */
23 #include "gxcolor2.h"
24 #include "gxdcolor.h"
25 #include "gxdevcli.h"
26 #include "gxdevmem.h"
27 #include "gxclip2.h"
28 #include "gxpcolor.h"
29 #include "gxp1impl.h"
30 #include "gxcldev.h"
31 #include "gxblend.h"
32 
33 /* Define the state for tile filling. */
34 typedef struct tile_fill_state_s {
35 
36     /* Original arguments */
37 
38     const gx_device_color *pdevc;	/* pattern color */
39     int x0, y0, w0, h0;
40     gs_logical_operation_t lop;
41     const gx_rop_source_t *source;
42 
43     /* Variables set at initialization */
44 
45     gx_device_tile_clip cdev;
46     gx_device *pcdev;		/* original device or &cdev */
47     const gx_strip_bitmap *tmask;
48     gs_int_point phase;
49 
50     /* Following are only for uncolored patterns */
51 
52     dev_color_proc_fill_rectangle((*fill_rectangle));
53 
54     /* Following are only for colored patterns */
55 
56     const gx_rop_source_t *rop_source;
57     gx_device *orig_dev;
58     int xoff, yoff;		/* set dynamically */
59 
60 } tile_fill_state_t;
61 
62 
63 /* Define the state for tile filling.
64    This is used for when we have
65    transparency */
66 typedef struct tile_fill_trans_state_s {
67 
68     /* Original arguments */
69 
70     const gx_device_color *pdevc;	/* pattern color */
71     int x0, y0, w0, h0;
72 
73     /* Variables set at initialization */
74 
75     gx_device *pcdev;		/* original device or &cdev */
76     gs_int_point phase;
77 
78     int xoff, yoff;		/* set dynamically */
79 
80 } tile_fill_trans_state_t;
81 
82 /* Initialize the filling state. */
83 static int
tile_fill_init(tile_fill_state_t * ptfs,const gx_device_color * pdevc,gx_device * dev,bool set_mask_phase)84 tile_fill_init(tile_fill_state_t * ptfs, const gx_device_color * pdevc,
85 	       gx_device * dev, bool set_mask_phase)
86 {
87     gx_color_tile *m_tile = pdevc->mask.m_tile;
88     int px, py;
89 
90     ptfs->pdevc = pdevc;
91     if (m_tile == 0) {		/* no clipping */
92 	ptfs->pcdev = dev;
93 	ptfs->phase = pdevc->phase;
94 	return 0;
95     }
96     ptfs->pcdev = (gx_device *) & ptfs->cdev;
97     ptfs->tmask = &m_tile->tmask;
98     ptfs->phase.x = pdevc->mask.m_phase.x;
99     ptfs->phase.y = pdevc->mask.m_phase.y;
100     /*
101      * For non-simple tiles, the phase will be reset on each pass of the
102      * tile_by_steps loop, but for simple tiles, we must set it now.
103      */
104     if (set_mask_phase && m_tile->is_simple) {
105 	px = imod(-(int)floor(m_tile->step_matrix.tx - ptfs->phase.x + 0.5),
106 		  m_tile->tmask.rep_width);
107 	py = imod(-(int)floor(m_tile->step_matrix.ty - ptfs->phase.y + 0.5),
108 		  m_tile->tmask.rep_height);
109     } else
110 	px = py = 0;
111     return tile_clip_initialize(&ptfs->cdev, ptfs->tmask, dev, px, py, NULL);
112 }
113 
114 /*
115  * Fill with non-standard X and Y stepping.
116  * ptile is pdevc->colors.pattern.{m,p}_tile.
117  * tbits_or_tmask is whichever of tbits and tmask is supplying
118  * the tile size.
119  * This implementation could be sped up considerably!
120  */
121 static int
tile_by_steps(tile_fill_state_t * ptfs,int x0,int y0,int w0,int h0,const gx_color_tile * ptile,const gx_strip_bitmap * tbits_or_tmask,int (* fill_proc)(const tile_fill_state_t * ptfs,int x,int y,int w,int h))122 tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0,
123 	      const gx_color_tile * ptile,
124 	      const gx_strip_bitmap * tbits_or_tmask,
125 	      int (*fill_proc) (const tile_fill_state_t * ptfs,
126 				int x, int y, int w, int h))
127 {
128     int x1 = x0 + w0, y1 = y0 + h0;
129     int i0, i1, j0, j1, i, j;
130     gs_matrix step_matrix;	/* translated by phase */
131     int code;
132 
133     ptfs->x0 = x0, ptfs->w0 = w0;
134     ptfs->y0 = y0, ptfs->h0 = h0;
135     step_matrix = ptile->step_matrix;
136     step_matrix.tx -= ptfs->phase.x;
137     step_matrix.ty -= ptfs->phase.y;
138     {
139 	gs_rect bbox;		/* bounding box in device space */
140 	gs_rect ibbox;		/* bounding box in stepping space */
141 	double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
142 	double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
143 	double u0, v0, u1, v1;
144 
145 	bbox.p.x = x0, bbox.p.y = y0;
146 	bbox.q.x = x1, bbox.q.y = y1;
147 	gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
148 	if_debug10('T',
149 	  "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
150 		   x0, y0, w0, h0,
151 		   ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
152 		   step_matrix.tx, step_matrix.ty);
153 	/*
154 	 * If the pattern is partly transparent and XStep/YStep is smaller
155 	 * than the device space BBox, we need to ensure that we cover
156 	 * each pixel of the rectangle being filled with *every* pattern
157 	 * that overlaps it, not just *some* pattern copy.
158 	 */
159 	u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001;
160 	v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001;
161 	u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001;
162 	v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001;
163 	if (!ptile->is_simple)
164 	    u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh;
165 	i0 = (int)floor(u0);
166 	j0 = (int)floor(v0);
167 	i1 = (int)ceil(u1);
168 	j1 = (int)ceil(v1);
169     }
170     if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
171     for (i = i0; i < i1; i++)
172 	for (j = j0; j < j1; j++) {
173 	    int x = (int)floor(step_matrix.xx * i +
174 			  step_matrix.yx * j + step_matrix.tx);
175 	    int y = (int)floor(step_matrix.xy * i +
176 			  step_matrix.yy * j + step_matrix.ty);
177 	    int w = tbits_or_tmask->size.x;
178 	    int h = tbits_or_tmask->size.y;
179 	    int xoff, yoff;
180 
181 	    if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
182 	    if (x < x0)
183 		xoff = x0 - x, x = x0, w -= xoff;
184 	    else
185 		xoff = 0;
186 	    if (y < y0)
187 		yoff = y0 - y, y = y0, h -= yoff;
188 	    else
189 		yoff = 0;
190 	    if (x + w > x1)
191 		w = x1 - x;
192 	    if (y + h > y1)
193 		h = y1 - y;
194 	    if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
195 		      x, y, w, h, xoff, yoff);
196 	    if (w > 0 && h > 0) {
197 		if (ptfs->pcdev == (gx_device *) & ptfs->cdev)
198 		    tile_clip_set_phase(&ptfs->cdev,
199 				imod(xoff - x, ptfs->tmask->rep_width),
200 				imod(yoff - y, ptfs->tmask->rep_height));
201 		/* Set the offsets for colored pattern fills */
202 		ptfs->xoff = xoff;
203 		ptfs->yoff = yoff;
204 		code = (*fill_proc) (ptfs, x, y, w, h);
205 		if (code < 0)
206 		    return code;
207 	    }
208 	}
209     return 0;
210 }
211 
212 /* Fill a rectangle with a colored Pattern. */
213 /* Note that we treat this as "texture" for RasterOp. */
214 static int
tile_colored_fill(const tile_fill_state_t * ptfs,int x,int y,int w,int h)215 tile_colored_fill(const tile_fill_state_t * ptfs,
216 		  int x, int y, int w, int h)
217 {
218     gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile;
219     gs_logical_operation_t lop = ptfs->lop;
220     const gx_rop_source_t *source = ptfs->source;
221     const gx_rop_source_t *rop_source = ptfs->rop_source;
222     gx_device *dev = ptfs->orig_dev;
223     int xoff = ptfs->xoff, yoff = ptfs->yoff;
224     gx_strip_bitmap *bits = &ptile->tbits;
225     const byte *data = bits->data;
226     bool full_transfer = (w == ptfs->w0 && h == ptfs->h0);
227     gx_bitmap_id source_id =
228     (full_transfer ? rop_source->id : gx_no_bitmap_id);
229     int code;
230 
231     if (source == NULL && lop_no_S_is_T(lop))
232 	code = (*dev_proc(ptfs->pcdev, copy_color))
233 	    (ptfs->pcdev, data + bits->raster * yoff, xoff,
234 	     bits->raster,
235 	     (full_transfer ? bits->id : gx_no_bitmap_id),
236 	     x, y, w, h);
237     else {
238 	gx_strip_bitmap data_tile;
239 
240 	data_tile.data = (byte *) data;		/* actually const */
241 	data_tile.raster = bits->raster;
242 	data_tile.size.x = data_tile.rep_width = ptile->tbits.size.x;
243 	data_tile.size.y = data_tile.rep_height = ptile->tbits.size.y;
244 	data_tile.id = bits->id;
245 	data_tile.shift = data_tile.rep_shift = 0;
246 	code = (*dev_proc(dev, strip_copy_rop))
247 	    (dev,
248 	     rop_source->sdata + (y - ptfs->y0) * rop_source->sraster,
249 	     rop_source->sourcex + (x - ptfs->x0),
250 	     rop_source->sraster, source_id,
251 	     (rop_source->use_scolors ? rop_source->scolors : NULL),
252 	     &data_tile, NULL,
253 	     x, y, w, h,
254 	     imod(xoff - x, data_tile.rep_width),
255 	     imod(yoff - y, data_tile.rep_height),
256 	     lop);
257     }
258     return code;
259 }
260 
261 /* Fill a rectangle with a colored Pattern. */
262 /* Note that we treat this as "texture" for RasterOp. */
263 static int
tile_pattern_clist(const tile_fill_state_t * ptfs,int x,int y,int w,int h)264 tile_pattern_clist(const tile_fill_state_t * ptfs,
265 		  int x, int y, int w, int h)
266 {
267     gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile;
268     gx_device_clist *cdev = ptile->cdev;
269     gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev;
270     gx_device *dev = ptfs->orig_dev;
271     int code;
272 
273     crdev->offset_map = NULL;
274     crdev->page_info.io_procs->rewind(crdev->page_info.bfile, false, NULL);
275     crdev->page_info.io_procs->rewind(crdev->page_info.cfile, false, NULL);
276 
277     if_debug0('L', "Pattern clist playback begin\n");
278     code = clist_playback_file_bands(playback_action_render,
279 		crdev, &crdev->page_info, dev, 0, 0, ptfs->xoff - x, ptfs->yoff - y);
280     if_debug0('L', "Pattern clist playback end\n");
281     return code;
282 }
283 
284 int
gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc,int x,int y,int w,int h,gx_device * dev,gs_logical_operation_t lop,const gx_rop_source_t * source)285 gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y,
286 			     int w, int h, gx_device * dev,
287 			     gs_logical_operation_t lop,
288 			     const gx_rop_source_t * source)
289 {
290     gx_color_tile *ptile = pdevc->colors.pattern.p_tile;
291     const gx_rop_source_t *rop_source = source;
292     gx_rop_source_t no_source;
293     gx_strip_bitmap *bits;
294     tile_fill_state_t state;
295     int code;
296 
297     if (ptile == 0)		/* null pattern */
298 	return 0;
299     if (rop_source == NULL)
300 	set_rop_no_source(rop_source, no_source, dev);
301     bits = &ptile->tbits;
302     code = tile_fill_init(&state, pdevc, dev, false);
303     if (code < 0)
304 	return code;
305     if (ptile->is_simple && ptile->cdev == NULL) {
306 	int px =
307 	    imod(-(int)floor(ptile->step_matrix.tx - state.phase.x + 0.5),
308 		 bits->rep_width);
309 	int py =
310 	    imod(-(int)floor(ptile->step_matrix.ty - state.phase.y + 0.5),
311 		 bits->rep_height);
312 
313 	if (state.pcdev != dev)
314 	    tile_clip_set_phase(&state.cdev, px, py);
315 	if (source == NULL && lop_no_S_is_T(lop))
316 	    code = (*dev_proc(state.pcdev, strip_tile_rectangle))
317 		(state.pcdev, bits, x, y, w, h,
318 		 gx_no_color_index, gx_no_color_index, px, py);
319 	else
320 	    code = (*dev_proc(state.pcdev, strip_copy_rop))
321 		(state.pcdev,
322 		 rop_source->sdata, rop_source->sourcex,
323 		 rop_source->sraster, rop_source->id,
324 		 (rop_source->use_scolors ? rop_source->scolors : NULL),
325 		 bits, NULL, x, y, w, h, px, py, lop);
326     } else {
327 	state.lop = lop;
328 	state.source = source;
329 	state.rop_source = rop_source;
330         state.orig_dev = dev;
331 	if (ptile->cdev == NULL) {
332 	    code = tile_by_steps(&state, x, y, w, h, ptile,
333 				 &ptile->tbits, tile_colored_fill);
334 	} else {
335 	    gx_device_clist *cdev = ptile->cdev;
336 	    gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev;
337 	    gx_strip_bitmap tbits;
338 
339 	    crdev->yplane.depth = 0; /* Don't know what to set here. */
340 	    crdev->yplane.shift = 0;
341 	    crdev->yplane.index = -1;
342 	    crdev->pages = NULL;
343 	    crdev->num_pages = 1;
344 	    state.orig_dev = dev;
345 	    tbits = ptile->tbits;
346 	    tbits.size.x = crdev->width;
347 	    tbits.size.y = crdev->height;
348 	    code = tile_by_steps(&state, x, y, w, h, ptile,
349 				 &tbits, tile_pattern_clist);
350 	}
351     }
352     return code;
353 }
354 
355 /* Fill a rectangle with an uncolored Pattern. */
356 /* Note that we treat this as "texture" for RasterOp. */
357 static int
tile_masked_fill(const tile_fill_state_t * ptfs,int x,int y,int w,int h)358 tile_masked_fill(const tile_fill_state_t * ptfs,
359 		 int x, int y, int w, int h)
360 {
361     if (ptfs->source == NULL)
362 	return (*ptfs->fill_rectangle)
363 	    (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, NULL);
364     else {
365 	const gx_rop_source_t *source = ptfs->source;
366 	gx_rop_source_t step_source;
367 
368 	step_source.sdata = source->sdata + (y - ptfs->y0) * source->sraster;
369 	step_source.sourcex = source->sourcex + (x - ptfs->x0);
370 	step_source.sraster = source->sraster;
371 	step_source.id = (w == ptfs->w0 && h == ptfs->h0 ?
372 			  source->id : gx_no_bitmap_id);
373 	step_source.scolors[0] = source->scolors[0];
374 	step_source.scolors[1] = source->scolors[1];
375 	step_source.use_scolors = source->use_scolors;
376 	return (*ptfs->fill_rectangle)
377 	    (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, &step_source);
378     }
379 }
380 int
gx_dc_pure_masked_fill_rect(const gx_device_color * pdevc,int x,int y,int w,int h,gx_device * dev,gs_logical_operation_t lop,const gx_rop_source_t * source)381 gx_dc_pure_masked_fill_rect(const gx_device_color * pdevc,
382 			    int x, int y, int w, int h, gx_device * dev,
383 			    gs_logical_operation_t lop,
384 			    const gx_rop_source_t * source)
385 {
386     gx_color_tile *ptile = pdevc->mask.m_tile;
387     tile_fill_state_t state;
388     int code;
389 
390     /*
391      * This routine should never be called if there is no masking,
392      * but we leave the checks below just in case.
393      */
394     code = tile_fill_init(&state, pdevc, dev, true);
395     if (code < 0)
396 	return code;
397     if (state.pcdev == dev || ptile->is_simple)
398 	return (*gx_dc_type_data_pure.fill_rectangle)
399 	    (pdevc, x, y, w, h, state.pcdev, lop, source);
400     else {
401 	state.lop = lop;
402 	state.source = source;
403 	state.fill_rectangle = gx_dc_type_data_pure.fill_rectangle;
404 	return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
405 			     tile_masked_fill);
406     }
407 }
408 int
gx_dc_binary_masked_fill_rect(const gx_device_color * pdevc,int x,int y,int w,int h,gx_device * dev,gs_logical_operation_t lop,const gx_rop_source_t * source)409 gx_dc_binary_masked_fill_rect(const gx_device_color * pdevc,
410 			      int x, int y, int w, int h, gx_device * dev,
411 			      gs_logical_operation_t lop,
412 			      const gx_rop_source_t * source)
413 {
414     gx_color_tile *ptile = pdevc->mask.m_tile;
415     tile_fill_state_t state;
416     int code;
417 
418     code = tile_fill_init(&state, pdevc, dev, true);
419     if (code < 0)
420 	return code;
421     if (state.pcdev == dev || ptile->is_simple)
422 	return (*gx_dc_type_data_ht_binary.fill_rectangle)
423 	    (pdevc, x, y, w, h, state.pcdev, lop, source);
424     else {
425 	state.lop = lop;
426 	state.source = source;
427 	state.fill_rectangle = gx_dc_type_data_ht_binary.fill_rectangle;
428 	return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
429 			     tile_masked_fill);
430     }
431 }
432 int
gx_dc_colored_masked_fill_rect(const gx_device_color * pdevc,int x,int y,int w,int h,gx_device * dev,gs_logical_operation_t lop,const gx_rop_source_t * source)433 gx_dc_colored_masked_fill_rect(const gx_device_color * pdevc,
434 			       int x, int y, int w, int h, gx_device * dev,
435 			       gs_logical_operation_t lop,
436 			       const gx_rop_source_t * source)
437 {
438     gx_color_tile *ptile = pdevc->mask.m_tile;
439     tile_fill_state_t state;
440     int code;
441 
442     code = tile_fill_init(&state, pdevc, dev, true);
443     if (code < 0)
444 	return code;
445     if (state.pcdev == dev || ptile->is_simple)
446 	return (*gx_dc_type_data_ht_colored.fill_rectangle)
447 	    (pdevc, x, y, w, h, state.pcdev, lop, source);
448     else {
449 	state.lop = lop;
450 	state.source = source;
451 	state.fill_rectangle = gx_dc_type_data_ht_colored.fill_rectangle;
452 	return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
453 			     tile_masked_fill);
454     }
455 }
456 
457 
458 /*
459  * This is somewhat a clone of the tile_by_steps function but one
460  * that performs filling from and to pdf14dev (transparency) buffers.
461  * At some point it may be desirable to do some optimization here.
462  */
463 static int
tile_by_steps_trans(tile_fill_trans_state_t * ptfs,int x0,int y0,int w0,int h0,gx_pattern_trans_t * fill_trans_buffer,const gx_color_tile * ptile)464 tile_by_steps_trans(tile_fill_trans_state_t * ptfs, int x0, int y0, int w0, int h0,
465 	      gx_pattern_trans_t *fill_trans_buffer, const gx_color_tile * ptile)
466 {
467     int x1 = x0 + w0, y1 = y0 + h0;
468     int i0, i1, j0, j1, i, j;
469     gs_matrix step_matrix;	/* translated by phase */
470     int code = 0;
471     gx_pattern_trans_t *ptrans_pat = ptile->ttrans;
472 
473     ptfs->x0 = x0, ptfs->w0 = w0;
474     ptfs->y0 = y0, ptfs->h0 = h0;
475     step_matrix = ptile->step_matrix;
476     step_matrix.tx -= ptfs->phase.x;
477     step_matrix.ty -= ptfs->phase.y;
478     {
479 	gs_rect bbox;		/* bounding box in device space */
480 	gs_rect ibbox;		/* bounding box in stepping space */
481 	double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
482 	double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
483 	double u0, v0, u1, v1;
484 
485 	bbox.p.x = x0, bbox.p.y = y0;
486 	bbox.q.x = x1, bbox.q.y = y1;
487 	gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
488 	if_debug10('T',
489 	  "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
490 		   x0, y0, w0, h0,
491 		   ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
492 		   step_matrix.tx, step_matrix.ty);
493 	/*
494 	 * If the pattern is partly transparent and XStep/YStep is smaller
495 	 * than the device space BBox, we need to ensure that we cover
496 	 * each pixel of the rectangle being filled with *every* pattern
497 	 * that overlaps it, not just *some* pattern copy.
498 	 */
499 	u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001;
500 	v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001;
501 	u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001;
502 	v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001;
503 	if (!ptile->is_simple)
504 	    u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh;
505 	i0 = (int)floor(u0);
506 	j0 = (int)floor(v0);
507 	i1 = (int)ceil(u1);
508 	j1 = (int)ceil(v1);
509     }
510     if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
511     for (i = i0; i < i1; i++)
512 	for (j = j0; j < j1; j++) {
513 	    int x = (int)floor(step_matrix.xx * i +
514 			  step_matrix.yx * j + step_matrix.tx);
515 	    int y = (int)floor(step_matrix.xy * i +
516 			  step_matrix.yy * j + step_matrix.ty);
517 	    int w = ptrans_pat->width;
518 	    int h = ptrans_pat->height;
519 	    int xoff, yoff;
520             int px, py;
521 
522 	    if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
523 	    if (x < x0)
524 		xoff = x0 - x, x = x0, w -= xoff;
525 	    else
526 		xoff = 0;
527 	    if (y < y0)
528 		yoff = y0 - y, y = y0, h -= yoff;
529 	    else
530 		yoff = 0;
531 	    if (x + w > x1)
532 		w = x1 - x;
533 	    if (y + h > y1)
534 		h = y1 - y;
535 	    if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
536 		      x, y, w, h, xoff, yoff);
537 	    if (w > 0 && h > 0) {
538 
539                 px = imod(xoff - x, ptile->ttrans->width);
540                 py = imod(yoff - y, ptile->ttrans->height);
541 
542 		/* Set the offsets for colored pattern fills */
543                 ptfs->xoff = xoff;
544                 ptfs->yoff = yoff;
545 
546                 /* We only go through blending during tiling, if
547                    there was overlap as defined by the step matrix
548                    and the bounding box */
549 
550                 ptile->ttrans->pat_trans_fill(x, y, x+w, y+h, px, py, ptile,
551                         fill_trans_buffer);
552             }
553 	}
554     return 0;
555 }
556 
557 /* This does the case of tiling with simple tiles.  Since it is not commented anywhere note
558    that simple means that the tile size is the same as the step matrix size and the cross
559    terms in the step matrix are 0.  Hence a simple case of tile replication. This needs to be optimized.  */
560 void
tile_rect_trans_simple(int xmin,int ymin,int xmax,int ymax,int px,int py,const gx_color_tile * ptile,gx_pattern_trans_t * fill_trans_buffer)561 tile_rect_trans_simple(int xmin, int ymin, int xmax, int ymax, int px, int py, const gx_color_tile *ptile,
562             gx_pattern_trans_t *fill_trans_buffer)
563 {
564     int kk, jj, ii, h, w, buff_y_offset, buff_x_offset;
565     unsigned char *ptr_out, *ptr_in, *buff_out, *buff_in, *ptr_out_temp;
566     unsigned char *row_ptr;
567     int in_row_offset;
568     int tile_width = ptile->ttrans->width;
569     int tile_height = ptile->ttrans->height;
570     int dx, dy;
571     int left_rem_end, left_width, num_full_tiles, right_tile_width;
572 
573     buff_y_offset = ymin - fill_trans_buffer->rect.p.y;
574     buff_x_offset = xmin - fill_trans_buffer->rect.p.x;
575 
576     buff_out = fill_trans_buffer->transbytes +
577         buff_y_offset * fill_trans_buffer->rowstride +
578         buff_x_offset;
579 
580     buff_in = ptile->ttrans->transbytes;
581 
582     h = ymax - ymin;
583     w = xmax - xmin;
584 
585     dx = (xmin + px) % tile_width;
586     dy = (ymin + py) % tile_height;
587 
588     /* To speed this up, the inner loop on the width is implemented with
589        mem copys where we have a left remainder, full tiles and a right remainder.
590        Depending upon the rect that we are filling we may have only one of these
591        three portions, or two or all three.  We compute the parts now outside the loops. */
592 
593     /* Left remainder part */
594 
595     left_rem_end = min(dx+w,tile_width);
596     left_width = left_rem_end - dx;
597 
598     /* Now the middle part */
599 
600     num_full_tiles = (int) floor((float) (w - left_width)/ (float) tile_width);
601 
602     /* Now the right part */
603 
604     right_tile_width = w - num_full_tiles*tile_width - left_width;
605 
606 
607     for (kk = 0; kk < fill_trans_buffer->n_chan; kk++){
608 
609         ptr_out = buff_out + kk * fill_trans_buffer->planestride;
610         ptr_in = buff_in + kk * ptile->ttrans->planestride;
611 
612         for (jj = 0; jj < h; jj++){
613 
614             in_row_offset = (jj + dy) % ptile->ttrans->height;
615             row_ptr = ptr_in + in_row_offset * ptile->ttrans->rowstride;
616 
617              /* This is the case when we have no blending. */
618 
619             ptr_out_temp = ptr_out;
620 
621             /* Left part */
622 
623             memcpy( ptr_out_temp, row_ptr + dx, left_width);
624             ptr_out_temp += left_width;
625 
626             /* Now the full tiles */
627 
628             for ( ii = 0; ii < num_full_tiles; ii++){
629 
630                 memcpy( ptr_out_temp, row_ptr, tile_width);
631                 ptr_out_temp += tile_width;
632 
633             }
634 
635             /* Now the remainder */
636 
637             memcpy( ptr_out_temp, row_ptr, right_tile_width);
638 
639             ptr_out += fill_trans_buffer->rowstride;
640 
641         }
642 
643     }
644 
645     /* If the group we are filling has a shape plane fill that now */
646     /* Note:  Since this was a virgin group push we can just blast it with 255 */
647 
648     if (fill_trans_buffer->has_shape) {
649 
650         ptr_out = buff_out + fill_trans_buffer->n_chan * fill_trans_buffer->planestride;
651 
652         for (jj = 0; jj < h; jj++){
653 
654             memset(ptr_out, 255, w);
655             ptr_out += fill_trans_buffer->rowstride;
656 
657         }
658 
659     }
660 
661 }
662 
663 
664 /* This does the case of tiling with non simple tiles.  In this case, the tiles may overlap and
665    so we really need to do blending within the existing buffer.  This needs some serious optimization. */
666 void
tile_rect_trans_blend(int xmin,int ymin,int xmax,int ymax,int px,int py,const gx_color_tile * ptile,gx_pattern_trans_t * fill_trans_buffer)667 tile_rect_trans_blend(int xmin, int ymin, int xmax, int ymax, int px, int py, const gx_color_tile *ptile,
668             gx_pattern_trans_t *fill_trans_buffer)
669 {
670     int kk, jj, ii, h, w, buff_y_offset, buff_x_offset;
671     unsigned char *buff_out, *buff_in;
672     unsigned char *buff_ptr, *row_ptr_in, *row_ptr_out;
673     unsigned char *tile_ptr;
674     int in_row_offset;
675     int tile_width = ptile->ttrans->width;
676     int tile_height = ptile->ttrans->height;
677     int dx, dy;
678     byte src[PDF14_MAX_PLANES];
679     byte dst[PDF14_MAX_PLANES];
680     int num_chan = ptile->ttrans->n_chan;  /* Includes alpha */
681 
682     buff_y_offset = ymin - fill_trans_buffer->rect.p.y;
683     buff_x_offset = xmin - fill_trans_buffer->rect.p.x;
684 
685     buff_out = fill_trans_buffer->transbytes +
686         buff_y_offset * fill_trans_buffer->rowstride +
687         buff_x_offset;
688 
689     buff_in = ptile->ttrans->transbytes;
690 
691     h = ymax - ymin;
692     w = xmax - xmin;
693 
694     dx = (xmin + px) % tile_width;
695     dy = (ymin + py) % tile_height;
696 
697     for (jj = 0; jj < h; jj++){
698 
699         in_row_offset = (jj + dy) % ptile->ttrans->height;
700         row_ptr_in = buff_in + in_row_offset * ptile->ttrans->rowstride;
701 
702         row_ptr_out = buff_out + jj * fill_trans_buffer->rowstride;
703 
704         for (ii = 0; ii < w; ii++) {
705 
706             tile_ptr = row_ptr_in + (dx + ii) % ptile->ttrans->width;
707             buff_ptr = row_ptr_out + ii;
708 
709             /* We need to blend here.  The blending mode from the current
710                imager state is used.
711             */
712 
713             /* The color values. This needs to be optimized */
714 
715             for (kk = 0; kk < num_chan; kk++){
716 
717                 dst[kk] = *(buff_ptr + kk * fill_trans_buffer->planestride);
718                 src[kk] = *(tile_ptr + kk * ptile->ttrans->planestride);
719 
720             }
721 
722             /* Blend */
723 
724            art_pdf_composite_pixel_alpha_8(dst, src, ptile->ttrans->n_chan-1,
725 			   		 ptile->ttrans->blending_mode, ptile->ttrans->blending_procs);
726 
727             /* Store the color values */
728 
729             for (kk = 0; kk < num_chan; kk++){
730 
731                 *(buff_ptr + kk * fill_trans_buffer->planestride) = dst[kk];
732 
733             }
734 
735         }
736 
737     }
738 
739     /* If the group we are filling has a shape plane fill that now */
740     /* Note:  Since this was a virgin group push we can just blast it with 255 */
741 
742     if (fill_trans_buffer->has_shape) {
743 
744         buff_ptr = buff_out + fill_trans_buffer->n_chan * fill_trans_buffer->planestride;
745 
746         for (jj = 0; jj < h; jj++){
747 
748             memset(buff_ptr, 255, w);
749             buff_ptr += fill_trans_buffer->rowstride;
750 
751         }
752 
753     }
754 
755 }
756 
757 
758 
759 /* This fills the transparency buffer rectangles with a pattern
760    buffer that includes transparency */
761 
762 int
gx_trans_pattern_fill_rect(int xmin,int ymin,int xmax,int ymax,gx_color_tile * ptile,gx_pattern_trans_t * fill_trans_buffer,gs_int_point phase)763 gx_trans_pattern_fill_rect(int xmin, int ymin, int xmax, int ymax, gx_color_tile *ptile,
764                                gx_pattern_trans_t *fill_trans_buffer, gs_int_point phase)
765 {
766 
767     tile_fill_trans_state_t state;
768     int code;
769 
770     if (ptile == 0)		/* null pattern */
771 	return 0;
772 
773     /* Initialize the fill state */
774 
775     state.phase.x = phase.x;
776     state.phase.y = phase.y;
777 
778     if (ptile->is_simple && ptile->cdev == NULL) {
779 
780         /* A simple case.  Tile is not clist and simple. */
781 
782 	int px =
783 	    imod(-(int)floor(ptile->step_matrix.tx - state.phase.x + 0.5),
784 		  ptile->ttrans->width);
785 	int py =
786 	    imod(-(int)floor(ptile->step_matrix.ty - state.phase.y + 0.5),
787 		 ptile->ttrans->height);
788 
789         tile_rect_trans_simple(xmin, ymin, xmax, ymax, px, py, ptile,
790             fill_trans_buffer);
791 
792     } else {
793 
794         if (ptile->cdev == NULL) {
795 
796             /* No clist for the pattern, but a complex case
797                This portion transforms the bounding box by the step matrix
798                and does partial rect fills with tiles that fall into this
799                transformed bbox */
800 
801             code = tile_by_steps_trans(&state, xmin, ymin, xmax-xmin, ymax-ymin,
802                 fill_trans_buffer, ptile);
803 
804 	} else {
805 
806             /* clist for the tile.  Currently this is not implemented
807                for the case when the tile has transparency.  This is
808                on the to do list.  Right now, all tiles with transparency
809                are rendered into the pattern cache or into the clist
810                */
811 	    return_error(gs_error_unregistered);
812 
813 	}
814     }
815 
816 return(0);
817 
818 }
819