~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to src/gdevbbox.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2001-2006 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, modified
8
 
   or distributed except as expressly authorized under the terms of that
9
 
   license.  Refer to licensing information at http://www.artifex.com/
10
 
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11
 
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12
 
*/
13
 
/*$Id: gdevbbox.c 8803 2008-06-24 14:16:29Z leonardo $ */
14
 
/* Device for tracking bounding box */
15
 
#include "math_.h"
16
 
#include "memory_.h"
17
 
#include "gx.h"
18
 
#include "gserrors.h"
19
 
#include "gsparam.h"
20
 
#include "gxdevice.h"
21
 
#include "gsdevice.h"           /* requires gsmatrix.h */
22
 
#include "gdevbbox.h"
23
 
#include "gxdcolor.h"           /* for gx_device_black/white */
24
 
#include "gxiparam.h"           /* for image source size */
25
 
#include "gxistate.h"
26
 
#include "gxpaint.h"
27
 
#include "gxpath.h"
28
 
#include "gxcpath.h"
29
 
 
30
 
/* GC descriptor */
31
 
public_st_device_bbox();
32
 
 
33
 
/* Device procedures */
34
 
static dev_proc_open_device(bbox_open_device);
35
 
static dev_proc_close_device(bbox_close_device);
36
 
static dev_proc_output_page(bbox_output_page);
37
 
static dev_proc_fill_rectangle(bbox_fill_rectangle);
38
 
static dev_proc_copy_mono(bbox_copy_mono);
39
 
static dev_proc_copy_color(bbox_copy_color);
40
 
static dev_proc_get_params(bbox_get_params);
41
 
static dev_proc_put_params(bbox_put_params);
42
 
static dev_proc_copy_alpha(bbox_copy_alpha);
43
 
static dev_proc_fill_path(bbox_fill_path);
44
 
static dev_proc_stroke_path(bbox_stroke_path);
45
 
static dev_proc_fill_mask(bbox_fill_mask);
46
 
static dev_proc_fill_trapezoid(bbox_fill_trapezoid);
47
 
static dev_proc_fill_parallelogram(bbox_fill_parallelogram);
48
 
static dev_proc_fill_triangle(bbox_fill_triangle);
49
 
static dev_proc_draw_thin_line(bbox_draw_thin_line);
50
 
static dev_proc_strip_tile_rectangle(bbox_strip_tile_rectangle);
51
 
static dev_proc_strip_copy_rop(bbox_strip_copy_rop);
52
 
static dev_proc_begin_typed_image(bbox_begin_typed_image);
53
 
static dev_proc_create_compositor(bbox_create_compositor);
54
 
static dev_proc_text_begin(bbox_text_begin);
55
 
 
56
 
/* The device prototype */
57
 
/*
58
 
 * Normally this would be static, but if the device is going to be used
59
 
 * stand-alone, it has to be public.
60
 
 */
61
 
/*static*/ const
62
 
/*
63
 
 * The bbox device sets the resolution to some value R (currently 4000), and
64
 
 * the page size in device pixels to slightly smaller than the largest
65
 
 * representable values (around 500K), leaving a little room for stroke
66
 
 * widths, rounding, etc.  If an input file (or the command line) resets the
67
 
 * resolution to a value R' > R, the page size in pixels will get multiplied
68
 
 * by R'/R, and will thereby exceed the representable range, causing a
69
 
 * limitcheck.  That is why the bbox device must set the resolution to a
70
 
 * value larger than that of any real device.  A consequence of this is that
71
 
 * the page size in inches is limited to the maximum representable pixel
72
 
 * size divided by R, which gives a limit of about 120" in each dimension.
73
 
 */
74
 
#define MAX_COORD (max_int_in_fixed - 1000)
75
 
#define MAX_RESOLUTION 4000
76
 
gx_device_bbox gs_bbox_device =
77
 
{
78
 
    /*
79
 
     * Define the device as 8-bit gray scale to avoid computing halftones.
80
 
     */
81
 
    std_device_dci_body(gx_device_bbox, 0, "bbox",
82
 
                        MAX_COORD, MAX_COORD,
83
 
                        MAX_RESOLUTION, MAX_RESOLUTION,
84
 
                        1, 8, 255, 0, 256, 1),
85
 
    {bbox_open_device,
86
 
     gx_upright_get_initial_matrix,
87
 
     NULL,                      /* sync_output */
88
 
     bbox_output_page,
89
 
     bbox_close_device,
90
 
     gx_default_gray_map_rgb_color,
91
 
     gx_default_gray_map_color_rgb,
92
 
     bbox_fill_rectangle,
93
 
     NULL,                      /* tile_rectangle */
94
 
     bbox_copy_mono,
95
 
     bbox_copy_color,
96
 
     NULL,                      /* draw_line */
97
 
     NULL,                      /* get_bits */
98
 
     bbox_get_params,
99
 
     bbox_put_params,
100
 
     gx_default_map_cmyk_color,
101
 
     NULL,                      /* get_xfont_procs */
102
 
     NULL,                      /* get_xfont_device */
103
 
     gx_default_map_rgb_alpha_color,
104
 
     gx_page_device_get_page_device,
105
 
     NULL,                      /* get_alpha_bits */
106
 
     bbox_copy_alpha,
107
 
     NULL,                      /* get_band */
108
 
     NULL,                      /* copy_rop */
109
 
     bbox_fill_path,
110
 
     bbox_stroke_path,
111
 
     bbox_fill_mask,
112
 
     bbox_fill_trapezoid,
113
 
     bbox_fill_parallelogram,
114
 
     bbox_fill_triangle,
115
 
     bbox_draw_thin_line,
116
 
     gx_default_begin_image,
117
 
     NULL,                      /* image_data */
118
 
     NULL,                      /* end_image */
119
 
     bbox_strip_tile_rectangle,
120
 
     bbox_strip_copy_rop,
121
 
     NULL,                      /* get_clipping_box */
122
 
     bbox_begin_typed_image,
123
 
     NULL,                      /* get_bits_rectangle */
124
 
     gx_default_map_color_rgb_alpha,
125
 
     bbox_create_compositor,
126
 
     NULL,                      /* get_hardware_params */
127
 
     bbox_text_begin,
128
 
     NULL,                      /* finish_copydevice */
129
 
     NULL,                      /* begin_transparency_group */
130
 
     NULL,                      /* end_transparency_group */
131
 
     NULL,                      /* begin_transparency_mask */
132
 
     NULL,                      /* end_transparency_mask */
133
 
     NULL,                      /* discard_transparency_layer */
134
 
     NULL,                      /* get_color_mapping_procs */
135
 
     NULL,                      /* get_color_comp_index */
136
 
     NULL,                      /* encode_color */
137
 
     NULL                       /* decode_color */
138
 
    },
139
 
    0,                          /* target */
140
 
    1,                          /*true *//* free_standing */
141
 
    1                           /*true *//* forward_open_close */
142
 
};
143
 
 
144
 
#undef MAX_COORD
145
 
#undef MAX_RESOLUTION
146
 
 
147
 
/* Default box procedures */
148
 
 
149
 
bool
150
 
bbox_default_init_box(void *pdata)
151
 
