Coverage Report

Created: 2025-06-10 06:58

/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
62.2k
{
162
62.2k
#if USE_FAST_HT_CODE
163
62.2k
    bool use_fast_code = true;
164
#else
165
    bool use_fast_code = false;
166
#endif
167
62.2k
    int code = 0;
168
    /* Set up the link now */
169
62.2k
    const gs_color_space *pcs;
170
62.2k
    gsicc_rendering_param_t rendering_params;
171
62.2k
    cmm_dev_profile_t *dev_profile;
172
62.2k
    bool dev_color_ok = false;
173
62.2k
    bool is_planar_dev = penum->dev->num_planar_planes;
174
175
62.2k
    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
10.1k
        dev_color_ok = ((penum->dev->color_info.num_components == 1 &&
187
10.1k
                         penum->dev->color_info.depth == 1) ||
188
#if 0
189
                         /* Don't allow CMYK Planar devices just yet */
190
                         0);
191
#else
192
10.1k
                        (penum->dev->color_info.num_components == 4 &&
193
10.1k
                         penum->dev->color_info.depth == 4 && is_planar_dev));
194
10.1k
#endif
195
196
10.1k
        if (use_fast_code && penum->pcs != NULL && dev_color_ok &&
197
10.1k
            penum->bps == 8 && (penum->posture == image_portrait
198
305
            || penum->posture == image_landscape) &&
199
10.1k
            penum->image_parent_type == gs_image_type1 &&
200
10.1k
            gx_transfer_is_monotonic(penum->pgs, 0)) {
201
305
            penum->icc_setup.need_decode = false;
202
            /* Check if we need to do any decoding.  */
203
305
            if ( penum->map[0].decoding != sd_none ) {
204
118
                if (!(penum->map[0].decoding == sd_compute
205
118
                     && penum->map[0].decode_factor == 1.0 &&
206
118
                        penum->map[0].decode_lookup[0] == 0.0)) {
207
6
                    penum->icc_setup.need_decode = true;
208
6
                }
209
118
            }
210
305
            code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile);
211
305
            if (code < 0)
212
0
                return code;
213
214
            /* Define the rendering intents */
215
305
            rendering_params.black_point_comp = penum->pgs->blackptcomp;
216
305
            rendering_params.graphics_type_tag = GS_IMAGE_TAG;
217
305
            rendering_params.override_icc = false;
218
305
            rendering_params.preserve_black = gsBKPRESNOTSPECIFIED;
219
305
            rendering_params.rendering_intent = penum->pgs->renderingintent;
220
305
            rendering_params.cmm = gsCMM_DEFAULT;
221
305
            if (gs_color_space_get_index(penum->pcs) ==
222
305
                gs_color_space_index_Indexed) {
223
118
                pcs = penum->pcs->base_space;
224
187
            } else {
225
187
                pcs = penum->pcs;
226
187
            }
227
305
            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
305
            if (pcs->cmm_icc_profile_data == NULL)
235
7
                goto not_fast_halftoning;
236
237
298
            penum->icc_setup.is_lab = pcs->cmm_icc_profile_data->islab;
238
298
            penum->icc_setup.must_halftone = gx_device_must_halftone(penum->dev);
239
            /* The effective transfer is built into the threshold array */
240
298
            penum->icc_setup.has_transfer = false;
241
298
            if (penum->icc_setup.is_lab)
242
13
                penum->icc_setup.need_decode = false;
243
298
            if (penum->icc_link == NULL) {
244
298
                penum->icc_link = gsicc_get_link(penum->pgs, penum->dev, pcs, NULL,
245
298
                    &rendering_params, penum->memory);
246
298
            }
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
298
            penum->use_cie_range = false;
252
298
            if (gs_color_space_is_PSCIE(penum->pcs) &&
253
298
                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
298
            code = image_init_color_cache(penum, penum->bps, penum->spp);
268
298
            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
298
                code = gxht_thresh_image_init(penum);
279
298
                if (code >= 0) {
280
298
                    *render_fn = &image_render_mono_ht;
281
298
                    return code;
282
298
                }
283
298
#endif
284
298
            }
