1 /* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises, 2001 Artifex Software. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /*$Id: gdevm40.c,v 1.3 2005/06/20 08:59:23 igor Exp $ */ 18 /* 40-bit-per-pixel "memory" (stored bitmap) device */ 19 #include "memory_.h" 20 #include "gx.h" 21 #include "gxdevice.h" 22 #include "gxdevmem.h" /* semi-public definitions */ 23 #include "gdevmem.h" /* private definitions */ 24 25 /* Define debugging statistics. */ 26 #ifdef DEBUG 27 struct stats_mem40_s { 28 long 29 fill, fwide, fgray[101], fsetc, fcolor[101], fnarrow[5], 30 fprevc[257]; 31 double ftotal; 32 } stats_mem40; 33 static int prev_count = 0; 34 static gx_color_index prev_colors[256]; 35 # define INCR(v) (++(stats_mem40.v)) 36 #else 37 # define INCR(v) DO_NOTHING 38 #endif 39 40 41 /* ================ Standard (byte-oriented) device ================ */ 42 43 #undef chunk 44 #define chunk byte 45 #define PIXEL_SIZE 5 46 47 /* Procedures */ 48 declare_mem_procs(mem_true40_copy_mono, mem_true40_copy_color, mem_true40_fill_rectangle); 49 50 /* The device descriptor. */ 51 const gx_device_memory mem_true40_device = 52 mem_full_alpha_device("image40", 40, 0, mem_open, 53 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb, 54 mem_true40_copy_mono, mem_true40_copy_color, mem_true40_fill_rectangle, 55 gx_default_map_cmyk_color, gx_default_copy_alpha, 56 gx_default_strip_tile_rectangle, mem_default_strip_copy_rop, 57 mem_get_bits_rectangle); 58 59 /* Convert x coordinate to byte offset in scan line. */ 60 #undef x_to_byte 61 #define x_to_byte(x) ((x) * PIXEL_SIZE) 62 63 /* Unpack a color into its bytes. */ 64 #define declare_unpack_color(a, b, c, d, e, color)\ 65 byte a = (byte)(color >> 32);\ 66 byte b = (byte)((uint)color >> 24);\ 67 byte c = (byte)((uint)color >> 16);\ 68 byte d = (byte)((uint)color >> 8);\ 69 byte e = (byte)color 70 /* Put a 40-bit color into the bitmap. */ 71 #define put5(ptr, a, b, c, d, e)\ 72 (ptr)[0] = a, (ptr)[1] = b, (ptr)[2] = c, (ptr)[3] = d, (ptr)[4] = e 73 /* Put 4 bytes of color into the bitmap. */ 74 #define putw(ptr, wxyz)\ 75 *(bits32 *)(ptr) = (wxyz) 76 /* Load the 5-word 40-bit-color cache. */ 77 /* Free variables: [m]dev, abcd, bcde, cdea, deab, earc. */ 78 #if arch_is_big_endian 79 # define set_color40_cache(color, a, b, c, d, e)\ 80 mdev->color40.abcd = abcd = (color) >> 8, \ 81 mdev->color40.bcde = bcde = (abcd << 8) | (e),\ 82 mdev->color40.cdea = cdea = (bcde << 8) | (a),\ 83 mdev->color40.deab = deab = (cdea << 8) | (b),\ 84 mdev->color40.eabc = eabc = (deab << 8) | (c),\ 85 mdev->color40.abcde = (color) 86 #else 87 # define set_color40_cache(color, a, b, c, d, e)\ 88 mdev->color40.abcd = abcd =\ 89 ((bits32)(d) << 24) | ((bits32)(c) << 16) |\ 90 ((bits16)(b) << 8) | (a),\ 91 mdev->color40.eabc = eabc = (abcd << 8) | (e),\ 92 mdev->color40.deab = deab = (eabc << 8) | (d),\ 93 mdev->color40.cdea = cdea = (deab << 8) | (c),\ 94 mdev->color40.bcde = bcde = (cdea << 8) | (b),\ 95 mdev->color40.abcde = (color) 96 #endif 97 98 /* Fill a rectangle with a color. */ 99 private int 100 mem_true40_fill_rectangle(gx_device * dev, 101 int x, int y, int w, int h, gx_color_index color) 102 { 103 gx_device_memory * const mdev = (gx_device_memory *)dev; 104 declare_unpack_color(a, b, c, d, e, color); 105 declare_scan_ptr(dest); 106 107 /* 108 * In order to avoid testing w > 0 and h > 0 twice, we defer 109 * executing setup_rect, and use fit_fill_xywh instead of 110 * fit_fill. 111 */ 112 fit_fill_xywh(dev, x, y, w, h); 113 INCR(fill); 114 #ifdef DEBUG 115 stats_mem40.ftotal += w; 116 #endif 117 if (w >= 5) { 118 if (h <= 0) 119 return 0; 120 INCR(fwide); 121 setup_rect(dest); 122 if (a == b && b == c && c == d && d == e) { 123 int bcnt = w * PIXEL_SIZE; 124 125 INCR(fgray[min(w, 100)]); 126 while (h-- > 0) { 127 memset(dest, a, bcnt); 128 inc_ptr(dest, draster); 129 } 130 } else { 131 int x3 = -x & 3, ww = w - x3; /* we know ww >= 2 */ 132 bits32 abcd, bcde, cdea, deab, eabc; 133 134 if (mdev->color40.abcde == color) { 135 abcd = mdev->color40.abcd; 136 bcde = mdev->color40.bcde; 137 cdea = mdev->color40.cdea; 138 deab = mdev->color40.deab; 139 eabc = mdev->color40.eabc; 140 } else { 141 INCR(fsetc); 142 set_color40_cache(color, a, b, c, d, e); 143 } 144 #ifdef DEBUG 145 { 146 int ci; 147 for (ci = 0; ci < prev_count; ++ci) 148 if (prev_colors[ci] == color) 149 break; 150 INCR(fprevc[ci]); 151 if (ci == prev_count) { 152 if (ci < countof(prev_colors)) 153 ++prev_count; 154 else 155 --ci; 156 } 157 if (ci) { 158 memmove(&prev_colors[1], &prev_colors[0], 159 ci * sizeof(prev_colors[0])); 160 prev_colors[0] = color; 161 } 162 } 163 #endif 164 INCR(fcolor[min(w, 100)]); 165 while (h-- > 0) { 166 register byte *pptr = dest; 167 int w1 = ww; 168 169 switch (x3) { 170 case 1: 171 pptr[0] = a; 172 putw(pptr + 1, bcde); 173 pptr += PIXEL_SIZE; 174 break; 175 case 2: 176 pptr[0] = a; 177 pptr[1] = b; 178 putw(pptr + 2, cdea); 179 putw(pptr + 6, bcde); 180 pptr += 2 * PIXEL_SIZE; 181 break; 182 case 3: 183 pptr[0] = a; 184 pptr[1] = b; 185 pptr[2] = c; 186 putw(pptr + 3, deab); 187 putw(pptr + 7, cdea); 188 putw(pptr + 11, bcde); 189 pptr += 3 * PIXEL_SIZE; 190 break; 191 case 0: 192 ; 193 } 194 while (w1 >= 4) { 195 putw(pptr, abcd); 196 putw(pptr + 4, eabc); 197 putw(pptr + 8, deab); 198 putw(pptr + 12, cdea); 199 putw(pptr + 16, bcde); 200 pptr += 4 * PIXEL_SIZE; 201 w1 -= 4; 202 } 203 switch (w1) { 204 case 1: 205 putw(pptr, abcd); 206 pptr[4] = e; 207 break; 208 case 2: 209 putw(pptr, abcd); 210 putw(pptr + 4, eabc); 211 pptr[8] = d; 212 pptr[9] = e; 213 break; 214 case 3: 215 putw(pptr, abcd); 216 putw(pptr + 4, eabc); 217 putw(pptr + 8, deab); 218 pptr[12] = c; 219 pptr[13] = d; 220 pptr[14] = e; 221 break; 222 case 0: 223 ; 224 } 225 inc_ptr(dest, draster); 226 } 227 } 228 } else if (h > 0) { /* w < 5 */ 229 INCR(fnarrow[max(w, 0)]); 230 setup_rect(dest); 231 switch (w) { 232 case 4: 233 do { 234 dest[15] = dest[10] = dest[5] = dest[0] = a; 235 dest[16] = dest[11] = dest[6] = dest[1] = b; 236 dest[17] = dest[12] = dest[7] = dest[2] = c; 237 dest[18] = dest[13] = dest[8] = dest[3] = d; 238 dest[19] = dest[14] = dest[9] = dest[4] = e; 239 inc_ptr(dest, draster); 240 } 241 while (--h); 242 break; 243 case 3: 244 do { 245 dest[10] = dest[5] = dest[0] = a; 246 dest[11] = dest[6] = dest[1] = b; 247 dest[12] = dest[7] = dest[2] = c; 248 dest[13] = dest[8] = dest[3] = d; 249 dest[14] = dest[9] = dest[4] = e; 250 inc_ptr(dest, draster); 251 } 252 while (--h); 253 break; 254 case 2: 255 do { 256 dest[5] = dest[0] = a; 257 dest[6] = dest[1] = b; 258 dest[7] = dest[2] = c; 259 dest[8] = dest[3] = d; 260 dest[9] = dest[4] = e; 261 inc_ptr(dest, draster); 262 } 263 while (--h); 264 break; 265 case 1: 266 do { 267 dest[0] = a; dest[1] = b; dest[2] = c; dest[3] = d; dest[4] = e; 268 inc_ptr(dest, draster); 269 } 270 while (--h); 271 break; 272 case 0: 273 default: 274 ; 275 } 276 } 277 return 0; 278 } 279 280 /* Copy a monochrome bitmap. */ 281 private int 282 mem_true40_copy_mono(gx_device * dev, 283 const byte * base, int sourcex, int sraster, gx_bitmap_id id, 284 int x, int y, int w, int h, gx_color_index zero, gx_color_index one) 285 { 286 gx_device_memory * const mdev = (gx_device_memory *)dev; 287 const byte *line; 288 int sbit; 289 int first_bit; 290 291 declare_scan_ptr(dest); 292 293 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); 294 setup_rect(dest); 295 line = base + (sourcex >> 3); 296 sbit = sourcex & 7; 297 first_bit = 0x80 >> sbit; 298 if (zero != gx_no_color_index) { /* Loop for halftones or inverted masks */ 299 /* (never used). */ 300 declare_unpack_color(a0, b0, c0, d0, e0, zero); 301 declare_unpack_color(a1, b1, c1, d1, e1, one); 302 while (h-- > 0) { 303 register byte *pptr = dest; 304 const byte *sptr = line; 305 register int sbyte = *sptr++; 306 register int bit = first_bit; 307 int count = w; 308 309 do { 310 if (sbyte & bit) { 311 if (one != gx_no_color_index) 312 put5(pptr, a1, b1, c1, d1, e1); 313 } else 314 put5(pptr, a0, b0, c0, d0, e0); 315 pptr += PIXEL_SIZE; 316 if ((bit >>= 1) == 0) 317 bit = 0x80, sbyte = *sptr++; 318 } 319 while (--count > 0); 320 line += sraster; 321 inc_ptr(dest, draster); 322 } 323 } else if (one != gx_no_color_index) { /* Loop for character and pattern masks. */ 324 /* This is used heavily. */ 325 declare_unpack_color(a1, b1, c1, d1, e1, one); 326 int first_mask = first_bit << 1; 327 int first_count, first_skip; 328 329 if (sbit + w > 8) 330 first_mask -= 1, 331 first_count = 8 - sbit; 332 else 333 first_mask -= first_mask >> w, 334 first_count = w; 335 first_skip = first_count * PIXEL_SIZE; 336 while (h-- > 0) { 337 register byte *pptr = dest; 338 const byte *sptr = line; 339 register int sbyte = *sptr++ & first_mask; 340 int count = w - first_count; 341 342 if (sbyte) { 343 register int bit = first_bit; 344 345 do { 346 if (sbyte & bit) 347 put5(pptr, a1, b1, c1, d1, e1); 348 pptr += PIXEL_SIZE; 349 } 350 while ((bit >>= 1) & first_mask); 351 } else 352 pptr += first_skip; 353 while (count >= 8) { 354 sbyte = *sptr++; 355 if (sbyte & 0xf0) { 356 if (sbyte & 0x80) 357 put5(pptr, a1, b1, c1, d1, e1); 358 if (sbyte & 0x40) 359 put5(pptr + 5, a1, b1, c1, d1, e1); 360 if (sbyte & 0x20) 361 put5(pptr + 10, a1, b1, c1, d1, e1); 362 if (sbyte & 0x10) 363 put5(pptr + 15, a1, b1, c1, d1, e1); 364 } 365 if (sbyte & 0xf) { 366 if (sbyte & 8) 367 put5(pptr + 20, a1, b1, c1, d1, e1); 368 if (sbyte & 4) 369 put5(pptr + 25, a1, b1, c1, d1, e1); 370 if (sbyte & 2) 371 put5(pptr + 30, a1, b1, c1, d1, e1); 372 if (sbyte & 1) 373 put5(pptr + 35, a1, b1, c1, d1, e1); 374 } 375 pptr += 8 * PIXEL_SIZE; 376 count -= 8; 377 } 378 if (count > 0) { 379 register int bit = 0x80; 380 381 sbyte = *sptr++; 382 do { 383 if (sbyte & bit) 384 put5(pptr, a1, b1, c1, d1, e1); 385 pptr += PIXEL_SIZE; 386 bit >>= 1; 387 } 388 while (--count > 0); 389 } 390 line += sraster; 391 inc_ptr(dest, draster); 392 } 393 } 394 return 0; 395 } 396 397 /* Copy a color bitmap. */ 398 private int 399 mem_true40_copy_color(gx_device * dev, 400 const byte * base, int sourcex, int sraster, gx_bitmap_id id, 401 int x, int y, int w, int h) 402 { 403 gx_device_memory * const mdev = (gx_device_memory *)dev; 404 405 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); 406 mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h); 407 return 0; 408 } 409 410 /* ================ "Word"-oriented device ================ */ 411 412 /* Note that on a big-endian machine, this is the same as the */ 413 /* standard byte-oriented-device. */ 414 415 #if !arch_is_big_endian 416 417 /* Procedures */ 418 declare_mem_procs(mem40_word_copy_mono, mem40_word_copy_color, mem40_word_fill_rectangle); 419 420 /* Here is the device descriptor. */ 421 const gx_device_memory mem_true40_word_device = 422 mem_full_device("image40w", 40, 0, mem_open, 423 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb, 424 mem40_word_copy_mono, mem40_word_copy_color, mem40_word_fill_rectangle, 425 gx_default_map_cmyk_color, gx_default_strip_tile_rectangle, 426 gx_no_strip_copy_rop, mem_word_get_bits_rectangle); 427 428 /* Fill a rectangle with a color. */ 429 private int 430 mem40_word_fill_rectangle(gx_device * dev, int x, int y, int w, int h, 431 gx_color_index color) 432 { 433 gx_device_memory * const mdev = (gx_device_memory *)dev; 434 byte *base; 435 uint raster; 436 437 fit_fill(dev, x, y, w, h); 438 base = scan_line_base(mdev, y); 439 raster = mdev->raster; 440 mem_swap_byte_rect(base, raster, x * 40, w * 40, h, true); 441 mem_true40_fill_rectangle(dev, x, y, w, h, color); 442 mem_swap_byte_rect(base, raster, x * 40, w * 40, h, false); 443 return 0; 444 } 445 446 /* Copy a bitmap. */ 447 private int 448 mem40_word_copy_mono(gx_device * dev, 449 const byte * base, int sourcex, int sraster, gx_bitmap_id id, 450 int x, int y, int w, int h, gx_color_index zero, gx_color_index one) 451 { 452 gx_device_memory * const mdev = (gx_device_memory *)dev; 453 byte *row; 454 uint raster; 455 bool store; 456 457 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); 458 row = scan_line_base(mdev, y); 459 raster = mdev->raster; 460 store = (zero != gx_no_color_index && one != gx_no_color_index); 461 mem_swap_byte_rect(row, raster, x * 40, w * 40, h, store); 462 mem_true40_copy_mono(dev, base, sourcex, sraster, id, 463 x, y, w, h, zero, one); 464 mem_swap_byte_rect(row, raster, x * 40, w * 40, h, false); 465 return 0; 466 } 467 468 /* Copy a color bitmap. */ 469 private int 470 mem40_word_copy_color(gx_device * dev, 471 const byte * base, int sourcex, int sraster, gx_bitmap_id id, 472 int x, int y, int w, int h) 473 { 474 gx_device_memory * const mdev = (gx_device_memory *)dev; 475 byte *row; 476 uint raster; 477 478 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); 479 row = scan_line_base(mdev, y); 480 raster = mdev->raster; 481 mem_swap_byte_rect(row, raster, x * 40, w * 40, h, true); 482 bytes_copy_rectangle(row + x * PIXEL_SIZE, raster, base + sourcex * PIXEL_SIZE, 483 sraster, w * PIXEL_SIZE, h); 484 mem_swap_byte_rect(row, raster, x * 40, w * 40, h, false); 485 return 0; 486 } 487 488 #endif /* !arch_is_big_endian */ 489