{
152
 
    gx_device_bbox *const bdev = (gx_device_bbox *)pdata;
153
 
    gs_fixed_rect *const pr = &bdev->bbox;
154
 
 
155
 
    pr->p.x = pr->p.y = max_fixed;
156
 
    pr->q.x = pr->q.y = min_fixed;
157
 
    return bdev->white != bdev->transparent;
158
 
}
159
 
#define BBOX_INIT_BOX(bdev)\
160
 
  bdev->box_procs.init_box(bdev->box_proc_data)
161
 
 
162
 
void
163
 
bbox_default_get_box(const void *pdata, gs_fixed_rect *pbox)
164
 
{
165
 
    const gx_device_bbox *const bdev = (const gx_device_bbox *)pdata;
166
 
 
167
 
    *pbox = bdev->bbox;
168
 
}
169
 
#define BBOX_GET_BOX(bdev, pbox)\
170
 
    bdev->box_procs.get_box(bdev->box_proc_data, pbox);
171
 
 
172
 
void
173
 
bbox_default_add_rect(void *pdata, fixed x0, fixed y0, fixed x1, fixed y1)
174
 
{
175
 
    gx_device_bbox *const bdev = (gx_device_bbox *)pdata;
176
 
    gs_fixed_rect *const pr = &bdev->bbox;
177
 
 
178
 
    if (x0 < pr->p.x)
179
 
        pr->p.x = x0;
180
 
    if (y0 < pr->p.y)
181
 
        pr->p.y = y0;
182
 
    if (x1 > pr->q.x)
183
 
        pr->q.x = x1;
184
 
    if (y1 > pr->q.y)
185
 
        pr->q.y = y1;
186
 
}
187
 
#define BBOX_ADD_RECT(bdev, x0, y0, x1, y1)\
188
 
    bdev->box_procs.add_rect(bdev->box_proc_data, x0, y0, x1, y1)
189
 
#define BBOX_ADD_INT_RECT(bdev, x0, y0, x1, y1)\
190
 
    BBOX_ADD_RECT(bdev, int2fixed(x0), int2fixed(y0), int2fixed(x1),\
191
 
                  int2fixed(y1))
192
 
 
193
 
bool
194
 
bbox_default_in_rect(const void *pdata, const gs_fixed_rect *pbox)
195
 
{
196
 
    const gx_device_bbox *const bdev = (const gx_device_bbox *)pdata;
197
 
 
198
 
    return rect_within(*pbox, bdev->bbox);
199
 
}
200
 
#define BBOX_IN_RECT(bdev, pbox)\
201
 
    bdev->box_procs.in_rect(bdev->box_proc_data, pbox)
202
 
 
203
 
static const gx_device_bbox_procs_t box_procs_default = {
204
 
    bbox_default_init_box, bbox_default_get_box, bbox_default_add_rect,
205
 
    bbox_default_in_rect
206
 
};
207
 
 
208
 
#define RECT_IS_PAGE(dev, x, y, w, h)\
209
 
  (x <= 0 && y <= 0 && x + w >= dev->width && y + h >= dev->height)
210
 
 
211
 
     /* ---------------- Open/close/page ---------------- */
212
 
 
213
 
/* Copy device parameters back from the target. */
214
 
static void
215
 
bbox_copy_params(gx_device_bbox * bdev, bool remap_colors)
216
 
{
217
 
    gx_device *tdev = bdev->target;
218
 
 
219
 
    if (tdev != 0)
220
 
        gx_device_copy_params((gx_device *)bdev, tdev);
221
 
    if (remap_colors) {
222
 
        bdev->black = gx_device_black((gx_device *)bdev);
223
 
        bdev->white = gx_device_white((gx_device *)bdev);
224
 
        bdev->transparent =
225
 
            (bdev->white_is_opaque ? gx_no_color_index : bdev->white);
226
 
    }
227
 
}
228
 
 
229
 
#define GX_DC_IS_TRANSPARENT(pdevc, bdev)\
230
 
  (gx_dc_pure_color(pdevc) == (bdev)->transparent && gx_dc_is_pure(pdevc))
231
 
 
232
 
static int
233
 
bbox_close_device(gx_device * dev)
234
 
{
235
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
236
 
    gx_device *tdev = bdev->target;
237
 
 
238
 
    if (bdev->box_procs.init_box != box_procs_default.init_box) {
239
 
        /*
240
 
         * This device was created as a wrapper for a compositor.
241
 
         * Just free the devices.
242
 
         */
243
 
        int code = (bdev->forward_open_close ? gs_closedevice(tdev) : 0);
244
 
 
245
 
        gs_free_object(dev->memory, dev, "bbox_close_device(composite)");
246
 
        return code;
247
 
    } else {
248
 
        return (tdev && bdev->forward_open_close ? gs_closedevice(tdev) : 0);
249
 
    }
250
 
}
251
 
 
252
 
/* Initialize a bounding box device. */
253
 
void
254
 
gx_device_bbox_init(gx_device_bbox * dev, gx_device * target, gs_memory_t *mem)
255
 
{
256
 
    gx_device_init((gx_device *) dev, (const gx_device *)&gs_bbox_device,
257
 
                   (target ? target->memory : mem), true);
258
 
    if (target) {
259
 
        gx_device_forward_fill_in_procs((gx_device_forward *) dev);
260
 
        set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix);
261
 
        set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color);
262
 
        set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb);
263
 
        set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color);
264
 
        set_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color);
265
 
        set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs);
266
 
        set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index);
267
 
        set_dev_proc(dev, encode_color, gx_forward_encode_color);
268
 
        set_dev_proc(dev, decode_color, gx_forward_decode_color);
269
 
        set_dev_proc(dev, pattern_manage, gx_forward_pattern_manage);
270
 
        set_dev_proc(dev, fill_rectangle_hl_color, gx_forward_fill_rectangle_hl_color);
271
 
        set_dev_proc(dev, include_color_space, gx_forward_include_color_space);
272
 
        set_dev_proc(dev, update_spot_equivalent_colors,
273
 
                                gx_forward_update_spot_equivalent_colors);
274
 
        set_dev_proc(dev, get_page_device, gx_forward_get_page_device);
275
 
        set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params);
276
 
        gx_device_set_target((gx_device_forward *)dev, target);
277
 
    } else {
278
 
        gx_device_fill_in_procs((gx_device *)dev);
279
 
        gx_device_forward_fill_in_procs((gx_device_forward *) dev);
280
 
    }
281
 
    dev->box_procs = box_procs_default;
282
 
    dev->box_proc_data = dev;
283
 
    bbox_copy_params(dev, false);
284
 
    dev->free_standing = false; /* being used as a component */
285
 
}
286
 
 
287
 
/* Set whether a bounding box device propagates open/close to its target. */
288
 
void
289
 
gx_device_bbox_fwd_open_close(gx_device_bbox * dev, bool forward_open_close)
290
 
{
291
 
    dev->forward_open_close = forward_open_close;
292
 
}
293
 
 
294
 
/* Set whether a bounding box device considers white to be opaque. */
295
 
void
296
 
gx_device_bbox_set_white_opaque(gx_device_bbox *bdev, bool white_is_opaque)
297
 