285
298
        }
286
9.81k
not_fast_halftoning:
287
        /*
288
         * Use the slow loop for imagemask with a halftone or a non-default
289
         * logical operation.
290
         */
291
9.81k
        penum->slow_loop =
292
9.81k
            (penum->masked && !color_is_pure(penum->icolor0)) ||
293
9.81k
            penum->use_rop;
294
        /* We can bypass X clipping for portrait mono-component images. */
295
9.81k
        if (!(penum->slow_loop || penum->posture != image_portrait))
296
9.79k
            penum->clip_image &= ~(image_clip_xmin | image_clip_xmax);
297
9.81k
        if_debug0m('b', penum->memory, "[b]render=mono\n");
298
        /* Precompute values needed for rasterizing. */
299
9.81k
        penum->dxx =
300
9.81k
            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
9.81k
        if (penum->use_mask_color) {
307
0
            gx_image_scale_mask_colors(penum, 0);
308
0
            if (penum->mask_color.values[0] <= 0)
309
0
                color_set_null(penum->icolor0);
310
0
            if (penum->mask_color.values[1] >= 255)
311
0
                color_set_null(penum->icolor1);
312
0
        }
313
        /* Reset the clues here, rather than in image_render_mono as
314
         * previously. Even doing so this often may be overzealous. */
315
9.81k
        image_init_clues(penum, penum->bps, penum->spp);
316
9.81k
        *render_fn = &image_render_mono;
317
9.81k
    }
318
61.9k
    return 0;
