xref: /plan9/sys/src/cmd/gs/src/gxp1fill.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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