/src/ghostpdl/base/gxp1fill.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 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, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* PatternType 1 filling algorithms */ |
18 | | #include "string_.h" |
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 | | #include "gxcldev.h" |
33 | | #include "gxblend.h" |
34 | | #include "gsicc_cache.h" |
35 | | #include "gxdevsop.h" |
36 | | #include <limits.h> /* For INT_MAX etc */ |
37 | | |
38 | | #include "gdevp14.h" |
39 | | |
40 | 106M | #define fastfloor(x) (((int)(x)) - (((x)<0) && ((x) != (float)(int)(x)))) |
41 | | |
42 | | /* Define the state for tile filling. */ |
43 | | typedef struct tile_fill_state_s { |
44 | | |
45 | | /* Original arguments */ |
46 | | |
47 | | const gx_device_color *pdevc; /* pattern color */ |
48 | | int x0, y0, w0, h0; |
49 | | gs_logical_operation_t lop; |
50 | | const gx_rop_source_t *source; |
51 | | |
52 | | /* Variables set at initialization */ |
53 | | |
54 | | gx_device_tile_clip *cdev; |
55 | | gx_device *pcdev; /* original device or cdev */ |
56 | | const gx_strip_bitmap *tmask; |
57 | | gs_int_point phase; |
58 | | int num_planes; /* negative if not planar */ |
59 | | |
60 | | |
61 | | /* Following are only for uncolored patterns */ |
62 | | |
63 | | dev_color_proc_fill_rectangle((*fill_rectangle)); |
64 | | |
65 | | /* Following are only for colored patterns */ |
66 | | |
67 | | gx_device *orig_dev; |
68 | | int xoff, yoff; /* set dynamically */ |
69 | | |
70 | | } tile_fill_state_t; |
71 | | |
72 | | /* Define the state for tile filling. |
73 | | This is used for when we have |
74 | | transparency */ |
75 | | typedef struct tile_fill_trans_state_s { |
76 | | |
77 | | /* Original arguments */ |
78 | | |
79 | | const gx_device_color *pdevc; /* pattern color */ |
80 | | int x0, y0, w0, h0; |
81 | | |
82 | | /* Variables set at initialization */ |
83 | | |
84 | | gx_device *pcdev; /* original device or &cdev */ |
85 | | gs_int_point phase; |
86 | | |
87 | | int xoff, yoff; /* set dynamically */ |
88 | | |
89 | | } tile_fill_trans_state_t; |
90 | | |
91 | | /* we need some means of detecting if a forwarding clipping device was |
92 | | installed. If the tile state cdev pointer is non-NULL, then the |
93 | | target output device must be the clipping device. */ |
94 | 1.02M | #define CLIPDEV_INSTALLED (state.cdev != NULL) |
95 | | |
96 | | /* Initialize the filling state. */ |
97 | | static int |
98 | | tile_fill_init(tile_fill_state_t * ptfs, const gx_device_color * pdevc, |
99 | | gx_device * dev, bool set_mask_phase) |
100 | 688k | { |
101 | 688k | gx_color_tile *m_tile = pdevc->mask.m_tile; |
102 | 688k | int px, py; |
103 | 688k | int num_planar_planes; |
104 | | |
105 | 688k | ptfs->pdevc = pdevc; |
106 | 688k | num_planar_planes = dev->num_planar_planes; |
107 | 688k | if (num_planar_planes) { |
108 | 73.1k | ptfs->num_planes = dev->num_planar_planes; |
109 | 615k | } else { |
110 | 615k | ptfs->num_planes = -1; |
111 | 615k | } |
112 | 688k | if (m_tile == 0) { /* no clipping */ |
113 | 442k | ptfs->cdev = NULL; |
114 | 442k | ptfs->pcdev = dev; |
115 | 442k | ptfs->phase = pdevc->phase; |
116 | 442k | return 0; |
117 | 442k | } |
118 | 246k | if ((ptfs->cdev = (gx_device_tile_clip *)gs_alloc_struct(dev->memory, |
119 | 246k | gx_device_tile_clip, |
120 | 246k | &st_device_tile_clip, |
121 | 246k | "tile_fill_init(cdev)")) == NULL) { |
122 | 0 | return_error(gs_error_VMerror); |
123 | 0 | } |
124 | 246k | ptfs->cdev->finalize = NULL; |
125 | 246k | ptfs->pcdev = (gx_device *)ptfs->cdev; |
126 | 246k | ptfs->tmask = &m_tile->tmask; |
127 | 246k | ptfs->phase.x = pdevc->mask.m_phase.x; |
128 | 246k | ptfs->phase.y = pdevc->mask.m_phase.y; |
129 | | /* |
130 | | * For non-simple tiles, the phase will be reset on each pass of the |
131 | | * tile_by_steps loop, but for simple tiles, we must set it now. |
132 | | */ |
133 | 246k | if (set_mask_phase && m_tile->is_simple) { |
134 | 16 | px = imod(-(int)fastfloor(m_tile->step_matrix.tx - ptfs->phase.x + 0.5), |
135 | 16 | m_tile->tmask.rep_width); |
136 | 16 | py = imod(-(int)fastfloor(m_tile->step_matrix.ty - ptfs->phase.y + 0.5), |
137 | 16 | m_tile->tmask.rep_height); |
138 | 16 | } else |
139 | 246k | px = py = 0; |
140 | 246k | return tile_clip_initialize(ptfs->cdev, ptfs->tmask, dev, px, py); |
141 | 246k | } |
142 | | |
143 | | static int |
144 | | threshold_ceil(float f, float e) |
145 | 598k | { |
146 | 598k | int i = (int)fastfloor(f); |
147 | | |
148 | 598k | if (f - i < e) |
149 | 8.50k | return i; |
150 | 590k | return i+1; |
151 | 598k | } |
152 | | static int |
153 | | threshold_floor(float f, float e) |
154 | 598k | { |
155 | 598k | int i = (int)fastfloor(f); |
156 | | |
157 | 598k | if (f - i > 1-e) |
158 | 417 | return i+1; |
159 | 598k | return i; |
160 | 598k | } |
161 | | |
162 | | /* Return a conservative approximation to the maximum expansion caused by |
163 | | * a given matrix. */ |
164 | | static float |
165 | | matrix_expansion(gs_matrix *m) |
166 | 299k | { |
167 | 299k | float e, f; |
168 | | |
169 | 299k | e = fabs(m->xx); |
170 | 299k | f = fabs(m->xy); |
171 | 299k | if (f > e) |
172 | 57.3k | e = f; |
173 | 299k | f = fabs(m->yx); |
174 | 299k | if (f > e) |
175 | 0 | e = f; |
176 | 299k | f = fabs(m->yy); |
177 | 299k | if (f > e) |
178 | 569 | e = f; |
179 | | |
180 | 299k | return e*e; |
181 | 299k | } |
182 | | /* |
183 | | * Fill with non-standard X and Y stepping. |
184 | | * ptile is pdevc->colors.pattern.{m,p}_tile. |
185 | | * tbits_or_tmask is whichever of tbits and tmask is supplying |
186 | | * the tile size. |
187 | | * This implementation could be sped up considerably! |
188 | | */ |
189 | | static int |
190 | | tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0, |
191 | | const gx_color_tile * ptile, |
192 | | const gx_strip_bitmap * tbits_or_tmask, |
193 | | int (*fill_proc) (const tile_fill_state_t * ptfs, |
194 | | int x, int y, int w, int h)) |
195 | 299k | { |
196 | 299k | int x1 = x0 + w0, y1 = y0 + h0; |
197 | 299k | int i0, i1, j0, j1, i, j; |
198 | 299k | gs_matrix step_matrix; /* translated by phase */ |
199 | 299k | int code; |
200 | | #ifdef DEBUG |
201 | | const gs_memory_t *mem = ptfs->pcdev->memory; |
202 | | #endif |
203 | | |
204 | 299k | ptfs->x0 = x0, ptfs->w0 = w0; |
205 | 299k | ptfs->y0 = y0, ptfs->h0 = h0; |
206 | 299k | step_matrix = ptile->step_matrix; |
207 | 299k | step_matrix.tx -= ptfs->phase.x; |
208 | 299k | step_matrix.ty -= ptfs->phase.y; |
209 | 299k | { |
210 | 299k | gs_rect bbox; /* bounding box in device space */ |
211 | 299k | gs_rect ibbox; /* bounding box in stepping space */ |
212 | 299k | double bbw = ptile->bbox.q.x - ptile->bbox.p.x; |
213 | 299k | double bbh = ptile->bbox.q.y - ptile->bbox.p.y; |
214 | 299k | double u0, v0, u1, v1; |
215 | | /* Any difference smaller than error is guaranteed to result in |
216 | | * less than a pixels difference in the output. Use this as a |
217 | | * threshold when rounding to allow for inaccuracies in |
218 | | * floating point maths. This enables us to avoid doing more |
219 | | * repeats than we need to. */ |
220 | 299k | float error = 1/matrix_expansion(&step_matrix); |
221 | | |
222 | 299k | bbox.p.x = x0, bbox.p.y = y0; |
223 | 299k | bbox.q.x = x1, bbox.q.y = y1; |
224 | 299k | code = gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox); |
225 | 299k | if (code < 0) |
226 | 0 | return code; |
227 | 299k | if_debug10m('T', mem, |
228 | 299k | "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n", |
229 | 299k | x0, y0, w0, h0, |
230 | 299k | ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y, |
231 | 299k | step_matrix.tx, step_matrix.ty); |
232 | | /* |
233 | | * If the pattern is partly transparent and XStep/YStep is smaller |
234 | | * than the device space BBox, we need to ensure that we cover |
235 | | * each pixel of the rectangle being filled with *every* pattern |
236 | | * that overlaps it, not just *some* pattern copy. |
237 | | */ |
238 | 299k | u0 = ibbox.p.x - max(ptile->bbox.p.x, 0); |
239 | 299k | v0 = ibbox.p.y - max(ptile->bbox.p.y, 0); |
240 | 299k | u1 = ibbox.q.x - min(ptile->bbox.q.x, 0); |
241 | 299k | v1 = ibbox.q.y - min(ptile->bbox.q.y, 0); |
242 | 299k | if (!ptile->is_simple) |
243 | 299k | u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh; |
244 | 299k | i0 = threshold_floor(u0, error); |
245 | 299k | j0 = threshold_floor(v0, error); |
246 | 299k | i1 = threshold_ceil(u1, error); |
247 | 299k | j1 = threshold_ceil(v1, error); |
248 | 299k | } |
249 | 299k | if_debug4m('T', mem, "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1); |
250 | 2.21M | for (i = i0; i < i1; i++) |
251 | 42.3M | for (j = j0; j < j1; j++) { |
252 | 40.3M | int x = (int)fastfloor(step_matrix.xx * i + |
253 | 40.3M | step_matrix.yx * j + step_matrix.tx); |
254 | 40.3M | int y = (int)fastfloor(step_matrix.xy * i + |
255 | 40.3M | step_matrix.yy * j + step_matrix.ty); |
256 | 40.3M | int w = tbits_or_tmask->size.x; |
257 | 40.3M | int h = tbits_or_tmask->size.y; |
258 | 40.3M | int xoff, yoff; |
259 | | |
260 | 40.3M | if_debug4m('T', mem, "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y); |
261 | 40.3M | if (x == INT_MIN || y == INT_MIN) { |
262 | 2 | if_debug0m('T', mem, " underflow!\n"); |
263 | 2 | continue; |
264 | 2 | } |
265 | 40.3M | if (x < x0) |
266 | 13.9M | xoff = x0 - x, x = x0, w -= xoff; |
267 | 26.3M | else |
268 | 26.3M | xoff = 0; |
269 | 40.3M | if (y < y0) |
270 | 15.2M | yoff = y0 - y, y = y0, h -= yoff; |
271 | 25.1M | else |
272 | 25.1M | yoff = 0; |
273 | | /* Check for overflow */ |
274 | 40.3M | if (h > 0 && max_int - h < y) |
275 | 0 | h = max_int - y; |
276 | 40.3M | if (w > 0 && max_int - w < x) |
277 | 0 | w = max_int - x; |
278 | 40.3M | if (x + w > x1) |
279 | 21.0M | w = x1 - x; |
280 | 40.3M | if (y + h > y1) |
281 | 34.7M | h = y1 - y; |
282 | 40.3M | if_debug6m('T', mem, "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n", |
283 | 40.3M | x, y, w, h, xoff, yoff); |
284 | 40.3M | if (w > 0 && h > 0) { |
285 | 4.27M | if (ptfs->pcdev == (gx_device *)ptfs->cdev) |
286 | 4.24M | tile_clip_set_phase(ptfs->cdev, |
287 | 4.24M | imod(xoff - x, ptfs->tmask->rep_width), |
288 | 4.24M | imod(yoff - y, ptfs->tmask->rep_height)); |
289 | | /* Set the offsets for colored pattern fills */ |
290 | 4.27M | ptfs->xoff = xoff; |
291 | 4.27M | ptfs->yoff = yoff; |
292 | 4.27M | code = (*fill_proc) (ptfs, x, y, w, h); |
293 | 4.27M | if (code < 0) |
294 | 0 | return code; |
295 | 4.27M | } |
296 | 40.3M | } |
297 | 299k | return 0; |
298 | 299k | } |
299 | | |
300 | | /* Fill a rectangle with a colored Pattern. */ |
301 | | /* Note that we treat this as "texture" for RasterOp. */ |
302 | | static int |
303 | | tile_colored_fill(const tile_fill_state_t * ptfs, |
304 | | int x, int y, int w, int h) |
305 | 4.18M | { |
306 | 4.18M | gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile; |
307 | 4.18M | gs_logical_operation_t lop = ptfs->lop; |
308 | 4.18M | const gx_rop_source_t *source = ptfs->source; |
309 | 4.18M | gx_device *dev = ptfs->orig_dev; |
310 | 4.18M | int xoff = ptfs->xoff, yoff = ptfs->yoff; |
311 | 4.18M | gx_strip_bitmap *bits = &ptile->tbits; |
312 | 4.18M | const byte *data = bits->data; |
313 | 4.18M | bool full_transfer = (w == ptfs->w0 && h == ptfs->h0); |
314 | 4.18M | int code = 0; |
315 | | |
316 | 4.18M | if (source == NULL && lop_no_S_is_T(lop) && dev_proc(dev, copy_planes) != gx_default_copy_planes && |
317 | 4.18M | ptfs->num_planes > 0) { |
318 | 776k | code = (*dev_proc(ptfs->pcdev, copy_planes)) |
319 | 776k | (ptfs->pcdev, data + bits->raster * yoff, xoff, |
320 | 776k | bits->raster, |
321 | 776k | (full_transfer ? bits->id : gx_no_bitmap_id), |
322 | 776k | x, y, w, h, ptile->tbits.rep_height); |
323 | 3.40M | } else if (source == NULL && lop_no_S_is_T(lop)) { |
324 | 3.40M | code = (*dev_proc(ptfs->pcdev, copy_color)) |
325 | 3.40M | (ptfs->pcdev, data + bits->raster * yoff, xoff, |
326 | 3.40M | bits->raster, |
327 | 3.40M | (full_transfer ? bits->id : gx_no_bitmap_id), |
328 | 3.40M | x, y, w, h); |
329 | 3.40M | } else { |
330 | 0 | gx_strip_bitmap data_tile; |
331 | 0 | gx_bitmap_id source_id; |
332 | 0 | gx_rop_source_t no_source; |
333 | |
|
334 | 0 | if (source == NULL) |
335 | 0 | set_rop_no_source(source, no_source, dev); |
336 | 0 | source_id = (full_transfer ? source->id : gx_no_bitmap_id); |
337 | 0 | data_tile.data = (byte *) data; /* actually const */ |
338 | 0 | data_tile.raster = bits->raster; |
339 | 0 | data_tile.size.x = data_tile.rep_width = ptile->tbits.size.x; |
340 | 0 | data_tile.size.y = data_tile.rep_height = ptile->tbits.size.y; |
341 | 0 | data_tile.id = bits->id; |
342 | 0 | data_tile.shift = data_tile.rep_shift = 0; |
343 | 0 | data_tile.num_planes = (ptfs->num_planes > 1 ? ptfs->num_planes : 1); |
344 | 0 | code = (*dev_proc(ptfs->pcdev, strip_copy_rop2)) |
345 | 0 | (ptfs->pcdev, |
346 | 0 | source->sdata + (y - ptfs->y0) * source->sraster, |
347 | 0 | source->sourcex + (x - ptfs->x0), |
348 | 0 | source->sraster, source_id, |
349 | 0 | (source->use_scolors ? source->scolors : NULL), |
350 | 0 | &data_tile, NULL, |
351 | 0 | x, y, w, h, |
352 | 0 | imod(xoff - x, data_tile.rep_width), |
353 | 0 | imod(yoff - y, data_tile.rep_height), |
354 | 0 | lop, |
355 | 0 | source->planar_height); |
356 | 0 | } |
357 | 4.18M | return code; |
358 | 4.18M | } |
359 | | |
360 | | /* Fill a rectangle with a colored Pattern. */ |
361 | | /* Note that we treat this as "texture" for RasterOp. */ |
362 | | static int |
363 | | tile_pattern_clist(const tile_fill_state_t * ptfs, |
364 | | int x, int y, int w, int h) |
365 | 34.9k | { |
366 | 34.9k | gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile; |
367 | 34.9k | gx_device_clist *cdev = ptile->cdev; |
368 | 34.9k | gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev; |
369 | 34.9k | gx_device *dev = ptfs->orig_dev; |
370 | 34.9k | int code; |
371 | | |
372 | 34.9k | crdev->offset_map = NULL; |
373 | 34.9k | code = crdev->page_info.io_procs->rewind(crdev->page_info.bfile, false, NULL); |
374 | 34.9k | if (code < 0) return code; |
375 | 34.9k | code = crdev->page_info.io_procs->rewind(crdev->page_info.cfile, false, NULL); |
376 | 34.9k | if (code < 0) return code; |
377 | | |
378 | 34.9k | clist_render_init(cdev); |
379 | | /* Check for and get ICC profile table */ |
380 | 34.9k | if (crdev->icc_table == NULL) { |
381 | 34.9k | code = clist_read_icctable(crdev); |
382 | 34.9k | if (code < 0) |
383 | 0 | return code; |
384 | 34.9k | } |
385 | | /* Also allocate the icc cache for the clist reader */ |
386 | 34.9k | if ( crdev->icc_cache_cl == NULL ) |
387 | 34.9k | crdev->icc_cache_cl = gsicc_cache_new(crdev->memory->thread_safe_memory); |
388 | 34.9k | if_debug0m('L', dev->memory, "Pattern clist playback begin\n"); |
389 | 34.9k | code = clist_playback_file_bands(playback_action_render, |
390 | 34.9k | crdev, &crdev->page_info, dev, 0, 0, ptfs->xoff - x, ptfs->yoff - y); |
391 | 34.9k | if_debug0m('L', dev->memory, "Pattern clist playback end\n"); |
392 | | /* FIXME: it would be preferable to have this persist, but as |
393 | | * clist_render_init() sets it to NULL, we currently have to |
394 | | * cleanup before returning. Set to NULL for safety |
395 | | */ |
396 | 34.9k | rc_decrement(crdev->icc_cache_cl, "tile_pattern_clist"); |
397 | 34.9k | crdev->icc_cache_cl = NULL; |
398 | 34.9k | return code; |
399 | 34.9k | } |
400 | | |
401 | | int |
402 | | gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y, |
403 | | int w, int h, gx_device * dev, |
404 | | gs_logical_operation_t lop, |
405 | | const gx_rop_source_t * source) |
406 | 9.05M | { |
407 | 9.05M | gx_color_tile *ptile = pdevc->colors.pattern.p_tile; |
408 | 9.05M | const gx_rop_source_t *rop_source = source; |
409 | 9.05M | gx_rop_source_t no_source; |
410 | 9.05M | gx_strip_bitmap *bits; |
411 | 9.05M | tile_fill_state_t state; |
412 | 9.05M | int code; |
413 | | |
414 | 9.05M | if (ptile == 0) /* null pattern */ |
415 | 8.43M | return 0; |
416 | 626k | if (rop_source == NULL) |
417 | 626k | set_rop_no_source(rop_source, no_source, dev); |
418 | 626k | bits = &ptile->tbits; |
419 | | |
420 | 626k | code = tile_fill_init(&state, pdevc, dev, false); /* This _may_ allocate state.cdev */ |
421 | 626k | if (code < 0) { |
422 | 0 | goto exit; |
423 | 0 | } |
424 | 626k | if (ptile->is_simple && ptile->cdev == NULL) { |
425 | 389k | int px = |
426 | 389k | imod(-(int)fastfloor(ptile->step_matrix.tx - state.phase.x + 0.5), |
427 | 389k | bits->rep_width); |
428 | 389k | int py = |
429 | 389k | imod(-(int)fastfloor(ptile->step_matrix.ty - state.phase.y + 0.5), |
430 | 389k | bits->rep_height); |
431 | | |
432 | 389k | if (CLIPDEV_INSTALLED) |
433 | 21.7k | tile_clip_set_phase(state.cdev, px, py); |
434 | 389k | if (source == NULL && lop_no_S_is_T(lop)) |
435 | 389k | code = (*dev_proc(state.pcdev, strip_tile_rectangle)) |
436 | 389k | (state.pcdev, bits, x, y, w, h, |
437 | 389k | gx_no_color_index, gx_no_color_index, px, py); |
438 | 0 | else |
439 | 0 | code = (*dev_proc(state.pcdev, strip_copy_rop2)) |
440 | 0 | (state.pcdev, |
441 | 0 | rop_source->sdata, rop_source->sourcex, |
442 | 0 | rop_source->sraster, rop_source->id, |
443 | 0 | (rop_source->use_scolors ? rop_source->scolors : NULL), |
444 | 0 | bits, NULL, x, y, w, h, px, py, lop, |
445 | 0 | rop_source->planar_height); |
446 | 389k | } else { |
447 | 236k | state.lop = lop; |
448 | 236k | state.source = source; |
449 | 236k | state.orig_dev = dev; |
450 | 236k | if (ptile->cdev == NULL) { |
451 | 217k | code = tile_by_steps(&state, x, y, w, h, ptile, |
452 | 217k | &ptile->tbits, tile_colored_fill); |
453 | 217k | } else { |
454 | 19.5k | gx_device_clist *cdev = ptile->cdev; |
455 | 19.5k | gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev; |
456 | 19.5k | gx_strip_bitmap tbits; |
457 | | |
458 | 19.5k | crdev->yplane.depth = 0; /* Don't know what to set here. */ |
459 | 19.5k | crdev->yplane.shift = 0; |
460 | 19.5k | crdev->yplane.index = -1; |
461 | 19.5k | crdev->pages = NULL; |
462 | 19.5k | crdev->num_pages = 1; |
463 | 19.5k | state.orig_dev = dev; |
464 | 19.5k | tbits = ptile->tbits; |
465 | 19.5k | tbits.size.x = crdev->width; |
466 | 19.5k | tbits.size.y = crdev->height; |
467 | 19.5k | code = tile_by_steps(&state, x, y, w, h, ptile, |
468 | 19.5k | &tbits, tile_pattern_clist); |
469 | 19.5k | } |
470 | 236k | } |
471 | 626k | exit: |
472 | 626k | if (CLIPDEV_INSTALLED) { |
473 | 236k | tile_clip_free((gx_device_tile_clip *)state.cdev); |
474 | 236k | state.cdev = NULL; |
475 | 236k | } |
476 | 626k | return code; |
477 | 626k | } |
478 | | |
479 | | /* Fill a rectangle with an uncolored Pattern. */ |
480 | | /* Note that we treat this as "texture" for RasterOp. */ |
481 | | static int |
482 | | tile_masked_fill(const tile_fill_state_t * ptfs, |
483 | | int x, int y, int w, int h) |
484 | 55.6k | { |
485 | 55.6k | if (ptfs->source == NULL) |
486 | 55.6k | return (*ptfs->fill_rectangle) |
487 | 55.6k | (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, NULL); |
488 | 0 | else { |
489 | 0 | const gx_rop_source_t *source = ptfs->source; |
490 | 0 | gx_rop_source_t step_source; |
491 | |
|
492 | 0 | step_source.sdata = source->sdata + (y - ptfs->y0) * source->sraster; |
493 | 0 | step_source.sourcex = source->sourcex + (x - ptfs->x0); |
494 | 0 | step_source.sraster = source->sraster; |
495 | 0 | step_source.id = (w == ptfs->w0 && h == ptfs->h0 ? |
496 | 0 | source->id : gx_no_bitmap_id); |
497 | 0 | step_source.scolors[0] = source->scolors[0]; |
498 | 0 | step_source.scolors[1] = source->scolors[1]; |
499 | 0 | step_source.planar_height = source->planar_height; |
500 | 0 | step_source.use_scolors = source->use_scolors; |
501 | 0 | return (*ptfs->fill_rectangle) |
502 | 0 | (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, &step_source); |
503 | 0 | } |
504 | 55.6k | } |
505 | | int |
506 | | gx_dc_pure_masked_fill_rect(const gx_device_color * pdevc, |
507 | | int x, int y, int w, int h, gx_device * dev, |
508 | | gs_logical_operation_t lop, |
509 | | const gx_rop_source_t * source) |
510 | 7.83k | { |
511 | 7.83k | gx_color_tile *ptile = pdevc->mask.m_tile; |
512 | 7.83k | tile_fill_state_t state; |
513 | 7.83k | int code; |
514 | | |
515 | | /* |
516 | | * This routine should never be called if there is no masking, |
517 | | * but we leave the checks below just in case. |
518 | | */ |
519 | 7.83k | code = tile_fill_init(&state, pdevc, dev, true); |
520 | 7.83k | if (code < 0) |
521 | 1 | goto exit; |
522 | 7.83k | if (state.pcdev == dev || ptile->is_simple) |
523 | 16 | code = (*gx_dc_type_data_pure.fill_rectangle) |
524 | 16 | (pdevc, x, y, w, h, state.pcdev, lop, source); |
525 | 7.82k | else { |
526 | 7.82k | state.lop = lop; |
527 | 7.82k | state.source = source; |
528 | 7.82k | state.fill_rectangle = gx_dc_type_data_pure.fill_rectangle; |
529 | 7.82k | code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask, |
530 | 7.82k | tile_masked_fill); |
531 | 7.82k | } |
532 | 7.83k | exit: |
533 | 7.83k | if (CLIPDEV_INSTALLED) { |
534 | 7.83k | tile_clip_free((gx_device_tile_clip *)state.cdev); |
535 | 7.83k | state.cdev = NULL; |
536 | 7.83k | } |
537 | 7.83k | return code; |
538 | 7.83k | } |
539 | | |
540 | | int |
541 | | gx_dc_devn_masked_fill_rect(const gx_device_color * pdevc, |
542 | | int x, int y, int w, int h, gx_device * dev, |
543 | | gs_logical_operation_t lop, |
544 | | const gx_rop_source_t * source) |
545 | 1.18k | { |
546 | 1.18k | gx_color_tile *ptile = pdevc->mask.m_tile; |
547 | 1.18k | tile_fill_state_t state; |
548 | 1.18k | int code; |
549 | | |
550 | | /* |
551 | | * This routine should never be called if there is no masking, |
552 | | * but we leave the checks below just in case. |
553 | | */ |
554 | 1.18k | code = tile_fill_init(&state, pdevc, dev, true); |
555 | 1.18k | if (code < 0) |
556 | 0 | goto exit; |
557 | 1.18k | if (state.pcdev == dev || ptile->is_simple) { |
558 | 0 | gx_device_color dcolor = *pdevc; |
559 | |
|
560 | 0 | if (ptile == NULL) { |
561 | 0 | int k; |
562 | | |
563 | | /* Have to set the pdevc to a non mask type since the pattern was stored as non-masking */ |
564 | 0 | dcolor.type = gx_dc_type_devn; |
565 | 0 | for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) { |
566 | 0 | dcolor.colors.devn.values[k] = pdevc->colors.devn.values[k]; |
567 | 0 | } |
568 | 0 | } |
569 | 0 | code = (*gx_dc_type_data_devn.fill_rectangle) |
570 | 0 | (&dcolor, x, y, w, h, state.pcdev, lop, source); |
571 | 1.18k | } else { |
572 | 1.18k | state.lop = lop; |
573 | 1.18k | state.source = source; |
574 | 1.18k | state.fill_rectangle = gx_dc_type_data_devn.fill_rectangle; |
575 | 1.18k | code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask, |
576 | 1.18k | tile_masked_fill); |
577 | 1.18k | } |
578 | 1.18k | exit: |
579 | 1.18k | if (CLIPDEV_INSTALLED) { |
580 | 1.18k | tile_clip_free((gx_device_tile_clip *)state.cdev); |
581 | 1.18k | state.cdev = NULL; |
582 | 1.18k | } |
583 | 1.18k | return code; |
584 | 1.18k | } |
585 | | |
586 | | int |
587 | | gx_dc_binary_masked_fill_rect(const gx_device_color * pdevc, |
588 | | int x, int y, int w, int h, gx_device * dev, |
589 | | gs_logical_operation_t lop, |
590 | | const gx_rop_source_t * source) |
591 | 8 | { |
592 | 8 | gx_color_tile *ptile = pdevc->mask.m_tile; |
593 | 8 | tile_fill_state_t state; |
594 | 8 | int code; |
595 | | |
596 | 8 | code = tile_fill_init(&state, pdevc, dev, true); |
597 | 8 | if (code < 0) |
598 | 0 | goto exit; |
599 | 8 | if (state.pcdev == dev || ptile->is_simple) |
600 | 0 | code = (*gx_dc_type_data_ht_binary.fill_rectangle) |
601 | 0 | (pdevc, x, y, w, h, state.pcdev, lop, source); |
602 | 8 | else { |
603 | 8 | state.lop = lop; |
604 | 8 | state.source = source; |
605 | 8 | state.fill_rectangle = gx_dc_type_data_ht_binary.fill_rectangle; |
606 | 8 | code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask, |
607 | 8 | tile_masked_fill); |
608 | 8 | } |
609 | 8 | exit: |
610 | 8 | if (CLIPDEV_INSTALLED) { |
611 | 8 | tile_clip_free((gx_device_tile_clip *)state.cdev); |
612 | 8 | state.cdev = NULL; |
613 | 8 | } |
614 | 8 | return code; |
615 | 8 | } |
616 | | |
617 | | int |
618 | | gx_dc_colored_masked_fill_rect(const gx_device_color * pdevc, |
619 | | int x, int y, int w, int h, gx_device * dev, |
620 | | gs_logical_operation_t lop, |
621 | | const gx_rop_source_t * source) |
622 | 1.14k | { |
623 | 1.14k | gx_color_tile *ptile = pdevc->mask.m_tile; |
624 | 1.14k | tile_fill_state_t state; |
625 | 1.14k | int code; |
626 | | |
627 | 1.14k | code = tile_fill_init(&state, pdevc, dev, true); |
628 | 1.14k | if (code < 0) |
629 | 0 | goto exit; |
630 | 1.14k | if (state.pcdev == dev || ptile->is_simple) |
631 | 0 | code = (*gx_dc_type_data_ht_colored.fill_rectangle) |
632 | 0 | (pdevc, x, y, w, h, state.pcdev, lop, source); |
633 | 1.14k | else { |
634 | 1.14k | state.lop = lop; |
635 | 1.14k | state.source = source; |
636 | 1.14k | state.fill_rectangle = gx_dc_type_data_ht_colored.fill_rectangle; |
637 | 1.14k | code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask, |
638 | 1.14k | tile_masked_fill); |
639 | 1.14k | } |
640 | 1.14k | exit: |
641 | 1.14k | if (CLIPDEV_INSTALLED) { |
642 | 1.14k | tile_clip_free((gx_device_tile_clip *)state.cdev); |
643 | 1.14k | state.cdev = NULL; |
644 | 1.14k | } |
645 | 1.14k | return code; |
646 | 1.14k | } |
647 | | |
648 | | /* |
649 | | * This is somewhat a clone of the tile_by_steps function but one |
650 | | * that performs filling from and to pdf14dev (transparency) buffers. |
651 | | * At some point it may be desirable to do some optimization here. |
652 | | */ |
653 | | static int |
654 | | tile_by_steps_trans(tile_fill_trans_state_t * ptfs, int x0, int y0, int w0, int h0, |
655 | | gx_pattern_trans_t *fill_trans_buffer, const gx_color_tile * ptile, |
656 | | int native16) |
657 | 19.9k | { |
658 | 19.9k | int x1 = x0 + w0, y1 = y0 + h0; |
659 | 19.9k | int i0, i1, j0, j1, i, j; |
660 | 19.9k | gs_matrix step_matrix; /* translated by phase */ |
661 | 19.9k | gx_pattern_trans_t *ptrans_pat = ptile->ttrans; |
662 | | #ifdef DEBUG |
663 | | const gs_memory_t *mem = ptile->ttrans->mem; |
664 | | #endif |
665 | 19.9k | int code; |
666 | | |
667 | 19.9k | ptfs->x0 = x0, ptfs->w0 = w0; |
668 | 19.9k | ptfs->y0 = y0, ptfs->h0 = h0; |
669 | 19.9k | step_matrix = ptile->step_matrix; |
670 | 19.9k | step_matrix.tx -= ptfs->phase.x; |
671 | 19.9k | step_matrix.ty -= ptfs->phase.y; |
672 | 19.9k | { |
673 | 19.9k | gs_rect bbox; /* bounding box in device space */ |
674 | 19.9k | gs_rect ibbox; /* bounding box in stepping space */ |
675 | 19.9k | double bbw = ptile->bbox.q.x - ptile->bbox.p.x; |
676 | 19.9k | double bbh = ptile->bbox.q.y - ptile->bbox.p.y; |
677 | 19.9k | double u0, v0, u1, v1; |
678 | | |
679 | 19.9k | bbox.p.x = x0, bbox.p.y = y0; |
680 | 19.9k | bbox.q.x = x1, bbox.q.y = y1; |
681 | 19.9k | code = gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox); |
682 | 19.9k | if (code < 0) |
683 | 0 | return code; |
684 | 19.9k | if_debug10m('T', mem, |
685 | 19.9k | "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n", |
686 | 19.9k | x0, y0, w0, h0, |
687 | 19.9k | ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y, |
688 | 19.9k | step_matrix.tx, step_matrix.ty); |
689 | | /* |
690 | | * If the pattern is partly transparent and XStep/YStep is smaller |
691 | | * than the device space BBox, we need to ensure that we cover |
692 | | * each pixel of the rectangle being filled with *every* pattern |
693 | | * that overlaps it, not just *some* pattern copy. |
694 | | */ |
695 | 19.9k | u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001; |
696 | 19.9k | v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001; |
697 | 19.9k | u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001; |
698 | 19.9k | v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001; |
699 | 19.9k | if (!ptile->is_simple) |
700 | 19.9k | u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh; |
701 | 19.9k | i0 = (int)fastfloor(u0); |
702 | 19.9k | j0 = (int)fastfloor(v0); |
703 | 19.9k | i1 = (int)ceil(u1); |
704 | 19.9k | j1 = (int)ceil(v1); |
705 | 19.9k | } |
706 | 19.9k | if_debug4m('T', mem, "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1); |
707 | 3.34M | for (i = i0; i < i1; i++) |
708 | 15.1M | for (j = j0; j < j1; j++) { |
709 | 11.7M | int x = (int)fastfloor(step_matrix.xx * i + |
710 | 11.7M | step_matrix.yx * j + step_matrix.tx); |
711 | 11.7M | int y = (int)fastfloor(step_matrix.xy * i + |
712 | 11.7M | step_matrix.yy * j + step_matrix.ty); |
713 | 11.7M | int w = ptrans_pat->width; |
714 | 11.7M | int h = ptrans_pat->height; |
715 | 11.7M | int xoff, yoff; |
716 | 11.7M | int px, py; |
717 | | |
718 | 11.7M | if_debug4m('T', mem, "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y); |
719 | 11.7M | if (x < x0) |
720 | 92.9k | xoff = x0 - x, x = x0, w -= xoff; |
721 | 11.7M | else |
722 | 11.7M | xoff = 0; |
723 | 11.7M | if (y < y0) |
724 | 3.36M | yoff = y0 - y, y = y0, h -= yoff; |
725 | 8.43M | else |
726 | 8.43M | yoff = 0; |
727 | 11.7M | if (x + w > x1) |
728 | 10.5M | w = x1 - x; |
729 | 11.7M | if (y + h > y1) |
730 | 1.27M | h = y1 - y; |
731 | 11.7M | if_debug6m('T', mem, "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n", |
732 | 11.7M | x, y, w, h, xoff, yoff); |
733 | 11.7M | if (w > 0 && h > 0) { |
734 | | |
735 | 14.5k | px = imod(xoff - x, ptile->ttrans->width); |
736 | 14.5k | py = imod(yoff - y, ptile->ttrans->height); |
737 | | |
738 | | /* Set the offsets for colored pattern fills */ |
739 | 14.5k | ptfs->xoff = xoff; |
740 | 14.5k | ptfs->yoff = yoff; |
741 | | |
742 | | /* We only go through blending during tiling, if there was overlap |
743 | | as defined by the step matrix and the bounding box. |
744 | | Ignore if the area is outside the fill_trans_buffer.rect (bug 700719) */ |
745 | 14.5k | if (x > fill_trans_buffer->rect.q.x || x+w < 0 || |
746 | 14.5k | y > fill_trans_buffer->rect.q.y || y+h < 0) |
747 | 0 | continue; /* skip the fill (can breakpoint here) */ |
748 | 14.5k | ptile->ttrans->pat_trans_fill(x, y, x+w, y+h, px, py, ptile, |
749 | 14.5k | fill_trans_buffer, native16); |
750 | 14.5k | } |
751 | 11.7M | } |
752 | 19.9k | return 0; |
753 | 19.9k | } |
754 | | |
755 | | static void |
756 | | be_rev_cpy(uint16_t *dst,const uint16_t *src,int n) |
757 | 0 | { |
758 | 0 | for (; n != 0; n--) { |
759 | 0 | uint16_t in = *src++; |
760 | 0 | ((byte *)dst)[0] = in>>8; |
761 | 0 | ((byte *)dst)[1] = in; |
762 | 0 | dst++; |
763 | 0 | } |
764 | 0 | } |
765 | | |
766 | | /* This does the case of tiling with simple tiles. Since it is not commented |
767 | | * anywhere note that simple means that the tile size is the same as the step |
768 | | * matrix size and the cross terms in the step matrix are 0. Hence a simple |
769 | | * case of tile replication. This needs to be optimized. */ |
770 | | /* Our source tile runs (conceptually) from (0,0) to |
771 | | * (ptile->ttrans->width, ptile->ttrans->height). In practise, only a limited |
772 | | * section of this (ptile->rect) may actually be used. */ |
773 | | void |
774 | | tile_rect_trans_simple(int xmin, int ymin, int xmax, int ymax, |
775 | | int px, int py, const gx_color_tile *ptile, |
776 | | gx_pattern_trans_t *fill_trans_buffer, |
777 | | int native16) |
778 | 52.7k | { |
779 | 52.7k | int kk, jj, ii, h, w; |
780 | 52.7k | int buff_out_y_offset, buff_out_x_offset; |
781 | 52.7k | unsigned char *ptr_out, *ptr_in, *buff_out, *buff_in, *ptr_out_temp; |
782 | 52.7k | unsigned char *row_ptr; |
783 | 52.7k | int in_row_offset; |
784 | 52.7k | int dx, dy; |
785 | 52.7k | int left_rem_end, left_width, num_full_tiles, right_tile_width; |
786 | 52.7k | int left_copy_rem_end, left_copy_width, left_copy_offset, left_copy_start; |
787 | 52.7k | int mid_copy_width, right_copy_width; |
788 | 52.7k | int tile_width = ptile->ttrans->width; |
789 | 52.7k | int tile_height = ptile->ttrans->height; |
790 | 52.7k | int src_planes = fill_trans_buffer->n_chan + (fill_trans_buffer->has_tags ? 1 : 0); |
791 | 52.7k | pdf14_buf *buf = fill_trans_buffer->buf; |
792 | 52.7k | bool deep = fill_trans_buffer->deep; |
793 | | |
794 | | /* Update the bbox in the topmost stack entry to reflect the fact that we |
795 | | * have drawn into it. FIXME: This makes the groups too large! */ |
796 | 52.7k | if (buf->dirty.p.x > xmin) |
797 | 33.6k | buf->dirty.p.x = xmin; |
798 | 52.7k | if (buf->dirty.p.y > ymin) |
799 | 31.7k | buf->dirty.p.y = ymin; |
800 | 52.7k | if (buf->dirty.q.x < xmax) |
801 | 33.6k | buf->dirty.q.x = xmax; |
802 | 52.7k | if (buf->dirty.q.y < ymax) |
803 | 41.1k | buf->dirty.q.y = ymax; |
804 | 52.7k | buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y; |
805 | 52.7k | buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x; |
806 | | |
807 | 52.7k | buff_out = fill_trans_buffer->transbytes + |
808 | 52.7k | buff_out_y_offset * fill_trans_buffer->rowstride + |
809 | 52.7k | (buff_out_x_offset<<deep); |
810 | | |
811 | 52.7k | buff_in = ptile->ttrans->transbytes; |
812 | | |
813 | 52.7k | h = ymax - ymin; |
814 | 52.7k | w = xmax - xmin; |
815 | | |
816 | 52.7k | if (h <= 0 || w <= 0) return; |
817 | | |
818 | | /* Calc dx, dy within the entire (conceptual) input tile. */ |
819 | 41.1k | dx = (xmin + px) % tile_width; |
820 | 41.1k | dy = (ymin + py) % tile_height; |
821 | | |
822 | | /* To speed this up, the inner loop on the width is implemented with |
823 | | * memcpys where we have a left remainder, full tiles and a right |
824 | | * remainder. Depending upon the rect that we are filling we may have |
825 | | * only one of these three portions, or two or all three. We compute |
826 | | * the parts now outside the loops. */ |
827 | | |
828 | | /* Left remainder part */ |
829 | 41.1k | left_rem_end = min(dx+w,tile_width); |
830 | 41.1k | left_width = left_rem_end - dx; |
831 | 41.1k | left_copy_start = max(dx,ptile->ttrans->rect.p.x); |
832 | 41.1k | left_copy_rem_end = min(dx+w,ptile->ttrans->rect.q.x); |
833 | 41.1k | left_copy_width = left_copy_rem_end - left_copy_start; |
834 | 41.1k | if (left_copy_width < 0) |
835 | 0 | left_copy_width = 0; |
836 | 41.1k | left_copy_offset = (left_copy_start-ptile->ttrans->rect.p.x)<<deep; |
837 | | |
838 | | /* Now the middle part */ |
839 | 41.1k | num_full_tiles = (int)fastfloor((float) (w - left_width)/ (float) tile_width); |
840 | 41.1k | mid_copy_width = ptile->ttrans->rect.q.x - ptile->ttrans->rect.p.x; |
841 | | |
842 | | /* Now the right part */ |
843 | 41.1k | right_tile_width = w - num_full_tiles*tile_width - left_width; |
844 | 41.1k | right_copy_width = right_tile_width - ptile->ttrans->rect.p.x; |
845 | 41.1k | if (right_copy_width > ptile->ttrans->rect.q.x) |
846 | 0 | right_copy_width = ptile->ttrans->rect.q.x; |
847 | 41.1k | right_copy_width -= ptile->ttrans->rect.p.x; |
848 | 41.1k | if (right_copy_width < 0) |
849 | 0 | right_copy_width = 0; |
850 | | |
851 | 41.1k | if (deep && native16) { |
852 | | /* fill_trans_buffer is in native endian. ptile is in big endian. */ |
853 | | /* Convert as we copy. */ |
854 | 0 | for (kk = 0; kk < src_planes; kk++) { |
855 | |
|
856 | 0 | ptr_out = buff_out + kk * fill_trans_buffer->planestride; |
857 | 0 | ptr_in = buff_in + kk * ptile->ttrans->planestride; |
858 | 0 | if (fill_trans_buffer->has_shape && kk == fill_trans_buffer->n_chan) |
859 | 0 | ptr_out += fill_trans_buffer->planestride; /* tag plane follows shape plane */ |
860 | |
|
861 | 0 | for (jj = 0; jj < h; jj++, ptr_out += fill_trans_buffer->rowstride) { |
862 | |
|
863 | 0 | in_row_offset = ((jj + dy) % ptile->ttrans->height); |
864 | 0 | if (in_row_offset >= ptile->ttrans->rect.q.y) |
865 | 0 | continue; |
866 | 0 | in_row_offset -= ptile->ttrans->rect.p.y; |
867 | 0 | if (in_row_offset < 0) |
868 | 0 | continue; |
869 | 0 | row_ptr = ptr_in + in_row_offset * ptile->ttrans->rowstride; |
870 | | |
871 | | /* This is the case when we have no blending. */ |
872 | 0 | ptr_out_temp = ptr_out; |
873 | | |
874 | | /* Left part */ |
875 | 0 | be_rev_cpy((uint16_t *)ptr_out_temp, (uint16_t *)(row_ptr + left_copy_offset), left_copy_width); |
876 | 0 | ptr_out_temp += left_width<<deep; |
877 | | |
878 | | /* Now the full tiles */ |
879 | |
|
880 | 0 | for ( ii = 0; ii < num_full_tiles; ii++){ |
881 | 0 | be_rev_cpy((uint16_t *)ptr_out_temp, (uint16_t *)row_ptr, mid_copy_width); |
882 | 0 | ptr_out_temp += tile_width<<deep; |
883 | 0 | } |
884 | | |
885 | | /* Now the remainder */ |
886 | 0 | be_rev_cpy((uint16_t *)ptr_out_temp, (uint16_t *)row_ptr, right_copy_width); |
887 | 0 | } |
888 | 0 | } |
889 | 41.1k | } else { |
890 | 183k | for (kk = 0; kk < src_planes; kk++) { |
891 | | |
892 | 142k | ptr_out = buff_out + kk * fill_trans_buffer->planestride; |
893 | 142k | ptr_in = buff_in + kk * ptile->ttrans->planestride; |
894 | 142k | if (fill_trans_buffer->has_shape && kk == fill_trans_buffer->n_chan) |
895 | 0 | ptr_out += fill_trans_buffer->planestride; /* tag plane follows shape plane */ |
896 | | |
897 | 1.04M | for (jj = 0; jj < h; jj++, ptr_out += fill_trans_buffer->rowstride) { |
898 | | |
899 | 899k | in_row_offset = ((jj + dy) % ptile->ttrans->height); |
900 | 899k | if (in_row_offset >= ptile->ttrans->rect.q.y) |
901 | 0 | continue; |
902 | 899k | in_row_offset -= ptile->ttrans->rect.p.y; |
903 | 899k | if (in_row_offset < 0) |
904 | 0 | continue; |
905 | 899k | row_ptr = ptr_in + in_row_offset * ptile->ttrans->rowstride; |
906 | | |
907 | | /* This is the case when we have no blending. */ |
908 | 899k | ptr_out_temp = ptr_out; |
909 | | |
910 | | /* Left part */ |
911 | 899k | memcpy( ptr_out_temp, row_ptr + left_copy_offset, left_copy_width<<deep); |
912 | 899k | ptr_out_temp += left_width<<deep; |
913 | | |
914 | | /* Now the full tiles */ |
915 | | |
916 | 1.43M | for ( ii = 0; ii < num_full_tiles; ii++){ |
917 | 533k | memcpy( ptr_out_temp, row_ptr, mid_copy_width<<deep); |
918 | 533k | ptr_out_temp += tile_width<<deep; |
919 | 533k | } |
920 | | |
921 | | /* Now the remainder */ |
922 | 899k | memcpy( ptr_out_temp, row_ptr, right_copy_width<<deep); |
923 | 899k | } |
924 | 142k | } |
925 | 41.1k | } |
926 | | |
927 | | /* If the group we are filling has a shape plane fill that now */ |
928 | | /* Note: Since this was a virgin group push we can just blast it with |
929 | | * 255 */ |
930 | 41.1k | if (fill_trans_buffer->has_shape) { |
931 | 0 | ptr_out = buff_out + fill_trans_buffer->n_chan * fill_trans_buffer->planestride; |
932 | 0 | for (jj = 0; jj < h; jj++,ptr_out += fill_trans_buffer->rowstride) { |
933 | 0 | memset(ptr_out, 255, w<<deep); |
934 | 0 | } |
935 | 0 | } |
936 | 41.1k | } |
937 | | |
938 | | /* This does the case of tiling with non simple tiles. In this case, the |
939 | | * tiles may overlap and so we really need to do blending within the existing |
940 | | * buffer. This needs some serious optimization. */ |
941 | | static void |
942 | | do_tile_rect_trans_blend(int xmin, int ymin, int xmax, int ymax, |
943 | | int px, int py, const gx_color_tile *ptile, |
944 | | gx_pattern_trans_t *fill_trans_buffer) |
945 | 901 | { |
946 | 901 | int kk, jj, ii, h, w; |
947 | 901 | int buff_out_y_offset, buff_out_x_offset; |
948 | 901 | unsigned char *buff_out, *buff_in; |
949 | 901 | unsigned char *buff_ptr, *row_ptr_in, *row_ptr_out; |
950 | 901 | unsigned char *tile_ptr; |
951 | 901 | int in_row_offset; |
952 | 901 | int dx, dy; |
953 | 901 | byte src[PDF14_MAX_PLANES]; |
954 | 901 | byte dst[PDF14_MAX_PLANES]; |
955 | 901 | int tile_width = ptile->ttrans->width; |
956 | 901 | int tile_height = ptile->ttrans->height; |
957 | 901 | int num_chan = ptile->ttrans->n_chan; /* Includes alpha */ |
958 | 901 | int tag_offset = fill_trans_buffer->n_chan + (fill_trans_buffer->has_shape ? 1 : 0); |
959 | 901 | pdf14_device *p14dev = (pdf14_device *) fill_trans_buffer->pdev14; |
960 | | |
961 | 901 | if (fill_trans_buffer->has_tags == 0) |
962 | 901 | tag_offset = 0; |
963 | | |
964 | 901 | buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y; |
965 | 901 | buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x; |
966 | | |
967 | 901 | h = ymax - ymin; |
968 | 901 | w = xmax - xmin; |
969 | | |
970 | 901 | if (h <= 0 || w <= 0) return; |
971 | | |
972 | | /* Calc dx, dy within the entire (conceptual) input tile. */ |
973 | 901 | dx = (xmin + px) % tile_width; |
974 | 901 | dy = (ymin + py) % tile_height; |
975 | | |
976 | 901 | buff_out = fill_trans_buffer->transbytes + |
977 | 901 | buff_out_y_offset * fill_trans_buffer->rowstride + |
978 | 901 | buff_out_x_offset; |
979 | | |
980 | 901 | buff_in = ptile->ttrans->transbytes; |
981 | | |
982 | 11.5k | for (jj = 0; jj < h; jj++){ |
983 | | |
984 | 10.6k | in_row_offset = (jj + dy) % ptile->ttrans->height; |
985 | 10.6k | if (in_row_offset >= ptile->ttrans->rect.q.y) |
986 | 0 | continue; |
987 | 10.6k | in_row_offset -= ptile->ttrans->rect.p.y; |
988 | 10.6k | if (in_row_offset < 0) |
989 | 0 | continue; |
990 | 10.6k | row_ptr_in = buff_in + in_row_offset * ptile->ttrans->rowstride; |
991 | | |
992 | 10.6k | row_ptr_out = buff_out + jj * fill_trans_buffer->rowstride; |
993 | | |
994 | 10.1M | for (ii = 0; ii < w; ii++) { |
995 | 10.1M | int x_in_offset = (dx + ii) % ptile->ttrans->width; |
996 | | |
997 | 10.1M | if (x_in_offset >= ptile->ttrans->rect.q.x) |
998 | 0 | continue; |
999 | 10.1M | x_in_offset -= ptile->ttrans->rect.p.x; |
1000 | 10.1M | if (x_in_offset < 0) |
1001 | 0 | continue; |
1002 | 10.1M | tile_ptr = row_ptr_in + x_in_offset; |
1003 | 10.1M | buff_ptr = row_ptr_out + ii; |
1004 | | |
1005 | | /* We need to blend here. The blending mode from the current |
1006 | | imager state is used. |
1007 | | */ |
1008 | | |
1009 | | /* The color values. This needs to be optimized */ |
1010 | 46.9M | for (kk = 0; kk < num_chan; kk++) { |
1011 | 36.8M | dst[kk] = *(buff_ptr + kk * fill_trans_buffer->planestride); |
1012 | 36.8M | src[kk] = *(tile_ptr + kk * ptile->ttrans->planestride); |
1013 | 36.8M | } |
1014 | | |
1015 | | /* Blend */ |
1016 | 10.1M | art_pdf_composite_pixel_alpha_8(dst, src, ptile->ttrans->n_chan-1, |
1017 | 10.1M | ptile->blending_mode, ptile->ttrans->n_chan-1, |
1018 | 10.1M | ptile->ttrans->blending_procs, p14dev); |
1019 | | |
1020 | | /* Store the color values */ |
1021 | 46.9M | for (kk = 0; kk < num_chan; kk++) { |
1022 | 36.8M | *(buff_ptr + kk * fill_trans_buffer->planestride) = dst[kk]; |
1023 | 36.8M | } |
1024 | | /* Now handle the blending of the tag. NB: dst tag_offset follows shape */ |
1025 | 10.1M | if (tag_offset > 0) { |
1026 | 0 | int src_tag = *(tile_ptr + num_chan * ptile->ttrans->planestride); |
1027 | 0 | int dst_tag = *(buff_ptr + tag_offset * fill_trans_buffer->planestride); |
1028 | |
|
1029 | 0 | dst_tag |= src_tag; /* simple blend combines tags */ |
1030 | 0 | *(buff_ptr + tag_offset * fill_trans_buffer->planestride) = dst_tag; |
1031 | 0 | } |
1032 | 10.1M | } |
1033 | 10.6k | } |
1034 | | |
1035 | | /* If the group we are filling has a shape plane fill that now */ |
1036 | | /* Note: Since this was a virgin group push we can just blast it with |
1037 | | * 255 */ |
1038 | 901 | if (fill_trans_buffer->has_shape) { |
1039 | 0 | buff_ptr = buff_out + fill_trans_buffer->n_chan * fill_trans_buffer->planestride; |
1040 | |
|
1041 | 0 | for (jj = 0; jj < h; jj++) { |
1042 | 0 | memset(buff_ptr, 255, w); |
1043 | 0 | buff_ptr += fill_trans_buffer->rowstride; |
1044 | 0 | } |
1045 | 0 | } |
1046 | 901 | } |
1047 | | |
1048 | | /* In this version, source data is big endian, dest is native endian */ |
1049 | | static void |
1050 | | do_tile_rect_trans_blend_16(int xmin, int ymin, int xmax, int ymax, |
1051 | | int px, int py, const gx_color_tile *ptile, |
1052 | | gx_pattern_trans_t *fill_trans_buffer) |
1053 | 0 | { |
1054 | 0 | int kk, jj, ii, h, w; |
1055 | 0 | int buff_out_y_offset, buff_out_x_offset; |
1056 | 0 | uint16_t *buff_out, *buff_in; |
1057 | 0 | uint16_t *buff_ptr, *row_ptr_in, *row_ptr_out; |
1058 | 0 | uint16_t *tile_ptr; |
1059 | 0 | int in_row_offset; |
1060 | 0 | int dx, dy; |
1061 | 0 | uint16_t src[PDF14_MAX_PLANES]; |
1062 | 0 | uint16_t dst[PDF14_MAX_PLANES]; |
1063 | 0 | int tile_width = ptile->ttrans->width; |
1064 | 0 | int tile_height = ptile->ttrans->height; |
1065 | 0 | int num_chan = ptile->ttrans->n_chan; /* Includes alpha */ |
1066 | 0 | int tag_offset = fill_trans_buffer->n_chan + (fill_trans_buffer->has_shape ? 1 : 0); |
1067 | 0 | pdf14_device *p14dev = (pdf14_device *) fill_trans_buffer->pdev14; |
1068 | |
|
1069 | 0 | if (fill_trans_buffer->has_tags == 0) |
1070 | 0 | tag_offset = 0; |
1071 | |
|
1072 | 0 | buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y; |
1073 | 0 | buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x; |
1074 | |
|
1075 | 0 | h = ymax - ymin; |
1076 | 0 | w = xmax - xmin; |
1077 | |
|
1078 | 0 | if (h <= 0 || w <= 0) return; |
1079 | | |
1080 | | /* Calc dx, dy within the entire (conceptual) input tile. */ |
1081 | 0 | dx = (xmin + px) % tile_width; |
1082 | 0 | dy = (ymin + py) % tile_height; |
1083 | |
|
1084 | 0 | buff_out = (uint16_t *)(void *)(fill_trans_buffer->transbytes + |
1085 | 0 | buff_out_y_offset * fill_trans_buffer->rowstride + |
1086 | 0 | buff_out_x_offset*2); |
1087 | |
|
1088 | 0 | buff_in = (uint16_t *)(void *)ptile->ttrans->transbytes; |
1089 | |
|
1090 | 0 | for (jj = 0; jj < h; jj++){ |
1091 | |
|
1092 | 0 | in_row_offset = (jj + dy) % ptile->ttrans->height; |
1093 | 0 | if (in_row_offset >= ptile->ttrans->rect.q.y) |
1094 | 0 | continue; |
1095 | 0 | in_row_offset -= ptile->ttrans->rect.p.y; |
1096 | 0 | if (in_row_offset < 0) |
1097 | 0 | continue; |
1098 | 0 | row_ptr_in = buff_in + in_row_offset * (ptile->ttrans->rowstride>>1); |
1099 | |
|
1100 | 0 | row_ptr_out = buff_out + jj * (fill_trans_buffer->rowstride>>1); |
1101 | |
|
1102 | 0 | for (ii = 0; ii < w; ii++) { |
1103 | 0 | int x_in_offset = (dx + ii) % ptile->ttrans->width; |
1104 | |
|
1105 | 0 | if (x_in_offset >= ptile->ttrans->rect.q.x) |
1106 | 0 | continue; |
1107 | 0 | x_in_offset -= ptile->ttrans->rect.p.x; |
1108 | 0 | if (x_in_offset < 0) |
1109 | 0 | continue; |
1110 | 0 | tile_ptr = row_ptr_in + x_in_offset; |
1111 | 0 | buff_ptr = row_ptr_out + ii; |
1112 | | |
1113 | | /* We need to blend here. The blending mode from the current |
1114 | | imager state is used. |
1115 | | */ |
1116 | | |
1117 | | /* Data is stored in big endian, but must be processed in native */ |
1118 | 0 | #define GET16_BE2NATIVE(v) \ |
1119 | 0 | ((((byte *)(v))[0]<<8) | (((byte *)(v))[1])) |
1120 | | |
1121 | | /* The color values. This needs to be optimized */ |
1122 | 0 | for (kk = 0; kk < num_chan; kk++) { |
1123 | 0 | dst[kk] = *(buff_ptr + kk * (fill_trans_buffer->planestride>>1)); |
1124 | 0 | src[kk] = GET16_BE2NATIVE(tile_ptr + kk * (ptile->ttrans->planestride>>1)); |
1125 | 0 | } |
1126 | | |
1127 | | /* Blend */ |
1128 | 0 | art_pdf_composite_pixel_alpha_16(dst, src, ptile->ttrans->n_chan-1, |
1129 | 0 | ptile->blending_mode, ptile->ttrans->n_chan-1, |
1130 | 0 | ptile->ttrans->blending_procs, p14dev); |
1131 | | |
1132 | | /* Store the color values */ |
1133 | 0 | for (kk = 0; kk < num_chan; kk++) { |
1134 | 0 | *(buff_ptr + kk * (fill_trans_buffer->planestride>>1)) = dst[kk]; |
1135 | 0 | } |
1136 | | /* Now handle the blending of the tag. NB: dst tag_offset follows shape */ |
1137 | 0 | if (tag_offset > 0) { |
1138 | 0 | int src_tag = GET16_BE2NATIVE(tile_ptr + (num_chan * ptile->ttrans->planestride>>1)); |
1139 | 0 | int dst_tag = *(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1)); |
1140 | |
|
1141 | 0 | dst_tag |= src_tag; /* simple blend combines tags */ |
1142 | 0 | *(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1)) = dst_tag; |
1143 | 0 | } |
1144 | 0 | } |
1145 | 0 | } |
1146 | 0 | #undef GET16_BE2NATIVE |
1147 | | |
1148 | | /* If the group we are filling has a shape plane fill that now */ |
1149 | | /* Note: Since this was a virgin group push we can just blast it with |
1150 | | * 255 */ |
1151 | 0 | if (fill_trans_buffer->has_shape) { |
1152 | 0 | buff_ptr = buff_out + fill_trans_buffer->n_chan * (fill_trans_buffer->planestride>>1); |
1153 | |
|
1154 | 0 | for (jj = 0; jj < h; jj++) { |
1155 | 0 | memset(buff_ptr, 255, w*2); |
1156 | 0 | buff_ptr += fill_trans_buffer->rowstride>>1; |
1157 | 0 | } |
1158 | 0 | } |
1159 | 0 | } |
1160 | | |
1161 | | /* In this version, both source and dest data is big endian */ |
1162 | | static void |
1163 | | do_tile_rect_trans_blend_16be(int xmin, int ymin, int xmax, int ymax, |
1164 | | int px, int py, const gx_color_tile *ptile, |
1165 | | gx_pattern_trans_t *fill_trans_buffer) |
1166 | 0 | { |
1167 | 0 | int kk, jj, ii, h, w; |
1168 | 0 | int buff_out_y_offset, buff_out_x_offset; |
1169 | 0 | uint16_t *buff_out, *buff_in; |
1170 | 0 | uint16_t *buff_ptr, *row_ptr_in, *row_ptr_out; |
1171 | 0 | uint16_t *tile_ptr; |
1172 | 0 | int in_row_offset; |
1173 | 0 | int dx, dy; |
1174 | 0 | uint16_t src[PDF14_MAX_PLANES]; |
1175 | 0 | uint16_t dst[PDF14_MAX_PLANES]; |
1176 | 0 | int tile_width = ptile->ttrans->width; |
1177 | 0 | int tile_height = ptile->ttrans->height; |
1178 | 0 | int num_chan = ptile->ttrans->n_chan; /* Includes alpha */ |
1179 | 0 | int tag_offset = fill_trans_buffer->n_chan + (fill_trans_buffer->has_shape ? 1 : 0); |
1180 | 0 | pdf14_device *p14dev = (pdf14_device *) fill_trans_buffer->pdev14; |
1181 | |
|
1182 | 0 | if (fill_trans_buffer->has_tags == 0) |
1183 | 0 | tag_offset = 0; |
1184 | |
|
1185 | 0 | buff_out_y_offset = ymin - fill_trans_buffer->rect.p.y; |
1186 | 0 | buff_out_x_offset = xmin - fill_trans_buffer->rect.p.x; |
1187 | |
|
1188 | 0 | h = ymax - ymin; |
1189 | 0 | w = xmax - xmin; |
1190 | |
|
1191 | 0 | if (h <= 0 || w <= 0) return; |
1192 | | |
1193 | | /* Calc dx, dy within the entire (conceptual) input tile. */ |
1194 | 0 | dx = (xmin + px) % tile_width; |
1195 | 0 | dy = (ymin + py) % tile_height; |
1196 | |
|
1197 | 0 | buff_out = (uint16_t *)(void *)(fill_trans_buffer->transbytes + |
1198 | 0 | buff_out_y_offset * fill_trans_buffer->rowstride + |
1199 | 0 | buff_out_x_offset*2); |
1200 | |
|
1201 | 0 | buff_in = (uint16_t *)(void *)ptile->ttrans->transbytes; |
1202 | |
|
1203 | 0 | for (jj = 0; jj < h; jj++){ |
1204 | |
|
1205 | 0 | in_row_offset = (jj + dy) % ptile->ttrans->height; |
1206 | 0 | if (in_row_offset >= ptile->ttrans->rect.q.y) |
1207 | 0 | continue; |
1208 | 0 | in_row_offset -= ptile->ttrans->rect.p.y; |
1209 | 0 | if (in_row_offset < 0) |
1210 | 0 | continue; |
1211 | 0 | row_ptr_in = buff_in + in_row_offset * (ptile->ttrans->rowstride>>1); |
1212 | |
|
1213 | 0 | row_ptr_out = buff_out + jj * (fill_trans_buffer->rowstride>>1); |
1214 | |
|
1215 | 0 | for (ii = 0; ii < w; ii++) { |
1216 | 0 | int x_in_offset = (dx + ii) % ptile->ttrans->width; |
1217 | |
|
1218 | 0 | if (x_in_offset >= ptile->ttrans->rect.q.x) |
1219 | 0 | continue; |
1220 | 0 | x_in_offset -= ptile->ttrans->rect.p.x; |
1221 | 0 | if (x_in_offset < 0) |
1222 | 0 | continue; |
1223 | 0 | tile_ptr = row_ptr_in + x_in_offset; |
1224 | 0 | buff_ptr = row_ptr_out + ii; |
1225 | | |
1226 | | /* We need to blend here. The blending mode from the current |
1227 | | imager state is used. |
1228 | | */ |
1229 | | |
1230 | | /* Data is stored in big endian, but must be processed in native */ |
1231 | 0 | #define GET16_BE2NATIVE(v) \ |
1232 | 0 | ((((byte *)(v))[0]<<8) | (((byte *)(v))[1])) |
1233 | 0 | #define PUT16_NATIVE2BE(p,v) \ |
1234 | 0 | ((((byte *)(p))[0] = v>>8), (((byte *)(p))[1] = v)) |
1235 | | |
1236 | | /* The color values. This needs to be optimized */ |
1237 | 0 | for (kk = 0; kk < num_chan; kk++) { |
1238 | 0 | dst[kk] = GET16_BE2NATIVE(buff_ptr + kk * (fill_trans_buffer->planestride>>1)); |
1239 | 0 | src[kk] = GET16_BE2NATIVE(tile_ptr + kk * (ptile->ttrans->planestride>>1)); |
1240 | 0 | } |
1241 | | |
1242 | | /* Blend */ |
1243 | 0 | art_pdf_composite_pixel_alpha_16(dst, src, ptile->ttrans->n_chan-1, |
1244 | 0 | ptile->blending_mode, ptile->ttrans->n_chan-1, |
1245 | 0 | ptile->ttrans->blending_procs, p14dev); |
1246 | | |
1247 | | /* Store the color values */ |
1248 | 0 | for (kk = 0; kk < num_chan; kk++) { |
1249 | 0 | PUT16_NATIVE2BE(buff_ptr + kk * (fill_trans_buffer->planestride>>1), dst[kk]); |
1250 | 0 | } |
1251 | | /* Now handle the blending of the tag. NB: dst tag_offset follows shape */ |
1252 | 0 | if (tag_offset > 0) { |
1253 | 0 | int src_tag = GET16_BE2NATIVE(tile_ptr + (num_chan * ptile->ttrans->planestride>>1)); |
1254 | 0 | int dst_tag = GET16_BE2NATIVE(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1)); |
1255 | |
|
1256 | 0 | dst_tag |= src_tag; /* simple blend combines tags */ |
1257 | 0 | PUT16_NATIVE2BE(buff_ptr + (tag_offset * fill_trans_buffer->planestride>>1), dst_tag); |
1258 | 0 | } |
1259 | 0 | } |
1260 | 0 | } |
1261 | | |
1262 | | /* If the group we are filling has a shape plane fill that now */ |
1263 | | /* Note: Since this was a virgin group push we can just blast it with |
1264 | | * 255 */ |
1265 | 0 | if (fill_trans_buffer->has_shape) { |
1266 | 0 | buff_ptr = buff_out + fill_trans_buffer->n_chan * (fill_trans_buffer->planestride>>1); |
1267 | |
|
1268 | 0 | for (jj = 0; jj < h; jj++) { |
1269 | 0 | memset(buff_ptr, 255, w*2); |
1270 | 0 | buff_ptr += fill_trans_buffer->rowstride>>1; |
1271 | 0 | } |
1272 | 0 | } |
1273 | 0 | } |
1274 | | |
1275 | | void |
1276 | | tile_rect_trans_blend(int xmin, int ymin, int xmax, int ymax, |
1277 | | int px, int py, const gx_color_tile *ptile, |
1278 | | gx_pattern_trans_t *fill_trans_buffer, |
1279 | | int native16) |
1280 | 901 | { |
1281 | 901 | pdf14_buf *buf = fill_trans_buffer->buf; |
1282 | | |
1283 | | /* Update the bbox in the topmost stack entry to reflect the fact that we |
1284 | | * have drawn into it. FIXME: This makes the groups too large! */ |
1285 | 901 | if (buf->dirty.p.x > xmin) |
1286 | 599 | buf->dirty.p.x = xmin; |
1287 | 901 | if (buf->dirty.p.y > ymin) |
1288 | 599 | buf->dirty.p.y = ymin; |
1289 | 901 | if (buf->dirty.q.x < xmax) |
1290 | 611 | buf->dirty.q.x = xmax; |
1291 | 901 | if (buf->dirty.q.y < ymax) |
1292 | 618 | buf->dirty.q.y = ymax; |
1293 | | |
1294 | 901 | if (!ptile->ttrans->deep) |
1295 | 901 | do_tile_rect_trans_blend(xmin, ymin, xmax, ymax, |
1296 | 901 | px, py, ptile, fill_trans_buffer); |
1297 | 0 | else if (native16) |
1298 | 0 | do_tile_rect_trans_blend_16(xmin, ymin, xmax, ymax, |
1299 | 0 | px, py, ptile, fill_trans_buffer); |
1300 | 0 | else |
1301 | 0 | do_tile_rect_trans_blend_16be(xmin, ymin, xmax, ymax, |
1302 | 0 | px, py, ptile, fill_trans_buffer); |
1303 | 901 | } |
1304 | | |
1305 | | /* This version does a rect fill with the transparency object */ |
1306 | | int |
1307 | | gx_dc_pat_trans_fill_rectangle(const gx_device_color * pdevc, int x, int y, |
1308 | | int w, int h, gx_device * dev, |
1309 | | gs_logical_operation_t lop, |
1310 | | const gx_rop_source_t * source) |
1311 | 0 | { |
1312 | 0 | gx_color_tile *ptile = pdevc->colors.pattern.p_tile; |
1313 | 0 | int code; |
1314 | 0 | gs_int_point phase; |
1315 | 0 | const gx_rop_source_t *rop_source = source; |
1316 | 0 | gx_rop_source_t no_source; |
1317 | |
|
1318 | 0 | if (ptile == 0) /* null pattern */ |
1319 | 0 | return 0; |
1320 | 0 | if (rop_source == NULL) |
1321 | 0 | set_rop_no_source(rop_source, no_source, dev); |
1322 | |
|
1323 | 0 | phase.x = pdevc->phase.x; |
1324 | 0 | phase.y = pdevc->phase.y; |
1325 | |
|
1326 | | #if 0 |
1327 | | if_debug8m('v', ptile->ttrans->mem, |
1328 | | "[v]gx_dc_pat_trans_fill_rectangle, Fill: (%d, %d), %d x %d To Buffer: (%d, %d), %d x %d \n", |
1329 | | x, y, w, h, ptile->ttrans->fill_trans_buffer->rect.p.x, |
1330 | | ptile->ttrans->fill_trans_buffer->rect.p.y, |
1331 | | ptile->ttrans->fill_trans_buffer->rect.q.x - |
1332 | | ptile->ttrans->fill_trans_buffer->rect.p.x, |
1333 | | ptile->ttrans->fill_trans_buffer->rect.q.y - |
1334 | | ptile->ttrans->fill_trans_buffer->rect.p.y); |
1335 | | #endif |
1336 | 0 | code = gx_trans_pattern_fill_rect(x, y, x+w, y+h, ptile, |
1337 | 0 | ptile->ttrans->fill_trans_buffer, phase, |
1338 | 0 | dev, pdevc, 0); |
1339 | 0 | return code; |
1340 | 0 | } |
1341 | | |
1342 | | /* This fills the transparency buffer rectangles with a pattern buffer |
1343 | | that includes transparency */ |
1344 | | int |
1345 | | gx_trans_pattern_fill_rect(int xmin, int ymin, int xmax, int ymax, |
1346 | | gx_color_tile *ptile, |
1347 | | gx_pattern_trans_t *fill_trans_buffer, |
1348 | | gs_int_point phase, gx_device *dev, |
1349 | | const gx_device_color * pdevc, |
1350 | | int native16) |
1351 | 111k | { |
1352 | 111k | tile_fill_trans_state_t state_trans; |
1353 | 111k | tile_fill_state_t state_clist_trans; |
1354 | 111k | int code = 0; |
1355 | 111k | int w = xmax - xmin; |
1356 | 111k | int h = ymax - ymin; |
1357 | | |
1358 | 111k | if (ptile == NULL) /* null pattern */ |
1359 | 0 | return 0; |
1360 | | |
1361 | 111k | fit_fill_xywh(dev, xmin, ymin, w, h); |
1362 | 111k | if (w < 0 || h < 0) |
1363 | 0 | return 0; |
1364 | 111k | xmax = w + xmin; |
1365 | 111k | ymax = h + ymin; |
1366 | | |
1367 | | /* Initialize the fill state */ |
1368 | 111k | state_trans.phase.x = phase.x; |
1369 | 111k | state_trans.phase.y = phase.y; |
1370 | | |
1371 | 111k | if (ptile->is_simple && ptile->cdev == NULL) { |
1372 | | /* A simple case. Tile is not clist and simple. */ |
1373 | 39.0k | int px = |
1374 | 39.0k | imod(-(int)fastfloor(ptile->step_matrix.tx - phase.x + 0.5), |
1375 | 39.0k | ptile->ttrans->width); |
1376 | 39.0k | int py = |
1377 | 39.0k | imod(-(int)fastfloor(ptile->step_matrix.ty - phase.y + 0.5), |
1378 | 39.0k | ptile->ttrans->height); |
1379 | | |
1380 | 39.0k | if (fill_trans_buffer == NULL) |
1381 | 0 | return_error(gs_error_unknownerror); |
1382 | | |
1383 | 39.0k | tile_rect_trans_simple(xmin, ymin, xmax, ymax, px, py, ptile, |
1384 | 39.0k | fill_trans_buffer, native16); |
1385 | 72.5k | } else { |
1386 | 72.5k | if (ptile->cdev == NULL) { |
1387 | | /* No clist for the pattern, but a complex case |
1388 | | This portion transforms the bounding box by the step matrix |
1389 | | and does partial rect fills with tiles that fall into this |
1390 | | transformed bbox */ |
1391 | 19.9k | if (fill_trans_buffer == NULL) |
1392 | 0 | return_error(gs_error_unknownerror); |
1393 | | |
1394 | 19.9k | code = tile_by_steps_trans(&state_trans, xmin, ymin, xmax-xmin, |
1395 | 19.9k | ymax-ymin, fill_trans_buffer, ptile, |
1396 | 19.9k | native16); |
1397 | | |
1398 | 52.5k | } else { |
1399 | | /* clist for the trans tile. This uses the pdf14 device as a target |
1400 | | and should blend directly into the buffer. Note that the |
1401 | | pattern can not have a push pdf14 device or a pop pdf14 device |
1402 | | compositor action. Those are removed during the compositor |
1403 | | clist writing operation where we check for the case of a pattern |
1404 | | with a transparency */ |
1405 | 52.5k | gx_device_clist *cdev = ptile->cdev; |
1406 | 52.5k | gx_device_clist_reader *crdev = (gx_device_clist_reader *)cdev; |
1407 | 52.5k | gx_strip_bitmap tbits; |
1408 | | |
1409 | 52.5k | code = tile_fill_init(&state_clist_trans, pdevc, dev, false); |
1410 | 52.5k | if (code < 0) |
1411 | 0 | { |
1412 | | /* Can't use CLIPDEV_INSTALLED macro because it assumes a tile_fill_state_t structure, called 'state' */ |
1413 | 0 | if (state_clist_trans.cdev != NULL) { |
1414 | 0 | tile_clip_free((gx_device_tile_clip *)state_clist_trans.cdev); |
1415 | 0 | state_clist_trans.cdev = NULL; |
1416 | 0 | } |
1417 | 0 | return code; |
1418 | 0 | } |
1419 | | |
1420 | 52.5k | state_clist_trans.phase.x = phase.x; |
1421 | 52.5k | state_clist_trans.phase.y = phase.y; |
1422 | 52.5k | crdev->yplane.depth = 0; |
1423 | 52.5k | crdev->yplane.shift = 0; |
1424 | 52.5k | crdev->yplane.index = -1; |
1425 | 52.5k | crdev->pages = NULL; |
1426 | 52.5k | crdev->num_pages = 1; |
1427 | 52.5k | state_clist_trans.orig_dev = dev; |
1428 | 52.5k | state_clist_trans.pdevc = pdevc; |
1429 | 52.5k | tbits = ptile->tbits; |
1430 | 52.5k | tbits.size.x = crdev->width; |
1431 | 52.5k | tbits.size.y = crdev->height; |
1432 | 52.5k | if (code >= 0) |
1433 | 52.5k | code = tile_by_steps(&state_clist_trans, xmin, ymin, xmax-xmin, |
1434 | 52.5k | ymax-ymin, ptile, &tbits, tile_pattern_clist); |
1435 | | |
1436 | 52.5k | if (code >= 0 && (state_clist_trans.cdev != NULL)) { |
1437 | 0 | tile_clip_free((gx_device_tile_clip *)state_clist_trans.cdev); |
1438 | 0 | state_clist_trans.cdev = NULL; |
1439 | 0 | } |
1440 | | |
1441 | 52.5k | } |
1442 | 72.5k | } |
1443 | 111k | return code; |
1444 | 111k | } |