319
62.2k
}
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
111k
{
377
111k
    const gs_gstate *pgs = penum->pgs;
378
111k
    gs_logical_operation_t lop = penum->log_op;
379
111k
    const bool masked = penum->masked;
380
111k
    const gs_color_space *pcs = NULL;   /* only set for non-masks */
381
111k
    cs_proc_remap_color((*remap_color)) = NULL; /* ditto */
382
111k
    gs_client_color cc;
383
111k
    gx_device_color *pdevc = penum->icolor1;    /* color for masking */
384
111k
    uint mask_base =            /* : 0 to pacify Valgrind */
385
111k
        (penum->use_mask_color ? penum->mask_color.values[0] : 0);
386
111k
    uint mask_limit =
387
111k
        (penum->use_mask_color ?
388
111k
         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
111k
#define IMAGE_SET_GRAY(sample_value)\
395
3.13M
  BEGIN\
396
3.13M
    pdevc = &penum->clues[sample_value].dev_color;\
397
3.13M
    if (!color_is_set(pdevc)) {\
398
304k
        if ((uint)(sample_value - mask_base) < mask_limit)\
399
304k
            color_set_null(pdevc);\
400
304k
        else {\
401
304k
            decode_sample(sample_value, cc, 0);\
402
304k
            code = (*remap_color)(&cc, pcs, pdevc, pgs, dev, gs_color_select_source);\
403
304k
            if (code < 0)\
404
304k
                goto err;\
405
304k
            pdevc->tag = device_current_tag(dev);\
406
304k
        }\
407
2.73M
    } else if (!color_is_pure(pdevc)) {\
408
2.66M
        code = gx_color_load_select(pdevc, pgs, dev, gs_color_select_source);\
409
2.66M
        if (code < 0)\
410
2.66M
            goto err;\
411
2.66M
    }\
412
3.13M
  END
413
111k
    gx_dda_fixed_point next;    /* (y not used in fast loop) */
414
111k
    gx_dda_step_fixed dxx2, dxx3, dxx4;         /* (not used in all loops) */
415
111k
    const byte *psrc_initial = buffer + data_x;
416
111k
    const byte *psrc = psrc_initial;
417
111k
    const byte *rsrc = psrc;    /* psrc at start of run */
418
111k
    const byte *endp = psrc + w;
419
111k
    const byte *stop = endp;
420
111k
    fixed xrun;                 /* x at start of run */
421
111k
    byte run;           /* run value */
422
111k
    int htrun = (masked ? 255 : -2);            /* halftone run value */
423
111k
    int i, code = 0;
424
425
111k
    if (h == 0)
426
19.5k
        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
91.7k
    next = penum->dda.pixel0;
434
91.7k
    xrun = dda_current(next.x);
435
91.7k
    if (!masked) {
436
90.6k
        pcs = penum->pcs;       /* (may not be set for masks) */
437
90.6k
        remap_color = pcs->type->remap_color;
438
90.6k
    }
439
91.7k
    run = *psrc;
440
    /* Find the last transition in the input. */
441
91.7k
    if (masked &&
442
91.7k
        (penum->posture != image_portrait) &&
443
91.7k
        (penum->posture != image_landscape)) {
444
        /* No need to calculate stop */
445
90.6k
    } else {
446
90.6k
        byte last = stop[-1];
447
448
14.1M
        while (stop > psrc && stop[-1] == last)
449
14.0M
            --stop;
450
90.6k
    }
451
91.7k
    if (penum->slow_loop || penum->posture != image_portrait) {
452
453
        /**************************************************************
454
         * Slow case (skewed, rotated, or imagemask with a halftone). *
455
         **************************************************************/
456
457
1.30k
        fixed yrun;
458
1.30k
        const fixed pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
459
1.30k
        const fixed pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
460
1.30k
        dev_proc_fill_parallelogram((*fill_pgram)) =
461
1.30k
            dev_proc(dev, fill_parallelogram);
462
463
1.02M
#define xl dda_current(next.x)
464
1.02M
#define ytf dda_current(next.y)
465
1.30k
        yrun = ytf;
466
1.30k
        if (masked) {
467
468
            /**********************
469
             * Slow case, masked. *
470
             **********************/
471
472
1.04k
            pdevc = penum->icolor1;
473
1.04k
            code = gx_color_load(pdevc, pgs, dev);
474
1.04k
            if (code < 0)
475
0
                return code;
476
1.04k
            if ((stop <= psrc) && (penum->adjust == 0) &&
477
1.04k
                ((penum->posture == image_portrait) ||
478
0
                 (penum->posture == image_landscape)))
479
0
                goto last;
480
1.04k
            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
1.04k
            } 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
0
                fixed ax =
569
0
                    (pdyx < 0 ? -penum->adjust : penum->adjust);
570
0
                fixed dyx = pdyx + (ax << 1);
571
0
                fixed ay =
572
0
                    (penum->matrix.xy < 0 ? -penum->adjust : penum->adjust);
573
574
0
                xrun -= ax;
575
0
                dda_translate(next.y, -ay);
576
0
                ay <<= 1;
577
0
                for (;;) {
578
0
                    for (; psrc < endp && !*psrc; ++psrc)
579
0
                        dda_next(next.y);
580
0
                    yrun = ytf;
581
0
                    if (psrc >= stop)
582
0
                        break;
583
0
                    for (; psrc < endp && *psrc; ++psrc)
584
0
                        dda_next(next.y);
585
0
                    code = (*fill_pgram)(dev, xrun, yrun, fixed_0,
586
0
                                         ytf - yrun + ay, dyx, fixed_0,
587
0
                                         pdevc, lop);
588
0
                    if (code < 0)
589
0
                        goto err;
590
0
                    rsrc = psrc;
591
0
                    if (psrc >= stop)
592
0
                        break;
593
0
                }
594
595
1.04k
            } 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
1.04k
                stop = endp;
610
2.31k
                for (;;) {
611
                    /* skip forward until we find a 1 bit */
612
23.3k
                    for (; psrc < stop && !*psrc; ++psrc) {
613
21.0k
                        dda_next(next.x);
614
21.0k
                        dda_next(next.y);
615
21.0k
                    }
616
2.31k
                    if (psrc >= endp) /* Note, endp NOT stop! */
617
1.04k
                        break;
618
                    /* Then draw the pgram and step forward until we find a
619
                     * 0 bit. */
620
485k
                    do {
621
485k
                        yrun = ytf;
622
485k
                        xrun = xl;
623
485k
                        dda_next(next.x);
624
485k
                        dda_next(next.y);
625
485k
                        code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
626
485k
                                             ytf - yrun, pdyx, pdyy, pdevc, lop);
627
485k
                        if (code < 0)
628
0
                            goto err;
629
485k
                        psrc++;
630
485k
                        rsrc = psrc;
631
485k
                        if (psrc >= stop)
632
981
                            break;
633
485k
                    } while (*psrc);
634
1.27k
                }
635
636
1.04k
            }
