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