1 /* Copyright (C) 1998, 1999 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: gxp1fill.c,v 1.6 2004/08/05 20:15:09 stefan Exp $ */
18 /* PatternType 1 filling algorithms */
19 #include "math_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsrop.h"
23 #include "gsmatrix.h"
24 #include "gxcspace.h" /* for gscolor2.h */
25 #include "gxcolor2.h"
26 #include "gxdcolor.h"
27 #include "gxdevcli.h"
28 #include "gxdevmem.h"
29 #include "gxclip2.h"
30 #include "gxpcolor.h"
31 #include "gxp1impl.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 /* Initialize the filling state. */
63 private int
tile_fill_init(tile_fill_state_t * ptfs,const gx_device_color * pdevc,gx_device * dev,bool set_mask_phase)64 tile_fill_init(tile_fill_state_t * ptfs, const gx_device_color * pdevc,
65 gx_device * dev, bool set_mask_phase)
66 {
67 gx_color_tile *m_tile = pdevc->mask.m_tile;
68 int px, py;
69
70 ptfs->pdevc = pdevc;
71 if (m_tile == 0) { /* no clipping */
72 ptfs->pcdev = dev;
73 ptfs->phase = pdevc->phase;
74 return 0;
75 }
76 ptfs->pcdev = (gx_device *) & ptfs->cdev;
77 ptfs->tmask = &m_tile->tmask;
78 ptfs->phase.x = pdevc->mask.m_phase.x;
79 ptfs->phase.y = pdevc->mask.m_phase.y;
80 /*
81 * For non-simple tiles, the phase will be reset on each pass of the
82 * tile_by_steps loop, but for simple tiles, we must set it now.
83 */
84 if (set_mask_phase && m_tile->is_simple) {
85 px = imod(-(int)(m_tile->step_matrix.tx - ptfs->phase.x + 0.5),
86 m_tile->tmask.rep_width);
87 py = imod(-(int)(m_tile->step_matrix.ty - ptfs->phase.y + 0.5),
88 m_tile->tmask.rep_height);
89 } else
90 px = py = 0;
91 return tile_clip_initialize(&ptfs->cdev, ptfs->tmask, dev, px, py, dev->memory);
92 /* leak ? was NULL memoryptr */
93 }
94
95 /*
96 * Fill with non-standard X and Y stepping.
97 * ptile is pdevc->colors.pattern.{m,p}_tile.
98 * tbits_or_tmask is whichever of tbits and tmask is supplying
99 * the tile size.
100 * This implementation could be sped up considerably!
101 */
102 private 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))103 tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0,
104 const gx_color_tile * ptile,
105 const gx_strip_bitmap * tbits_or_tmask,
106 int (*fill_proc) (const tile_fill_state_t * ptfs,
107 int x, int y, int w, int h))
108 {
109 int x1 = x0 + w0, y1 = y0 + h0;
110 int i0, i1, j0, j1, i, j;
111 gs_matrix step_matrix; /* translated by phase */
112 int code;
113
114 ptfs->x0 = x0, ptfs->w0 = w0;
115 ptfs->y0 = y0, ptfs->h0 = h0;
116 step_matrix = ptile->step_matrix;
117 step_matrix.tx -= ptfs->phase.x;
118 step_matrix.ty -= ptfs->phase.y;
119 {
120 gs_rect bbox; /* bounding box in device space */
121 gs_rect ibbox; /* bounding box in stepping space */
122 double bbw = ptile->bbox.q.x - ptile->bbox.p.x;
123 double bbh = ptile->bbox.q.y - ptile->bbox.p.y;
124 double u0, v0, u1, v1;
125
126 bbox.p.x = x0, bbox.p.y = y0;
127 bbox.q.x = x1, bbox.q.y = y1;
128 gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox);
129 if_debug10('T',
130 "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n",
131 x0, y0, w0, h0,
132 ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y,
133 step_matrix.tx, step_matrix.ty);
134 /*
135 * If the pattern is partly transparent and XStep/YStep is smaller
136 * than the device space BBox, we need to ensure that we cover
137 * each pixel of the rectangle being filled with *every* pattern
138 * that overlaps it, not just *some* pattern copy.
139 */
140 u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001;
141 v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001;
142 u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001;
143 v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001;
144 if (!ptile->is_simple)
145 u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh;
146 i0 = (int)floor(u0);
147 j0 = (int)floor(v0);
148 i1 = (int)ceil(u1);
149 j1 = (int)ceil(v1);
150 }
151 if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1);
152 for (i = i0; i < i1; i++)
153 for (j = j0; j < j1; j++) {
154 int x = (int)(step_matrix.xx * i +
155 step_matrix.yx * j + step_matrix.tx);
156 int y = (int)(step_matrix.xy * i +
157 step_matrix.yy * j + step_matrix.ty);
158 int w = tbits_or_tmask->size.x;
159 int h = tbits_or_tmask->size.y;
160 int xoff, yoff;
161
162 if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y);
163 if (x < x0)
164 xoff = x0 - x, x = x0, w -= xoff;
165 else
166 xoff = 0;
167 if (y < y0)
168 yoff = y0 - y, y = y0, h -= yoff;
169 else
170 yoff = 0;
171 if (x + w > x1)
172 w = x1 - x;
173 if (y + h > y1)
174 h = y1 - y;
175 if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n",
176 x, y, w, h, xoff, yoff);
177 if (w > 0 && h > 0) {
178 if (ptfs->pcdev == (gx_device *) & ptfs->cdev)
179 tile_clip_set_phase(&ptfs->cdev,
180 imod(xoff - x, ptfs->tmask->rep_width),
181 imod(yoff - y, ptfs->tmask->rep_height));
182 /* Set the offsets for colored pattern fills */
183 ptfs->xoff = xoff;
184 ptfs->yoff = yoff;
185 code = (*fill_proc) (ptfs, x, y, w, h);
186 if (code < 0)
187 return code;
188 }
189 }
190 return 0;
191 }
192
193 /* Fill a rectangle with a colored Pattern. */
194 /* Note that we treat this as "texture" for RasterOp. */
195 private int
tile_colored_fill(const tile_fill_state_t * ptfs,int x,int y,int w,int h)196 tile_colored_fill(const tile_fill_state_t * ptfs,
197 int x, int y, int w, int h)
198 {
199 gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile;
200 gs_logical_operation_t lop = ptfs->lop;
201 const gx_rop_source_t *source = ptfs->source;
202 const gx_rop_source_t *rop_source = ptfs->rop_source;
203 gx_device *dev = ptfs->orig_dev;
204 int xoff = ptfs->xoff, yoff = ptfs->yoff;
205 gx_strip_bitmap *bits = &ptile->tbits;
206 const byte *data = bits->data;
207 bool full_transfer = (w == ptfs->w0 && h == ptfs->h0);
208 gx_bitmap_id source_id =
209 (full_transfer ? rop_source->id : gx_no_bitmap_id);
210 int code;
211
212 if (source == NULL && lop_no_S_is_T(lop))
213 code = (*dev_proc(ptfs->pcdev, copy_color))
214 (ptfs->pcdev, data + bits->raster * yoff, xoff,
215 bits->raster,
216 (full_transfer ? bits->id : gx_no_bitmap_id),
217 x, y, w, h);
218 else {
219 gx_strip_bitmap data_tile;
220
221 data_tile.data = (byte *) data; /* actually const */
222 data_tile.raster = bits->raster;
223 data_tile.size.x = data_tile.rep_width = ptile->tbits.size.x;
224 data_tile.size.y = data_tile.rep_height = ptile->tbits.size.y;
225 data_tile.id = bits->id;
226 data_tile.shift = data_tile.rep_shift = 0;
227 code = (*dev_proc(dev, strip_copy_rop))
228 (dev,
229 rop_source->sdata + (y - ptfs->y0) * rop_source->sraster,
230 rop_source->sourcex + (x - ptfs->x0),
231 rop_source->sraster, source_id,
232 (rop_source->use_scolors ? rop_source->scolors : NULL),
233 &data_tile, NULL,
234 x, y, w, h,
235 imod(xoff - x, data_tile.rep_width),
236 imod(yoff - y, data_tile.rep_height),
237 lop);
238 }
239 return code;
240 }
241 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)242 gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y,
243 int w, int h, gx_device * dev,
244 gs_logical_operation_t lop,
245 const gx_rop_source_t * source)
246 {
247 gx_color_tile *ptile = pdevc->colors.pattern.p_tile;
248 const gx_rop_source_t *rop_source = source;
249 gx_rop_source_t no_source;
250 gx_strip_bitmap *bits;
251 tile_fill_state_t state;
252 int code;
253
254 if (ptile == 0) /* null pattern */
255 return 0;
256 if (rop_source == NULL)
257 set_rop_no_source(rop_source, no_source, dev);
258 bits = &ptile->tbits;
259 code = tile_fill_init(&state, pdevc, dev, false);
260 if (code < 0)
261 return code;
262 if (ptile->is_simple) {
263 int px =
264 imod(-(int)(ptile->step_matrix.tx - state.phase.x + 0.5),
265 bits->rep_width);
266 int py =
267 imod(-(int)(ptile->step_matrix.ty - state.phase.y + 0.5),
268 bits->rep_height);
269
270 if (state.pcdev != dev)
271 tile_clip_set_phase(&state.cdev, px, py);
272 if (source == NULL && lop_no_S_is_T(lop))
273 code = (*dev_proc(state.pcdev, strip_tile_rectangle))
274 (state.pcdev, bits, x, y, w, h,
275 gx_no_color_index, gx_no_color_index, px, py);
276 else
277 code = (*dev_proc(state.pcdev, strip_copy_rop))
278 (state.pcdev,
279 rop_source->sdata, rop_source->sourcex,
280 rop_source->sraster, rop_source->id,
281 (rop_source->use_scolors ? rop_source->scolors : NULL),
282 bits, NULL, x, y, w, h, px, py, lop);
283 } else {
284 state.lop = lop;
285 state.source = source;
286 state.rop_source = rop_source;
287 state.orig_dev = dev;
288 code = tile_by_steps(&state, x, y, w, h, ptile,
289 &ptile->tbits, tile_colored_fill);
290 }
291 return code;
292 }
293
294 /* Fill a rectangle with an uncolored Pattern. */
295 /* Note that we treat this as "texture" for RasterOp. */
296 private int
tile_masked_fill(const tile_fill_state_t * ptfs,int x,int y,int w,int h)297 tile_masked_fill(const tile_fill_state_t * ptfs,
298 int x, int y, int w, int h)
299 {
300 if (ptfs->source == NULL)
301 return (*ptfs->fill_rectangle)
302 (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, NULL);
303 else {
304 const gx_rop_source_t *source = ptfs->source;
305 gx_rop_source_t step_source;
306
307 step_source.sdata = source->sdata + (y - ptfs->y0) * source->sraster;
308 step_source.sourcex = source->sourcex + (x - ptfs->x0);
309 step_source.sraster = source->sraster;
310 step_source.id = (w == ptfs->w0 && h == ptfs->h0 ?
311 source->id : gx_no_bitmap_id);
312 step_source.scolors[0] = source->scolors[0];
313 step_source.scolors[1] = source->scolors[1];
314 step_source.use_scolors = source->use_scolors;
315 return (*ptfs->fill_rectangle)
316 (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, &step_source);
317 }
318 }
319 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)320 gx_dc_pure_masked_fill_rect(const gx_device_color * pdevc,
321 int x, int y, int w, int h, gx_device * dev,
322 gs_logical_operation_t lop,
323 const gx_rop_source_t * source)
324 {
325 gx_color_tile *ptile = pdevc->mask.m_tile;
326 tile_fill_state_t state;
327 int code;
328
329 /*
330 * This routine should never be called if there is no masking,
331 * but we leave the checks below just in case.
332 */
333 code = tile_fill_init(&state, pdevc, dev, true);
334 if (code < 0)
335 return code;
336 if (state.pcdev == dev || ptile->is_simple)
337 return (*gx_dc_type_data_pure.fill_rectangle)
338 (pdevc, x, y, w, h, state.pcdev, lop, source);
339 else {
340 state.lop = lop;
341 state.source = source;
342 state.fill_rectangle = gx_dc_type_data_pure.fill_rectangle;
343 return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
344 tile_masked_fill);
345 }
346 }
347 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)348 gx_dc_binary_masked_fill_rect(const gx_device_color * pdevc,
349 int x, int y, int w, int h, gx_device * dev,
350 gs_logical_operation_t lop,
351 const gx_rop_source_t * source)
352 {
353 gx_color_tile *ptile = pdevc->mask.m_tile;
354 tile_fill_state_t state;
355 int code;
356
357 code = tile_fill_init(&state, pdevc, dev, true);
358 if (code < 0)
359 return code;
360 if (state.pcdev == dev || ptile->is_simple)
361 return (*gx_dc_type_data_ht_binary.fill_rectangle)
362 (pdevc, x, y, w, h, state.pcdev, lop, source);
363 else {
364 state.lop = lop;
365 state.source = source;
366 state.fill_rectangle = gx_dc_type_data_ht_binary.fill_rectangle;
367 return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
368 tile_masked_fill);
369 }
370 }
371 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)372 gx_dc_colored_masked_fill_rect(const gx_device_color * pdevc,
373 int x, int y, int w, int h, gx_device * dev,
374 gs_logical_operation_t lop,
375 const gx_rop_source_t * source)
376 {
377 gx_color_tile *ptile = pdevc->mask.m_tile;
378 tile_fill_state_t state;
379 int code;
380
381 code = tile_fill_init(&state, pdevc, dev, true);
382 if (code < 0)
383 return code;
384 if (state.pcdev == dev || ptile->is_simple)
385 return (*gx_dc_type_data_ht_colored.fill_rectangle)
386 (pdevc, x, y, w, h, state.pcdev, lop, source);
387 else {
388 state.lop = lop;
389 state.source = source;
390 state.fill_rectangle = gx_dc_type_data_ht_colored.fill_rectangle;
391 return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask,
392 tile_masked_fill);
393 }
394 }
395