637
638
1.04k
        } 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
264
        } else if (penum->posture == image_landscape) {
703
704
            /**************************************
705
             * Slow case, not masked, landscape. *
706
             **************************************/
707
0
            dev_proc_fill_rectangle((*fill_proc)) =
708
0
                dev_proc(dev, fill_rectangle);
709
0
            int ix = fixed2int_pixround(xrun);
710
0
            int iw = fixed2int_pixround(xrun + pdyx) - ix;
711
0
            if (iw < 0)
712
0
                ix += iw, iw = -iw;
713
714
            /* In this case, we can fill runs quickly. */
715
            /****** DOESN'T DO ADJUSTMENT ******/
716
0
            if (stop <= psrc)
717
0
                goto last;
718
0
            for (;;) {
719
0
                byte c = *psrc++;
720
0
                if (c != run) {
721
0
                    int iy = fixed2int_pixround(yrun);
722
0
                    int ih = fixed2int_pixround(ytf) - iy;
723
0
                    if (ih < 0)
724
0
                        iy += ih, ih = -ih;
725
0
                    switch (run)
726
0
                    {
727
0
                    case 0:
728
0
                        if (!color_is_pure(penum->icolor0))
729
0
                            goto ht_land;
730
0
                        code = (*fill_proc) (dev, ix, iy, iw, ih,
731
0
                                             penum->icolor0->colors.pure);
732
0
                        break;
733
0
                    case 0xff:
734
0
                        if (!color_is_pure(penum->icolor1))
735
0
                            goto ht_land;
736
0
                        code = (*fill_proc) (dev, ix, iy, iw, ih,
737
0
                                             penum->icolor1->colors.pure);
738
0
                        break;
739
0
                    default:
740
0
                        ht_land:
741
0
                        if (run != htrun) {
742
0
                            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
0
                            IMAGE_SET_GRAY(run);
750
0
#endif
751
0
                        }
752
0
                        code = gx_fill_rectangle_device_rop(ix, iy, iw, ih,
753
0
                                                            pdevc, dev, lop);
754
0
                    }
755
0
                    if (code < 0)
756
0
                        goto err;
757
0
                    yrun = ytf;
758
0
                    rsrc = psrc;
759
0
                    if (psrc > stop)
760
0
                        break;
761
0
                    run = c;
762
0
                }
763
0
                dda_next(next.y);
764
0
                if (psrc >= endp)
765
0
                    break;
766
0
            }
767
264
        } 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
264
            stop = endp;
778
25.9k
            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
25.9k
                if (run != htrun) {
783
2.68k
                    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
2.68k
                    IMAGE_SET_GRAY(run);
791
2.68k
#endif
792
2.68k
                }
793
25.9k
                code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
794
25.9k
                                      ytf - yrun, pdyx, pdyy, pdevc, lop);
795
25.9k
                if (code < 0)
796
0
                    goto err;
797
25.9k
                yrun = ytf;
798
25.9k
                xrun = xl;
799
25.9k
                rsrc = psrc;
800
25.9k
                if (psrc >= stop)
801
264
                    break;
802
25.6k
                run = *psrc++;
803
25.6k
                dda_next(next.x);
804
25.6k
                dda_next(next.y);       /* harmless if no skew */
805
25.6k
            }
806
807
264
        }
808
        /* Fill the last run. */
809
1.30k
      last:if (stop < endp && (*stop || !masked)) {
810
0
            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
0
                    IMAGE_SET_GRAY(*stop);
818
0
#endif
819
0
            }
820
0
            dda_advance(next.x, endp - stop);
821
0
            dda_advance(next.y, endp - stop);
822
0
            code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
823
0
                                  ytf - yrun, pdyx, pdyy, pdevc, lop);
824
0
        }