{
298
 
    bdev->white_is_opaque = white_is_opaque;
299
 
    bdev->transparent =
300
 
        (bdev->white_is_opaque ? gx_no_color_index : bdev->white);
301
 
}
302
 
 
303
 
/* Release a bounding box device. */
304
 
void
305
 
gx_device_bbox_release(gx_device_bbox *dev)
306
 
{
307
 
    /* Just release the reference to the target. */
308
 
    gx_device_set_target((gx_device_forward *)dev, NULL);
309
 
}
310
 
 
311
 
/* Read back the bounding box in 1/72" units. */
312
 
void
313
 
gx_device_bbox_bbox(gx_device_bbox * dev, gs_rect * pbbox)
314
 
{
315
 
    gs_fixed_rect bbox;
316
 
 
317
 
    BBOX_GET_BOX(dev, &bbox);
318
 
    if (bbox.p.x > bbox.q.x || bbox.p.y > bbox.q.y) {
319
 
        /* Nothing has been written on this page. */
320
 
        pbbox->p.x = pbbox->p.y = pbbox->q.x = pbbox->q.y = 0;
321
 
    } else {
322
 
        gs_rect dbox;
323
 
        gs_matrix mat;
324
 
 
325
 
        dbox.p.x = fixed2float(bbox.p.x);
326
 
        dbox.p.y = fixed2float(bbox.p.y);
327
 
        dbox.q.x = fixed2float(bbox.q.x);
328
 
        dbox.q.y = fixed2float(bbox.q.y);
329
 
        gs_deviceinitialmatrix((gx_device *)dev, &mat);
330
 
        gs_bbox_transform_inverse(&dbox, &mat, pbbox);
331
 
    }
332
 
}
333
 
 
334
 
static int
335
 
bbox_open_device(gx_device * dev)
336
 
{
337
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
338
 
 
339
 
    if (bdev->free_standing) {
340
 
        gx_device_forward_fill_in_procs((gx_device_forward *) dev);
341
 
        bdev->box_procs = box_procs_default;
342
 
        bdev->box_proc_data = bdev;
343
 
    }
344
 
    if (bdev->box_procs.init_box == box_procs_default.init_box)
345
 
        BBOX_INIT_BOX(bdev);
346
 
    /* gx_forward_open_device doesn't exist */
347
 
    {
348
 
        gx_device *tdev = bdev->target;
349
 
        int code =
350
 
            (tdev && bdev->forward_open_close ? gs_opendevice(tdev) : 0);
351
 
 
352
 
        bbox_copy_params(bdev, true);
353
 
        return code;
354
 
    }
355
 
}
356
 
 
357
 
static int
358
 
bbox_output_page(gx_device * dev, int num_copies, int flush)
359
 
{
360
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
361
 
 
362
 
    if (bdev->free_standing) {
363
 
        /*
364
 
         * This is a free-standing device.  Print the page bounding box.
365
 
         */
366
 
        gs_rect bbox;
367
 
 
368
 
        gx_device_bbox_bbox(bdev, &bbox);
369
 
        dlprintf4("%%%%BoundingBox: %d %d %d %d\n",
370
 
                  (int)floor(bbox.p.x), (int)floor(bbox.p.y),
371
 
                  (int)ceil(bbox.q.x), (int)ceil(bbox.q.y));
372
 
        dlprintf4("%%%%HiResBoundingBox: %f %f %f %f\n",
373
 
                  bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
374
 
    }
375
 
    return gx_forward_output_page(dev, num_copies, flush);
376
 
}
377
 
 
378
 
/* ---------------- Low-level drawing ---------------- */
379
 
 
380
 
static int
381
 
bbox_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
382
 
                    gx_color_index color)
383
 
{
384
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
385
 
    gx_device *tdev = bdev->target;
386
 
    /* gx_forward_fill_rectangle doesn't exist */
387
 
    int code =
388
 
        (tdev == 0 ? 0 :
389
 
         dev_proc(tdev, fill_rectangle)(tdev, x, y, w, h, color));
390
 
 
391
 
    /* Check for erasing the entire page. */
392
 
    if (RECT_IS_PAGE(dev, x, y, w, h)) {
393
 
        if (!BBOX_INIT_BOX(bdev))
394
 
            return code;
395
 
    }
396
 
    if (color != bdev->transparent)
397
 
        BBOX_ADD_INT_RECT(bdev, x, y, x + w, y + h);
398
 
    return code;
399
 
}
400
 
 
401
 
static int
402
 
bbox_copy_mono(gx_device * dev, const byte * data,
403
 
            int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
404
 
               gx_color_index zero, gx_color_index one)
405
 
{
406
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
407
 
    /* gx_forward_copy_mono doesn't exist */
408
 
    gx_device *tdev = bdev->target;
409
 
    int code =
410
 
        (tdev == 0 ? 0 :
411
 
         dev_proc(tdev, copy_mono)
412
 
         (tdev, data, dx, raster, id, x, y, w, h, zero, one));
413
 
 
414
 
    if ((one != gx_no_color_index && one != bdev->transparent) ||
415
 
        (zero != gx_no_color_index && zero != bdev->transparent)
416
 
        )
417
 
        BBOX_ADD_INT_RECT(bdev, x, y, x + w, y + h);
418
 
    return code;
419
 
}
420
 
 
421
 
static int
422
 
bbox_copy_color(gx_device * dev, const byte * data,
423
 
            int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h)
424
 
{
425
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
426
 
    /* gx_forward_copy_color doesn't exist */
427
 
    gx_device *tdev = bdev->target;
428
 
    int code =
429
 
        (tdev == 0 ? 0 :
430
 
         dev_proc(tdev, copy_color)
431
 
         (tdev, data, dx, raster, id, x, y, w, h));
432
 
 
433
 
    BBOX_ADD_INT_RECT(bdev, x, y, x + w, y + h);
434
 
    return code;
435
 
}
436
 
 
437
 
static int
438
 
bbox_copy_alpha(gx_device * dev, const byte * data, int data_x,
439
 
                int raster, gx_bitmap_id id, int x, int y, int w, int h,
440
 
                gx_color_index color, int depth)
441
 
{
442
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
443
 
    /* gx_forward_copy_alpha doesn't exist */
444
 
    gx_device *tdev = bdev->target;
445
 
    int code =
446
 
        (tdev == 0 ? 0 :
447
 
         dev_proc(tdev, copy_alpha)
448
 
         (tdev, data, data_x, raster, id, x, y, w, h, color, depth));
449
 
 
450
 
    BBOX_ADD_INT_RECT(bdev, x, y, x + w, y + h);
451
 
    return code;
452
 
}
453
 
 
454
 
static int
455
 
bbox_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
456
 
   int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
457
 
                          int px, int py)
458
 
{
459
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
460
 
    /* Skip the call if there is no target. */
461
 
    gx_device *tdev = bdev->target;
462
 
    int code =
463
 
        (tdev == 0 ? 0 :
464
 
         dev_proc(tdev, strip_tile_rectangle)
465
 
         (tdev, tiles, x, y, w, h, color0, color1, px, py));
466
 
 
467
 
    if (RECT_IS_PAGE(dev, x, y, w, h)) {
468
 
        if (!BBOX_INIT_BOX(bdev))
469
 
            return code;
470
 
    }
471
 
    BBOX_ADD_INT_RECT(bdev, x, y, x + w, y + h);
472
 
    return code;
473
 
}
474
 
 
475
 
