home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / UsingPDF / GhostScript / source / gs5.10 / gdevbbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-03  |  23.5 KB  |  758 lines

  1. /* Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevbbox.c */
  20. /* Device for tracking bounding box */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gsparam.h"
  26. #include "gxdevice.h"
  27. #include "gsdevice.h"        /* requires gsmatrix.h */
  28. #include "gdevbbox.h"
  29. #include "gxistate.h"
  30. #include "gxpaint.h"
  31. #include "gxpath.h"
  32. #include "gxcpath.h"
  33.  
  34. /* Define TEST to create an output_page procedure for testing. */
  35. /*#define TEST*/
  36.  
  37. /* GC descriptor */
  38. public_st_device_bbox();
  39.  
  40. /* Device procedures */
  41. private dev_proc_open_device(bbox_open_device);
  42. private dev_proc_close_device(gx_forward_close_device);    /* see below */
  43. private dev_proc_output_page(bbox_output_page);
  44. private dev_proc_fill_rectangle(bbox_fill_rectangle);
  45. private dev_proc_copy_mono(bbox_copy_mono);
  46. private dev_proc_copy_color(bbox_copy_color);
  47. private dev_proc_draw_line(bbox_draw_line);
  48. private dev_proc_get_params(bbox_get_params);
  49. private dev_proc_put_params(bbox_put_params);
  50. private dev_proc_copy_alpha(bbox_copy_alpha);
  51. private dev_proc_fill_path(bbox_fill_path);
  52. private dev_proc_stroke_path(bbox_stroke_path);
  53. private dev_proc_fill_mask(bbox_fill_mask);
  54. private dev_proc_fill_trapezoid(bbox_fill_trapezoid);
  55. private dev_proc_fill_parallelogram(bbox_fill_parallelogram);
  56. private dev_proc_fill_triangle(bbox_fill_triangle);
  57. private dev_proc_draw_thin_line(bbox_draw_thin_line);
  58. private dev_proc_begin_image(bbox_begin_image);
  59. private dev_proc_image_data(bbox_image_data);
  60. private dev_proc_end_image(bbox_end_image);
  61. private dev_proc_strip_tile_rectangle(bbox_strip_tile_rectangle);
  62. private dev_proc_strip_copy_rop(bbox_strip_copy_rop);
  63.  
  64. /* The device prototype */
  65. #ifndef TEST
  66. private const
  67. #endif
  68. /*
  69.  * The bbox device sets the resolution to some value R (currently 4000), and
  70.  * the page size in device pixels to slightly smaller than the largest
  71.  * representable values (around 500K), leaving a little room for stroke
  72.  * widths, rounding, etc.  If an input file (or the command line) resets the
  73.  * resolution to a value R' > R, the page size in pixels will get multiplied
  74.  * by R'/R, and will thereby exceed the representable range, causing a
  75.  * limitcheck.  That is why the bbox device must set the resolution to a
  76.  * value larger than that of any real device.  A consequence of this is that
  77.  * the page size in inches is limited to the maximum representable pixel
  78.  * size divided by R, which gives a limit of about 120" in each dimension.
  79.  */
  80. #define max_coord (min(max_int, fixed2int(max_fixed)) - 1000)
  81. #define max_resolution 4000
  82. gx_device_bbox far_data gs_bbox_device = {
  83.     std_device_std_body(gx_device_bbox, 0, "bbox",
  84.                 max_coord, max_coord,
  85.                 max_resolution, max_resolution),
  86.     {    bbox_open_device,
  87.         NULL,            /* get_initial_matrix */
  88.         NULL,            /* sync_output */
  89.         bbox_output_page,
  90.         gx_forward_close_device,
  91.         NULL,            /* map_rgb_color */
  92.         NULL,            /* map_color_rgb */
  93.         bbox_fill_rectangle,
  94.         NULL,            /* tile_rectangle */
  95.         bbox_copy_mono,
  96.         bbox_copy_color,
  97.         bbox_draw_line,
  98.         NULL,            /* get_bits */
  99.         bbox_get_params,
  100.         bbox_put_params,
  101.         NULL,            /* map_cmyk_color */
  102.         NULL,            /* get_xfont_procs */
  103.         NULL,            /* get_xfont_device */
  104.         NULL,            /* map_rgb_alpha_color */
  105.         gx_page_device_get_page_device,
  106.         NULL,            /* get_alpha_bits */
  107.         bbox_copy_alpha,
  108.         NULL,            /* get_band */
  109.         NULL,            /* copy_rop */
  110.         bbox_fill_path,
  111.         bbox_stroke_path,
  112.         bbox_fill_mask,
  113.         bbox_fill_trapezoid,
  114.         bbox_fill_parallelogram,
  115.         bbox_fill_triangle,
  116.         bbox_draw_thin_line,
  117.         bbox_begin_image,
  118.         bbox_image_data,
  119.         bbox_end_image,
  120.         bbox_strip_tile_rectangle,
  121.         bbox_strip_copy_rop
  122.     },
  123.     0                /* target */
  124. };
  125. #undef max_coord
  126. #undef max_resolution
  127.  
  128. /* Copy device parameters back from the target. */
  129. private void
  130. bbox_copy_params(gx_device_bbox *bdev)
  131. {    gx_device *tdev = bdev->target;
  132.     if ( tdev != 0 )
  133.       { /* This is kind of scatter-shot.... */
  134. #define copy_param(p) bdev->p = tdev->p
  135. #define copy_array_param(p) memcpy(bdev->p, tdev->p, sizeof(bdev->p))
  136.         copy_param(width);
  137.         copy_param(height);
  138.         copy_array_param(MediaSize);
  139.         copy_array_param(ImagingBBox);
  140.         copy_param(ImagingBBox_set);
  141.         copy_array_param(HWResolution);
  142.         copy_array_param(MarginsHWResolution);
  143.         copy_array_param(Margins);
  144.         copy_array_param(HWMargins);
  145.         copy_param(color_info);
  146. #undef copy_param
  147. #undef copy_array_param
  148.       }
  149.     if ( dev_proc(bdev, map_rgb_color) != 0 )
  150.       bdev->white =
  151.         (*dev_proc(bdev, map_rgb_color))
  152.           ((gx_device *)bdev, gx_max_color_value, gx_max_color_value,
  153.            gx_max_color_value);
  154. }
  155.  
  156. #define bdev ((gx_device_bbox *)dev)
  157.  
  158. #define gx_dc_is_white(pdevc, bdev)\
  159.   (gx_dc_is_pure(pdevc) && gx_dc_pure_color(pdevc) == (bdev)->white)
  160.  
  161. /* Note that some of the "forward" procedures don't exist. */
  162. /* We open-code all but this one below. */
  163. private int
  164. gx_forward_close_device(gx_device *dev)
  165. {    gx_device *tdev = bdev->target;
  166.     return (tdev == 0 ? 0 : (*dev_proc(tdev, close_device))(tdev));
  167. }
  168.  
  169. /* Bounding box utilities */
  170.  
  171. private void near
  172. bbox_initialize(gs_fixed_rect *pr)
  173. {    pr->p.x = pr->p.y = max_fixed;
  174.     pr->q.x = pr->q.y = min_fixed;
  175. }
  176.  
  177. private void near
  178. bbox_add_rect(gs_fixed_rect *pr, fixed x0, fixed y0, fixed x1, fixed y1)
  179. {    if ( x0 < pr->p.x )
  180.       pr->p.x = x0;
  181.     if ( y0 < pr->p.y )
  182.       pr->p.y = y0;
  183.     if ( x1 > pr->q.x )
  184.       pr->q.x = x1;
  185.     if ( y1 > pr->q.y )
  186.       pr->q.y = y1;
  187. }
  188. private void near
  189. bbox_add_point(gs_fixed_rect *pr, fixed x, fixed y)
  190. {    bbox_add_rect(pr, x, y, x, y);
  191. }
  192. private void near
  193. bbox_add_int_rect(gs_fixed_rect *pr, int x0, int y0, int x1, int y1)
  194. {    bbox_add_rect(pr, int2fixed(x0), int2fixed(y0), int2fixed(x1),
  195.               int2fixed(y1));
  196. }
  197.  
  198. #define rect_is_page(dev, x, y, w, h)\
  199.   (x <= 0 && y <= 0 && w >= x + dev->width && h >= y + dev->height)
  200.  
  201. /* ---------------- Open/close/page ---------------- */
  202.  
  203. /* Initialize a bounding box device. */
  204. void
  205. gx_device_bbox_init(gx_device_bbox *dev, gx_device *target)
  206. {    *dev = gs_bbox_device;
  207.     gx_device_forward_fill_in_procs((gx_device_forward *)dev);
  208.     bdev->target = target;
  209.     bbox_copy_params(dev);
  210. }
  211.  
  212. /* Read back the bounding box in 1/72" units. */
  213. void
  214. gx_device_bbox_bbox(gx_device_bbox *dev, gs_rect *pbbox)
  215. {    gs_matrix mat;
  216.     gs_rect dbox;
  217.  
  218.     gs_deviceinitialmatrix((gx_device *)dev, &mat);
  219.     dbox.p.x = fixed2float(bdev->bbox.p.x);
  220.     dbox.p.y = fixed2float(bdev->bbox.p.y);
  221.     dbox.q.x = fixed2float(bdev->bbox.q.x);
  222.     dbox.q.y = fixed2float(bdev->bbox.q.y);
  223.     gs_bbox_transform_inverse(&dbox, &mat, pbbox);
  224. }
  225.  
  226.  
  227. private int
  228. bbox_open_device(gx_device *dev)
  229. {    bbox_initialize(&bdev->bbox);
  230. #ifdef TEST
  231.     gx_device_forward_fill_in_procs((gx_device_forward *)dev);
  232. #endif
  233.     /* gx_forward_open_device doesn't exist */
  234.     { gx_device *tdev = bdev->target;
  235.       int code = (tdev == 0 ? 0 : (*dev_proc(tdev, open_device))(tdev));
  236.       bbox_copy_params(bdev);
  237.       return code;
  238.     }
  239. }
  240.  
  241. private int 
  242. bbox_output_page(gx_device *dev, int num_copies, int flush)
  243. {
  244. #ifdef TEST
  245.     gs_rect bbox;
  246.  
  247.     /* Print the page bounding box. */
  248.     gx_device_bbox_bbox((gx_device_bbox *)dev, &bbox);
  249.     dprintf2("[gdevbbox] lower left  = %f %f\n", bbox.p.x, bbox.p.y);
  250.     dprintf2("[gdevbbox] upper right = %f %f\n", bbox.q.x, bbox.q.y);
  251. #endif
  252.     /* Propagate the PageCount to the target, */
  253.     /* since it changes every time gs_output_page is called. */
  254.     if ( bdev->target )
  255.       bdev->target->PageCount = dev->PageCount;
  256.     return gx_forward_output_page(dev, num_copies, flush);
  257. }
  258.  
  259. /* ---------------- Low-level drawing ---------------- */
  260.  
  261. private int
  262. bbox_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  263.   gx_color_index color)
  264. {    /* Check for erasing the entire page. */
  265.     if ( rect_is_page(dev, x, y, w, h) )
  266.       bbox_initialize(&bdev->bbox);
  267.     else if ( color != bdev->white )
  268.       bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  269.     /* gx_forward_fill_rectangle doesn't exist */
  270.     { gx_device *tdev = bdev->target;
  271.       return (tdev == 0 ? 0 :
  272.           (*dev_proc(tdev, fill_rectangle))(tdev, x, y, w, h, color));
  273.     }
  274. }
  275.  
  276. private int
  277. bbox_copy_mono(gx_device *dev, const byte *data,
  278.   int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h,
  279.   gx_color_index zero, gx_color_index one)
  280. {    if ( (one != gx_no_color_index && one != bdev->white) ||
  281.          (zero != gx_no_color_index && zero != bdev->white)
  282.        )
  283.       bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  284.     /* gx_forward_copy_mono doesn't exist */
  285.     { gx_device *tdev = bdev->target;
  286.       return (tdev == 0 ? 0 :
  287.           (*dev_proc(tdev, copy_mono))(tdev, data, dx, raster, id,
  288.                            x, y, w, h, zero, one));
  289.     }
  290. }
  291.  
  292. private int
  293. bbox_copy_color(gx_device *dev, const byte *data,
  294.   int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h)
  295. {    bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  296.     /* gx_forward_copy_color doesn't exist */
  297.     { gx_device *tdev = bdev->target;
  298.       return (tdev == 0 ? 0 :
  299.           (*dev_proc(tdev, copy_color))(tdev, data, dx, raster, id,
  300.                            x, y, w, h));
  301.     }
  302. }
  303.  
  304. private int
  305. bbox_draw_line(gx_device *dev,
  306.   int x0, int y0, int x1, int y1, gx_color_index color)
  307. {    int xp, yp, xq, yq;
  308.     if ( x0 < x1 )
  309.       xp = x0, xq = x1 + 1;
  310.     else
  311.       xp = x1, xq = x0 + 1;
  312.     if ( y0 < y1 )
  313.       yp = y0, yq = y1 + 1;
  314.     else
  315.       yp = y1, yq = y0 + 1;
  316.     if ( color != bdev->white )
  317.       bbox_add_int_rect(&bdev->bbox, xp, yp, xq, yq);
  318.     /* gx_forward_draw_line doesn't exist */
  319.     { gx_device *tdev = bdev->target;
  320.       return (tdev == 0 ? 0 :
  321.           (*dev_proc(tdev, draw_line))(tdev, x0, y0, x1, y1, color));
  322.     }
  323. }
  324.  
  325. private int
  326. bbox_copy_alpha(gx_device *dev, const byte *data, int data_x,
  327.   int raster, gx_bitmap_id id, int x, int y, int w, int h,
  328.   gx_color_index color, int depth)
  329. {    bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  330.     /* gx_forward_copy_alpha doesn't exist */
  331.     { gx_device *tdev = bdev->target;
  332.       return (tdev == 0 ? 0 :
  333.           (*dev_proc(tdev, copy_alpha))(tdev, data, data_x, raster, id,
  334.                         x, y, w, h, color, depth));
  335.     }
  336. }
  337.  
  338. private int
  339. bbox_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles,
  340.   int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
  341.   int px, int py)
  342. {    if ( rect_is_page(dev, x, y, w, h) )
  343.       bbox_initialize(&bdev->bbox);
  344.     else
  345.       bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  346.     /* Skip the call if there is no target. */
  347.     { gx_device *tdev = bdev->target;
  348.       return (tdev == 0 ? 0 :
  349.           (*dev_proc(tdev, strip_tile_rectangle))(tdev, tiles, x, y,
  350.                         w, h, color0, color1, px, py));
  351.     }
  352. }
  353.  
  354. private int
  355. bbox_strip_copy_rop(gx_device *dev,
  356.   const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
  357.   const gx_color_index *scolors,
  358.   const gx_strip_bitmap *textures, const gx_color_index *tcolors,
  359.   int x, int y, int w, int h,
  360.   int phase_x, int phase_y, gs_logical_operation_t lop)
  361. {    bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  362.     /* gx_forward_strip_copy_rop doesn't exist */
  363.     { gx_device *tdev = bdev->target;
  364.       return (tdev == 0 ? 0 :
  365.           (*dev_proc(tdev, strip_copy_rop))(tdev,
  366.                           sdata, sourcex, sraster, id,
  367.                           scolors, textures, tcolors,
  368.                           x, y, w, h,
  369.                           phase_x, phase_y, lop));
  370.     }
  371. }
  372.  
  373. /* ---------------- Parameters ---------------- */
  374.  
  375. /* We implement get_params to provide a way to read out the bounding box. */
  376. private int
  377. bbox_get_params(gx_device *dev, gs_param_list *plist)
  378. {    int code = gx_forward_get_params(dev, plist);
  379.     gs_param_float_array bba;
  380.     float bbox[4];
  381.  
  382.     if ( code < 0 )
  383.       return code;
  384.     bbox[0] = fixed2float(bdev->bbox.p.x);
  385.     bbox[1] = fixed2float(bdev->bbox.p.y);
  386.     bbox[2] = fixed2float(bdev->bbox.q.x);
  387.     bbox[3] = fixed2float(bdev->bbox.q.y);
  388.     bba.data = bbox, bba.size = 4, bba.persistent = false;
  389.     return param_write_float_array(plist, "PageBoundingBox", &bba);
  390. }
  391.  
  392. /* We implement put_params to ensure that we keep the important */
  393. /* device parameters up to date, and to prevent an /undefined error */
  394. /* from PageBoundingBox. */
  395. private int
  396. bbox_put_params(gx_device *dev, gs_param_list *plist)
  397. {    int code;
  398.     int ecode = 0;
  399.     gs_param_name param_name;
  400.     gs_param_float_array bba;
  401.  
  402.     code = param_read_float_array(plist, (param_name = "PageBoundingBox"),
  403.                       &bba);
  404.     switch ( code )
  405.       {
  406.       case 0:
  407.         if ( bba.size != 4 )
  408.           { ecode = gs_note_error(gs_error_rangecheck);
  409.             goto e;
  410.           }
  411.         break;
  412.       default:
  413.         ecode = code;
  414. e:        param_signal_error(plist, param_name, ecode);
  415.       case 1:
  416.         bba.data = 0;
  417.       }
  418.  
  419.     code = gx_forward_put_params(dev, plist);
  420.     if ( ecode < 0 )
  421.       code = ecode;
  422.     if ( code >= 0 && bba.data != 0 )
  423.       { bdev->bbox.p.x = float2fixed(bba.data[0]);
  424.         bdev->bbox.p.y = float2fixed(bba.data[1]);
  425.         bdev->bbox.q.x = float2fixed(bba.data[2]);
  426.         bdev->bbox.q.y = float2fixed(bba.data[3]);
  427.       }
  428.     bbox_copy_params(bdev);
  429.     return code;
  430. }
  431.  
  432. /* ---------------- Polygon drawing ---------------- */
  433.  
  434. private fixed
  435. edge_x_at_y(const gs_fixed_edge *edge, fixed y)
  436. {    return fixed_mult_quo(edge->end.x - edge->start.x,
  437.                   y - edge->start.y,
  438.                   edge->end.y - edge->start.y) + edge->start.x;
  439. }
  440. private int
  441. bbox_fill_trapezoid(gx_device *dev,
  442.   const gs_fixed_edge *left, const gs_fixed_edge *right,
  443.   fixed ybot, fixed ytop, bool swap_axes,
  444.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  445. {    if ( !gx_dc_is_white(pdevc, bdev) )
  446.       { fixed x0l =
  447.           (left->start.y == ybot ? left->start.x :
  448.            edge_x_at_y(left, ybot));
  449.         fixed x1l =
  450.           (left->end.y == ytop ? left->end.x :
  451.            edge_x_at_y(left, ytop));
  452.         fixed x0r =
  453.           (right->start.y == ybot ? right->start.x :
  454.            edge_x_at_y(right, ybot));
  455.         fixed x1r =
  456.           (right->end.y == ytop ? right->end.x :
  457.            edge_x_at_y(right, ytop));
  458.         fixed xminl = min(x0l, x1l), xmaxl = max(x0l, x1l);
  459.         fixed xminr = min(x0r, x1r), xmaxr = max(x0r, x1r);
  460.         fixed x0 = min(xminl, xminr), x1 = max(xmaxl, xmaxr);
  461.  
  462.         if ( swap_axes )
  463.           bbox_add_rect(&bdev->bbox, ybot, x0, ytop, x1);
  464.         else
  465.           bbox_add_rect(&bdev->bbox, x0, ybot, x1, ytop);
  466.       }
  467.     /* Skip the call if there is no target. */
  468.     { gx_device *tdev = bdev->target;
  469.       return (tdev == 0 ? 0 :
  470.           (*dev_proc(tdev, fill_trapezoid))
  471.            (tdev, left, right, ybot, ytop, swap_axes, pdevc, lop));
  472.     }
  473. }
  474.  
  475. private int
  476. bbox_fill_parallelogram(gx_device *dev,
  477.   fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  478.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  479. {    if ( !gx_dc_is_white(pdevc, bdev) )
  480.       { fixed pax = px + ax, pay = py + ay;
  481.         bbox_add_rect(&bdev->bbox, px, py, px + bx, py + by);
  482.         bbox_add_rect(&bdev->bbox, pax, pay, pax + bx, pay + by);
  483.       }
  484.     /* Skip the call if there is no target. */
  485.     { gx_device *tdev = bdev->target;
  486.       return (tdev == 0 ? 0 :
  487.           (*dev_proc(tdev, fill_parallelogram))(tdev, px, py, ax, ay,
  488.                             bx, by, pdevc, lop));
  489.     }
  490. }
  491.  
  492. private int
  493. bbox_fill_triangle(gx_device *dev,
  494.   fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  495.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  496. {    if ( !gx_dc_is_white(pdevc, bdev) )
  497.       { bbox_add_rect(&bdev->bbox, px, py, px + bx, py + by);
  498.         bbox_add_point(&bdev->bbox, px + ax, py + ay);
  499.       }
  500.     /* Skip the call if there is no target. */
  501.     { gx_device *tdev = bdev->target;
  502.       return (tdev == 0 ? 0 :
  503.           (*dev_proc(tdev, fill_triangle))(tdev, px, py, ax, ay,
  504.                            bx, by, pdevc, lop));
  505.     }
  506. }
  507.  
  508. private int
  509. bbox_draw_thin_line(gx_device *dev,
  510.   fixed fx0, fixed fy0, fixed fx1, fixed fy1,
  511.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  512. {    if ( !gx_dc_is_white(pdevc, bdev) )
  513.       bbox_add_rect(&bdev->bbox, fx0, fy0, fx1, fy1);
  514.     /* Skip the call if there is no target. */
  515.     { gx_device *tdev = bdev->target;
  516.       return (tdev == 0 ? 0 :
  517.           (*dev_proc(tdev, draw_thin_line))(tdev, fx0, fy0, fx1, fy0,
  518.                             pdevc, lop));
  519.     }
  520. }
  521.  
  522. /* ---------------- High-level drawing ---------------- */
  523.  
  524. #define adjust_box(pbox, adj)\
  525.   ((pbox)->p.x -= (adj).x, (pbox)->p.y -= (adj).y,\
  526.    (pbox)->q.x += (adj).x, (pbox)->q.y += (adj).y)
  527.  
  528. private int
  529. bbox_fill_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  530.   const gx_fill_params *params, const gx_device_color *pdevc,
  531.   const gx_clip_path *pcpath)
  532. {    gx_device *tdev = bdev->target;
  533.  
  534.     if ( !gx_dc_is_white(pdevc, bdev) )
  535.       { gs_fixed_rect ibox;
  536.         gs_fixed_point adjust;
  537.  
  538.         if ( gx_path_bbox(ppath, &ibox) < 0 )
  539.           return 0;
  540.         adjust = params->adjust;
  541.         if ( params->fill_zero_width )
  542.           gx_adjust_if_empty(&ibox, &adjust);
  543.         adjust_box(&ibox, adjust);
  544.         if ( pcpath != NULL &&
  545.          !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
  546.                           ibox.q.x, ibox.q.y)
  547.            )
  548.           { /* Let the target do the drawing, but break down the */
  549.         /* fill path into pieces for computing the bounding box. */
  550.         bdev->target = NULL;
  551.         gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath);
  552.         bdev->target = tdev;
  553.           }
  554.         else
  555.           { /* Just use the path bounding box. */
  556.         bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x,
  557.                   ibox.q.y);
  558.           }
  559.       }
  560.     /* Skip the call if there is no target. */
  561.     return (tdev == 0 ? 0 :
  562.         (*dev_proc(tdev, fill_path))(tdev, pis, ppath, params, pdevc,
  563.                          pcpath));
  564. }
  565.  
  566. private int
  567. bbox_stroke_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  568.   const gx_stroke_params *params,
  569.   const gx_drawing_color *pdevc, const gx_clip_path *pcpath)
  570. {    gx_device *tdev = bdev->target;
  571.  
  572.     if ( !gx_dc_is_white(pdevc, bdev) )
  573.       { gs_fixed_rect ibox;
  574.         gs_fixed_point expand;
  575.  
  576.         if ( gx_path_bbox(ppath, &ibox) < 0 )
  577.           return 0;
  578.         if ( gx_stroke_path_expansion(pis, ppath, &expand) < 0 )
  579.           ibox.p.x = ibox.p.y = min_fixed, ibox.q.x = ibox.q.y = max_fixed;
  580.         else
  581.           adjust_box(&ibox, expand);
  582.         if ( pcpath != NULL &&
  583.          !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
  584.                           ibox.q.x, ibox.q.y)
  585.            )
  586.           { /* Let the target do the drawing, but break down the */
  587.         /* fill path into pieces for computing the bounding box. */
  588.         bdev->target = NULL;
  589.         gx_default_stroke_path(dev, pis, ppath, params, pdevc, pcpath);
  590.         bdev->target = tdev;
  591.           }
  592.         else
  593.           { /* Just use the path bounding box. */
  594.         bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x,
  595.                   ibox.q.y);
  596.           }
  597.       }
  598.     /* Skip the call if there is no target. */
  599.     return (tdev == 0 ? 0 :
  600.         (*dev_proc(tdev, stroke_path))(tdev, pis, ppath, params,
  601.                            pdevc, pcpath));
  602. }
  603.  
  604. private int
  605. bbox_fill_mask(gx_device *dev,
  606.   const byte *data, int dx, int raster, gx_bitmap_id id,
  607.   int x, int y, int w, int h,
  608.   const gx_drawing_color *pdcolor, int depth,
  609.   gs_logical_operation_t lop, const gx_clip_path *pcpath)
  610. {    gx_device *tdev = bdev->target;
  611.  
  612.     if ( pcpath != NULL &&
  613.          !gx_cpath_includes_rectangle(pcpath, int2fixed(x), int2fixed(y),
  614.                       int2fixed(x + w),
  615.                       int2fixed(y + h))
  616.        )
  617.       { /* Let the target do the drawing, but break down the */
  618.         /* image into pieces for computing the bounding box. */
  619.         bdev->target = NULL;
  620.         gx_default_fill_mask(dev, data, dx, raster, id, x, y, w, h,
  621.                  pdcolor, depth, lop, pcpath);
  622.         bdev->target = tdev;
  623.       }
  624.     else
  625.       { /* Just use the mask bounding box. */
  626.         bbox_add_int_rect(&bdev->bbox, x, y, x + w, y + h);
  627.       }
  628.     /* Skip the call if there is no target. */
  629.     return (tdev == 0 ? 0 :
  630.         (*dev_proc(tdev, fill_mask))(tdev, data, dx, raster, id, x, y,
  631.                      w, h, pdcolor, depth, lop, pcpath));
  632. }
  633.  
  634. /* ------ Bitmap imaging ------ */
  635.  
  636. typedef struct bbox_image_enum_s {
  637.     gs_memory_t *memory;
  638.     gs_matrix matrix;    /* map from image space to device space */
  639.     const gx_clip_path *pcpath;
  640.     void *target_info;
  641.     int x0, x1;
  642.     int y, height;
  643. } bbox_image_enum;
  644. gs_private_st_ptrs2(st_bbox_image_enum, bbox_image_enum, "bbox_image_enum",
  645.   bbox_image_enum_enum_ptrs, bbox_image_enum_reloc_ptrs, pcpath, target_info);
  646.  
  647. private int
  648. bbox_begin_image(gx_device *dev,
  649.   const gs_imager_state *pis, const gs_image_t *pim,
  650.   gs_image_format_t format, const gs_int_rect *prect,
  651.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
  652.   gs_memory_t *memory, void **pinfo)
  653. {    int code;
  654.     gs_matrix mat;
  655.     bbox_image_enum *pbe;
  656.  
  657.     if ( (code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
  658.          (code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat)) < 0
  659.        )
  660.       return code;
  661.     pbe = gs_alloc_struct(memory, bbox_image_enum, &st_bbox_image_enum,
  662.                   "bbox_begin_image");
  663.     if ( pbe == 0 )
  664.       return_error(gs_error_VMerror);
  665.     pbe->memory = memory;
  666.     pbe->matrix = mat;
  667.     pbe->pcpath = pcpath;
  668.     pbe->target_info = 0;        /* in case no target */
  669.     if ( prect )
  670.       { pbe->x0 = prect->p.x, pbe->x1 = prect->q.x;
  671.         pbe->y = prect->p.y, pbe->height = prect->q.y - prect->p.y;
  672.       }
  673.     else
  674.       { pbe->x0 = 0, pbe->x1 = pim->Width;
  675.         pbe->y = 0, pbe->height = pim->Height;
  676.       }
  677.     *pinfo = pbe;
  678.     /* Skip the call if there is no target. */
  679.     { gx_device *tdev = bdev->target;
  680.       return (tdev == 0 ? 0 :
  681.           (*dev_proc(tdev, begin_image))(tdev, pis, pim, format, prect,
  682.                          pdcolor, pcpath, memory,
  683.                          &pbe->target_info));
  684.     }
  685. }
  686.  
  687. private int
  688. bbox_image_data(gx_device *dev,
  689.   void *info, const byte **planes, int data_x, uint raster, int height)
  690. {    gx_device *tdev = bdev->target;
  691.     bbox_image_enum *pbe = info;
  692.     const gx_clip_path *pcpath = pbe->pcpath;
  693.     gs_rect sbox, dbox;
  694.     gs_point corners[4];
  695.     gs_fixed_rect ibox;
  696.  
  697.     sbox.p.x = pbe->x0;
  698.     sbox.p.y = pbe->y;
  699.     sbox.q.x = pbe->x1;
  700.     sbox.q.y = pbe->y += height;
  701.     gs_bbox_transform_only(&sbox, &pbe->matrix, corners);
  702.     gs_points_bbox(corners, &dbox);
  703.     ibox.p.x = float2fixed(dbox.p.x);
  704.     ibox.p.y = float2fixed(dbox.p.y);
  705.     ibox.q.x = float2fixed(dbox.q.x);
  706.     ibox.q.y = float2fixed(dbox.q.y);
  707.     if ( pcpath != NULL &&
  708.          !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
  709.                       ibox.q.x, ibox.q.y)
  710.        )
  711.       { /* Let the target do the drawing, but drive two triangles */
  712.         /* through the clipping path to get an accurate bounding box. */
  713.         gx_device_clip cdev;
  714.         gx_drawing_color devc;
  715.         fixed x0 = float2fixed(corners[0].x),
  716.           y0 = float2fixed(corners[0].y);
  717.         fixed bx2 = float2fixed(corners[2].x) - x0,
  718.           by2 = float2fixed(corners[2].y) - y0;
  719.  
  720.         gx_make_clip_path_device(&cdev, pcpath);
  721.         cdev.target = dev;
  722.         (*dev_proc(&cdev, open_device))((gx_device *)&cdev);
  723.         color_set_pure(&devc, 0);        /* any color will do */
  724.         bdev->target = NULL;
  725.         gx_default_fill_triangle((gx_device *)&cdev, x0, y0,
  726.                      float2fixed(corners[1].x) - x0,
  727.                      float2fixed(corners[1].y) - y0,
  728.                      bx2, by2, &devc, lop_default);
  729.         gx_default_fill_triangle((gx_device *)&cdev, x0, y0,
  730.                      float2fixed(corners[3].x) - x0,
  731.                      float2fixed(corners[3].y) - y0,
  732.                      bx2, by2, &devc, lop_default);
  733.         bdev->target = tdev;
  734.       }
  735.     else
  736.       { /* Just use the bounding box. */
  737.         bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
  738.       }
  739.     /* Skip the call if there is no target. */
  740.     return (tdev == 0 ? pbe->y >= pbe->height :
  741.         (*dev_proc(tdev, image_data))(tdev, pbe->target_info, planes,
  742.                           data_x, raster, height));
  743. }
  744.  
  745. private int
  746. bbox_end_image(gx_device *dev, void *info, bool draw_last)
  747. {    bbox_image_enum *pbe = info;
  748.     void *target_info = pbe->target_info;
  749.     /* Skip the call if there is no target. */
  750.     gx_device *tdev = bdev->target;
  751.     int code =
  752.       (tdev == 0 ? 0 :
  753.        (*dev_proc(tdev, end_image))(tdev, target_info, draw_last));
  754.  
  755.     gs_free_object(pbe->memory, pbe, "bbox_end_image");
  756.     return code;
  757. }
  758.