825
1.30k
#undef xl
826
1.30k
#undef ytf
827
828
90.3k
    } else {
829
830
        /**********************************************************
831
         * Fast case: no skew, and not imagemask with a halftone. *
832
         **********************************************************/
833
834
90.3k
        const fixed adjust = penum->adjust;
835
90.3k
        const fixed dxx = penum->dxx;
836
90.3k
        fixed xa = (dxx >= 0 ? adjust : -adjust);
837
90.3k
        const int yt = penum->yci, iht = penum->hci;
838
839
90.3k
        dev_proc_fill_rectangle((*fill_proc)) =
840
90.3k
            dev_proc(dev, fill_rectangle);
841
90.3k
        int xmin = fixed2int_pixround(penum->clip_outer.p.x);
842
90.3k
        int xmax = fixed2int_pixround(penum->clip_outer.q.x);
843
3.54M
#define xl dda_current(next.x)
844
845
90.3k
        if_debug2m('b', penum->memory, "[b]image y=%d  dda.y.Q=%lg\n",
846
90.3k
                   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
90.3k
        xrun = xrun - xa + (fixed_half - fixed_epsilon);
850
90.3k
        dda_translate(next.x, xa + (fixed_half - fixed_epsilon));
851
90.3k
        xa <<= 1;
852
        /* Calculate multiples of the DDA step. */
853
90.3k
        dxx2 = next.x.step;
854
90.3k
        dda_step_add(dxx2, next.x.step);
855
90.3k
        dxx3 = dxx2;
856
90.3k
        dda_step_add(dxx3, next.x.step);
857
90.3k
        dxx4 = dxx3;
858
90.3k
        dda_step_add(dxx4, next.x.step);
859
90.3k
        if (stop > psrc)
860
3.54M
            for (;;) {          /* Skip large constant regions quickly, */
861
                /* but don't slow down transitions too much. */
862
5.15M
              skf:if (psrc[0] == run) {
863
2.24M
                    if (psrc[1] == run) {
864
1.85M
                        if (psrc[2] == run) {
865
1.70M
                            if (psrc[3] == run) {
866
1.61M
                                psrc += 4;
867
1.61M
                                dda_state_next(next.x.state, dxx4);
868
1.61M
                                if (psrc >= endp)
869
0
                                    break;
870
1.61M
                                goto skf;
871
1.61M
                            } else {
872
91.6k
                                psrc += 4;
873
91.6k
                                dda_state_next(next.x.state, dxx3);
874
91.6k
                            }
875
1.70M
                        } else {
876
146k
                            psrc += 3;
877
146k
                            dda_state_next(next.x.state, dxx2);
878
146k
                        }
879
1.85M
                    } else {
880
387k
                        psrc += 2;
881
387k
                        dda_next(next.x);
882
387k
                    }
883
2.24M
                } else
884
2.91M
                    psrc++;
885
3.54M
                {               /* Now fill the region between xrun and xl. */
886
3.54M
                    int xi = fixed2int_var(xrun);
887
3.54M
                    int wi = fixed2int_var(xl) - xi;
888
3.54M
                    int xei;
889
890
3.54M
                    if (wi <= 0) {
891
506k
                        if (wi == 0)
892
504k
                            goto mt;
893
1.66k
                        xi += wi, wi = -wi;
894
1.66k
                    }
895
3.03M
                    if ((xei = xi + wi) > xmax || xi < xmin) {  /* Do X clipping */
896
1.18k
                        if (xi < xmin)
897
1.11k
                            wi -= xmin - xi, xi = xmin;
898
1.18k
                        if (xei > xmax)
899
69
                            wi -= xei - xmax;
900
1.18k
                        if (wi <= 0)
901
150
                            goto mt;
902
1.18k
                    }
903
3.03M
                    switch (run) {
904
130k
                        case 0:
905
130k
                            if (masked)
906
0
                                goto mt;
907
130k
                            if (!color_is_pure(penum->icolor0))
908
97.9k
                                goto ht;
909
32.3k
                            code = (*fill_proc) (dev, xi, yt, wi, iht,
910
32.3k
                                                 penum->icolor0->colors.pure);
911
32.3k
                            break;
912
251k
                        case 255:       /* just for speed */
913
251k
                            if (!color_is_pure(penum->icolor1))
914
251k
                                goto ht;
915
627
                            code = (*fill_proc) (dev, xi, yt, wi, iht,
916
627
                                                 penum->icolor1->colors.pure);
917
627
                            break;
918
2.65M
                        default:
919
3.00M
                          ht:   /* Use halftone if needed */
920
3.00M
                            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
2.95M
                                IMAGE_SET_GRAY(run);
928
2.95M
#endif
929
2.95M
                                htrun = run;
930
2.95M
                            }
931
3.00M
                            code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
932
3.03M
                                                                 pdevc, dev, lop);
933
3.03M
                    }
934
3.03M
                    if (code < 0)
935
0
                        goto err;
936
3.54M
                  mt:xrun = xl - xa;    /* original xa << 1 */
937
3.54M
                    rsrc = psrc - 1;
938
3.54M
                    if (psrc > stop) {
939
37.4k
                        --psrc;
940
37.4k
                        break;
941
37.4k
                    }
942
3.50M
                    run = psrc[-1];
943
3.50M
                }
944
3.50M
                dda_next(next.x);
945
3.50M
            }