static int
476
 
bbox_strip_copy_rop(gx_device * dev,
477
 
                    const byte * sdata, int sourcex, uint sraster,
478
 
                    gx_bitmap_id id,
479
 
                    const gx_color_index * scolors,
480
 
                    const gx_strip_bitmap * textures,
481
 
                    const gx_color_index * tcolors,
482
 
                    int x, int y, int w, int h,
483
 
                    int phase_x, int phase_y, gs_logical_operation_t lop)
484
 
{
485
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
486
 
    /* gx_forward_strip_copy_rop doesn't exist */
487
 
    gx_device *tdev = bdev->target;
488
 
    int code =
489
 
        (tdev == 0 ? 0 :
490
 
         dev_proc(tdev, strip_copy_rop)
491
 
         (tdev, sdata, sourcex, sraster, id, scolors,
492
 
          textures, tcolors, x, y, w, h, phase_x, phase_y, lop));
493
 
 
494
 
    BBOX_ADD_INT_RECT(bdev, x, y, x + w, y + h);
495
 
    return code;
496
 
}
497
 
 
498
 
/* ---------------- Parameters ---------------- */
499
 
 
500
 
/* We implement get_params to provide a way to read out the bounding box. */
501
 
static int
502
 
bbox_get_params(gx_device * dev, gs_param_list * plist)
503
 
{
504
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
505
 
    gs_fixed_rect fbox;
506
 
    int code = gx_forward_get_params(dev, plist);
507
 
    gs_param_float_array bba;
508
 
    float bbox[4];
509
 
 
510
 
    if (code < 0)
511
 
        return code;
512
 
    /*
513
 
     * We might be calling get_params before the device has been
514
 
     * initialized: in this case, box_proc_data = 0.
515
 
     */
516
 
    if (bdev->box_proc_data == 0)
517
 
        fbox = bdev->bbox;
518
 
    else
519
 
        BBOX_GET_BOX(bdev, &fbox);
520
 
    bbox[0] = fixed2float(fbox.p.x);
521
 
    bbox[1] = fixed2float(fbox.p.y);
522
 
    bbox[2] = fixed2float(fbox.q.x);
523
 
    bbox[3] = fixed2float(fbox.q.y);
524
 
    bba.data = bbox, bba.size = 4, bba.persistent = false;
525
 
    code = param_write_float_array(plist, "PageBoundingBox", &bba);
526
 
    if (code < 0)
527
 
        return code;
528
 
    code = param_write_bool(plist, "WhiteIsOpaque", &bdev->white_is_opaque);
529
 
    return code;
530
 
}
531
 
 
532
 
/* We implement put_params to ensure that we keep the important */
533
 
/* device parameters up to date, and to prevent an /undefined error */
534
 
/* from PageBoundingBox. */
535
 
static int
536
 
bbox_put_params(gx_device * dev, gs_param_list * plist)
537
 
{
538
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
539
 
    int code;
540
 
    int ecode = 0;
541
 
    bool white_is_opaque = bdev->white_is_opaque;
542
 
    gs_param_name param_name;
543
 
    gs_param_float_array bba;
544
 
 
545
 
    code = param_read_float_array(plist, (param_name = "PageBoundingBox"),
546
 
                                  &bba);
547
 
    switch (code) {
548
 
        case 0:
549
 
            if (bba.size != 4) {
550
 
                ecode = gs_note_error(gs_error_rangecheck);
551
 
                goto e;
552
 
            }
553
 
            break;
554
 
        default:
555
 
            ecode = code;
556
 
            e:param_signal_error(plist, param_name, ecode);
557
 
        case 1:
558
 
            bba.data = 0;
559
 
    }
560
 
 
561
 
    switch (code = param_read_bool(plist, (param_name = "WhiteIsOpaque"), &white_is_opaque)) {
562
 
        default:
563
 
            ecode = code;
564
 
            param_signal_error(plist, param_name, ecode);
565
 
        case 0:
566
 
        case 1:
567
 
            break;
568
 
    }
569
 
 
570
 
    code = gx_forward_put_params(dev, plist);
571
 
    if (ecode < 0)
572
 
        code = ecode;
573
 
    if (code >= 0) {
574
 
        if( bba.data != 0) {
575
 
            BBOX_INIT_BOX(bdev);
576
 
            BBOX_ADD_RECT(bdev, float2fixed(bba.data[0]), float2fixed(bba.data[1]),
577
 
                          float2fixed(bba.data[2]), float2fixed(bba.data[3]));
578
 
        }
579
 
        bdev->white_is_opaque = white_is_opaque;
580
 
    }
581
 
    bbox_copy_params(bdev, bdev->is_open);
582
 
    return code;
583
 
}
584
 
 
585
 
/* ---------------- Polygon drawing ---------------- */
586
 
 
587
 
static fixed
588
 
edge_x_at_y(const gs_fixed_edge * edge, fixed y)
589
 
{
590
 
    return fixed_mult_quo(edge->end.x - edge->start.x,
591
 
                          y - edge->start.y,
592
 
                          edge->end.y - edge->start.y) + edge->start.x;
593
 
}
594
 
static int
595
 
bbox_fill_trapezoid(gx_device * dev,
596
 
                    const gs_fixed_edge * left, const gs_fixed_edge * right,
597
 
                    fixed ybot, fixed ytop, bool swap_axes,
598
 
                    const gx_device_color * pdevc, gs_logical_operation_t lop)
599
 
{
600
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
601
 
    /* Skip the call if there is no target. */
602
 
    gx_device *tdev = bdev->target;
603
 
    int code =
604
 
        (tdev == 0 ? 0 :
605
 
         dev_proc(tdev, fill_trapezoid)
606
 
         (tdev, left, right, ybot, ytop, swap_axes, pdevc, lop));
607
 
 
608
 
    if (!GX_DC_IS_TRANSPARENT(pdevc, bdev)) {
609
 
        fixed x0l =
610
 
            (left->start.y == ybot ? left->start.x :
611
 
             edge_x_at_y(left, ybot));
612
 
        fixed x1l =
613
 
            (left->end.y == ytop ? left->end.x :
614
 
             edge_x_at_y(left, ytop));
615
 
        fixed x0r =
616
 
            (right->start.y == ybot ? right->start.x :
617
 
             edge_x_at_y(right, ybot));
618
 
        fixed x1r =
619
 
            (right->end.y == ytop ? right->end.x :
620
 
             edge_x_at_y(right, ytop));
621
 
        fixed xminl = min(x0l, x1l), xmaxl = max(x0l, x1l);
622
 
        fixed xminr = min(x0r, x1r), xmaxr = max(x0r, x1r);
623
 
        fixed x0 = min(xminl, xminr), x1 = max(xmaxl, xmaxr);
624
 
 
625
 
        if (swap_axes)
626
 
            BBOX_ADD_RECT(bdev, ybot, x0, ytop, x1);
627
 
        else
628
 
            BBOX_ADD_RECT(bdev, x0, ybot, x1, ytop);
629
 
    }
630
 
    return code;
631
 
}
632
 
 
633
 
