/src/ghostpdl/base/gximono.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 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 | | /* General mono-component image rendering */ |
18 | | #include "gx.h" |
19 | | #include "memory_.h" |
20 | | #include "gpcheck.h" |
21 | | #include "gserrors.h" |
22 | | #include "gxfixed.h" |
23 | | #include "gxarith.h" |
24 | | #include "gxmatrix.h" |
25 | | #include "gsccolor.h" |
26 | | #include "gspaint.h" |
27 | | #include "gsutil.h" |
28 | | #include "gxdevice.h" |
29 | | #include "gxcmap.h" |
30 | | #include "gxdcolor.h" |
31 | | #include "gxgstate.h" |
32 | | #include "gxdevmem.h" |
33 | | #include "gdevmem.h" /* for mem_mono_device */ |
34 | | #include "gxcpath.h" |
35 | | #include "gximage.h" |
36 | | #include "gzht.h" |
37 | | #include "gsicc.h" |
38 | | #include "gsicc_cache.h" |
39 | | #include "gsicc_cms.h" |
40 | | #include "gxcie.h" |
41 | | #include "gscie.h" |
42 | | #include "gxht_thresh.h" |
43 | | #include "gxdda.h" |
44 | | #include "gxdevsop.h" |
45 | | #ifdef WITH_CAL |
46 | | #include "cal.h" |
47 | | #endif |
48 | | |
49 | | #define fastfloor(x) (((int)(x)) - (((x)<0) && ((x) != (float)(int)(x)))) |
50 | | |
51 | | /* Enable the following define to perform a little extra work to stop |
52 | | * spurious valgrind errors. The code should perform perfectly even without |
53 | | * this enabled, but enabling it makes debugging much easier. |
54 | | */ |
55 | | /* #define PACIFY_VALGRIND */ |
56 | | |
57 | | /* ------ Strategy procedure ------ */ |
58 | | |
59 | | /* Check the prototype. */ |
60 | | iclass_proc(gs_image_class_3_mono); |
61 | | |
62 | | static irender_proc(image_render_mono); |
63 | | #ifndef WITH_CAL |
64 | | static irender_proc(image_render_mono_ht); |
65 | | #else |
66 | | static irender_proc(image_render_mono_ht_cal); |
67 | | static int image_render_mono_ht_cal_skip_line(gx_image_enum *penum, |
68 | | gx_device *dev); |
69 | | |
70 | | static void |
71 | | halftone_callback(cal_halftone_data_t *ht, void *arg) |
72 | | { |
73 | | gx_device *dev = arg; |
74 | | gx_color_index dev_white = gx_device_white(dev); |
75 | | gx_color_index dev_black = gx_device_black(dev); |
76 | | |
77 | | if (dev->num_planar_planes) { |
78 | | (*dev_proc(dev, copy_planes)) (dev, ht->data, ht->x + (ht->offset_x<<3), ht->raster, |
79 | | gx_no_bitmap_id, ht->x, ht->y, ht->w, ht->h, |
80 | | ht->plane_raster); |
81 | | } else { |
82 | | (*dev_proc(dev, copy_mono)) (dev, ht->data, ht->x + (ht->offset_x<<3), ht->raster, |
83 | | gx_no_bitmap_id, ht->x, ht->y, ht->w, ht->h, dev_white, |
84 | | dev_black); |
85 | | } |
86 | | } |
87 | | |
88 | | static cal_halftone* |
89 | | halftone_init(gx_image_enum *penum) |
90 | | { |
91 | | cal_halftone *cal_ht = NULL; |
92 | | gx_dda_fixed dda_ht; |
93 | | int k; |
94 | | gx_ht_order *d_order; |
95 | | int code; |
96 | | byte *cache = (penum->color_cache != NULL ? penum->color_cache->device_contone : NULL); |
97 | | cal_matrix matrix; |
98 | | int clip_x, clip_y; |
99 | | gx_device_halftone *pdht = gx_select_dev_ht(penum->pgs); |
100 | | |
101 | | if (!gx_device_must_halftone(penum->dev)) |
102 | | return NULL; |
103 | | |
104 | | if (penum->pgs == NULL || pdht == NULL) |
105 | | return NULL; |
106 | | |
107 | | dda_ht = penum->dda.pixel0.x; |
108 | | if (penum->dxx > 0) |
109 | | dda_translate(dda_ht, -fixed_epsilon); |
110 | | matrix.xx = penum->matrix.xx; |
111 | | matrix.xy = penum->matrix.xy; |
112 | | matrix.yx = penum->matrix.yx; |
113 | | matrix.yy = penum->matrix.yy; |
114 | | matrix.tx = penum->matrix.tx + matrix.xx * penum->rect.x + matrix.yx * penum->rect.y; |
115 | | matrix.ty = penum->matrix.ty + matrix.xy * penum->rect.x + matrix.yy * penum->rect.y; |
116 | | |
117 | | clip_x = fixed2int(penum->clip_outer.p.x); |
118 | | clip_y = fixed2int(penum->clip_outer.p.y); |
119 | | cal_ht = cal_halftone_init(penum->memory->gs_lib_ctx->core->cal_ctx, |
120 | | penum->memory->non_gc_memory, |
121 | | penum->rect.w, |
122 | | penum->rect.h, |
123 | | &matrix, |
124 | | penum->dev->color_info.num_components, |
125 | | cache, |
126 | | clip_x, |
127 | | clip_y, |
128 | | fixed2int_ceiling(penum->clip_outer.q.x) - clip_x, |
129 | | fixed2int_ceiling(penum->clip_outer.q.y) - clip_y, |
130 | | penum->adjust); |
131 | | if (cal_ht == NULL) |
132 | | goto fail; |
133 | | |
134 | | for (k = 0; k < pdht->num_comp; k++) { |
135 | | d_order = &(pdht->components[k].corder); |
136 | | code = gx_ht_construct_threshold(d_order, penum->dev, penum->pgs, k); |
137 | | if (code < 0) |
138 | | goto fail; |
139 | | if (cal_halftone_add_screen(penum->memory->gs_lib_ctx->core->cal_ctx, |
140 | | penum->memory->non_gc_memory, |
141 | | cal_ht, |
142 | | pdht->components[k].corder.threshold_inverted, |
143 | | pdht->components[k].corder.width, |
144 | | pdht->components[k].corder.full_height, |
145 | | penum->pgs->screen_phase[k].x, |
146 | | -penum->pgs->screen_phase[k].y, |
147 | | pdht->components[k].corder.threshold) < 0) |
148 | | goto fail; |
149 | | } |
150 | | |
151 | | return cal_ht; |
152 | | |
153 | | fail: |
154 | | cal_halftone_fin(cal_ht, penum->memory->non_gc_memory); |
155 | | return NULL; |
156 | | } |
157 | | #endif |
158 | | |
159 | | int |
160 | | gs_image_class_3_mono(gx_image_enum * penum, irender_proc_t *render_fn) |
161 | 1.99M | { |
162 | 1.99M | #if USE_FAST_HT_CODE |
163 | 1.99M | bool use_fast_code = true; |
164 | | #else |
165 | | bool use_fast_code = false; |
166 | | #endif |
167 | 1.99M | int code = 0; |
168 | | /* Set up the link now */ |
169 | 1.99M | const gs_color_space *pcs; |
170 | 1.99M | gsicc_rendering_param_t rendering_params; |
171 | 1.99M | cmm_dev_profile_t *dev_profile; |
172 | 1.99M | bool dev_color_ok = false; |
173 | 1.99M | bool is_planar_dev = penum->dev->num_planar_planes; |
174 | | |
175 | 1.99M | if (penum->spp == 1) { |
176 | | /* At this point in time, only use the ht approach if our device |
177 | | uses halftoning, and our source image is a reasonable size. We |
178 | | probably don't want to do this if we have a bunch of tiny little |
179 | | images. Then the rect fill approach is probably not all that bad. |
180 | | Also for now avoid images that include a type3 image mask. Due |
181 | | to the limited precision and mismatch of the stepping space in which |
182 | | the interpolations occur this can cause a minor mismatch at large |
183 | | scalings */ |
184 | | |
185 | | /* Allow this for CMYK planar and mono binary halftoned devices */ |
186 | 705k | dev_color_ok = ((penum->dev->color_info.num_components == 1 && |
187 | 705k | penum->dev->color_info.depth == 1) || |
188 | | #if 0 |
189 | | /* Don't allow CMYK Planar devices just yet */ |
190 | | 0); |
191 | | #else |
192 | 705k | (penum->dev->color_info.num_components == 4 && |
193 | 594k | penum->dev->color_info.depth == 4 && is_planar_dev)); |
194 | 705k | #endif |
195 | | |
196 | 705k | if (use_fast_code && penum->pcs != NULL && dev_color_ok && |
197 | 705k | penum->bps == 8 && (penum->posture == image_portrait |
198 | 85.4k | || penum->posture == image_landscape) && |
199 | 705k | penum->image_parent_type == gs_image_type1 && |
200 | 705k | gx_transfer_is_monotonic(penum->pgs, 0)) { |
201 | 85.4k | penum->icc_setup.need_decode = false; |
202 | | /* Check if we need to do any decoding. */ |
203 | 85.4k | if ( penum->map[0].decoding != sd_none ) { |
204 | 1.77k | if (!(penum->map[0].decoding == sd_compute |
205 | 1.77k | && penum->map[0].decode_factor == 1.0 && |
206 | 1.77k | penum->map[0].decode_lookup[0] == 0.0)) { |
207 | 13 | penum->icc_setup.need_decode = true; |
208 | 13 | } |
209 | 1.77k | } |
210 | 85.4k | code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile); |
211 | 85.4k | if (code < 0) |
212 | 0 | return code; |
213 | | |
214 | | /* Define the rendering intents */ |
215 | 85.4k | rendering_params.black_point_comp = penum->pgs->blackptcomp; |
216 | 85.4k | rendering_params.graphics_type_tag = GS_IMAGE_TAG; |
217 | 85.4k | rendering_params.override_icc = false; |
218 | 85.4k | rendering_params.preserve_black = gsBKPRESNOTSPECIFIED; |
219 | 85.4k | rendering_params.rendering_intent = penum->pgs->renderingintent; |
220 | 85.4k | rendering_params.cmm = gsCMM_DEFAULT; |
221 | 85.4k | if (gs_color_space_get_index(penum->pcs) == |
222 | 85.4k | gs_color_space_index_Indexed) { |
223 | 1.77k | pcs = penum->pcs->base_space; |
224 | 83.6k | } else { |
225 | 83.6k | pcs = penum->pcs; |
226 | 83.6k | } |
227 | 85.4k | if (gs_color_space_is_PSCIE(pcs) && pcs->icc_equivalent != NULL) { |
228 | 0 | pcs = pcs->icc_equivalent; |
229 | 0 | } |
230 | | |
231 | | /* The code below falls over if cmm->icc_profile_data is NULL. |
232 | | * For now, just drop out. Michael can review this when he |
233 | | * returns. */ |
234 | 85.4k | if (pcs->cmm_icc_profile_data == NULL) |
235 | 26 | goto not_fast_halftoning; |
236 | | |
237 | 85.3k | penum->icc_setup.is_lab = pcs->cmm_icc_profile_data->islab; |
238 | 85.3k | penum->icc_setup.must_halftone = gx_device_must_halftone(penum->dev); |
239 | | /* The effective transfer is built into the threshold array */ |
240 | 85.3k | penum->icc_setup.has_transfer = false; |
241 | 85.3k | if (penum->icc_setup.is_lab) |
242 | 34 | penum->icc_setup.need_decode = false; |
243 | 85.3k | if (penum->icc_link == NULL) { |
244 | 85.3k | penum->icc_link = gsicc_get_link(penum->pgs, penum->dev, pcs, NULL, |
245 | 85.3k | &rendering_params, penum->memory); |
246 | 85.3k | } |
247 | | /* PS CIE color spaces may have addition decoding that needs to |
248 | | be performed to ensure that the range of 0 to 1 is provided |
249 | | to the CMM since ICC profiles are restricted to that range |
250 | | but the PS color spaces are not. */ |
251 | 85.3k | penum->use_cie_range = false; |
252 | 85.3k | if (gs_color_space_is_PSCIE(penum->pcs) && |
253 | 85.3k | penum->pcs->icc_equivalent != NULL) { |
254 | | /* We have a PS CIE space. Check the range */ |
255 | 0 | if ( !check_cie_range(penum->pcs) ) { |
256 | | /* It is not 0 to 1. We will be doing decode |
257 | | plus an additional linear adjustment */ |
258 | 0 | penum->use_cie_range = (get_cie_range(penum->pcs) != NULL); |
259 | 0 | } |
260 | 0 | } |
261 | | /* If the image has more than 256 pixels then go ahead and |
262 | | precompute the contone device colors for all of our 256 source |
263 | | values. We should not be taking this path for cases where |
264 | | we have lots of tiny little images. Mark those that are |
265 | | transparent or masked also at this time. Since halftoning will |
266 | | be done via thresholding we will keep clues in continuous tone */ |
267 | 85.3k | code = image_init_color_cache(penum, penum->bps, penum->spp); |
268 | 85.3k | if (code >= 0) { |
269 | | #ifdef WITH_CAL |
270 | | penum->cal_ht = halftone_init(penum); |
271 | | if (penum->cal_ht != NULL) |
272 | | { |
273 | | penum->skip_next_line = image_render_mono_ht_cal_skip_line; |
274 | | *render_fn = &image_render_mono_ht_cal; |
275 | | return code; |
276 | | } |
277 | | #else |
278 | 85.3k | code = gxht_thresh_image_init(penum); |
279 | 85.3k | if (code >= 0) { |
280 | 85.3k | *render_fn = &image_render_mono_ht; |
281 | 85.3k | return code; |
282 | 85.3k | } |
283 | 85.3k | #endif |
284 | 85.3k | } |
285 | 85.3k | } |
286 | 620k | not_fast_halftoning: |
287 | | /* |
288 | | * Use the slow loop for imagemask with a halftone or a non-default |
289 | | * logical operation. |
290 | | */ |
291 | 620k | penum->slow_loop = |
292 | 620k | (penum->masked && !color_is_pure(penum->icolor0)) || |
293 | 620k | penum->use_rop; |
294 | | /* We can bypass X clipping for portrait mono-component images. */ |
295 | 620k | if (!(penum->slow_loop || penum->posture != image_portrait)) |
296 | 504k | penum->clip_image &= ~(image_clip_xmin | image_clip_xmax); |
297 | 620k | if_debug0m('b', penum->memory, "[b]render=mono\n"); |
298 | | /* Precompute values needed for rasterizing. */ |
299 | 620k | penum->dxx = |
300 | 620k | float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2); |
301 | | /* |
302 | | * Scale the mask colors to match the scaling of each sample to a |
303 | | * full byte. Also, if black or white is transparent, reset icolor0 |
304 | | * or icolor1, which are used directly in the fast case loop. |
305 | | */ |
306 | 620k | if (penum->use_mask_color) { |
307 | 11 | gx_image_scale_mask_colors(penum, 0); |
308 | 11 | if (penum->mask_color.values[0] <= 0) |
309 | 0 | color_set_null(penum->icolor0); |
310 | 11 | if (penum->mask_color.values[1] >= 255) |
311 | 0 | color_set_null(penum->icolor1); |
312 | 11 | } |
313 | | /* Reset the clues here, rather than in image_render_mono as |
314 | | * previously. Even doing so this often may be overzealous. */ |
315 | 620k | image_init_clues(penum, penum->bps, penum->spp); |
316 | 620k | *render_fn = &image_render_mono; |
317 | 620k | } |
318 | 1.90M | return 0; |
319 | 1.99M | } |
320 | | |
321 | | #define USE_SET_GRAY_FUNCTION 0 |
322 | | #if USE_SET_GRAY_FUNCTION |
323 | | /* Temporary function to make it easier to debug the uber-macro below */ |
324 | | static inline int |
325 | | image_set_gray(byte sample_value, const bool masked, uint mask_base, |
326 | | uint mask_limit, gx_device_color **ppdevc, gs_client_color *cc, |
327 | | const gs_color_space *pcs, const gs_gstate *pgs, |
328 | | gx_device * dev, gs_color_select_t gs_color_select_source, |
329 | | gx_image_enum * penum) |
330 | | { |
331 | | cs_proc_remap_color((*remap_color)); |
332 | | int code; |
333 | | gx_device_color *pdevc; |
334 | | pdevc = *ppdevc = &penum->clues[sample_value].dev_color; |
335 | | |
336 | | if (!color_is_set(pdevc)) { |
337 | | if ((uint)(sample_value - mask_base) < mask_limit) { |
338 | | color_set_null(pdevc); |
339 | | } else { |
340 | | switch ( penum->map[0].decoding ) |
341 | | { |
342 | | case sd_none: |
343 | | cc->paint.values[0] = (sample_value) * (1.0f / 255.0f); /* faster than / */ |
344 | | break; |
345 | | case sd_lookup: /* <= 4 significant bits */ |
346 | | cc->paint.values[0] = |
347 | | penum->map[0].decode_lookup[(sample_value) >> 4]; |
348 | | break; |
349 | | case sd_compute: |
350 | | cc->paint.values[0] = |
351 | | penum->map[0].decode_base + (sample_value) * penum->map[0].decode_factor; |
352 | | } |
353 | | remap_color = pcs->type->remap_color; |
354 | | code = (*remap_color)(cc, pcs, pdevc, pgs, dev, gs_color_select_source); |
355 | | return(code); |
356 | | } |
357 | | } else if (!color_is_pure(pdevc)) { |
358 | | code = gx_color_load_select(pdevc, pgs, dev, gs_color_select_source); |
359 | | if (code < 0) |
360 | | return(code); |
361 | | } |
362 | | return(0); |
363 | | } |
364 | | #endif |
365 | | |
366 | | /* |
367 | | * Rendering procedure for general mono-component images, dealing with |
368 | | * multiple bit-per-sample images, general transformations, arbitrary |
369 | | * single-component color spaces (DeviceGray, DevicePixel, CIEBasedA, |
370 | | * Separation, Indexed), and color masking. This procedure handles a |
371 | | * single scan line. |
372 | | */ |
373 | | static int |
374 | | image_render_mono(gx_image_enum * penum, const byte * buffer, int data_x, |
375 | | uint w, int h, gx_device * dev) |
376 | 10.0M | { |
377 | 10.0M | const gs_gstate *pgs = penum->pgs; |
378 | 10.0M | gs_logical_operation_t lop = penum->log_op; |
379 | 10.0M | const bool masked = penum->masked; |
380 | 10.0M | const gs_color_space *pcs = NULL; /* only set for non-masks */ |
381 | 10.0M | cs_proc_remap_color((*remap_color)) = NULL; /* ditto */ |
382 | 10.0M | gs_client_color cc; |
383 | 10.0M | gx_device_color *pdevc = penum->icolor1; /* color for masking */ |
384 | 10.0M | uint mask_base = /* : 0 to pacify Valgrind */ |
385 | 10.0M | (penum->use_mask_color ? penum->mask_color.values[0] : 0); |
386 | 10.0M | uint mask_limit = |
387 | 10.0M | (penum->use_mask_color ? |
388 | 10.0M | penum->mask_color.values[1] - mask_base + 1 : 0); |
389 | | /* |
390 | | * Free variables of IMAGE_SET_GRAY: |
391 | | * Read: penum, pgs, dev, mask_base, mask_limit |
392 | | * Set: pdevc, code, cc |
393 | | */ |
394 | 10.0M | #define IMAGE_SET_GRAY(sample_value)\ |
395 | 106M | BEGIN\ |
396 | 106M | pdevc = &penum->clues[sample_value].dev_color;\ |
397 | 106M | if (!color_is_set(pdevc)) {\ |
398 | 11.0M | if ((uint)(sample_value - mask_base) < mask_limit)\ |
399 | 11.0M | color_set_null(pdevc);\ |
400 | 11.0M | else {\ |
401 | 11.0M | decode_sample(sample_value, cc, 0);\ |
402 | 11.0M | code = (*remap_color)(&cc, pcs, pdevc, pgs, dev, gs_color_select_source);\ |
403 | 11.0M | if (code < 0)\ |
404 | 11.0M | goto err;\ |
405 | 11.0M | pdevc->tag = device_current_tag(dev);\ |
406 | 11.0M | }\ |
407 | 91.2M | } else if (!color_is_pure(pdevc)) {\ |
408 | 21.7M | code = gx_color_load_select(pdevc, pgs, dev, gs_color_select_source);\ |
409 | 21.7M | if (code < 0)\ |
410 | 21.7M | goto err;\ |
411 | 21.7M | }\ |
412 | 106M | END |
413 | 10.0M | gx_dda_fixed_point next; /* (y not used in fast loop) */ |
414 | 10.0M | gx_dda_step_fixed dxx2, dxx3, dxx4; /* (not used in all loops) */ |
415 | 10.0M | const byte *psrc_initial = buffer + data_x; |
416 | 10.0M | const byte *psrc = psrc_initial; |
417 | 10.0M | const byte *rsrc = psrc; /* psrc at start of run */ |
418 | 10.0M | const byte *endp = psrc + w; |
419 | 10.0M | const byte *stop = endp; |
420 | 10.0M | fixed xrun; /* x at start of run */ |
421 | 10.0M | byte run; /* run value */ |
422 | 10.0M | int htrun = (masked ? 255 : -2); /* halftone run value */ |
423 | 10.0M | int i, code = 0; |
424 | | |
425 | 10.0M | if (h == 0) |
426 | 1.23M | return 0; |
427 | | /* |
428 | | * Make sure the cache setup matches the graphics state. Also determine |
429 | | * whether all tiles fit in the cache. We may bypass the latter check |
430 | | * for masked images with a pure color. |
431 | | */ |
432 | | |
433 | 8.82M | next = penum->dda.pixel0; |
434 | 8.82M | xrun = dda_current(next.x); |
435 | 8.82M | if (!masked) { |
436 | 4.46M | pcs = penum->pcs; /* (may not be set for masks) */ |
437 | 4.46M | remap_color = pcs->type->remap_color; |
438 | 4.46M | } |
439 | 8.82M | run = *psrc; |
440 | | /* Find the last transition in the input. */ |
441 | 8.82M | if (masked && |
442 | 8.82M | (penum->posture != image_portrait) && |
443 | 8.82M | (penum->posture != image_landscape)) { |
444 | | /* No need to calculate stop */ |
445 | 4.48M | } else { |
446 | 4.48M | byte last = stop[-1]; |
447 | | |
448 | 857M | while (stop > psrc && stop[-1] == last) |
449 | 852M | --stop; |
450 | 4.48M | } |
451 | 8.82M | if (penum->slow_loop || penum->posture != image_portrait) { |
452 | | |
453 | | /************************************************************** |
454 | | * Slow case (skewed, rotated, or imagemask with a halftone). * |
455 | | **************************************************************/ |
456 | | |
457 | 4.36M | fixed yrun; |
458 | 4.36M | const fixed pdyx = dda_current(penum->dda.row.x) - penum->cur.x; |
459 | 4.36M | const fixed pdyy = dda_current(penum->dda.row.y) - penum->cur.y; |
460 | 4.36M | dev_proc_fill_parallelogram((*fill_pgram)) = |
461 | 4.36M | dev_proc(dev, fill_parallelogram); |
462 | | |
463 | 190M | #define xl dda_current(next.x) |
464 | 195M | #define ytf dda_current(next.y) |
465 | 4.36M | yrun = ytf; |
466 | 4.36M | if (masked) { |
467 | | |
468 | | /********************** |
469 | | * Slow case, masked. * |
470 | | **********************/ |
471 | | |
472 | 4.34M | pdevc = penum->icolor1; |
473 | 4.34M | code = gx_color_load(pdevc, pgs, dev); |
474 | 4.34M | if (code < 0) |
475 | 0 | return code; |
476 | 4.34M | if ((stop <= psrc) && (penum->adjust == 0) && |
477 | 4.34M | ((penum->posture == image_portrait) || |
478 | 0 | (penum->posture == image_landscape))) |
479 | 0 | goto last; |
480 | 4.34M | if (penum->posture == image_portrait) { |
481 | | |
482 | | /******************************** |
483 | | * Slow case, masked, portrait. * |
484 | | ********************************/ |
485 | | |
486 | | /* |
487 | | * We don't have to worry about the Y DDA, and the fill |
488 | | * regions are rectangles. Calculate multiples of the DDA |
489 | | * step. |
490 | | */ |
491 | 0 | fixed ax = |
492 | 0 | (penum->matrix.xx < 0 ? -penum->adjust : penum->adjust); |
493 | 0 | fixed ay = |
494 | 0 | (pdyy < 0 ? -penum->adjust : penum->adjust); |
495 | 0 | fixed dyy = pdyy + (ay << 1); |
496 | |
|
497 | 0 | yrun -= ay; |
498 | 0 | dda_translate(next.x, -ax); |
499 | 0 | ax <<= 1; |
500 | 0 | dxx2 = next.x.step; |
501 | 0 | dda_step_add(dxx2, next.x.step); |
502 | 0 | dxx3 = dxx2; |
503 | 0 | dda_step_add(dxx3, next.x.step); |
504 | 0 | dxx4 = dxx3; |
505 | 0 | dda_step_add(dxx4, next.x.step); |
506 | 0 | for (;;) { /* Skip a run of zeros. */ |
507 | 0 | while (!psrc[0]) |
508 | 0 | if (psrc + 4 <= endp) { |
509 | | /* We can use fast skipping */ |
510 | 0 | if (!psrc[1]) { |
511 | 0 | if (!psrc[2]) { |
512 | 0 | if (!psrc[3]) { |
513 | 0 | psrc += 4; |
514 | 0 | dda_state_next(next.x.state, dxx4); |
515 | 0 | if (psrc >= endp) |
516 | 0 | break; |
517 | 0 | continue; |
518 | 0 | } |
519 | 0 | psrc += 3; |
520 | 0 | dda_state_next(next.x.state, dxx3); |
521 | 0 | break; |
522 | 0 | } |
523 | 0 | psrc += 2; |
524 | 0 | dda_state_next(next.x.state, dxx2); |
525 | 0 | break; |
526 | 0 | } else { |
527 | 0 | ++psrc; |
528 | 0 | dda_next(next.x); |
529 | 0 | break; |
530 | 0 | } |
531 | 0 | } else { |
532 | | /* We're too close to the end - skip 1 at a time */ |
533 | 0 | while (!psrc[0]) { |
534 | 0 | ++psrc; |
535 | 0 | dda_next(next.x); |
536 | 0 | if (psrc >= endp) |
537 | 0 | break; |
538 | 0 | } |
539 | 0 | if (psrc >= endp) |
540 | 0 | break; |
541 | 0 | } |
542 | 0 | xrun = xl; |
543 | 0 | if (psrc >= stop) |
544 | 0 | break; |
545 | 0 | for (; psrc < endp && *psrc; ++psrc) |
546 | 0 | dda_next(next.x); |
547 | 0 | code = (*fill_pgram)(dev, xrun, yrun, |
548 | 0 | xl - xrun + ax, fixed_0, fixed_0, dyy, |
549 | 0 | pdevc, lop); |
550 | 0 | if (code < 0) |
551 | 0 | goto err; |
552 | 0 | rsrc = psrc; |
553 | 0 | if (psrc >= stop) |
554 | 0 | break; |
555 | 0 | } |
556 | |
|
557 | 4.34M | } else if (penum->posture == image_landscape) { |
558 | | |
559 | | /********************************* |
560 | | * Slow case, masked, landscape. * |
561 | | *********************************/ |
562 | | |
563 | | /* |
564 | | * We don't have to worry about the X DDA. However, we do |
565 | | * have to take adjustment into account. We don't bother to |
566 | | * optimize this as heavily as the portrait case. |
567 | | */ |
568 | 2 | fixed ax = |
569 | 2 | (pdyx < 0 ? -penum->adjust : penum->adjust); |
570 | 2 | fixed dyx = pdyx + (ax << 1); |
571 | 2 | fixed ay = |
572 | 2 | (penum->matrix.xy < 0 ? -penum->adjust : penum->adjust); |
573 | | |
574 | 2 | xrun -= ax; |
575 | 2 | dda_translate(next.y, -ay); |
576 | 2 | ay <<= 1; |
577 | 3 | for (;;) { |
578 | 41 | for (; psrc < endp && !*psrc; ++psrc) |
579 | 38 | dda_next(next.y); |
580 | 3 | yrun = ytf; |
581 | 3 | if (psrc >= stop) |
582 | 1 | break; |
583 | 14 | for (; psrc < endp && *psrc; ++psrc) |
584 | 12 | dda_next(next.y); |
585 | 2 | code = (*fill_pgram)(dev, xrun, yrun, fixed_0, |
586 | 2 | ytf - yrun + ay, dyx, fixed_0, |
587 | 2 | pdevc, lop); |
588 | 2 | if (code < 0) |
589 | 0 | goto err; |
590 | 2 | rsrc = psrc; |
591 | 2 | if (psrc >= stop) |
592 | 1 | break; |
593 | 2 | } |
594 | | |
595 | 4.34M | } else { |
596 | | |
597 | | /************************************** |
598 | | * Slow case, masked, not orthogonal. * |
599 | | **************************************/ |
600 | | /* FIXME: RJW: This code doesn't do adjustment. Should it? |
601 | | * In the grand scheme of things it almost certainly doesn't |
602 | | * matter (as adjust should only be used when plotting chars, |
603 | | * and we use freetype now), but we record the fact that this |
604 | | * may be a defect here. */ |
605 | | /* Previous code here used to skip blocks of matching pixels |
606 | | * and plot them all in one go. We can't do that, as it can |
607 | | * cause rounding errors and mismatches with the image pixels |
608 | | * that will be plotted after us. */ |
609 | 4.34M | stop = endp; |
610 | 19.9M | for (;;) { |
611 | | /* skip forward until we find a 1 bit */ |
612 | 140M | for (; psrc < stop && !*psrc; ++psrc) { |
613 | 120M | dda_next(next.x); |
614 | 120M | dda_next(next.y); |
615 | 120M | } |
616 | 19.9M | if (psrc >= endp) /* Note, endp NOT stop! */ |
617 | 4.34M | break; |
618 | | /* Then draw the pgram and step forward until we find a |
619 | | * 0 bit. */ |
620 | 62.1M | do { |
621 | 62.1M | yrun = ytf; |
622 | 62.1M | xrun = xl; |
623 | 62.1M | dda_next(next.x); |
624 | 62.1M | dda_next(next.y); |
625 | 62.1M | code = (*fill_pgram)(dev, xrun, yrun, xl - xrun, |
626 | 62.1M | ytf - yrun, pdyx, pdyy, pdevc, lop); |
627 | 62.1M | if (code < 0) |
628 | 0 | goto err; |
629 | 62.1M | psrc++; |
630 | 62.1M | rsrc = psrc; |
631 | 62.1M | if (psrc >= stop) |
632 | 1.59M | break; |
633 | 62.1M | } while (*psrc); |
634 | 15.5M | } |
635 | | |
636 | 4.34M | } |
637 | | |
638 | 4.34M | } else if (penum->posture == image_portrait) { |
639 | | /************************************** |
640 | | * Slow case, not masked, portrait. * |
641 | | **************************************/ |
642 | 0 | dev_proc_fill_rectangle((*fill_proc)) = |
643 | 0 | dev_proc(dev, fill_rectangle); |
644 | 0 | int iy = fixed2int_pixround(yrun); |
645 | 0 | int ih = fixed2int_pixround(yrun + pdyy) - iy; |
646 | 0 | if (ih < 0) |
647 | 0 | iy += ih, ih = -ih; |
648 | | |
649 | | /* In this case, we can fill runs quickly. */ |
650 | | /****** DOESN'T DO ADJUSTMENT ******/ |
651 | 0 | if (stop <= psrc) |
652 | 0 | goto last; |
653 | 0 | for (;;) { |
654 | 0 | byte c = *psrc++; |
655 | 0 | if (c != run) { |
656 | 0 | int ix = fixed2int_pixround(xrun); |
657 | 0 | int iw = fixed2int_pixround(xl) - ix; |
658 | 0 | if (iw < 0) |
659 | 0 | ix += iw, iw = -iw; |
660 | 0 | switch (run) |
661 | 0 | { |
662 | 0 | case 0: |
663 | 0 | if (!color_is_pure(penum->icolor0)) |
664 | 0 | goto ht_port; |
665 | 0 | code = (*fill_proc) (dev, ix, iy, iw, ih, |
666 | 0 | penum->icolor0->colors.pure); |
667 | 0 | break; |
668 | 0 | case 0xff: |
669 | 0 | if (!color_is_pure(penum->icolor1)) |
670 | 0 | goto ht_port; |
671 | 0 | code = (*fill_proc) (dev, ix, iy, iw, ih, |
672 | 0 | penum->icolor1->colors.pure); |
673 | 0 | break; |
674 | 0 | default: |
675 | 0 | ht_port: |
676 | 0 | if (run != htrun) { |
677 | 0 | htrun = run; |
678 | | #if USE_SET_GRAY_FUNCTION |
679 | | code = image_set_gray(run,masked,mask_base,mask_limit,&pdevc, |
680 | | &cc,pcs,pgs,dev,gs_color_select_source,penum); |
681 | | if (code < 0) |
682 | | goto err; |
683 | | #else |
684 | 0 | IMAGE_SET_GRAY(run); |
685 | 0 | #endif |
686 | 0 | } |
687 | 0 | code = gx_fill_rectangle_device_rop(ix, iy, iw, ih, |
688 | 0 | pdevc, dev, lop); |
689 | 0 | } |
690 | 0 | if (code < 0) |
691 | 0 | goto err; |
692 | 0 | xrun = xl; |
693 | 0 | rsrc = psrc; |
694 | 0 | if (psrc > stop) |
695 | 0 | break; |
696 | 0 | run = c; |
697 | 0 | } |
698 | 0 | dda_next(next.x); |
699 | 0 | if (psrc >= endp) |
700 | 0 | break; |
701 | 0 | } |
702 | 24.2k | } else if (penum->posture == image_landscape) { |
703 | | |
704 | | /************************************** |
705 | | * Slow case, not masked, landscape. * |
706 | | **************************************/ |
707 | 540 | dev_proc_fill_rectangle((*fill_proc)) = |
708 | 540 | dev_proc(dev, fill_rectangle); |
709 | 540 | int ix = fixed2int_pixround(xrun); |
710 | 540 | int iw = fixed2int_pixround(xrun + pdyx) - ix; |
711 | 540 | if (iw < 0) |
712 | 207 | ix += iw, iw = -iw; |
713 | | |
714 | | /* In this case, we can fill runs quickly. */ |
715 | | /****** DOESN'T DO ADJUSTMENT ******/ |
716 | 540 | if (stop <= psrc) |
717 | 9 | goto last; |
718 | 43.1k | for (;;) { |
719 | 43.1k | byte c = *psrc++; |
720 | 43.1k | if (c != run) { |
721 | 34.9k | int iy = fixed2int_pixround(yrun); |
722 | 34.9k | int ih = fixed2int_pixround(ytf) - iy; |
723 | 34.9k | if (ih < 0) |
724 | 13.1k | iy += ih, ih = -ih; |
725 | 34.9k | switch (run) |
726 | 34.9k | { |
727 | 196 | case 0: |
728 | 196 | if (!color_is_pure(penum->icolor0)) |
729 | 154 | goto ht_land; |
730 | 42 | code = (*fill_proc) (dev, ix, iy, iw, ih, |
731 | 42 | penum->icolor0->colors.pure); |
732 | 42 | break; |
733 | 47 | case 0xff: |
734 | 47 | if (!color_is_pure(penum->icolor1)) |
735 | 6 | goto ht_land; |
736 | 41 | code = (*fill_proc) (dev, ix, iy, iw, ih, |
737 | 41 | penum->icolor1->colors.pure); |
738 | 41 | break; |
739 | 34.6k | default: |
740 | 34.8k | ht_land: |
741 | 34.8k | if (run != htrun) { |
742 | 34.7k | htrun = run; |
743 | | #if USE_SET_GRAY_FUNCTION |
744 | | code = image_set_gray(run,masked,mask_base,mask_limit,&pdevc, |
745 | | &cc,pcs,pgs,dev,gs_color_select_source,penum); |
746 | | if (code < 0) |
747 | | goto err; |
748 | | #else |
749 | 34.7k | IMAGE_SET_GRAY(run); |
750 | 34.7k | #endif |
751 | 34.7k | } |
752 | 34.8k | code = gx_fill_rectangle_device_rop(ix, iy, iw, ih, |
753 | 34.9k | pdevc, dev, lop); |
754 | 34.9k | } |
755 | 34.9k | if (code < 0) |
756 | 0 | goto err; |
757 | 34.9k | yrun = ytf; |
758 | 34.9k | rsrc = psrc; |
759 | 34.9k | if (psrc > stop) |
760 | 531 | break; |
761 | 34.3k | run = c; |
762 | 34.3k | } |
763 | 42.5k | dda_next(next.y); |
764 | 42.5k | if (psrc >= endp) |
765 | 0 | break; |
766 | 42.5k | } |
767 | 23.7k | } else { |
768 | | |
769 | | /****************************************** |
770 | | * Slow case, not masked, not orthogonal. * |
771 | | ******************************************/ |
772 | | |
773 | | /* |
774 | | * Since we have to check for the end after every pixel |
775 | | * anyway, we may as well avoid the last-run code. |
776 | | */ |
777 | 23.7k | stop = endp; |
778 | 33.1M | for (;;) { |
779 | | /* We can't skip large constant regions quickly, */ |
780 | | /* because this leads to rounding errors. */ |
781 | | /* Just fill the region between xrun and xl. */ |
782 | 33.1M | if (run != htrun) { |
783 | 336k | htrun = run; |
784 | | #if USE_SET_GRAY_FUNCTION |
785 | | code = image_set_gray(run,masked,mask_base,mask_limit,&pdevc, |
786 | | &cc,pcs,pgs,dev,gs_color_select_source,penum); |
787 | | if (code < 0) |
788 | | goto err; |
789 | | #else |
790 | 336k | IMAGE_SET_GRAY(run); |
791 | 336k | #endif |
792 | 336k | } |
793 | 33.1M | code = (*fill_pgram) (dev, xrun, yrun, xl - xrun, |
794 | 33.1M | ytf - yrun, pdyx, pdyy, pdevc, lop); |
795 | 33.1M | if (code < 0) |
796 | 0 | goto err; |
797 | 33.1M | yrun = ytf; |
798 | 33.1M | xrun = xl; |
799 | 33.1M | rsrc = psrc; |
800 | 33.1M | if (psrc >= stop) |
801 | 23.7k | break; |
802 | 33.1M | run = *psrc++; |
803 | 33.1M | dda_next(next.x); |
804 | 33.1M | dda_next(next.y); /* harmless if no skew */ |
805 | 33.1M | } |
806 | | |
807 | 23.7k | } |
808 | | /* Fill the last run. */ |
809 | 4.36M | last:if (stop < endp && (*stop || !masked)) { |
810 | 541 | if (!masked) { |
811 | | #if USE_SET_GRAY_FUNCTION |
812 | | code = image_set_gray(*stop, masked,mask_base,mask_limit,&pdevc, |
813 | | &cc,pcs,pgs,dev,gs_color_select_source,penum); |
814 | | if (code < 0) |
815 | | goto err; |
816 | | #else |
817 | 540 | IMAGE_SET_GRAY(*stop); |
818 | 540 | #endif |
819 | 540 | } |
820 | 541 | dda_advance(next.x, endp - stop); |
821 | 541 | dda_advance(next.y, endp - stop); |
822 | 541 | code = (*fill_pgram) (dev, xrun, yrun, xl - xrun, |
823 | 541 | ytf - yrun, pdyx, pdyy, pdevc, lop); |
824 | 541 | } |
825 | 4.36M | #undef xl |
826 | 4.36M | #undef ytf |
827 | | |
828 | 4.46M | } else { |
829 | | |
830 | | /********************************************************** |
831 | | * Fast case: no skew, and not imagemask with a halftone. * |
832 | | **********************************************************/ |
833 | | |
834 | 4.46M | const fixed adjust = penum->adjust; |
835 | 4.46M | const fixed dxx = penum->dxx; |
836 | 4.46M | fixed xa = (dxx >= 0 ? adjust : -adjust); |
837 | 4.46M | const int yt = penum->yci, iht = penum->hci; |
838 | | |
839 | 4.46M | dev_proc_fill_rectangle((*fill_proc)) = |
840 | 4.46M | dev_proc(dev, fill_rectangle); |
841 | 4.46M | int xmin = fixed2int_pixround(penum->clip_outer.p.x); |
842 | 4.46M | int xmax = fixed2int_pixround(penum->clip_outer.q.x); |
843 | 187M | #define xl dda_current(next.x) |
844 | | |
845 | 4.46M | if_debug2m('b', penum->memory, "[b]image y=%d dda.y.Q=%lg\n", |
846 | 4.46M | penum->y + penum->rect.y, penum->dda.row.y.state.Q / 256.); |
847 | | /* Fold the adjustment into xrun and xl, */ |
848 | | /* including the +0.5-epsilon for rounding. */ |
849 | 4.46M | xrun = xrun - xa + (fixed_half - fixed_epsilon); |
850 | 4.46M | dda_translate(next.x, xa + (fixed_half - fixed_epsilon)); |
851 | 4.46M | xa <<= 1; |
852 | | /* Calculate multiples of the DDA step. */ |
853 | 4.46M | dxx2 = next.x.step; |
854 | 4.46M | dda_step_add(dxx2, next.x.step); |
855 | 4.46M | dxx3 = dxx2; |
856 | 4.46M | dda_step_add(dxx3, next.x.step); |
857 | 4.46M | dxx4 = dxx3; |
858 | 4.46M | dda_step_add(dxx4, next.x.step); |
859 | 4.46M | if (stop > psrc) |
860 | 187M | for (;;) { /* Skip large constant regions quickly, */ |
861 | | /* but don't slow down transitions too much. */ |
862 | 429M | skf:if (psrc[0] == run) { |
863 | 323M | if (psrc[1] == run) { |
864 | 282M | if (psrc[2] == run) { |
865 | 257M | if (psrc[3] == run) { |
866 | 241M | psrc += 4; |
867 | 241M | dda_state_next(next.x.state, dxx4); |
868 | 241M | if (psrc >= endp) |
869 | 0 | break; |
870 | 241M | goto skf; |
871 | 241M | } else { |
872 | 15.2M | psrc += 4; |
873 | 15.2M | dda_state_next(next.x.state, dxx3); |
874 | 15.2M | } |
875 | 257M | } else { |
876 | 25.4M | psrc += 3; |
877 | 25.4M | dda_state_next(next.x.state, dxx2); |
878 | 25.4M | } |
879 | 282M | } else { |
880 | 40.8M | psrc += 2; |
881 | 40.8M | dda_next(next.x); |
882 | 40.8M | } |
883 | 323M | } else |
884 | 105M | psrc++; |
885 | 187M | { /* Now fill the region between xrun and xl. */ |
886 | 187M | int xi = fixed2int_var(xrun); |
887 | 187M | int wi = fixed2int_var(xl) - xi; |
888 | 187M | int xei; |
889 | | |
890 | 187M | if (wi <= 0) { |
891 | 7.74M | if (wi == 0) |
892 | 7.67M | goto mt; |
893 | 69.2k | xi += wi, wi = -wi; |
894 | 69.2k | } |
895 | 179M | if ((xei = xi + wi) > xmax || xi < xmin) { /* Do X clipping */ |
896 | 121k | if (xi < xmin) |
897 | 57.8k | wi -= xmin - xi, xi = xmin; |
898 | 121k | if (xei > xmax) |
899 | 64.9k | wi -= xei - xmax; |
900 | 121k | if (wi <= 0) |
901 | 91.7k | goto mt; |
902 | 121k | } |
903 | 179M | switch (run) { |
904 | 39.3M | case 0: |
905 | 39.3M | if (masked) |
906 | 7.02k | goto mt; |
907 | 39.3M | if (!color_is_pure(penum->icolor0)) |
908 | 497k | goto ht; |
909 | 38.8M | code = (*fill_proc) (dev, xi, yt, wi, iht, |
910 | 38.8M | penum->icolor0->colors.pure); |
911 | 38.8M | break; |
912 | 40.2M | case 255: /* just for speed */ |
913 | 40.2M | if (!color_is_pure(penum->icolor1)) |
914 | 686k | goto ht; |
915 | 39.5M | code = (*fill_proc) (dev, xi, yt, wi, iht, |
916 | 39.5M | penum->icolor1->colors.pure); |
917 | 39.5M | break; |
918 | 100M | default: |
919 | 101M | ht: /* Use halftone if needed */ |
920 | 101M | if (run != htrun) { |
921 | | #if USE_SET_GRAY_FUNCTION |
922 | | code = image_set_gray(run, masked,mask_base,mask_limit,&pdevc, |
923 | | &cc,pcs,pgs,dev,gs_color_select_source,penum); |
924 | | if (code < 0) |
925 | | goto err; |
926 | | #else |
927 | 97.4M | IMAGE_SET_GRAY(run); |
928 | 97.4M | #endif |
929 | 97.4M | htrun = run; |
930 | 97.4M | } |
931 | 101M | code = gx_fill_rectangle_device_rop(xi, yt, wi, iht, |
932 | 179M | pdevc, dev, lop); |
933 | 179M | } |
934 | 179M | if (code < 0) |
935 | 0 | goto err; |
936 | 187M | mt:xrun = xl - xa; /* original xa << 1 */ |
937 | 187M | rsrc = psrc - 1; |
938 | 187M | if (psrc > stop) { |
939 | 2.54M | --psrc; |
940 | 2.54M | break; |
941 | 2.54M | } |
942 | 184M | run = psrc[-1]; |
943 | 184M | } |
944 | 184M | dda_next(next.x); |
945 | 184M | } |
946 | | /* Fill the last run. */ |
947 | 4.46M | if (*stop != 0 || !masked) { |
948 | 4.44M | int xi = fixed2int_var(xrun); |
949 | 4.44M | int wi, xei; |
950 | | |
951 | 4.44M | dda_advance(next.x, endp - stop); |
952 | 4.44M | wi = fixed2int_var(xl) - xi; |
953 | 4.44M | if (wi <= 0) { |
954 | 20.0k | if (wi == 0) |
955 | 2.79k | goto lmt; |
956 | 17.2k | xi += wi, wi = -wi; |
957 | 17.2k | } |
958 | 4.44M | if ((xei = xi + wi) > xmax || xi < xmin) { /* Do X clipping */ |
959 | 201k | if (xi < xmin) |
960 | 10.8k | wi -= xmin - xi, xi = xmin; |
961 | 201k | if (xei > xmax) |
962 | 191k | wi -= xei - xmax; |
963 | 201k | if (wi <= 0) |
964 | 22.5k | goto lmt; |
965 | 201k | } |
966 | | #if USE_SET_GRAY_FUNCTION |
967 | | code = image_set_gray(*stop, masked,mask_base,mask_limit,&pdevc, |
968 | | &cc,pcs,pgs,dev,gs_color_select_source,penum); |
969 | | if (code < 0) |
970 | | goto err; |
971 | | #else |
972 | 4.44M | IMAGE_SET_GRAY(*stop); |
973 | 4.41M | #endif |
974 | 4.41M | code = gx_fill_rectangle_device_rop(xi, yt, wi, iht, |
975 | 4.41M | pdevc, dev, lop); |
976 | 4.44M | lmt:; |
977 | 4.44M | } |
978 | | |
979 | 4.46M | } |
980 | 8.82M | #undef xl |
981 | 8.82M | if (code >= 0) { |
982 | 8.82M | code = 1; |
983 | 8.82M | goto done; |
984 | 8.82M | } |
985 | | /* Save position if error, in case we resume. */ |
986 | 0 | err: |
987 | 0 | penum->used.x = rsrc - psrc_initial; |
988 | 0 | penum->used.y = 0; |
989 | 8.82M | done: |
990 | | /* Since dev_color.binary.b_tile is just a pointer to an entry in the halftone tile "cache" |
991 | | we cannot leave it set in case the interpeter changes the halftone |
992 | | (whilst it shouldn't do it, it is possible for Postscript image data source |
993 | | procedure to execute setcreen or similar). This also doesn't really adversely |
994 | | affect performance, as we'll call gx_color_load_select() for all the samples |
995 | | from the next buffer, which will NULL the b_tile pointer anyway (it only gets |
996 | | set when we actually try to draw with it. |
997 | | */ |
998 | 2.26G | for (i = 0; i < 256; i++) { |
999 | 2.26G | penum->clues[i].dev_color.colors.binary.b_tile = NULL; |
1000 | 2.26G | } |
1001 | 8.82M | return code; |
1002 | 0 | } |
1003 | | |
1004 | | #ifdef WITH_CAL |
1005 | | static int |
1006 | | image_render_mono_ht_cal_skip_line(gx_image_enum *penum, |
1007 | | gx_device *dev) |
1008 | | { |
1009 | | return !cal_halftone_next_line_required(penum->cal_ht); |
1010 | | } |
1011 | | |
1012 | | static int |
1013 | | image_render_mono_ht_cal(gx_image_enum * penum, const byte * buffer, int data_x, |
1014 | | uint w, int h, gx_device * dev) |
1015 | | { |
1016 | | const byte *input = buffer + data_x; |
1017 | | |
1018 | | if (buffer == NULL) |
1019 | | return 0; |
1020 | | |
1021 | | return cal_halftone_process_planar(penum->cal_ht, penum->memory->non_gc_memory, |
1022 | | (const byte * const *)&input, halftone_callback, dev); |
1023 | | } |
1024 | | #else |
1025 | | /* |
1026 | | An image render case where the source color is monochrome or indexed and |
1027 | | the output is to be halftoned. If the source color requires decoding, |
1028 | | an index look-up or ICC color managment, these operations have already been |
1029 | | performed on the index values and we are ready now to halftone */ |
1030 | | static int |
1031 | | image_render_mono_ht(gx_image_enum * penum_orig, const byte * buffer, int data_x, |
1032 | | uint w, int h, gx_device * dev) |
1033 | 1.28M | { |
1034 | 1.28M | gx_image_enum *penum = penum_orig; /* const within proc */ |
1035 | 1.28M | image_posture posture = penum->posture; |
1036 | 1.28M | int vdi; /* amounts to replicate */ |
1037 | 1.28M | fixed xrun; |
1038 | 1.28M | byte *thresh_align; |
1039 | 1.28M | int spp_out = penum->dev->color_info.num_components; |
1040 | 1.28M | byte *devc_contone[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
1041 | 1.28M | byte *devc_contone_gray; |
1042 | 1.28M | const byte *psrc = buffer + data_x; |
1043 | 1.28M | int dest_width, dest_height, data_length; |
1044 | 1.28M | byte *color_cache; |
1045 | 1.28M | int position, k, j; |
1046 | 1.28M | int offset_bits = penum->ht_offset_bits; |
1047 | 1.28M | int contone_stride = 0; /* Not used in landscape case */ |
1048 | 1.28M | fixed offset; |
1049 | 1.28M | int src_size; |
1050 | 1.28M | bool flush_buff = false; |
1051 | 1.28M | int offset_contone[GX_DEVICE_COLOR_MAX_COMPONENTS]; /* to ensure 128 bit boundary */ |
1052 | 1.28M | int offset_threshold; /* to ensure 128 bit boundary */ |
1053 | 1.28M | gx_dda_fixed dda_ht; |
1054 | 1.28M | int xn, xr; /* destination position (pixel, not contone buffer offset) */ |
1055 | 1.28M | int code = 0; |
1056 | 1.28M | byte *dev_value; |
1057 | | |
1058 | 1.28M | if (h == 0 || penum->line_size == 0) { /* line_size == 0, nothing to do */ |
1059 | 170k | if (penum->ht_landscape.count == 0 || posture == image_portrait) { |
1060 | 170k | return 0; |
1061 | 170k | } else { |
1062 | | /* Need to flush the buffer */ |
1063 | 1 | offset_bits = penum->ht_landscape.count; |
1064 | 1 | penum->ht_offset_bits = offset_bits; |
1065 | 1 | penum->ht_landscape.offset_set = true; |
1066 | 1 | flush_buff = true; |
1067 | 1 | } |
1068 | 170k | } |
1069 | 1.10M | src_size = penum->rect.w; |
1070 | | |
1071 | | /* Set up the dda. We could move this out but the cost is pretty small */ |
1072 | 1.10M | dda_ht = (posture == image_portrait) ? penum->dda.pixel0.x : penum->dda.pixel0.y; |
1073 | 1.10M | if (penum->dxx > 0) |
1074 | 1.10M | dda_translate(dda_ht, -fixed_epsilon); /* to match rounding in non-fast code */ |
1075 | | |
1076 | 1.10M | switch (posture) { |
1077 | 1.10M | case image_portrait: |
1078 | | /* Figure out our offset in the contone and threshold data |
1079 | | buffers so that we ensure that we are on the 128bit |
1080 | | memory boundaries when we get offset_bits into the data. */ |
1081 | | /* Can't do this earlier, as GC might move the buffers. */ |
1082 | 1.10M | xrun = dda_current(dda_ht); |
1083 | 1.10M | dest_width = gxht_dda_length(&dda_ht, src_size); |
1084 | 1.10M | if (penum->x_extent.x < 0) |
1085 | 0 | xrun += penum->x_extent.x; |
1086 | 1.10M | vdi = penum->hci; |
1087 | 1.10M | contone_stride = penum->line_size; |
1088 | 1.10M | offset_threshold = (- (((int)(intptr_t)(penum->thresh_buffer)) + |
1089 | 1.10M | penum->ht_offset_bits)) & 15; |
1090 | 2.28M | for (k = 0; k < spp_out; k ++) { |
1091 | 1.17M | offset_contone[k] = (- (((int)(intptr_t)(penum->line)) + |
1092 | 1.17M | contone_stride * k + |
1093 | 1.17M | penum->ht_offset_bits)) & 15; |
1094 | 1.17M | } |
1095 | 1.10M | data_length = dest_width; |
1096 | 1.10M | dest_height = fixed2int_var_rounded(any_abs(penum->y_extent.y)); |
1097 | | #ifdef DEBUG |
1098 | | /* Help in spotting problems */ |
1099 | | memset(penum->ht_buffer, 0x00, penum->ht_stride * vdi * spp_out); |
1100 | | #endif |
1101 | 1.10M | break; |
1102 | 2 | case image_landscape: |
1103 | 2 | default: |
1104 | | /* Figure out our offset in the contone and threshold data buffers |
1105 | | so that we ensure that we are on the 128bit memory boundaries. |
1106 | | Can't do this earlier as GC may move the buffers. |
1107 | | */ |
1108 | 2 | vdi = penum->wci; |
1109 | 2 | contone_stride = penum->line_size; |
1110 | 2 | dest_width = fixed2int_var_rounded(any_abs(penum->y_extent.x)); |
1111 | | /* match height in gxht_thresh.c dev_width calculation */ |
1112 | 2 | xrun = dda_current(dda_ht); /* really yrun, but just used here for landscape */ |
1113 | 2 | dest_height = gxht_dda_length(&dda_ht, src_size); |
1114 | 2 | data_length = dest_height; |
1115 | 2 | offset_threshold = (-(int)(intptr_t)(penum->thresh_buffer)) & 15; |
1116 | 4 | for (k = 0; k < spp_out; k ++) { |
1117 | 2 | offset_contone[k] = (- ((int)(intptr_t)(penum->line) + |
1118 | 2 | contone_stride * k)) & 15; |
1119 | 2 | } |
1120 | | /* In the landscaped case, we want to accumulate multiple columns |
1121 | | of data before sending to the device. We want to have a full |
1122 | | byte of HT data in one write. This may not be possible at the |
1123 | | left or right and for those and for those we have so send partial |
1124 | | chunks */ |
1125 | | /* Initialize our xstart and compute our partial bit chunk so |
1126 | | that we get in sync with the 1 bit mem device 16 bit positions |
1127 | | for the rest of the chunks */ |
1128 | 2 | if (penum->ht_landscape.count == 0) { |
1129 | | /* In the landscape case, the size depends upon |
1130 | | if we are moving left to right or right to left with |
1131 | | the image data. This offset is to ensure that we get |
1132 | | aligned in our chunks along 16 bit boundaries */ |
1133 | 1 | penum->ht_landscape.offset_set = true; |
1134 | 1 | if (penum->ht_landscape.index < 0) { |
1135 | 0 | penum->ht_landscape.xstart = penum->xci + vdi - 1; |
1136 | 0 | offset_bits = (penum->ht_landscape.xstart % 16) + 1; |
1137 | | /* xci can be negative, so allow for that */ |
1138 | 0 | if (offset_bits <= 0) offset_bits += 16; |
1139 | 1 | } else { |
1140 | 1 | penum->ht_landscape.xstart = penum->xci; |
1141 | | /* xci can be negative, see Bug 692569. */ |
1142 | 1 | offset_bits = 16 - penum->xci % 16; |
1143 | 1 | if (offset_bits >= 16) offset_bits -= 16; |
1144 | 1 | } |
1145 | 1 | if (offset_bits == 0 || offset_bits == 16) { |
1146 | 1 | penum->ht_landscape.offset_set = false; |
1147 | 1 | penum->ht_offset_bits = 0; |
1148 | 1 | } else { |
1149 | 0 | penum->ht_offset_bits = offset_bits; |
1150 | 0 | } |
1151 | 1 | } |
1152 | 2 | break; |
1153 | 1.10M | } |
1154 | 1.10M | if (flush_buff) |
1155 | 1 | goto flush; /* All done */ |
1156 | | |
1157 | | /* Get the pointers to our buffers */ |
1158 | 2.28M | for (k = 0; k < spp_out; k++) { |
1159 | 1.17M | if (posture == image_portrait) { |
1160 | 1.17M | devc_contone[k] = penum->line + contone_stride * k + |
1161 | 1.17M | offset_contone[k]; |
1162 | 1.17M | } else { |
1163 | 1 | devc_contone[k] = penum->line + offset_contone[k] + |
1164 | 1 | LAND_BITS * k * contone_stride; |
1165 | 1 | } |
1166 | 1.17M | } |
1167 | 1.10M | xr = fixed2int_var_rounded(dda_current(dda_ht)); /* indexes in the destination (contone) */ |
1168 | | |
1169 | 1.10M | devc_contone_gray = devc_contone[0]; |
1170 | 1.10M | if (penum->color_cache == NULL) { |
1171 | | /* No look-up in the cache to fill the source buffer. Still need to |
1172 | | have the data at device resolution. Do these in quick small |
1173 | | loops. This likely could be a vectorized function. Note that |
1174 | | since the color_cache is NULL we must be in a case where we |
1175 | | are going to a monochrome device. */ |
1176 | 922k | switch (posture) { |
1177 | 922k | case image_portrait: |
1178 | 922k | if (penum->dst_width > 0) { |
1179 | 922k | if (src_size == dest_width) { |
1180 | 915k | memcpy(devc_contone_gray, psrc, data_length); |
1181 | 915k | } else if (src_size * 2 == dest_width) { |
1182 | 0 | const byte *psrc_temp = psrc; |
1183 | 0 | for (k = 0; k < data_length; k+=2, devc_contone_gray+=2, |
1184 | 0 | psrc_temp++) { |
1185 | 0 | *devc_contone_gray = *(devc_contone_gray+1) = *psrc_temp; |
1186 | 0 | } |
1187 | 7.52k | } else { |
1188 | | /* Mono case, forward */ |
1189 | 1.43M | for (k=0; k<src_size; k++) { |
1190 | 1.42M | byte c = *psrc++; |
1191 | 1.42M | dda_next(dda_ht); |
1192 | 1.42M | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1193 | 4.52M | while (xr < xn) { |
1194 | 3.09M | *devc_contone_gray++ = c; |
1195 | 3.09M | xr++; |
1196 | 3.09M | } /* at loop exit xn will be >= xr */ |
1197 | 1.42M | } |
1198 | 7.52k | } |
1199 | 922k | } else { |
1200 | | /* Mono case, backwards */ |
1201 | 0 | devc_contone_gray += (data_length - 1); |
1202 | 0 | for (k=0; k<src_size; k++) { |
1203 | 0 | byte c = *psrc++; |
1204 | 0 | dda_next(dda_ht); |
1205 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1206 | 0 | while (xr > xn) { |
1207 | 0 | *devc_contone_gray-- = c; |
1208 | 0 | xr--; |
1209 | 0 | } /* at loop exit xn will be >= xr */ |
1210 | 0 | } |
1211 | 0 | } |
1212 | 922k | break; |
1213 | 1 | case image_landscape: |
1214 | | /* We store the data at this point into a column. Depending |
1215 | | upon our landscape direction we may be going left to right |
1216 | | or right to left. */ |
1217 | 1 | if (penum->ht_landscape.flipy) { |
1218 | 0 | position = penum->ht_landscape.curr_pos + |
1219 | 0 | LAND_BITS * (data_length - 1); |
1220 | 0 | for (k=0; k<src_size; k++) { |
1221 | 0 | byte c = *psrc++; |
1222 | 0 | dda_next(dda_ht); |
1223 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1224 | 0 | while (xr > xn) { |
1225 | 0 | devc_contone_gray[position] = c; |
1226 | 0 | position -= LAND_BITS; |
1227 | 0 | xr--; |
1228 | 0 | } /* at loop exit xn will be <= xr */ |
1229 | 0 | } |
1230 | 1 | } else { |
1231 | 1 | position = penum->ht_landscape.curr_pos; |
1232 | | /* Code up special cases for when we have no scaling |
1233 | | and 2x scaling which we will run into in 300 and |
1234 | | 600dpi devices and content */ |
1235 | 1 | if (src_size == dest_height) { |
1236 | 0 | for (k = 0; k < data_length; k++) { |
1237 | 0 | devc_contone_gray[position] = psrc[k]; |
1238 | 0 | position += LAND_BITS; |
1239 | 0 | } |
1240 | 1 | } else if (src_size*2 == dest_height) { |
1241 | 0 | for (k = 0; k < data_length; k+=2) { |
1242 | 0 | offset = fixed2int_rounded(fixed_half * k); |
1243 | 0 | devc_contone_gray[position] = |
1244 | 0 | devc_contone_gray[position + LAND_BITS] = psrc[offset]; |
1245 | 0 | position += LAND_BITS*2; |
1246 | 0 | } |
1247 | 1 | } else { |
1248 | | /* use dda */ |
1249 | 257 | for (k=0; k<src_size; k++) { |
1250 | 256 | byte c = *psrc++; |
1251 | 256 | dda_next(dda_ht); |
1252 | 256 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1253 | 259 | while (xr < xn) { |
1254 | 3 | devc_contone_gray[position] = c; |
1255 | 3 | position += LAND_BITS; |
1256 | 3 | xr++; |
1257 | 3 | } /* at loop exit xn will be >= xr */ |
1258 | 256 | } |
1259 | 1 | } |
1260 | 1 | } |
1261 | | /* Store the width information and update our counts */ |
1262 | 1 | penum->ht_landscape.count += vdi; |
1263 | 1 | penum->ht_landscape.widths[penum->ht_landscape.curr_pos] = vdi; |
1264 | 1 | penum->ht_landscape.curr_pos += penum->ht_landscape.index; |
1265 | 1 | penum->ht_landscape.num_contones++; |
1266 | 1 | break; |
1267 | 0 | default: |
1268 | | /* error not allowed */ |
1269 | 0 | break; |
1270 | 922k | } |
1271 | 922k | } else { |
1272 | | /* look-up in the cache to fill the source buffer. If our spp_out |
1273 | | is 4 then we need to write out the pixels in the color_cache into |
1274 | | the planes */ |
1275 | 186k | color_cache = penum->color_cache->device_contone; |
1276 | 186k | switch (posture) { |
1277 | 186k | case image_portrait: |
1278 | 186k | if (penum->dst_width > 0) { |
1279 | | /* loop filling contone values selected from the source */ |
1280 | 186k | if (spp_out == 1) { |
1281 | | /* Mono case, forward */ |
1282 | 38.3M | for (k=0; k<src_size; k++) { |
1283 | 38.1M | byte c = color_cache[*psrc++]; |
1284 | 38.1M | dda_next(dda_ht); |
1285 | 38.1M | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1286 | 105M | while (xr < xn) { |
1287 | 67.1M | *devc_contone_gray++ = c; |
1288 | 67.1M | xr++; |
1289 | 67.1M | } /* at loop exit xn will be >= xr */ |
1290 | 38.1M | } |
1291 | 166k | } else { |
1292 | | /* CMYK case, forward */ |
1293 | 6.25M | for (k=0; k<src_size; k++) { |
1294 | 6.23M | dev_value = &(color_cache[*psrc++ * spp_out]); |
1295 | 6.23M | dda_next(dda_ht); |
1296 | 6.23M | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1297 | 20.1M | while (xr < xn) { |
1298 | 69.4M | for (j = 0; j < spp_out; j++) { |
1299 | 55.5M | *(devc_contone[j])++ = dev_value[j]; |
1300 | 55.5M | } |
1301 | 13.8M | xr++; |
1302 | 13.8M | } /* at loop exit xn will be >= xr */ |
1303 | 6.23M | } |
1304 | 20.7k | } |
1305 | 186k | } else { |
1306 | 0 | if (spp_out == 1) { |
1307 | | /* Mono case, backwards */ |
1308 | 0 | devc_contone_gray += data_length - 1; /* move to end */ |
1309 | 0 | for (k=0; k<src_size; k++) { |
1310 | 0 | byte c = color_cache[*psrc++]; |
1311 | 0 | dda_next(dda_ht); |
1312 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1313 | 0 | while (xr > xn) { |
1314 | 0 | *devc_contone_gray-- = c; |
1315 | 0 | xr--; |
1316 | 0 | } /* at loop exit xn will be <= xr */ |
1317 | 0 | } |
1318 | 0 | } else { |
1319 | | /* CMYK case, backwards */ |
1320 | | /* Move to the other end and we will decrement */ |
1321 | 0 | for (j = 0; j < spp_out; j++) { |
1322 | 0 | devc_contone[j] = devc_contone[j] + data_length - 1; |
1323 | 0 | } |
1324 | 0 | for (k=0; k<src_size; k++) { |
1325 | 0 | dev_value = &(color_cache[*psrc++ * spp_out]); |
1326 | 0 | dda_next(dda_ht); |
1327 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1328 | 0 | while (xr > xn) { |
1329 | 0 | for (j = 0; j < spp_out; j++) { |
1330 | 0 | *(devc_contone[j])-- = dev_value[j]; |
1331 | 0 | } |
1332 | 0 | xr--; |
1333 | 0 | } /* at loop exit xn will be <= xr */ |
1334 | 0 | } |
1335 | 0 | } |
1336 | 0 | } |
1337 | 186k | break; |
1338 | 0 | case image_landscape: |
1339 | | /* We store the data at this point into a column. Depending |
1340 | | upon our landscape direction we may be going left to right |
1341 | | or right to left. */ |
1342 | 0 | if (penum->ht_landscape.flipy) { |
1343 | 0 | position = penum->ht_landscape.curr_pos + |
1344 | 0 | LAND_BITS * (data_length - 1); |
1345 | | /* use dda */ |
1346 | 0 | if (spp_out == 1) { |
1347 | | /* Mono case */ |
1348 | | /* loop filling contone values selected from the source */ |
1349 | 0 | for (k=0; k<src_size; k++) { |
1350 | 0 | byte c = color_cache[*psrc++]; |
1351 | 0 | dda_next(dda_ht); |
1352 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1353 | 0 | while (xr > xn) { |
1354 | 0 | devc_contone_gray[position] = c; |
1355 | 0 | position -= LAND_BITS; |
1356 | 0 | xr--; |
1357 | 0 | } /* at loop exit xn will be <= xr */ |
1358 | 0 | } |
1359 | 0 | } else { |
1360 | | /* CMYK case */ |
1361 | 0 | for (k=0; k<src_size; k++) { |
1362 | 0 | dev_value = &(color_cache[*psrc++ * spp_out]); |
1363 | 0 | dda_next(dda_ht); |
1364 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1365 | 0 | while (xr > xn) { |
1366 | 0 | for (j = 0; j < spp_out; j++) { |
1367 | 0 | *(devc_contone[j] + position) = dev_value[j]; |
1368 | 0 | } |
1369 | 0 | position -= LAND_BITS; |
1370 | 0 | xr--; |
1371 | 0 | } /* at loop exit xn will be <= xr */ |
1372 | 0 | } |
1373 | 0 | } |
1374 | 0 | } else { /* Not flipped in Y */ |
1375 | 0 | position = penum->ht_landscape.curr_pos; |
1376 | | /* use dda */ |
1377 | 0 | if (spp_out == 1) { |
1378 | | /* Mono case */ |
1379 | | /* loop filling contone values selected from the source */ |
1380 | 0 | for (k=0; k<src_size; k++) { |
1381 | 0 | byte c = color_cache[*psrc++]; |
1382 | 0 | dda_next(dda_ht); |
1383 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1384 | 0 | while (xr < xn) { |
1385 | 0 | devc_contone_gray[position] = c; |
1386 | 0 | position += LAND_BITS; |
1387 | 0 | xr++; |
1388 | 0 | } /* at loop exit xn will be >= xr */ |
1389 | 0 | } |
1390 | 0 | } else { |
1391 | | /* CMYK case */ |
1392 | | /* Apply initial offset */ |
1393 | 0 | for (k = 0; k < spp_out; k++) { |
1394 | 0 | devc_contone[k] = devc_contone[k] + position; |
1395 | 0 | } |
1396 | | /* CMYK case */ |
1397 | 0 | for (k=0; k<src_size; k++) { |
1398 | 0 | dev_value = &(color_cache[*psrc++ * spp_out]); |
1399 | 0 | dda_next(dda_ht); |
1400 | 0 | xn = fixed2int_var_rounded(dda_current(dda_ht)); |
1401 | 0 | while (xr < xn) { |
1402 | 0 | for (j = 0; j < spp_out; j++) { |
1403 | 0 | *(devc_contone[j] + position) = dev_value[j]; |
1404 | 0 | } |
1405 | 0 | position += LAND_BITS; |
1406 | 0 | xr++; |
1407 | 0 | } /* at loop exit xn will be >= xr */ |
1408 | 0 | } |
1409 | 0 | } |
1410 | 0 | } |
1411 | | /* Store the width information and update our counts */ |
1412 | 0 | penum->ht_landscape.count += vdi; |
1413 | 0 | penum->ht_landscape.widths[penum->ht_landscape.curr_pos] = vdi; |
1414 | 0 | penum->ht_landscape.curr_pos += penum->ht_landscape.index; |
1415 | 0 | penum->ht_landscape.num_contones++; |
1416 | 0 | break; |
1417 | 0 | default: |
1418 | | /* error not allowed */ |
1419 | 0 | break; |
1420 | 186k | } |
1421 | 186k | } |
1422 | | /* Apply threshold array to image data */ |
1423 | 1.10M | flush: |
1424 | 1.10M | thresh_align = penum->thresh_buffer + offset_threshold; |
1425 | 1.10M | code = gxht_thresh_planes(penum, xrun, dest_width, dest_height, |
1426 | 1.10M | thresh_align, dev, offset_contone, |
1427 | 1.10M | contone_stride); |
1428 | 1.10M | return code; |
1429 | 1.10M | } |
1430 | | #endif |