946
        /* Fill the last run. */
947
90.3k
        if (*stop != 0 || !masked) {
948
90.3k
            int xi = fixed2int_var(xrun);
949
90.3k
            int wi, xei;
950
951
90.3k
            dda_advance(next.x, endp - stop);
952
90.3k
            wi = fixed2int_var(xl) - xi;
953
90.3k
            if (wi <= 0) {
954
597
                if (wi == 0)
955
180
                    goto lmt;
956
417
                xi += wi, wi = -wi;
957
417
            }
958
90.2k
            if ((xei = xi + wi) > xmax || xi < xmin) {  /* Do X clipping */
959
314
                if (xi < xmin)
960
34
                    wi -= xmin - xi, xi = xmin;
961
314
                if (xei > xmax)
962
308
                    wi -= xei - xmax;
963
314
                if (wi <= 0)
964
64
                    goto lmt;
965
314
            }
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
90.2k
            IMAGE_SET_GRAY(*stop);
973
90.1k
#endif
974
90.1k
            code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
975
90.1k
                                                pdevc, dev, lop);
976
90.3k
          lmt:;
977
90.3k
        }
978
979
90.3k
    }
980
91.7k
#undef xl
981
91.7k
    if (code >= 0) {
982
91.7k
        code = 1;
983
91.7k
        goto done;
984
91.7k
    }
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
91.7k
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
23.5M
    for (i = 0; i < 256; i++) {
999
23.4M
        penum->clues[i].dev_color.colors.binary.b_tile = NULL;
1000
23.4M
    }
1001
91.7k
    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