static int
634
 
bbox_fill_parallelogram(gx_device * dev,
635
 
                        fixed px, fixed py, fixed ax, fixed ay,
636
 
                        fixed bx, fixed by, const gx_device_color * pdevc,
637
 
                        gs_logical_operation_t lop)
638
 
{
639
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
640
 
    /* Skip the call if there is no target. */
641
 
    gx_device *tdev = bdev->target;
642
 
    int code =
643
 
        (tdev == 0 ? 0 :
644
 
         dev_proc(tdev, fill_parallelogram)
645
 
         (tdev, px, py, ax, ay, bx, by, pdevc, lop));
646
 
 
647
 
    if (!GX_DC_IS_TRANSPARENT(pdevc, bdev)) {
648
 
        fixed xmin, ymin, xmax, ymax;
649
 
 
650
 
        /* bbox_add_rect requires points in correct order. */
651
 
#define SET_MIN_MAX(vmin, vmax, av, bv)\
652
 
  BEGIN\
653
 
    if (av <= 0) {\
654
 
        if (bv <= 0)\
655
 
            vmin = av + bv, vmax = 0;\
656
 
        else\
657
 
            vmin = av, vmax = bv;\
658
 
    } else if (bv <= 0)\
659
 
        vmin = bv, vmax = av;\
660
 
    else\
661
 
        vmin = 0, vmax = av + bv;\
662
 
  END
663
 
        SET_MIN_MAX(xmin, xmax, ax, bx);
664
 
        SET_MIN_MAX(ymin, ymax, ay, by);
665
 
#undef SET_MIN_MAX
666
 
        BBOX_ADD_RECT(bdev, px + xmin, py + ymin, px + xmax, py + ymax);
667
 
    }
668
 
    return code;
669
 
}
670
 
 
671
 
static int
672
 
bbox_fill_triangle(gx_device * dev,
673
 
                   fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
674
 
                   const gx_device_color * pdevc, gs_logical_operation_t lop)
675
 
{
676
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
677
 
    /* Skip the call if there is no target. */
678
 
    gx_device *tdev = bdev->target;
679
 
    int code =
680
 
        (tdev == 0 ? 0 :
681
 
         dev_proc(tdev, fill_triangle)
682
 
         (tdev, px, py, ax, ay, bx, by, pdevc, lop));
683
 
 
684
 
    if (!GX_DC_IS_TRANSPARENT(pdevc, bdev)) {
685
 
        fixed xmin, ymin, xmax, ymax;
686
 
 
687
 
        /* bbox_add_rect requires points in correct order. */
688
 
#define SET_MIN_MAX(vmin, vmax, av, bv)\
689
 
  BEGIN\
690
 
    if (av <= 0) {\
691
 
        if (bv <= 0)\
692
 
            vmin = min(av, bv), vmax = 0;\
693
 
        else\
694
 
            vmin = av, vmax = bv;\
695
 
    } else if (bv <= 0)\
696
 
        vmin = bv, vmax = av;\
697
 
    else\
698
 
        vmin = 0, vmax = max(av, bv);\
699
 
  END
700
 
        SET_MIN_MAX(xmin, xmax, ax, bx);
701
 
        SET_MIN_MAX(ymin, ymax, ay, by);
702
 
#undef SET_MIN_MAX
703
 
        BBOX_ADD_RECT(bdev, px + xmin, py + ymin, px + xmax, py + ymax);
704
 
    }
705
 
    return code;
706
 
}
707
 
 
708
 
static int
709
 
bbox_draw_thin_line(gx_device * dev,
710
 
                    fixed fx0, fixed fy0, fixed fx1, fixed fy1,
711
 
                    const gx_device_color * pdevc, gs_logical_operation_t lop)
712
 
{
713
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
714
 
    /* Skip the call if there is no target. */
715
 
    gx_device *tdev = bdev->target;
716
 
    int code =
717
 
        (tdev == 0 ? 0 :
718
 
         dev_proc(tdev, draw_thin_line)
719
 
         (tdev, fx0, fy0, fx1, fy0, pdevc, lop));
720
 
 
721
 
    if (!GX_DC_IS_TRANSPARENT(pdevc, bdev)) {
722
 
        fixed xmin, ymin, xmax, ymax;
723
 
 
724
 
        /* bbox_add_rect requires points in correct order. */
725
 
#define SET_MIN_MAX(vmin, vmax, av, bv)\
726
 
  BEGIN\
727
 
    if (av < bv)\
728
 
        vmin = av, vmax = bv;\
729
 
    else\
730
 
        vmin = bv, vmax = av;\
731
 
  END
732
 
        SET_MIN_MAX(xmin, xmax, fx0, fx1);
733
 
        SET_MIN_MAX(ymin, ymax, fy0, fy1);
734
 
#undef SET_MIN_MAX
735
 
        BBOX_ADD_RECT(bdev, xmin, ymin, xmax, ymax);
736
 
    }
737
 
    return code;
738
 
}
739
 
 
740
 
/* ---------------- High-level drawing ---------------- */
741
 
 
742
 
#define adjust_box(pbox, adj)\
743
 
((pbox)->p.x -= (adj).x, (pbox)->p.y -= (adj).y,\
744
 
 (pbox)->q.x += (adj).x, (pbox)->q.y += (adj).y)
745
 
 
746
 
static int
747
 
bbox_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
748
 
               const gx_fill_params * params, const gx_device_color * pdevc,
749
 
               const gx_clip_path * pcpath)
750
 
{
751
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
752
 
    gx_device *tdev = bdev->target;
753
 
    dev_proc_fill_path((*fill_path)) =
754
 
        (tdev == 0 ? dev_proc(&gs_null_device, fill_path) :
755
 
         dev_proc(tdev, fill_path));
756
 
    int code;
757
 
 
758
 
    if (ppath == NULL) {
759
 
        /* A special handling of shfill with no path. */
760
 
        gs_fixed_rect ibox;
761
 
        gs_fixed_point adjust;
762
 
 
763
 
        if (pcpath == NULL)
764
 
            return 0;
765
 
        gx_cpath_inner_box(pcpath, &ibox);
766
 
        adjust = params->adjust;
767
 
        if (params->fill_zero_width)
768
 
            gx_adjust_if_empty(&ibox, &adjust);
769
 
        adjust_box(&ibox, adjust);
770
 
        BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
771
 
        return 0;
772
 
    } else if (!GX_DC_IS_TRANSPARENT(pdevc, bdev) && !gx_path_is_void(ppath)) {
773
 
        gs_fixed_rect ibox;
774
 
        gs_fixed_point adjust;
775
 
 
776
 
        if (gx_path_bbox(ppath, &ibox) < 0)
777
 
            return 0;
778
 
        adjust = params->adjust;
779
 
        if (params->fill_zero_width)
780
 
            gx_adjust_if_empty(&ibox, &adjust);
781
 
        adjust_box(&ibox, adjust);
782
 
        /*
783
 
         * If the path lies within the already accumulated box, just draw
784
 
         * on the target.
785
 
         */
786
 
        if (BBOX_IN_RECT(bdev, &ibox))
787
 
            return fill_path(tdev, pis, ppath, params, pdevc, pcpath);
788
 
        /*
789
 
         * If the target uses the default algorithm, just draw on the
790
 
         * bbox device.
791
 
         */
792
 
        if (tdev != 0 && fill_path == gx_default_fill_path)
793
 
            return fill_path(dev, pis, ppath, params, pdevc, pcpath);
794
 
        /* Draw on the target now. */
795
 
        code = fill_path(tdev, pis, ppath, params, pdevc, pcpath);
796
 
        if (code < 0)
797
 
            return code;
798
 
        if (pcpath != NULL &&
799
 
            !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
800
 
                                         ibox.q.x, ibox.q.y)
801
 
            ) {
802
 
            /*
803
 
             * Let the target do the drawing, but break down the
804
 
             * fill path into pieces for computing the bounding box.
805
 
             */
806
 
            gx_drawing_color devc;
807
 
 
808
 
            set_nonclient_dev_color(&devc, bdev->black);  /* any non-white color will do */
809
 
            bdev->target = NULL;
810
 
            code = gx_default_fill_path(dev, pis, ppath, params, &devc, pcpath);
811
 
            bdev->target = tdev;
812
 
        } else {                /* Just use the path bounding box. */
813
 
            BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
814
 
        }
815
 
        return code;
816
 
    } else
