/* Copyright (C) 1995, 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevmr1.c,v 1.2.6.1.2.1 2003/01/17 00:49:01 giles Exp $ */ /* RasterOp implementation for monobit memory devices */ #include "memory_.h" #include "gx.h" #include "gsbittab.h" #include "gserrors.h" #include "gsropt.h" #include "gxcindex.h" #include "gxdcolor.h" #include "gxdevice.h" #include "gxdevmem.h" #include "gxdevrop.h" #include "gdevmrop.h" /* Calculate the X offset for a given Y value, */ /* taking shift into account if necessary. */ #define x_offset(px, ty, textures)\ ((textures)->shift == 0 ? (px) :\ (px) + (ty) / (textures)->rep_height * (textures)->rep_shift) /* ---------------- Monobit RasterOp ---------------- */ int mem_mono_strip_copy_rop(gx_device * dev, const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id, const gx_color_index * scolors, const gx_strip_bitmap * textures, const gx_color_index * tcolors, int x, int y, int width, int height, int phase_x, int phase_y, gs_logical_operation_t lop) { gx_device_memory *mdev = (gx_device_memory *) dev; gs_rop3_t rop = gs_transparent_rop(lop); /* handle transparency */ gx_strip_bitmap no_texture; bool invert; uint draster = mdev->raster; uint traster; int line_count; byte *drow; const byte *srow; int ty; /* If map_rgb_color isn't the default one for monobit memory */ /* devices, palette might not be set; set it now if needed. */ if (mdev->palette.data == 0) gdev_mem_mono_set_inverted(mdev, (*dev_proc(dev, map_rgb_color)) (dev, (gx_color_value) 0, (gx_color_value) 0, (gx_color_value) 0) != 0); invert = mdev->palette.data[0] != 0; #ifdef DEBUG if (gs_debug_c('b')) trace_copy_rop("mem_mono_strip_copy_rop", dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, x, y, width, height, phase_x, phase_y, lop); if (gs_debug_c('B')) debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster, height, "initial dest bits"); #endif /* * RasterOp is defined as operating in RGB space; in the monobit * case, this means black = 0, white = 1. However, most monobit * devices use the opposite convention. To make this work, * we must precondition the Boolean operation by swapping the * order of bits end-for-end and then inverting. */ if (invert) rop = byte_reverse_bits[rop] ^ 0xff; /* * From this point on, rop works in terms of device pixel values, * not RGB-space values. */ /* Modify the raster operation according to the source palette. */ if (scolors != 0) { /* Source with palette. */ switch ((int)((scolors[1] << 1) + scolors[0])) { case 0: rop = rop3_know_S_0(rop); break; case 1: rop = rop3_invert_S(rop); break; case 2: break; case 3: rop = rop3_know_S_1(rop); break; } } /* Modify the raster operation according to the texture palette. */ if (tcolors != 0) { /* Texture with palette. */ switch ((int)((tcolors[1] << 1) + tcolors[0])) { case 0: rop = rop3_know_T_0(rop); break; case 1: rop = rop3_invert_T(rop); break; case 2: break; case 3: rop = rop3_know_T_1(rop); break; } } /* Handle constant source and/or texture, and other special cases. */ { gx_color_index color0, color1; switch (rop_usage_table[rop]) { case rop_usage_none: /* We're just filling with a constant. */ return (*dev_proc(dev, fill_rectangle)) (dev, x, y, width, height, (gx_color_index) (rop & 1)); case rop_usage_D: /* This is either D (no-op) or ~D. */ if (rop == rop3_D) return 0; /* Code no_S inline, then finish with no_T. */ fit_fill(dev, x, y, width, height); sdata = scan_line_base(mdev, 0); sourcex = x; sraster = 0; goto no_T; case rop_usage_S: /* This is either S or ~S, which copy_mono can handle. */ if (rop == rop3_S) color0 = 0, color1 = 1; else color0 = 1, color1 = 0; do_copy:return (*dev_proc(dev, copy_mono)) (dev, sdata, sourcex, sraster, id, x, y, width, height, color0, color1); case rop_usage_DS: /* This might be a case that copy_mono can handle. */ #define copy_case(c0, c1) color0 = c0, color1 = c1; goto do_copy; switch ((uint) rop) { /* cast shuts up picky compilers */ case rop3_D & rop3_not(rop3_S): copy_case(gx_no_color_index, 0); case rop3_D | rop3_S: copy_case(gx_no_color_index, 1); case rop3_D & rop3_S: copy_case(0, gx_no_color_index); case rop3_D | rop3_not(rop3_S): copy_case(1, gx_no_color_index); default:; } #undef copy_case fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height); no_T: /* Texture is not used; textures may be garbage. */ no_texture.data = scan_line_base(mdev, 0); /* arbitrary */ no_texture.raster = 0; no_texture.size.x = width; no_texture.size.y = height; no_texture.rep_width = no_texture.rep_height = 1; no_texture.rep_shift = no_texture.shift = 0; textures = &no_texture; break; case rop_usage_T: /* This is either T or ~T, which tile_rectangle can handle. */ if (rop == rop3_T) color0 = 0, color1 = 1; else color0 = 1, color1 = 0; do_tile:return (*dev_proc(dev, strip_tile_rectangle)) (dev, textures, x, y, width, height, color0, color1, phase_x, phase_y); case rop_usage_DT: /* This might be a case that tile_rectangle can handle. */ #define tile_case(c0, c1) color0 = c0, color1 = c1; goto do_tile; switch ((uint) rop) { /* cast shuts up picky compilers */ case rop3_D & rop3_not(rop3_T): tile_case(gx_no_color_index, 0); case rop3_D | rop3_T: tile_case(gx_no_color_index, 1); case rop3_D & rop3_T: tile_case(0, gx_no_color_index); case rop3_D | rop3_not(rop3_T): tile_case(1, gx_no_color_index); default:; } #undef tile_case fit_fill(dev, x, y, width, height); /* Source is not used; sdata et al may be garbage. */ sdata = mdev->base; /* arbitrary, as long as all */ /* accesses are valid */ sourcex = x; /* guarantee no source skew */ sraster = 0; break; default: /* rop_usage_[D]ST */ fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height); } } #ifdef DEBUG if_debug1('b', "final rop=0x%x\n", rop); #endif /* Set up transfer parameters. */ line_count = height; srow = sdata; drow = scan_line_base(mdev, y); traster = textures->raster; ty = y + phase_y; /* Loop over scan lines. */ for (; line_count-- > 0; drow += draster, srow += sraster, ++ty) { int sx = sourcex; int dx = x; int w = width; const byte *trow = textures->data + (ty % textures->rep_height) * traster; int xoff = x_offset(phase_x, ty, textures); int nw; /* Loop over (horizontal) copies of the tile. */ for (; w > 0; sx += nw, dx += nw, w -= nw) { int dbit = dx & 7; int sbit = sx & 7; int sskew = sbit - dbit; int tx = (dx + xoff) % textures->rep_width; int tbit = tx & 7; int tskew = tbit - dbit; int left = nw = min(w, textures->size.x - tx); byte lmask = 0xff >> dbit; byte rmask = 0xff << (~(dbit + nw - 1) & 7); byte mask = lmask; int nx = 8 - dbit; byte *dptr = drow + (dx >> 3); const byte *sptr = srow + (sx >> 3); const byte *tptr = trow + (tx >> 3); if (sskew < 0) --sptr, sskew += 8; if (tskew < 0) --tptr, tskew += 8; for (; left > 0; left -= nx, mask = 0xff, nx = 8, ++dptr, ++sptr, ++tptr ) { byte dbyte = *dptr; #define fetch1(ptr, skew)\ (skew ? (ptr[0] << skew) + (ptr[1] >> (8 - skew)) : *ptr) byte sbyte = fetch1(sptr, sskew); byte tbyte = fetch1(tptr, tskew); #undef fetch1 byte result = (*rop_proc_table[rop]) (dbyte, sbyte, tbyte); if (left <= nx) mask &= rmask; *dptr = (mask == 0xff ? result : (result & mask) | (dbyte & ~mask)); } } } #ifdef DEBUG if (gs_debug_c('B')) debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster, height, "final dest bits"); #endif return 0; }