21.3k
{
1034
21.3k
    gx_image_enum *penum = penum_orig; /* const within proc */
1035
21.3k
    image_posture posture = penum->posture;
1036
21.3k
    int vdi;  /* amounts to replicate */
1037
21.3k
    fixed xrun;
1038
21.3k
    byte *thresh_align;
1039
21.3k
    int spp_out = penum->dev->color_info.num_components;
1040
21.3k
    byte *devc_contone[GX_DEVICE_COLOR_MAX_COMPONENTS];
1041
21.3k
    byte *devc_contone_gray;
1042
21.3k
    const byte *psrc = buffer + data_x;
1043
21.3k
    int dest_width, dest_height, data_length;
1044
21.3k
    byte *color_cache;
1045
21.3k
    int position, k, j;
1046
21.3k
    int offset_bits = penum->ht_offset_bits;
1047
21.3k
    int contone_stride = 0;  /* Not used in landscape case */
1048
21.3k
    fixed offset;
1049
21.3k
    int src_size;
1050
21.3k
    bool flush_buff = false;
1051
21.3k
    int offset_contone[GX_DEVICE_COLOR_MAX_COMPONENTS];    /* to ensure 128 bit boundary */
1052
21.3k
    int offset_threshold;  /* to ensure 128 bit boundary */
1053
21.3k
    gx_dda_fixed dda_ht;
1054
21.3k
    int xn, xr;   /* destination position (pixel, not contone buffer offset) */
1055
21.3k
    int code = 0;
1056
21.3k
    byte *dev_value;
1057
1058
21.3k
    if (h == 0 || penum->line_size == 0) {      /* line_size == 0, nothing to do */
1059
581
        if (penum->ht_landscape.count == 0 || posture == image_portrait) {
1060
581
            return 0;
1061
581
        } else {
1062
            /* Need to flush the buffer */
1063
0
            offset_bits = penum->ht_landscape.count;
1064
0
            penum->ht_offset_bits = offset_bits;
1065
0
            penum->ht_landscape.offset_set = true;
1066
0
            flush_buff = true;
1067
0
        }
1068
581
    }
1069
20.7k
    src_size = penum->rect.w;
1070
1071
    /* Set up the dda.  We could move this out but the cost is pretty small */
1072
20.7k
    dda_ht = (posture == image_portrait) ? penum->dda.pixel0.x : penum->dda.pixel0.y;
1073
20.7k
    if (penum->dxx > 0)
1074
20.7k
        dda_translate(dda_ht, -fixed_epsilon);      /* to match rounding in non-fast code */
1075
1076
20.7k
    switch (posture) {
1077
20.7k
        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
20.7k
            xrun = dda_current(dda_ht);
1083
20.7k
            dest_width = gxht_dda_length(&dda_ht, src_size);
1084
20.7k
            if (penum->x_extent.x < 0)
1085
0
                xrun += penum->x_extent.x;
1086
20.7k
            vdi = penum->hci;
1087
20.7k
            contone_stride = penum->line_size;
1088
20.7k
            offset_threshold = (- (((int)(intptr_t)(penum->thresh_buffer)) +
1089
20.7k
                                   penum->ht_offset_bits)) & 15;
1090
103k
            for (k = 0; k < spp_out; k ++) {
1091
83.1k
                offset_contone[k]   = (- (((int)(intptr_t)(penum->line)) +
1092
83.1k
                                           contone_stride * k +
1093
83.1k
                                           penum->ht_offset_bits)) & 15;
1094
83.1k
            }
1095
20.7k
            data_length = dest_width;
1096
20.7k
            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
20.7k
            break;
1102
0
        case image_landscape:
1103
0
        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
0
            vdi = penum->wci;
1109
0
            contone_stride = penum->line_size;
1110
0
            dest_width = fixed2int_var_rounded(any_abs(penum->y_extent.x));
1111
            /* match height in gxht_thresh.c dev_width calculation */
1112
0
            xrun = dda_current(dda_ht);            /* really yrun, but just used here for landscape */
1113
0
            dest_height = gxht_dda_length(&dda_ht, src_size);
1114
0
            data_length = dest_height;
1115
0
            offset_threshold = (-(int)(intptr_t)(penum->thresh_buffer)) & 15;
1116
0
            for (k = 0; k < spp_out; k ++) {
1117
0
                offset_contone[k] = (- ((int)(intptr_t)(penum->line) +
1118
0
                                        contone_stride * k)) & 15;
1119
0
            }
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
0
            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
0
                penum->ht_landscape.offset_set = true;
1134
0
                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
0
                } else {
1140
0
                    penum->ht_landscape.xstart = penum->xci;
1141
                    /* xci can be negative, see Bug 692569. */
1142
0
                    offset_bits = 16 - penum->xci % 16;
1143
0
                    if (offset_bits >= 16) offset_bits -= 16;
1144
0
                }
1145
0
                if (offset_bits == 0 || offset_bits == 16) {
1146
0
                    penum->ht_landscape.offset_set = false;
1147
0
                    penum->ht_offset_bits = 0;
1148
0
                } else {
1149
0
                    penum->ht_offset_bits = offset_bits;
1150
0
                }
1151
0
            }
1152
0
            break;
1153
20.7k
    }
1154
20.7k
    if (flush_buff)
1155
0
        goto flush;  /* All done */
1156
1157
    /* Get the pointers to our buffers */