817
 
        return fill_path(tdev, pis, ppath, params, pdevc, pcpath);
818
 
}
819
 
 
820
 
static int
821
 
bbox_stroke_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
822
 
                 const gx_stroke_params * params,
823
 
                 const gx_drawing_color * pdevc, const gx_clip_path * pcpath)
824
 
{
825
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
826
 
    gx_device *tdev = bdev->target;
827
 
    /* Skip the call if there is no target. */
828
 
    int code =
829
 
        (tdev == 0 ? 0 :
830
 
         dev_proc(tdev, stroke_path)(tdev, pis, ppath, params, pdevc, pcpath));
831
 
 
832
 
    if (!GX_DC_IS_TRANSPARENT(pdevc, bdev)) {
833
 
        gs_fixed_rect ibox;
834
 
        gs_fixed_point expand;
835
 
 
836
 
        if (gx_stroke_path_expansion(pis, ppath, &expand) == 0 &&
837
 
            gx_path_bbox(ppath, &ibox) >= 0
838
 
            ) {
839
 
            /* The fast result is exact. */
840
 
            adjust_box(&ibox, expand);
841
 
        } else {
842
 
            /*
843
 
             * The result is not exact.  Compute an exact result using
844
 
             * strokepath.
845
 
             */
846
 
            gx_path *spath = gx_path_alloc(pis->memory, "bbox_stroke_path");
847
 
            int code = 0;
848
 
 
849
 
            if (spath)
850
 
                code = gx_imager_stroke_add(ppath, spath, dev, pis);
851
 
            else
852
 
                code = -1;
853
 
            if (code >= 0)
854
 
                code = gx_path_bbox(spath, &ibox);
855
 
            if (code < 0) {
856
 
                ibox.p.x = ibox.p.y = min_fixed;
857
 
                ibox.q.x = ibox.q.y = max_fixed;
858
 
            }
859
 
            if (spath)
860
 
                gx_path_free(spath, "bbox_stroke_path");
861
 
        }
862
 
        if (pcpath != NULL &&
863
 
            !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
864
 
                                         ibox.q.x, ibox.q.y)
865
 
            ) {
866
 
            /* Let the target do the drawing, but break down the */
867
 
            /* fill path into pieces for computing the bounding box. */
868
 
            gx_drawing_color devc;
869
 
 
870
 
            set_nonclient_dev_color(&devc, bdev->black);  /* any non-white color will do */
871
 
            bdev->target = NULL;
872
 
            gx_default_stroke_path(dev, pis, ppath, params, &devc, pcpath);
873
 
            bdev->target = tdev;
874
 
        } else {
875
 
            /* Just use the path bounding box. */
876
 
            BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
877
 
        }
878
 
    }
879
 
    return code;
880
 
}
881
 
 
882
 
static int
883
 
bbox_fill_mask(gx_device * dev,
884
 
               const byte * data, int dx, int raster, gx_bitmap_id id,
885
 
               int x, int y, int w, int h,
886
 
               const gx_drawing_color * pdcolor, int depth,
887
 
               gs_logical_operation_t lop, const gx_clip_path * pcpath)
888
 
{
889
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
890
 
    gx_device *tdev = bdev->target;
891
 
    /* Skip the call if there is no target. */
892
 
    int code =
893
 
        (tdev == 0 ? 0 :
894
 
         dev_proc(tdev, fill_mask)
895
 
         (tdev, data, dx, raster, id, x, y, w, h,
896
 
          pdcolor, depth, lop, pcpath));
897
 
 
898
 
    if (pcpath != NULL &&
899
 
        !gx_cpath_includes_rectangle(pcpath, int2fixed(x), int2fixed(y),
900
 
                                     int2fixed(x + w),
901
 
                                     int2fixed(y + h))
902
 
        ) {
903
 
        /* Let the target do the drawing, but break down the */
904
 
        /* image into pieces for computing the bounding box. */
905
 
        bdev->target = NULL;
906
 
        gx_default_fill_mask(dev, data, dx, raster, id, x, y, w, h,
907
 
                             pdcolor, depth, lop, pcpath);
908
 
        bdev->target = tdev;
909
 
    } else {
910
 
        /* Just use the mask bounding box. */
911
 
        BBOX_ADD_INT_RECT(bdev, x, y, x + w, y + h);
912
 
    }
913
 
    return code;
914
 
}
915
 
 
916
 
/* ------ Bitmap imaging ------ */
917
 
 
918
 
typedef struct bbox_image_enum_s {
919
 
    gx_image_enum_common;
920
 
    gs_matrix matrix;           /* map from image space to device space */
921
 
    const gx_clip_path *pcpath;
922
 
    gx_image_enum_common_t *target_info;
923
 
    bool params_are_const;
924
 
    int x0, x1;
925
 
    int y, height;
926
 
} bbox_image_enum;
927
 
 
928
 
gs_private_st_suffix_add2(st_bbox_image_enum, bbox_image_enum,
929
 
  "bbox_image_enum", bbox_image_enum_enum_ptrs, bbox_image_enum_reloc_ptrs,
930
 
  st_gx_image_enum_common, pcpath, target_info);
931
 
 
932
 
static image_enum_proc_plane_data(bbox_image_plane_data);
933
 
static image_enum_proc_end_image(bbox_image_end_image);
934
 
static image_enum_proc_flush(bbox_image_flush);
935
 
static image_enum_proc_planes_wanted(bbox_image_planes_wanted);
936
 
static const gx_image_enum_procs_t bbox_image_enum_procs = {
937
 
    bbox_image_plane_data, bbox_image_end_image,
938
 
    bbox_image_flush, bbox_image_planes_wanted
939
 
};
940
 
 
941
 
static int
942
 
