home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved.
- Distributed by Free Software Foundation, Inc.
-
- This file is part of Ghostscript.
-
- Ghostscript is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
- to anyone for the consequences of using it or for whether it serves any
- particular purpose or works at all, unless he says so in writing. Refer
- to the Ghostscript General Public License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- Ghostscript, but only under the conditions described in the Ghostscript
- General Public License. A copy of this license is supposed to have been
- given to you along with Ghostscript so you can know your rights and
- responsibilities. It should be in a file named COPYING. Among other
- things, the copyright notice and this notice must be preserved on all
- copies. */
-
- /* gxdraw.c */
- /* Primitive drawing routines for Ghostscript imaging library */
- #include "gx.h"
- #include "math_.h"
- #include "gxfixed.h"
- #include "gxmatrix.h"
- #include "gxbitmap.h"
- #include "gzstate.h"
- #include "gzdevice.h" /* requires gsstate.h */
- #include "gzcolor.h" /* requires gxdevice.h */
-
- /* Fill a rectangle. */
- int
- gz_fill_rectangle(int x, int y, int w, int h, gx_device_color *pdevc,
- gs_state *pgs)
- { gx_color_index darker = pdevc->color1;
- gx_color_index lighter;
- gx_device *dev = pgs->device->info;
- gx_bitmap *tile;
- int px, py, code;
- #ifdef DEBUG
- if ( gs_debug['q'] )
- dprintf7("[q]x=%d y=%d w=%d h=%d c1=%ld c2=%ld htl=%d\n",
- x, y, w, h, darker, (long)pdevc->color2,
- (long)pdevc->halftone_level);
- #endif
- if ( color_is_pure(pdevc) ) /* no halftoning */
- { return (*dev->procs->fill_rectangle)(dev, x, y, w, h, darker);
- }
- px = pgs->phase_mod.x;
- py = pgs->phase_mod.y;
- lighter = pdevc->color2;
- tile = pdevc->tile;
- /* See if the entire transfer falls within a single tile. */
- /* This is worth a quick check, because tiling is slow. */
- if ( w <= tile->width && h <= tile->height )
- { int xmod = (x + px) % tile->width, ymod;
- if ( xmod + w <= tile->width &&
- (ymod = (y + py) % tile->height) + h <= tile->height
- )
- { /* Just do a copy. */
- int raster = tile->raster;
- byte *tdata = tile->data + ymod * raster;
- return (color_is_color_halftone(pdevc) ?
- (*dev->procs->copy_color)(dev, tdata,
- xmod, raster, x, y, w, h) :
- (*dev->procs->copy_mono)(dev, tdata,
- xmod, raster, x, y, w, h,
- darker, lighter));
- }
- }
- /* Try to tile the rectangle primitively; */
- /* if this fails, use the default implementation. */
- if ( color_is_color_halftone(pdevc) )
- darker = lighter = gx_no_color_index;
- code = (*dev->procs->tile_rectangle)(dev, tile,
- x, y, w, h, darker, lighter, px, py);
- if ( code < 0 )
- { /* Use the default implementation */
- code = gx_default_tile_rectangle(dev, tile,
- x, y, w, h, darker, lighter, px, py);
- }
- return code;
- }
-
- /*
- * Auxiliary procedures for computing a * b / c and a * b % c
- * when a, b, and c are all non-negative,
- * b < c, and a * b exceeds (or might exceed) the capacity of a long.
- * It's really annoying that C doesn't provide any way to get at
- * the double-length multiply/divide instructions that
- * the machine undoubtedly provides....
- *
- * Note that these routines are exported for the benefit of gxfill.c.
- */
-
- fixed
- fixed_mult_quo(fixed a, fixed b, fixed c)
- { return (fixed)floor((double)a * b / c);
- }
- fixed
- fixed_mult_rem(fixed a, fixed b, fixed c)
- { double prod = (double)a * b;
- return (fixed)(prod - floor(prod / c) * c);
- }
-
- /* Fill a trapezoid. Requires: wt >= 0, wb >= 0, h >= 0. */
- /* Note that the arguments are fixeds, not ints! */
- /* This is derived from Paul Haeberli's floating point algorithm. */
- typedef struct trap_line_s {
- int di; fixed df; /* dx/dy ratio */
- fixed ldi, ldf; /* increment per scan line */
- fixed x, xf; /* current value */
- } trap_line;
- int
- gz_fill_trapezoid_fixed(fixed fx0, fixed fw0, fixed fy0,
- fixed fx1, fixed fw1, fixed fh, int swap_axes,
- gx_device_color *pdevc, gs_state *pgs)
- { const fixed ymin = fixed_rounded(fy0) + float2fixed(0.5);
- const fixed ymax = fixed_rounded(fy0 + fh);
- int iy = fixed2int_var(ymin);
- const int iy1 = fixed2int_var(ymax);
- if ( iy >= iy1 ) return 0; /* no scan lines to sample */
- { trap_line l, r;
- int rxl, rxr, ry;
- const fixed dxl = fx1 - fx0;
- const fixed dxr = dxl + fw1 - fw0;
- const fixed yline = ymin - fy0; /* partial pixel offset to */
- /* first line to sample */
- int fill_direct = color_is_pure(pdevc);
- gx_color_index cindex;
- gx_device *dev;
- dev_proc_fill_rectangle((*fill_rect));
-
- r.x = (l.x = fx0 + float2fixed(0.5)) + fw0;
- if ( fill_direct )
- cindex = pdevc->color1,
- dev = pgs->device->info,
- fill_rect = dev->procs->fill_rectangle;
- #define fill_trap_rect(x,y,w,h)\
- (fill_direct ?\
- (swap_axes ? (*fill_rect)(dev, y, x, h, w, cindex) :\
- (*fill_rect)(dev, x, y, w, h, cindex)) :\
- swap_axes ? gz_fill_rectangle(y, x, h, w, pdevc, pgs) :\
- gz_fill_rectangle(x, y, w, h, pdevc, pgs))
-
- /* Compute the dx/dy ratios. */
- /* dx# = dx#i + (dx#f / fh). */
- #define compute_dx(tl, d)\
- if ( d >= 0 )\
- { if ( d < fh ) tl.di = 0, tl.df = d;\
- else tl.di = (int)(d / fh), tl.df = d - tl.di * fh, tl.x += yline * tl.di;\
- }\
- else\
- { if ( (tl.df = d + fh) >= 0 /* d >= -fh */ ) tl.di = -1, tl.x -= yline;\
- else tl.di = (int)-((fh - 1 - d) / fh), tl.df = d - tl.di * fh, tl.x += yline * tl.di;\
- }
- compute_dx(l, dxl);
- compute_dx(r, dxr);
-
- /* We need to be careful in computing yline * dx#f {/,%} fh */
- /* because the multiplication may overflow. We know that */
- /* all the quantities involved are non-negative, and that */
- /* yline is less than 1 (as a fixed, of course); this gives us */
- /* a cheap conservative check for overflow in the multiplication. */
- #define ymult_limit (max_fixed / int2fixed(1))
- #define ymult_quo(yl, dxxf)\
- (dxxf < ymult_limit ? yl * dxxf / fh : fixed_mult_quo(yl, dxxf, fh))
- #define ymult_rem(yl, dxxf)\
- (dxxf < ymult_limit ? yl * dxxf % fh : fixed_mult_rem(yl, dxxf, fh))
-
- /* Compute the x offsets at the first scan line to sample. */
- l.x += ymult_quo(yline, l.df);
- r.x += ymult_quo(yline, r.df);
- rxl = fixed2int_var(l.x);
- rxr = fixed2int_var(r.x);
- ry = iy;
-
- /* Compute one line's worth of dx/dy. */
- /* dx# * int2fixed(1) = ld#i + (ld#f / fh). */
- /* We don't have to bother with this if */
- /* we're only sampling a single scan line. */
- if ( iy1 - iy == 1 )
- { iy++;
- goto last;
- }
- #define compute_ldx(tl)\
- if ( tl.df < ymult_limit )\
- tl.ldi = int2fixed(tl.di) + int2fixed(tl.df) / fh,\
- tl.ldf = int2fixed(tl.df) % fh,\
- tl.xf = yline * tl.df % fh - fh;\
- else\
- tl.ldi = int2fixed(tl.di) + fixed_mult_quo(int2fixed(1), tl.df, fh),\
- tl.ldf = fixed_mult_rem(int2fixed(1), tl.df, fh),\
- tl.xf = fixed_mult_rem(yline, tl.df, fh) - fh
- compute_ldx(l);
- compute_ldx(r);
- #undef compute_ldx
-
- while ( ++iy != iy1 )
- { int ixl, ixr;
- #define step_line(tl)\
- tl.x += tl.ldi;\
- if ( (tl.xf += tl.ldf) >= 0 ) tl.xf -= fh, tl.x++;
- step_line(l);
- step_line(r);
- #undef step_line
- ixl = fixed2int_var(l.x);
- ixr = fixed2int_var(r.x);
- if ( ixl != rxl || ixr != rxr )
- { int code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry);
- if ( code < 0 ) return code;
- rxl = ixl, rxr = ixr, ry = iy;
- }
- }
- last: return fill_trap_rect(rxl, ry, rxr - rxl, iy - ry);
- }
- }
-
- /* Default implementation of tile_rectangle */
- int
- gx_default_tile_rectangle(gx_device *dev, register gx_bitmap *tile,
- int x, int y, int w, int h, gx_color_index color0, gx_color_index color1,
- int px, int py)
- { /* Fill the rectangle in chunks */
- int width = tile->width;
- int height = tile->height;
- int raster = tile->raster;
- int ex = x + w, ey = y + h;
- int fex = ex - width, fey = ey - height;
- int irx = ((width & (width - 1)) == 0 ? /* power of 2 */
- (x + px) & (width - 1) :
- (x + px) % width);
- int ry = (y + py) % height;
- int icw = width - irx;
- int ch = height - ry;
- byte *row = tile->data + ry * raster;
- int (*proc_mono)(P10(gx_device *, byte *, int, int,
- int, int, int, int, gx_color_index, gx_color_index));
- int (*proc_color)(P8(gx_device *, byte *, int, int,
- int, int, int, int));
- int color_halftone =
- (color0 == gx_no_color_index && color1 == gx_no_color_index);
- int cx, cy;
- int code;
- if ( color_halftone )
- proc_color = dev->procs->copy_color;
- else
- proc_mono = dev->procs->copy_mono;
- #ifdef DEBUG
- if ( gs_debug['t'] )
- { int ptx, pty;
- byte *ptp = tile->data;
- dprintf3("[t]tile %dx%d raster=%d;",
- tile->width, tile->height, tile->raster);
- dprintf6(" x,y=%d,%d w,h=%d,%d p=%d,%d\n",
- x, y, w, h, px, py);
- for ( pty = 0; pty < tile->height; pty++ )
- { dprintf(" ");
- for ( ptx = 0; ptx < tile->raster; ptx++ )
- dprintf1("%3x", *ptp++);
- }
- dputc('\n');
- }
- #endif
- if ( icw > w ) icw = w;
- if ( ch > h ) ch = h;
- #define real_copy_tile(sourcex, tx, tw)\
- code =\
- (color_halftone ?\
- (*proc_color)(dev, row, sourcex, raster, tx, cy, tw, ch) :\
- (*proc_mono)(dev, row, sourcex, raster, tx, cy, tw, ch, color0, color1));\
- if ( code < 0 ) return code
- #ifdef DEBUG
- #define copy_tile(sx, tx, tw)\
- if ( gs_debug['t'] )\
- dprintf5(" copy sx=%d x=%d y=%d w=%d h=%d\n",\
- sx, tx, cy, tw, ch);\
- real_copy_tile(sx, tx, tw)
- #else
- #define copy_tile(sx, tx, tw)\
- real_copy_tile(sx, tx, tw)
- #endif
- for ( cy = y; cy < ey; )
- { copy_tile(irx, x, icw);
- cx = x + icw;
- while ( cx <= fex )
- { copy_tile(0, cx, width);
- cx += width;
- }
- if ( cx < ex )
- { copy_tile(0, cx, ex - cx);
- }
- cy += ch;
- ch = (cy > fey ? ey - cy : height);
- row = tile->data;
- }
- #undef copy_tile
- #undef real_copy_tile
- return 0;
- }
-
- /* Draw a one-pixel-wide line. */
- int
- gz_draw_line_fixed(fixed ixf, fixed iyf, fixed itoxf, fixed itoyf,
- gx_device_color *pdevc, gs_state *pgs)
- { int ix = fixed2int_var_rounded(ixf);
- int iy = fixed2int_var_rounded(iyf);
- int itox = fixed2int_var_rounded(itoxf);
- int itoy = fixed2int_var_rounded(itoyf);
- gx_device *dev;
- if ( itoy == iy ) /* horizontal line */
- { return (ix <= itox ?
- gz_fill_rectangle(ix, iy, itox - ix, 1, pdevc, pgs) :
- gz_fill_rectangle(itox, iy, ix - itox, 1, pdevc, pgs)
- );
- }
- if ( color_is_pure(pdevc) &&
- (dev = pgs->device->info,
- (*dev->procs->draw_line)(dev, ix, iy, itox, itoy,
- pdevc->color1)) >= 0 )
- return 0;
- { fixed h = itoyf - iyf;
- fixed w = itoxf - ixf;
- fixed tf;
- #define fswap(a, b) tf = a, a = b, b = tf
- #define half float2fixed(0.5)
- if ( (w < 0 ? -w : w) <= (h < 0 ? -h : h) )
- { if ( h < 0 )
- fswap(ixf, itoxf), fswap(iyf, itoyf),
- h = -h;
- return gz_fill_trapezoid_fixed(ixf - half, int2fixed(1), iyf,
- itoxf - half, int2fixed(1), h,
- 0, pdevc, pgs);
- }
- else
- { if ( w < 0 )
- fswap(ixf, itoxf), fswap(iyf, itoyf),
- w = -w;
- return gz_fill_trapezoid_fixed(iyf - half, int2fixed(1), ixf,
- itoyf - half, int2fixed(1), w,
- 1, pdevc, pgs);
- }
- #undef half
- #undef fswap
- }
- }
-
- /****** STUBS ******/
- int
- gx_default_draw_line(gx_device *dev,
- int x0, int y0, int x1, int y1, gx_color_index color)
- { return -1;
- }
- int
- gx_default_fill_trapezoid(gx_device *dev,
- int x0, int y0, int width0, int x1, int y1, int width1,
- gx_color_index color)
- { return -1;
- }
- int
- gx_default_tile_trapezoid(gx_device *dev, gx_bitmap *tile,
- int x0, int y0, int width0, int x1, int y1, int width1,
- gx_color_index color0, gx_color_index color1, int px, int py)
- { return -1;
- }
- int
- gx_default_tile_trapezoid_color(gx_device *dev, gx_bitmap *tile,
- int x0, int y0, int width0, int x1, int y1, int width1, int px, int py)
- { return -1;
- }
-