1158
103k
    for (k = 0; k < spp_out; k++) {
1159
83.1k
        if (posture == image_portrait) {
1160
83.1k
            devc_contone[k] = penum->line + contone_stride * k +
1161
83.1k
                              offset_contone[k];
1162
83.1k
        } else {
1163
0
            devc_contone[k] = penum->line + offset_contone[k] +
1164
0
                              LAND_BITS * k * contone_stride;
1165
0
        }
1166
83.1k
    }
1167
20.7k
    xr = fixed2int_var_rounded(dda_current(dda_ht));  /* indexes in the destination (contone) */
1168
1169
20.7k
    devc_contone_gray = devc_contone[0];
1170
20.7k
    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
0
        switch (posture) {
1177
0
            case image_portrait:
1178
0
                if (penum->dst_width > 0) {
1179
0
                    if (src_size == dest_width) {
1180
0
                        memcpy(devc_contone_gray, psrc, data_length);
1181
0
                    } 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
0
                    } else {
1188
                        /* Mono case, forward */
1189
0
                        for (k=0; k<src_size; k++) {
1190
0
                            byte c = *psrc++;
1191
0
                            dda_next(dda_ht);
1192
0
                            xn = fixed2int_var_rounded(dda_current(dda_ht));
1193
0
                            while (xr < xn) {
1194
0
                                *devc_contone_gray++ = c;
1195
0
                                xr++;
1196
0
                            }           /* at loop exit xn will be >= xr */
1197
0
                        }
1198
0
                    }
1199
0
                } 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
0
                break;
1213
0
            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
0
                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
0
                } else {
1231
0
                    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
0
                    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
0
                    } 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
0
                    } else {
1248
                        /* use dda */
1249
0
                        for (k=0; k<src_size; k++) {
1250
0
                            byte c = *psrc++;
1251
0
                            dda_next(dda_ht);
1252
0
                            xn = fixed2int_var_rounded(dda_current(dda_ht));
1253
0
                            while (xr < xn) {
1254
0
                                devc_contone_gray[position] = c;
1255
0
                                position += LAND_BITS;
1256
0
                                xr++;
1257
0
                            }           /* at loop exit xn will be >= xr */
1258
0
                        }
1259
0
                    }
1260
0
                }
1261
                /* Store the width information and update our counts */
1262
0
                penum->ht_landscape.count += vdi;
1263
0
                penum->ht_landscape.widths[penum->ht_landscape.curr_pos] = vdi;
1264
0
                penum->ht_landscape.curr_pos += penum->ht_landscape.index;
1265
0
                penum->ht_landscape.num_contones++;
1266
0
                break;
1267
0
            default:
1268
                /* error not allowed */
1269
0
                break;
1270
0
            }
1271
20.7k
    } 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
20.7k
        color_cache = penum->color_cache->device_contone;
1276
20.7k
        switch (posture) {
1277
20.7k
            case image_portrait:
1278
20.7k
                if (penum->dst_width > 0) {
1279
                    /* loop filling contone values selected from the source */
1280
20.7k
                    if (spp_out == 1) {
1281
                        /* Mono case, forward */
1282
0
                        for (k=0; k<src_size; k++) {
1283
0
                            byte c = color_cache[*psrc++];
1284
0
                            dda_next(dda_ht);
1285
0
                            xn = fixed2int_var_rounded(dda_current(dda_ht));
1286
0
                            while (xr < xn) {
1287
0
                                *devc_contone_gray++ = c;
1288
0
                                xr++;
1289
0
                            }           /* at loop exit xn will be >= xr */
1290
0
                        }
1291
20.7k
                    } 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
20.7k
                } 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
20.7k
                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
20.7k
        }
1421
20.7k
    }
1422
    /* Apply threshold array to image data */
1423
20.7k
flush:
1424
20.7k
    thresh_align = penum->thresh_buffer + offset_threshold;
1425
20.7k
    code = gxht_thresh_planes(penum, xrun, dest_width, dest_height,
1426
20.7k
                              thresh_align, dev, offset_contone,
1427
20.7k
                              contone_stride);
1428
20.7k
    return code;
1429
20.7k
}
1430
#endif