bbox_image_begin(const gs_imager_state * pis, const gs_matrix * pmat,
943
 
                 const gs_image_common_t * pic, const gs_int_rect * prect,
944
 
                 const gx_clip_path * pcpath, gs_memory_t * memory,
945
 
                 bbox_image_enum ** ppbe)
946
 
{
947
 
    int code;
948
 
    gs_matrix mat;
949
 
    bbox_image_enum *pbe;
950
 
 
951
 
    if (pmat == 0)
952
 
        pmat = &ctm_only(pis);
953
 
    if ((code = gs_matrix_invert(&pic->ImageMatrix, &mat)) < 0 ||
954
 
        (code = gs_matrix_multiply(&mat, pmat, &mat)) < 0
955
 
        )
956
 
        return code;
957
 
    pbe = gs_alloc_struct(memory, bbox_image_enum, &st_bbox_image_enum,
958
 
                          "bbox_image_begin");
959
 
    if (pbe == 0)
960
 
        return_error(gs_error_VMerror);
961
 
    pbe->memory = memory;
962
 
    pbe->matrix = mat;
963
 
    pbe->pcpath = pcpath;
964
 
    pbe->target_info = 0;       /* in case no target */
965
 
    pbe->params_are_const = false;      /* check the first time */
966
 
    if (prect) {
967
 
        pbe->x0 = prect->p.x, pbe->x1 = prect->q.x;
968
 
        pbe->y = prect->p.y, pbe->height = prect->q.y - prect->p.y;
969
 
    } else {
970
 
        gs_int_point size;
971
 
        int code = (*pic->type->source_size) (pis, pic, &size);
972
 
 
973
 
        if (code < 0) {
974
 
            gs_free_object(memory, pbe, "bbox_image_begin");
975
 
            return code;
976
 
        }
977
 
        pbe->x0 = 0, pbe->x1 = size.x;
978
 
        pbe->y = 0, pbe->height = size.y;
979
 
    }
980
 
    *ppbe = pbe;
981
 
    return 0;
982
 
}
983
 
 
984
 
static void
985
 
bbox_image_copy_target_info(bbox_image_enum * pbe)
986
 
{
987
 
    const gx_image_enum_common_t *target_info = pbe->target_info;
988
 
 
989
 
    pbe->num_planes = target_info->num_planes;
990
 
    memcpy(pbe->plane_depths, target_info->plane_depths,
991
 
           pbe->num_planes * sizeof(pbe->plane_depths[0]));
992
 
    memcpy(pbe->plane_widths, target_info->plane_widths,
993
 
           pbe->num_planes * sizeof(pbe->plane_widths[0]));
994
 
}
995
 
 
996
 
static int
997
 
bbox_begin_typed_image(gx_device * dev,
998
 
                       const gs_imager_state * pis, const gs_matrix * pmat,
999
 
                   const gs_image_common_t * pic, const gs_int_rect * prect,
1000
 
                       const gx_drawing_color * pdcolor,
1001
 
                       const gx_clip_path * pcpath,
1002
 
                       gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
1003
 
{
1004
 
    bbox_image_enum *pbe;
1005
 
    int code =
1006
 
        bbox_image_begin(pis, pmat, pic, prect, pcpath, memory, &pbe);
1007
 
 
1008
 
    if (code < 0)
1009
 
        return code;
1010
 
    /*
1011
 
     * If there is no target, we still have to call default_begin_image
1012
 
     * to get the correct num_planes and plane_depths.
1013
 
     */
1014
 
    {
1015
 
        gx_device_bbox *const bdev = (gx_device_bbox *) dev;
1016
 
        gx_device *tdev = bdev->target;
1017
 
        dev_proc_begin_typed_image((*begin_typed_image));
1018
 
        byte wanted[GS_IMAGE_MAX_COMPONENTS];
1019
 
 
1020
 
        if (tdev == 0) {
1021
 
            tdev = dev;
1022
 
            begin_typed_image = gx_default_begin_typed_image;
1023
 
        } else {
1024
 
            begin_typed_image = dev_proc(tdev, begin_typed_image);
1025
 
        }
1026
 
        code = (*begin_typed_image)
1027
 
            (tdev, pis, pmat, pic, prect, pdcolor, pcpath, memory,
1028
 
             &pbe->target_info);
1029
 
        if (code) {
1030
 
            bbox_image_end_image((gx_image_enum_common_t *)pbe, false);
1031
 
            return code;
1032
 
        }
1033
 
        /*
1034
 
         * We fill in num_planes and plane_depths later.  format is
1035
 
         * irrelevant.  NOTE: we assume that if begin_typed_image returned
1036
 
         * 0, the image is a data image.
1037
 
         */
1038
 
        code = gx_image_enum_common_init((gx_image_enum_common_t *) pbe,
1039
 
                                         (const gs_data_image_t *)pic,
1040
 
                                         &bbox_image_enum_procs, dev,
1041
 
                                         0, gs_image_format_chunky);
1042
 
        if (code < 0)
1043
 
            return code;
1044
 
        bbox_image_copy_target_info(pbe);
1045
 
        pbe->params_are_const =
1046
 
            gx_image_planes_wanted(pbe->target_info, wanted);
1047
 
    }
1048
 
    *pinfo = (gx_image_enum_common_t *) pbe;
1049
 
    return 0;
1050
 
}
1051
 
 
1052
 
static int
1053
 
bbox_image_plane_data(gx_image_enum_common_t * info,
1054
 
                      const gx_image_plane_t * planes, int height,
1055
 
                      int *rows_used)
1056
 
{
1057
 
    gx_device *dev = info->dev;
1058
 
    gx_device_bbox *const bdev = (gx_device_bbox *)dev;
1059
 
    gx_device *tdev = bdev->target;
1060
 
    bbox_image_enum *pbe = (bbox_image_enum *) info;
1061
 
    const gx_clip_path *pcpath = pbe->pcpath;
1062
 
    gs_rect sbox, dbox;
1063
 
    gs_point corners[4];
1064
 
    gs_fixed_rect ibox;
1065
 
    int code;
1066
 
 
1067
 
    code = gx_image_plane_data_rows(pbe->target_info, planes, height,
1068
 
                                    rows_used);
1069
 
    if (code != 1 && !pbe->params_are_const)
1070
 
        bbox_image_copy_target_info(pbe);
1071
 
    sbox.p.x = pbe->x0;
1072
 
    sbox.p.y = pbe->y;
1073
 
    sbox.q.x = pbe->x1;
1074
 
    sbox.q.y = pbe->y = min(pbe->y + height, pbe->height);
1075
 
    gs_bbox_transform_only(&sbox, &pbe->matrix, corners);
1076
 
    gs_points_bbox(corners, &dbox);
1077
 
    ibox.p.x = float2fixed(dbox.p.x);
1078
 
    ibox.p.y = float2fixed(dbox.p.y);
1079
 
    ibox.q.x = float2fixed(dbox.q.x);
1080
 
    ibox.q.y = float2fixed(dbox.q.y);
1081
 
    if (pcpath != NULL &&
1082
 
        !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
1083
 
                                     ibox.q.x, ibox.q.y)
1084
 
        ) {
1085
 
        /* Let the target do the drawing, but drive two triangles */
1086
 
        /* through the clipping path to get an accurate bounding box. */
1087
 
        gx_device_clip cdev;
1088
 
        gx_drawing_color devc;
1089
 
        fixed x0 = float2fixed(corners[0].x), y0 = float2fixed(corners[0].y);
1090
 
        fixed bx2 = float2fixed(corners[2].x) - x0, by2 = float2fixed(corners[2].y) - y0;
1091
 
 
1092
 
        gx_make_clip_device_on_stack(&cdev, pcpath, dev);
1093
 
        set_nonclient_dev_color(&devc, bdev->black);  /* any non-white color will do */
1094
 
        bdev->target = NULL;
1095
 
        gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
1096
 
                                 float2fixed(corners[1].x) - x0,
1097
 
                                 float2fixed(corners[1].y) - y0,
1098
 
                                 bx2, by2, &devc, lop_default);
1099
 
        gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
1100
 
                                 float2fixed(corners[3].x) - x0,
1101
 
                                 float2fixed(corners[3].y) - y0,
1102
 
                                 bx2, by2, &devc, lop_default);
