17dd7cddfSDavid du Colombier /* Copyright (C) 1995, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gdevmr1.c,v 1.5 2002/08/22 07:12:28 henrys Exp $ */
187dd7cddfSDavid du Colombier /* RasterOp implementation for monobit memory devices */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gx.h"
217dd7cddfSDavid du Colombier #include "gsbittab.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gsropt.h"
247dd7cddfSDavid du Colombier #include "gxcindex.h"
257dd7cddfSDavid du Colombier #include "gxdcolor.h"
267dd7cddfSDavid du Colombier #include "gxdevice.h"
277dd7cddfSDavid du Colombier #include "gxdevmem.h"
287dd7cddfSDavid du Colombier #include "gxdevrop.h"
297dd7cddfSDavid du Colombier #include "gdevmrop.h"
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier /* Calculate the X offset for a given Y value, */
327dd7cddfSDavid du Colombier /* taking shift into account if necessary. */
337dd7cddfSDavid du Colombier #define x_offset(px, ty, textures)\
347dd7cddfSDavid du Colombier ((textures)->shift == 0 ? (px) :\
357dd7cddfSDavid du Colombier (px) + (ty) / (textures)->rep_height * (textures)->rep_shift)
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier /* ---------------- Monobit RasterOp ---------------- */
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier 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)407dd7cddfSDavid du Colombier mem_mono_strip_copy_rop(gx_device * dev,
417dd7cddfSDavid du Colombier const byte * sdata, int sourcex, uint sraster, gx_bitmap_id id,
427dd7cddfSDavid du Colombier const gx_color_index * scolors,
437dd7cddfSDavid du Colombier const gx_strip_bitmap * textures, const gx_color_index * tcolors,
447dd7cddfSDavid du Colombier int x, int y, int width, int height,
457dd7cddfSDavid du Colombier int phase_x, int phase_y, gs_logical_operation_t lop)
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier gx_device_memory *mdev = (gx_device_memory *) dev;
487dd7cddfSDavid du Colombier gs_rop3_t rop = gs_transparent_rop(lop); /* handle transparency */
497dd7cddfSDavid du Colombier gx_strip_bitmap no_texture;
507dd7cddfSDavid du Colombier bool invert;
517dd7cddfSDavid du Colombier uint draster = mdev->raster;
527dd7cddfSDavid du Colombier uint traster;
537dd7cddfSDavid du Colombier int line_count;
547dd7cddfSDavid du Colombier byte *drow;
557dd7cddfSDavid du Colombier const byte *srow;
567dd7cddfSDavid du Colombier int ty;
577dd7cddfSDavid du Colombier
587dd7cddfSDavid du Colombier /* If map_rgb_color isn't the default one for monobit memory */
597dd7cddfSDavid du Colombier /* devices, palette might not be set; set it now if needed. */
60*593dc095SDavid du Colombier if (mdev->palette.data == 0) {
61*593dc095SDavid du Colombier gx_color_value cv[3];
62*593dc095SDavid du Colombier cv[0] = cv[1] = cv[2] = 0;
637dd7cddfSDavid du Colombier gdev_mem_mono_set_inverted(mdev,
647dd7cddfSDavid du Colombier (*dev_proc(dev, map_rgb_color))
65*593dc095SDavid du Colombier (dev, cv) != 0);
66*593dc095SDavid du Colombier }
677dd7cddfSDavid du Colombier invert = mdev->palette.data[0] != 0;
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier #ifdef DEBUG
707dd7cddfSDavid du Colombier if (gs_debug_c('b'))
717dd7cddfSDavid du Colombier trace_copy_rop("mem_mono_strip_copy_rop",
727dd7cddfSDavid du Colombier dev, sdata, sourcex, sraster,
737dd7cddfSDavid du Colombier id, scolors, textures, tcolors,
747dd7cddfSDavid du Colombier x, y, width, height, phase_x, phase_y, lop);
757dd7cddfSDavid du Colombier if (gs_debug_c('B'))
767dd7cddfSDavid du Colombier debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
777dd7cddfSDavid du Colombier height, "initial dest bits");
787dd7cddfSDavid du Colombier #endif
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier /*
817dd7cddfSDavid du Colombier * RasterOp is defined as operating in RGB space; in the monobit
827dd7cddfSDavid du Colombier * case, this means black = 0, white = 1. However, most monobit
837dd7cddfSDavid du Colombier * devices use the opposite convention. To make this work,
847dd7cddfSDavid du Colombier * we must precondition the Boolean operation by swapping the
857dd7cddfSDavid du Colombier * order of bits end-for-end and then inverting.
867dd7cddfSDavid du Colombier */
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier if (invert)
897dd7cddfSDavid du Colombier rop = byte_reverse_bits[rop] ^ 0xff;
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier /*
927dd7cddfSDavid du Colombier * From this point on, rop works in terms of device pixel values,
937dd7cddfSDavid du Colombier * not RGB-space values.
947dd7cddfSDavid du Colombier */
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier /* Modify the raster operation according to the source palette. */
977dd7cddfSDavid du Colombier if (scolors != 0) { /* Source with palette. */
987dd7cddfSDavid du Colombier switch ((int)((scolors[1] << 1) + scolors[0])) {
997dd7cddfSDavid du Colombier case 0:
1007dd7cddfSDavid du Colombier rop = rop3_know_S_0(rop);
1017dd7cddfSDavid du Colombier break;
1027dd7cddfSDavid du Colombier case 1:
1037dd7cddfSDavid du Colombier rop = rop3_invert_S(rop);
1047dd7cddfSDavid du Colombier break;
1057dd7cddfSDavid du Colombier case 2:
1067dd7cddfSDavid du Colombier break;
1077dd7cddfSDavid du Colombier case 3:
1087dd7cddfSDavid du Colombier rop = rop3_know_S_1(rop);
1097dd7cddfSDavid du Colombier break;
1107dd7cddfSDavid du Colombier }
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier /* Modify the raster operation according to the texture palette. */
1137dd7cddfSDavid du Colombier if (tcolors != 0) { /* Texture with palette. */
1147dd7cddfSDavid du Colombier switch ((int)((tcolors[1] << 1) + tcolors[0])) {
1157dd7cddfSDavid du Colombier case 0:
1167dd7cddfSDavid du Colombier rop = rop3_know_T_0(rop);
1177dd7cddfSDavid du Colombier break;
1187dd7cddfSDavid du Colombier case 1:
1197dd7cddfSDavid du Colombier rop = rop3_invert_T(rop);
1207dd7cddfSDavid du Colombier break;
1217dd7cddfSDavid du Colombier case 2:
1227dd7cddfSDavid du Colombier break;
1237dd7cddfSDavid du Colombier case 3:
1247dd7cddfSDavid du Colombier rop = rop3_know_T_1(rop);
1257dd7cddfSDavid du Colombier break;
1267dd7cddfSDavid du Colombier }
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier /* Handle constant source and/or texture, and other special cases. */
1297dd7cddfSDavid du Colombier {
1307dd7cddfSDavid du Colombier gx_color_index color0, color1;
1317dd7cddfSDavid du Colombier
1327dd7cddfSDavid du Colombier switch (rop_usage_table[rop]) {
1337dd7cddfSDavid du Colombier case rop_usage_none:
1347dd7cddfSDavid du Colombier /* We're just filling with a constant. */
1357dd7cddfSDavid du Colombier return (*dev_proc(dev, fill_rectangle))
1367dd7cddfSDavid du Colombier (dev, x, y, width, height, (gx_color_index) (rop & 1));
1377dd7cddfSDavid du Colombier case rop_usage_D:
1387dd7cddfSDavid du Colombier /* This is either D (no-op) or ~D. */
1397dd7cddfSDavid du Colombier if (rop == rop3_D)
1407dd7cddfSDavid du Colombier return 0;
1417dd7cddfSDavid du Colombier /* Code no_S inline, then finish with no_T. */
1427dd7cddfSDavid du Colombier fit_fill(dev, x, y, width, height);
1437dd7cddfSDavid du Colombier sdata = scan_line_base(mdev, 0);
1447dd7cddfSDavid du Colombier sourcex = x;
1457dd7cddfSDavid du Colombier sraster = 0;
1467dd7cddfSDavid du Colombier goto no_T;
1477dd7cddfSDavid du Colombier case rop_usage_S:
1487dd7cddfSDavid du Colombier /* This is either S or ~S, which copy_mono can handle. */
1497dd7cddfSDavid du Colombier if (rop == rop3_S)
1507dd7cddfSDavid du Colombier color0 = 0, color1 = 1;
1517dd7cddfSDavid du Colombier else
1527dd7cddfSDavid du Colombier color0 = 1, color1 = 0;
1537dd7cddfSDavid du Colombier do_copy:return (*dev_proc(dev, copy_mono))
1547dd7cddfSDavid du Colombier (dev, sdata, sourcex, sraster, id, x, y, width, height,
1557dd7cddfSDavid du Colombier color0, color1);
1567dd7cddfSDavid du Colombier case rop_usage_DS:
1577dd7cddfSDavid du Colombier /* This might be a case that copy_mono can handle. */
1587dd7cddfSDavid du Colombier #define copy_case(c0, c1) color0 = c0, color1 = c1; goto do_copy;
1597dd7cddfSDavid du Colombier switch ((uint) rop) { /* cast shuts up picky compilers */
1607dd7cddfSDavid du Colombier case rop3_D & rop3_not(rop3_S):
1617dd7cddfSDavid du Colombier copy_case(gx_no_color_index, 0);
1627dd7cddfSDavid du Colombier case rop3_D | rop3_S:
1637dd7cddfSDavid du Colombier copy_case(gx_no_color_index, 1);
1647dd7cddfSDavid du Colombier case rop3_D & rop3_S:
1657dd7cddfSDavid du Colombier copy_case(0, gx_no_color_index);
1667dd7cddfSDavid du Colombier case rop3_D | rop3_not(rop3_S):
1677dd7cddfSDavid du Colombier copy_case(1, gx_no_color_index);
1687dd7cddfSDavid du Colombier default:;
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier #undef copy_case
1717dd7cddfSDavid du Colombier fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
1727dd7cddfSDavid du Colombier no_T: /* Texture is not used; textures may be garbage. */
1737dd7cddfSDavid du Colombier no_texture.data = scan_line_base(mdev, 0); /* arbitrary */
1747dd7cddfSDavid du Colombier no_texture.raster = 0;
1757dd7cddfSDavid du Colombier no_texture.size.x = width;
1767dd7cddfSDavid du Colombier no_texture.size.y = height;
1777dd7cddfSDavid du Colombier no_texture.rep_width = no_texture.rep_height = 1;
1787dd7cddfSDavid du Colombier no_texture.rep_shift = no_texture.shift = 0;
1797dd7cddfSDavid du Colombier textures = &no_texture;
1807dd7cddfSDavid du Colombier break;
1817dd7cddfSDavid du Colombier case rop_usage_T:
1827dd7cddfSDavid du Colombier /* This is either T or ~T, which tile_rectangle can handle. */
1837dd7cddfSDavid du Colombier if (rop == rop3_T)
1847dd7cddfSDavid du Colombier color0 = 0, color1 = 1;
1857dd7cddfSDavid du Colombier else
1867dd7cddfSDavid du Colombier color0 = 1, color1 = 0;
1877dd7cddfSDavid du Colombier do_tile:return (*dev_proc(dev, strip_tile_rectangle))
1887dd7cddfSDavid du Colombier (dev, textures, x, y, width, height, color0, color1,
1897dd7cddfSDavid du Colombier phase_x, phase_y);
1907dd7cddfSDavid du Colombier case rop_usage_DT:
1917dd7cddfSDavid du Colombier /* This might be a case that tile_rectangle can handle. */
1927dd7cddfSDavid du Colombier #define tile_case(c0, c1) color0 = c0, color1 = c1; goto do_tile;
1937dd7cddfSDavid du Colombier switch ((uint) rop) { /* cast shuts up picky compilers */
1947dd7cddfSDavid du Colombier case rop3_D & rop3_not(rop3_T):
1957dd7cddfSDavid du Colombier tile_case(gx_no_color_index, 0);
1967dd7cddfSDavid du Colombier case rop3_D | rop3_T:
1977dd7cddfSDavid du Colombier tile_case(gx_no_color_index, 1);
1987dd7cddfSDavid du Colombier case rop3_D & rop3_T:
1997dd7cddfSDavid du Colombier tile_case(0, gx_no_color_index);
2007dd7cddfSDavid du Colombier case rop3_D | rop3_not(rop3_T):
2017dd7cddfSDavid du Colombier tile_case(1, gx_no_color_index);
2027dd7cddfSDavid du Colombier default:;
2037dd7cddfSDavid du Colombier }
2047dd7cddfSDavid du Colombier #undef tile_case
2057dd7cddfSDavid du Colombier fit_fill(dev, x, y, width, height);
2067dd7cddfSDavid du Colombier /* Source is not used; sdata et al may be garbage. */
2077dd7cddfSDavid du Colombier sdata = mdev->base; /* arbitrary, as long as all */
2087dd7cddfSDavid du Colombier /* accesses are valid */
2097dd7cddfSDavid du Colombier sourcex = x; /* guarantee no source skew */
2107dd7cddfSDavid du Colombier sraster = 0;
2117dd7cddfSDavid du Colombier break;
2127dd7cddfSDavid du Colombier default: /* rop_usage_[D]ST */
2137dd7cddfSDavid du Colombier fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier }
2167dd7cddfSDavid du Colombier
2177dd7cddfSDavid du Colombier #ifdef DEBUG
2187dd7cddfSDavid du Colombier if_debug1('b', "final rop=0x%x\n", rop);
2197dd7cddfSDavid du Colombier #endif
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier /* Set up transfer parameters. */
2227dd7cddfSDavid du Colombier line_count = height;
2237dd7cddfSDavid du Colombier srow = sdata;
2247dd7cddfSDavid du Colombier drow = scan_line_base(mdev, y);
2257dd7cddfSDavid du Colombier traster = textures->raster;
2267dd7cddfSDavid du Colombier ty = y + phase_y;
2277dd7cddfSDavid du Colombier
2287dd7cddfSDavid du Colombier /* Loop over scan lines. */
2297dd7cddfSDavid du Colombier for (; line_count-- > 0; drow += draster, srow += sraster, ++ty) {
2307dd7cddfSDavid du Colombier int sx = sourcex;
2317dd7cddfSDavid du Colombier int dx = x;
2327dd7cddfSDavid du Colombier int w = width;
2337dd7cddfSDavid du Colombier const byte *trow =
2347dd7cddfSDavid du Colombier textures->data + (ty % textures->rep_height) * traster;
2357dd7cddfSDavid du Colombier int xoff = x_offset(phase_x, ty, textures);
2367dd7cddfSDavid du Colombier int nw;
2377dd7cddfSDavid du Colombier
2387dd7cddfSDavid du Colombier /* Loop over (horizontal) copies of the tile. */
2397dd7cddfSDavid du Colombier for (; w > 0; sx += nw, dx += nw, w -= nw) {
2407dd7cddfSDavid du Colombier int dbit = dx & 7;
2417dd7cddfSDavid du Colombier int sbit = sx & 7;
2427dd7cddfSDavid du Colombier int sskew = sbit - dbit;
2437dd7cddfSDavid du Colombier int tx = (dx + xoff) % textures->rep_width;
2447dd7cddfSDavid du Colombier int tbit = tx & 7;
2457dd7cddfSDavid du Colombier int tskew = tbit - dbit;
2467dd7cddfSDavid du Colombier int left = nw = min(w, textures->size.x - tx);
2477dd7cddfSDavid du Colombier byte lmask = 0xff >> dbit;
2487dd7cddfSDavid du Colombier byte rmask = 0xff << (~(dbit + nw - 1) & 7);
2497dd7cddfSDavid du Colombier byte mask = lmask;
2507dd7cddfSDavid du Colombier int nx = 8 - dbit;
2517dd7cddfSDavid du Colombier byte *dptr = drow + (dx >> 3);
2527dd7cddfSDavid du Colombier const byte *sptr = srow + (sx >> 3);
2537dd7cddfSDavid du Colombier const byte *tptr = trow + (tx >> 3);
2547dd7cddfSDavid du Colombier
2557dd7cddfSDavid du Colombier if (sskew < 0)
2567dd7cddfSDavid du Colombier --sptr, sskew += 8;
2577dd7cddfSDavid du Colombier if (tskew < 0)
2587dd7cddfSDavid du Colombier --tptr, tskew += 8;
2597dd7cddfSDavid du Colombier for (; left > 0;
2607dd7cddfSDavid du Colombier left -= nx, mask = 0xff, nx = 8,
2617dd7cddfSDavid du Colombier ++dptr, ++sptr, ++tptr
2627dd7cddfSDavid du Colombier ) {
2637dd7cddfSDavid du Colombier byte dbyte = *dptr;
2647dd7cddfSDavid du Colombier
2657dd7cddfSDavid du Colombier #define fetch1(ptr, skew)\
2667dd7cddfSDavid du Colombier (skew ? (ptr[0] << skew) + (ptr[1] >> (8 - skew)) : *ptr)
2677dd7cddfSDavid du Colombier byte sbyte = fetch1(sptr, sskew);
2687dd7cddfSDavid du Colombier byte tbyte = fetch1(tptr, tskew);
2697dd7cddfSDavid du Colombier
2707dd7cddfSDavid du Colombier #undef fetch1
2717dd7cddfSDavid du Colombier byte result =
2727dd7cddfSDavid du Colombier (*rop_proc_table[rop]) (dbyte, sbyte, tbyte);
2737dd7cddfSDavid du Colombier
2747dd7cddfSDavid du Colombier if (left <= nx)
2757dd7cddfSDavid du Colombier mask &= rmask;
2767dd7cddfSDavid du Colombier *dptr = (mask == 0xff ? result :
2777dd7cddfSDavid du Colombier (result & mask) | (dbyte & ~mask));
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier }
2817dd7cddfSDavid du Colombier #ifdef DEBUG
2827dd7cddfSDavid du Colombier if (gs_debug_c('B'))
2837dd7cddfSDavid du Colombier debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster,
2847dd7cddfSDavid du Colombier height, "final dest bits");
2857dd7cddfSDavid du Colombier #endif
2867dd7cddfSDavid du Colombier return 0;
2877dd7cddfSDavid du Colombier }
288