1103
 
        bdev->target = tdev;
1104
 
    } else {
1105
 
        /* Just use the bounding box. */
1106
 
        BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
1107
 
    }
1108
 
    return code;
1109
 
}
1110
 
 
1111
 
static int
1112
 
bbox_image_end_image(gx_image_enum_common_t * info, bool draw_last)
1113
 
{
1114
 
    bbox_image_enum *pbe = (bbox_image_enum *) info;
1115
 
    int code = gx_image_end(pbe->target_info, draw_last);
1116
 
 
1117
 
    gx_image_free_enum(&info);
1118
 
    return code;
1119
 
}
1120
 
 
1121
 
static int
1122
 
bbox_image_flush(gx_image_enum_common_t * info)
1123
 
{
1124
 
    bbox_image_enum *pbe = (bbox_image_enum *) info;
1125
 
    gx_image_enum_common_t *target_info = pbe->target_info;
1126
 
 
1127
 
    return (target_info ? gx_image_flush(target_info) : 0);
1128
 
}
1129
 
 
1130
 
static bool
1131
 
bbox_image_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
1132
 
{
1133
 
    /* This is only used if target_info != 0. */
1134
 
    const bbox_image_enum *pbe = (const bbox_image_enum *)info;
1135
 
    
1136
 
    return gx_image_planes_wanted(pbe->target_info, wanted);
1137
 
}
1138
 
 
1139
 
/* Compositing */
1140
 
 
1141
 
static bool
1142
 
bbox_forward_init_box(void *pdata)
1143
 
{
1144
 
    gx_device_bbox *const bdev = (gx_device_bbox *)pdata;
1145
 
 
1146
 
    return BBOX_INIT_BOX(bdev);
1147
 
}
1148
 
static void
1149
 
bbox_forward_get_box(const void *pdata, gs_fixed_rect *pbox)
1150
 
{
1151
 
    const gx_device_bbox *const bdev = (const gx_device_bbox *)pdata;
1152
 
 
1153
 
    BBOX_GET_BOX(bdev, pbox);
1154
 
}
1155
 
static void
1156
 
bbox_forward_add_rect(void *pdata, fixed x0, fixed y0, fixed x1, fixed y1)
1157
 
{
1158
 
    gx_device_bbox *const bdev = (gx_device_bbox *)pdata;
1159
 
 
1160
 
    BBOX_ADD_RECT(bdev, x0, y0, x1, y1);
1161
 
}
1162
 
static bool
1163
 
bbox_forward_in_rect(const void *pdata, const gs_fixed_rect *pbox)
1164
 
{
1165
 
    const gx_device_bbox *const bdev = (const gx_device_bbox *)pdata;
1166
 
 
1167
 
    return BBOX_IN_RECT(bdev, pbox);
1168
 
}
1169
 
static const gx_device_bbox_procs_t box_procs_forward = {
1170
 
    bbox_forward_init_box, bbox_forward_get_box, bbox_forward_add_rect,
1171
 
    bbox_forward_in_rect
1172
 
};
1173
 
 
1174
 
static int
1175
 
bbox_create_compositor(gx_device * dev,
1176
 
                       gx_device ** pcdev, const gs_composite_t * pcte,
1177
 
                       gs_imager_state * pis, gs_memory_t * memory)
1178
 
{
1179
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
1180
 
    gx_device *target = bdev->target;
1181
 
 
1182
 
    /*
1183
 
     * If there isn't a target, all we care about is the bounding box,
1184
 
     * so don't bother with actually compositing.
1185
 
     */
1186
 
    if (target == 0) {
1187
 
        *pcdev = dev;
1188
 
        return 0;
1189
 
    }
1190
 
    /*
1191
 
     * Create a compositor for the target, and then wrap another
1192
 
     * bbox device around it, but still accumulating the bounding
1193
 
     * box in the same place.
1194
 
     */
1195
 
    {
1196
 
        gx_device *cdev;
1197
 
        gx_device_bbox *bbcdev;
1198
 
        int code = (*dev_proc(target, create_compositor))
1199
 
            (target, &cdev, pcte, pis, memory);
1200
 
 
1201
 
        /* If the target did not create a new compositor then we are done. */
1202
 
        if (code < 0 || target == cdev) {
1203
 
            *pcdev = dev;
1204
 
            return code;
1205
 
        }
1206
 
        bbcdev = gs_alloc_struct_immovable(memory, gx_device_bbox,
1207
 
                                           &st_device_bbox,
1208
 
                                           "bbox_create_compositor");
1209
 
        if (bbcdev == 0) {
1210
 
            (*dev_proc(cdev, close_device)) (cdev);
1211
 
            return_error(gs_error_VMerror);
1212
 
        }
1213
 
        gx_device_bbox_init(bbcdev, target, memory);
1214
 
        gx_device_set_target((gx_device_forward *)bbcdev, cdev);
1215
 
        bbcdev->box_procs = box_procs_forward;
1216
 
        bbcdev->box_proc_data = bdev;
1217
 
        *pcdev = (gx_device *) bbcdev;
1218
 
        return 0;
1219
 
    }
1220
 
}
1221
 
 
1222
 
/* ------ Text imaging ------ */
1223
 
 
1224
 
static int
1225
 
bbox_text_begin(gx_device * dev, gs_imager_state * pis,
1226
 
                const gs_text_params_t * text, gs_font * font,
1227
 
                gx_path * path, const gx_device_color * pdcolor,
1228
 
                const gx_clip_path * pcpath,
1229
 
                gs_memory_t * memory, gs_text_enum_t ** ppenum)
1230
 
{
1231
 
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
1232
 
    int code = gx_default_text_begin(dev, pis, text, font, path, pdcolor,
1233
 
                                     pcpath, memory, ppenum);
1234
 
 
1235
 
    if (bdev->target != NULL) {
1236
 
        /* See note on imaging_dev in gxtext.h */
1237
 
        rc_assign((*ppenum)->imaging_dev, dev, "bbox_text_begin");
1238
 
    }
1239
 
 
1240
 
    return code;
1241
 
}
1242