1 /* Copyright (C) 1998, 1999 Aladdin Enterprises. 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: gdevplnx.c,v 1.10 2004/08/04 19:36:12 stefan Exp $*/ 18 /* Plane extraction device */ 19 #include "gx.h" 20 #include "gserrors.h" 21 #include "gsbitops.h" 22 #include "gsrop.h" /* for logical op access */ 23 #include "gsstruct.h" 24 #include "gsutil.h" 25 #include "gxdcolor.h" 26 #include "gxcmap.h" /* requires gxdcolor.h */ 27 #include "gxdevice.h" 28 #include "gxdevmem.h" 29 #include "gxdither.h" 30 #include "gxgetbit.h" 31 #include "gxiparam.h" 32 #include "gxistate.h" 33 #include "gdevplnx.h" 34 35 /* Define the size of the locally allocated bitmap buffers. */ 36 #define COPY_COLOR_BUF_SIZE 100 37 #define TILE_RECTANGLE_BUF_SIZE 100 38 #define COPY_ROP_SOURCE_BUF_SIZE 100 39 #define COPY_ROP_TEXTURE_BUF_SIZE 100 40 41 /* GC procedures */ 42 private 43 ENUM_PTRS_WITH(device_plane_extract_enum_ptrs, gx_device_plane_extract *edev) 44 ENUM_PREFIX(st_device_forward, 1); 45 case 0: ENUM_RETURN(gx_device_enum_ptr(edev->target)); 46 ENUM_PTRS_END 47 private RELOC_PTRS_WITH(device_plane_extract_reloc_ptrs, gx_device_plane_extract *edev) 48 { 49 RELOC_PREFIX(st_device_forward); 50 edev->plane_dev = gx_device_reloc_ptr(edev->plane_dev, gcst); 51 } 52 RELOC_PTRS_END 53 public_st_device_plane_extract(); 54 55 /* Driver procedures */ 56 private dev_proc_open_device(plane_open_device); 57 private dev_proc_fill_rectangle(plane_fill_rectangle); 58 private dev_proc_copy_mono(plane_copy_mono); 59 private dev_proc_copy_color(plane_copy_color); 60 private dev_proc_copy_alpha(plane_copy_alpha); 61 private dev_proc_fill_path(plane_fill_path); 62 private dev_proc_stroke_path(plane_stroke_path); 63 private dev_proc_fill_mask(plane_fill_mask); 64 private dev_proc_fill_parallelogram(plane_fill_parallelogram); 65 private dev_proc_fill_triangle(plane_fill_triangle); 66 private dev_proc_strip_tile_rectangle(plane_strip_tile_rectangle); 67 private dev_proc_strip_copy_rop(plane_strip_copy_rop); 68 private dev_proc_begin_typed_image(plane_begin_typed_image); 69 private dev_proc_get_bits_rectangle(plane_get_bits_rectangle); 70 71 /* Device prototype */ 72 private const gx_device_plane_extract gs_plane_extract_device = { 73 std_device_std_body(gx_device_plane_extract, 0, "plane_extract", 74 0, 0, 72, 72), 75 { 76 plane_open_device, 77 NULL, 78 NULL, 79 NULL, 80 gx_default_close_device, 81 NULL, 82 NULL, 83 plane_fill_rectangle, 84 gx_default_tile_rectangle, 85 plane_copy_mono, 86 plane_copy_color, 87 gx_default_draw_line, 88 gx_default_get_bits, 89 NULL, 90 NULL, 91 NULL, 92 NULL, 93 NULL, 94 NULL, 95 NULL, 96 NULL, 97 plane_copy_alpha, 98 NULL, 99 gx_default_copy_rop, 100 plane_fill_path, 101 plane_stroke_path, 102 plane_fill_mask, 103 gx_default_fill_trapezoid, 104 plane_fill_parallelogram, 105 plane_fill_triangle, 106 gx_default_draw_thin_line, 107 gx_default_begin_image, 108 gx_default_image_data, 109 gx_default_end_image, 110 plane_strip_tile_rectangle, 111 plane_strip_copy_rop, 112 NULL, 113 plane_begin_typed_image, 114 plane_get_bits_rectangle, 115 NULL, 116 gx_no_create_compositor, /* WRONG */ 117 NULL, 118 gx_default_text_begin 119 }, 120 /* device-specific members */ 121 NULL, /* target */ 122 NULL, /* plane_dev */ 123 { 0 }, /* plane */ 124 0, /* plane_white */ 125 0, /* plane_mask */ 126 0, /* plane_dev_is_memory */ 127 1 /*true*/ /* any_marks */ 128 }; 129 130 /* ---------------- Utilities ---------------- */ 131 132 /* Extract the selected plane from a color (gx_color_index). */ 133 #define COLOR_PIXEL(edev, color)\ 134 ( ((color) >> (edev)->plane.shift) & (edev)->plane_mask ) 135 /* Do the same if the color might be transparent. */ 136 #define TRANS_COLOR_PIXEL(edev, color)\ 137 ((color) == gx_no_color_index ? gx_no_color_index : COLOR_PIXEL(edev, color)) 138 139 /* 140 * Reduce the drawing color to one for the selected plane. 141 * All we care about is whether the drawing operation should be skipped. 142 */ 143 typedef enum { 144 REDUCE_SKIP, 145 REDUCE_DRAW, 146 REDUCE_FAILED /* couldn't reduce */ 147 } reduced_color_t; 148 #define REDUCE_PURE(edev, pixel)\ 149 ((pixel) == (edev)->plane_white && !(edev)->any_marks ? REDUCE_SKIP :\ 150 ((edev)->any_marks = true, REDUCE_DRAW)) 151 private reduced_color_t 152 reduce_drawing_color(gx_device_color *ppdc, gx_device_plane_extract *edev, 153 const gx_drawing_color *pdevc, 154 gs_logical_operation_t *plop) 155 { 156 reduced_color_t reduced; 157 158 if (gx_dc_is_pure(pdevc)) { 159 gx_color_index pixel = COLOR_PIXEL(edev, gx_dc_pure_color(pdevc)); 160 161 set_nonclient_dev_color(ppdc, pixel); 162 reduced = REDUCE_PURE(edev, pixel); 163 } else if (gx_dc_is_binary_halftone(pdevc)) { 164 gx_color_index pixel0 = 165 TRANS_COLOR_PIXEL(edev, gx_dc_binary_color0(pdevc)); 166 gx_color_index pixel1 = 167 TRANS_COLOR_PIXEL(edev, gx_dc_binary_color1(pdevc)); 168 169 if (pixel0 == pixel1) { 170 set_nonclient_dev_color(ppdc, pixel0); 171 reduced = REDUCE_PURE(edev, pixel0); 172 } else { 173 *ppdc = *pdevc; 174 ppdc->colors.binary.color[0] = pixel0; 175 ppdc->colors.binary.color[1] = pixel1; 176 edev->any_marks = true; 177 reduced = REDUCE_DRAW; 178 } 179 } else if (color_is_colored_halftone(pdevc)) { 180 int plane = edev->plane.index; 181 int i; 182 183 *ppdc = *pdevc; 184 for (i = 0; i < countof(ppdc->colors.colored.c_base); ++i) 185 if (i != edev->plane.index) { 186 ppdc->colors.colored.c_base[i] = 0; 187 ppdc->colors.colored.c_level[i] = 0; 188 } 189 ppdc->colors.colored.plane_mask &= 1 << plane; 190 if (ppdc->colors.colored.c_level[plane] == 0) { 191 gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev); 192 ppdc->colors.pure = COLOR_PIXEL(edev, ppdc->colors.pure); 193 reduced = REDUCE_PURE(edev, gx_dc_pure_color(ppdc)); 194 } else if (ppdc->colors.colored.alpha != gx_max_color_value) 195 return REDUCE_FAILED; /* can't reduce */ 196 else { 197 gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev); 198 ppdc->colors.binary.color[0] = 199 COLOR_PIXEL(edev, ppdc->colors.binary.color[0]); 200 ppdc->colors.binary.color[1] = 201 COLOR_PIXEL(edev, ppdc->colors.binary.color[1]); 202 gx_color_load(ppdc, NULL, (gx_device *)edev); 203 edev->any_marks = true; 204 reduced = REDUCE_DRAW; 205 } 206 } else 207 return REDUCE_FAILED; /* can't handle it */ 208 if (*plop & lop_T_transparent) { 209 /* 210 * If the logical operation invokes transparency for the texture, we 211 * must do some extra work, since a color that was originally opaque 212 * may become transparent (white) if reduced to a single plane. If 213 * RasterOp transparency were calculated before halftoning, life 214 * would be easy: we would simply turn off texture transparency in 215 * the logical operation iff the original (not reduced) color was 216 * not white. Unfortunately, RasterOp transparency is calculated 217 * after halftoning. (This is arguably wrong, but it's how we've 218 * defined it.) Therefore, if transparency is involved with a 219 * white color or a halftone that can include white, we must keep 220 * the entire pixel together for the RasterOp. 221 */ 222 gx_color_index white = gx_device_white((gx_device *)edev); 223 224 /* 225 * Given that we haven't failed, the only possible colors at this 226 * point are pure or binary halftone. 227 */ 228 if (gx_dc_is_pure(ppdc)) { 229 if (gx_dc_pure_color(pdevc) != white) 230 *plop &= ~lop_T_transparent; 231 else if (!gx_dc_is_pure(pdevc)) 232 return REDUCE_FAILED; 233 } else { 234 if (gx_dc_binary_color0(pdevc) != white && 235 gx_dc_binary_color1(pdevc) != white) { 236 *plop &= ~lop_T_transparent; 237 } else 238 return REDUCE_FAILED; 239 } 240 } 241 return reduced; 242 } 243 244 /* 245 * Set up to create the plane-extracted bitmap corresponding to a 246 * source or halftone pixmap. If the bitmap doesn't fit in the locally 247 * allocated buffer, we may either do the operation in pieces, or allocate 248 * a buffer on the heap. The control structure is: 249 * begin_tiling(&state, ...); 250 * do { 251 * extract_partial_tile(&state); 252 * ... process tile in buffer ... 253 * } while (next_tile(&state)); 254 * end_tiling(&state); 255 * If partial_ok is false, there is only a single tile, so the do ... while 256 * is not used. 257 */ 258 typedef struct tiling_state_s { 259 /* Save the original operands. */ 260 const gx_device_plane_extract *edev; 261 const byte *data; 262 int data_x; 263 uint raster; 264 int width, height; 265 int dest_x; /* only for copy_color, defaults to 0 */ 266 /* Define the (aligned) buffer for doing the operation. */ 267 struct tsb_ { 268 byte *data; 269 uint size; 270 uint raster; 271 bool on_heap; 272 } buffer; 273 /* Record the current tile available for processing. */ 274 /* The client may read these out. */ 275 gs_int_point offset; 276 gs_int_point size; 277 /* Record private tiling parameters. */ 278 int per_tile_width; 279 } tiling_state_t; 280 281 /* 282 * Extract the plane's data from one subrectangle of a source tile. 283 */ 284 inline private int /* ignore the return value */ 285 extract_partial_tile(const tiling_state_t *pts) 286 { 287 const gx_device_plane_extract * const edev = pts->edev; 288 bits_plane_t dest, source; 289 290 dest.data.write = pts->buffer.data + pts->offset.y * pts->buffer.raster; 291 dest.raster = pts->buffer.raster; 292 dest.depth = edev->plane.depth; 293 dest.x = pts->dest_x; 294 295 source.data.read = pts->data + pts->offset.y * pts->raster; 296 source.raster = pts->raster; 297 source.depth = edev->color_info.depth; 298 source.x = pts->data_x + pts->offset.x; 299 300 bits_extract_plane(&dest, &source, edev->plane.shift, 301 pts->size.x, pts->size.y); 302 return 0; 303 } 304 305 /* 306 * Set up to start (possibly) tiling. Return 0 if the entire tile fit, 307 * 1 if a partial tile fit, or a negative error code. 308 */ 309 private int 310 begin_tiling(tiling_state_t *pts, gx_device_plane_extract *edev, 311 const byte *data, int data_x, uint raster, int width, int height, 312 byte *local_buffer, uint buffer_size, bool partial_ok) 313 { 314 uint width_raster = 315 bitmap_raster(width * edev->plane_dev->color_info.depth); 316 uint full_size = width_raster * height; 317 318 pts->edev = edev; 319 pts->data = data, pts->data_x = data_x, pts->raster = raster; 320 pts->width = width, pts->height = height; 321 pts->dest_x = 0; 322 if (full_size <= buffer_size) { 323 pts->buffer.data = local_buffer; 324 pts->buffer.size = buffer_size; 325 pts->buffer.raster = width_raster; 326 pts->buffer.on_heap = false; 327 pts->size.x = width, pts->size.y = height; 328 } else if (partial_ok) { 329 pts->buffer.data = local_buffer; 330 pts->buffer.size = buffer_size; 331 pts->buffer.on_heap = false; 332 if (buffer_size >= width_raster) { 333 pts->buffer.raster = width_raster; 334 pts->size.x = width; 335 pts->size.y = buffer_size / width_raster; 336 } else { 337 pts->buffer.raster = buffer_size & -align_bitmap_mod; 338 pts->size.x = 339 pts->buffer.raster * (8 / edev->plane_dev->color_info.depth); 340 pts->size.y = 1; 341 } 342 } else { 343 pts->buffer.data = 344 gs_alloc_bytes(edev->memory, full_size, "begin_tiling"); 345 if (!pts->buffer.data) 346 return_error(gs_error_VMerror); 347 pts->buffer.size = full_size; 348 pts->buffer.raster = width_raster; 349 pts->buffer.on_heap = true; 350 pts->size.x = width, pts->size.y = height; 351 } 352 pts->buffer.raster = width_raster; 353 pts->offset.x = pts->offset.y = 0; 354 pts->per_tile_width = pts->size.x; 355 return pts->buffer.size < full_size; 356 } 357 358 /* 359 * Advance to the next tile. Return true if there are more tiles to do. 360 */ 361 private bool 362 next_tile(tiling_state_t *pts) 363 { 364 if ((pts->offset.x += pts->size.x) >= pts->width) { 365 if ((pts->offset.y += pts->size.y) >= pts->height) 366 return false; 367 pts->offset.x = 0; 368 pts->size.x = pts->per_tile_width; 369 if (pts->offset.y + pts->size.y >= pts->height) 370 pts->size.y = pts->height - pts->offset.y; 371 } else if (pts->offset.x + pts->size.x >= pts->width) 372 pts->size.x = pts->width - pts->offset.x; 373 return true; 374 } 375 376 /* 377 * Finish tiling by freeing the buffer if necessary. 378 */ 379 private void 380 end_tiling(tiling_state_t *pts) 381 { 382 if (pts->buffer.on_heap) 383 gs_free_object(pts->edev->memory, pts->buffer.data, "end_tiling"); 384 } 385 386 /* ---------------- Initialization ---------------- */ 387 388 int 389 plane_device_init(gx_device_plane_extract *edev, gx_device *target, 390 gx_device *plane_dev, const gx_render_plane_t *render_plane, bool clear) 391 { 392 /* Check for compatibility of the plane specification. */ 393 if (render_plane->depth > plane_dev->color_info.depth) 394 return_error(gs_error_rangecheck); 395 gx_device_init((gx_device *)edev, 396 (const gx_device *)&gs_plane_extract_device, 397 edev->memory, true); 398 check_device_separable((gx_device *)edev); 399 gx_device_forward_fill_in_procs((gx_device_forward *)edev); 400 gx_device_set_target((gx_device_forward *)edev, target); 401 gx_device_copy_params((gx_device *)edev, target); 402 edev->plane_dev = plane_dev; 403 edev->plane = *render_plane; 404 plane_open_device((gx_device *)edev); 405 if (clear) { 406 dev_proc(plane_dev, fill_rectangle) 407 (plane_dev, 0, 0, plane_dev->width, plane_dev->height, 408 edev->plane_white); 409 edev->any_marks = false; 410 } 411 return 0; 412 } 413 414 /* ---------------- Driver procedures ---------------- */ 415 416 private int 417 plane_open_device(gx_device *dev) 418 { 419 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 420 gx_device * const plane_dev = edev->plane_dev; 421 int plane_depth = plane_dev->color_info.depth; 422 const gx_device_memory * const mdproto = 423 gdev_mem_device_for_bits(plane_depth); 424 425 edev->plane_white = gx_device_white(plane_dev); 426 edev->plane_mask = (1 << plane_depth) - 1; 427 edev->plane_dev_is_memory = mdproto != 0 && 428 dev_proc(plane_dev, copy_color) == dev_proc(mdproto, copy_color); 429 /* We don't set or clear any_marks here: see ...init above. */ 430 return 0; 431 } 432 433 private int 434 plane_fill_rectangle(gx_device *dev, 435 int x, int y, int w, int h, gx_color_index color) 436 { 437 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 438 gx_device * const plane_dev = edev->plane_dev; 439 gx_color_index pixel = COLOR_PIXEL(edev, color); 440 441 if (pixel != edev->plane_white) 442 edev->any_marks = true; 443 else if (!edev->any_marks) 444 return 0; 445 return dev_proc(plane_dev, fill_rectangle) 446 (plane_dev, x, y, w, h, pixel); 447 } 448 449 private int 450 plane_copy_mono(gx_device *dev, 451 const byte *data, int data_x, int raster, gx_bitmap_id id, 452 int x, int y, int w, int h, 453 gx_color_index color0, gx_color_index color1) 454 { 455 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 456 gx_device * const plane_dev = edev->plane_dev; 457 gx_color_index pixel0 = TRANS_COLOR_PIXEL(edev, color0); 458 gx_color_index pixel1 = TRANS_COLOR_PIXEL(edev, color1); 459 460 if (pixel0 == pixel1) 461 return plane_fill_rectangle(dev, x, y, w, h, color0); 462 if ((pixel0 == edev->plane_white || pixel0 == gx_no_color_index) && 463 (pixel1 == edev->plane_white || pixel1 == gx_no_color_index)) { 464 /* This operation will only write white. */ 465 if (!edev->any_marks) 466 return 0; 467 } else 468 edev->any_marks = true; 469 return dev_proc(plane_dev, copy_mono) 470 (plane_dev, data, data_x, raster, id, x, y, w, h, pixel0, pixel1); 471 } 472 473 private int 474 plane_copy_color(gx_device *dev, 475 const byte *data, int data_x, int raster, gx_bitmap_id id, 476 int x, int y, int w, int h) 477 { 478 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 479 gx_device * const plane_dev = edev->plane_dev; 480 tiling_state_t state; 481 long buf[COPY_COLOR_BUF_SIZE / sizeof(long)]; 482 int code; 483 484 if (edev->plane_dev_is_memory) { 485 /* Reduce the source directly into the plane device. */ 486 gx_device_memory * const mdev = (gx_device_memory *)plane_dev; 487 488 fit_copy(edev, data, data_x, raster, id, x, y, w, h); 489 code = begin_tiling(&state, edev, data, data_x, raster, w, h, 490 scan_line_base(mdev, y), max_uint, false); 491 if (code < 0) 492 return code; 493 state.dest_x = x; 494 state.buffer.raster = mdev->raster; 495 extract_partial_tile(&state); 496 end_tiling(&state); 497 edev->any_marks = true; 498 return 0; 499 } 500 code = begin_tiling(&state, edev, data, data_x, raster, 501 w, h, (byte *)buf, sizeof(buf), true); 502 if (code < 0) 503 return code; 504 do { 505 extract_partial_tile(&state); 506 code = dev_proc(plane_dev, copy_color) 507 (plane_dev, state.buffer.data, 0, state.buffer.raster, 508 gx_no_bitmap_id, x + state.offset.x, y + state.offset.y, 509 state.size.x, state.size.y); 510 } while (code >= 0 && next_tile(&state)); 511 end_tiling(&state); 512 edev->any_marks = true; 513 return code; 514 } 515 516 private int 517 plane_copy_alpha(gx_device *dev, const byte *data, int data_x, 518 int raster, gx_bitmap_id id, int x, int y, int w, int h, 519 gx_color_index color, int depth) 520 { 521 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 522 gx_device * const plane_dev = edev->plane_dev; 523 gx_color_index pixel = COLOR_PIXEL(edev, color); 524 525 if (pixel != edev->plane_white) 526 edev->any_marks = true; 527 else if (!edev->any_marks) 528 return 0; 529 return dev_proc(plane_dev, copy_alpha) 530 (plane_dev, data, data_x, raster, id, x, y, w, h, pixel, depth); 531 } 532 533 private int 534 plane_fill_path(gx_device *dev, 535 const gs_imager_state *pis, gx_path *ppath, 536 const gx_fill_params *params, 537 const gx_drawing_color *pdevc, const gx_clip_path *pcpath) 538 { 539 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 540 gx_device * const plane_dev = edev->plane_dev; 541 gs_logical_operation_t lop_orig = 542 gs_current_logical_op((const gs_state *)pis); 543 gs_logical_operation_t lop = lop_orig; 544 gx_device_color dcolor; 545 546 switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) { 547 case REDUCE_SKIP: 548 return 0; 549 case REDUCE_DRAW: { 550 gs_imager_state lopis; 551 const gs_imager_state *pis_draw = pis; 552 553 if (lop != lop_orig) { 554 lopis = *pis; 555 gs_set_logical_op((gs_state *)&lopis, lop); 556 pis_draw = &lopis; 557 } 558 return dev_proc(plane_dev, fill_path) 559 (plane_dev, pis_draw, ppath, params, &dcolor, pcpath); 560 } 561 default /*REDUCE_FAILED*/: 562 return gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath); 563 } 564 } 565 566 private int 567 plane_stroke_path(gx_device *dev, 568 const gs_imager_state *pis, gx_path *ppath, 569 const gx_stroke_params *params, 570 const gx_drawing_color *pdevc, const gx_clip_path *pcpath) 571 { 572 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 573 gx_device * const plane_dev = edev->plane_dev; 574 gs_logical_operation_t lop_orig = 575 gs_current_logical_op((const gs_state *)pis); 576 gs_logical_operation_t lop = lop_orig; 577 gx_device_color dcolor; 578 579 switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) { 580 case REDUCE_SKIP: 581 return 0; 582 case REDUCE_DRAW: { 583 gs_imager_state lopis; 584 const gs_imager_state *pis_draw = pis; 585 586 if (lop != lop_orig) { 587 lopis = *pis; 588 gs_set_logical_op((gs_state *)&lopis, lop); 589 pis_draw = &lopis; 590 } 591 return dev_proc(plane_dev, stroke_path) 592 (plane_dev, pis_draw, ppath, params, &dcolor, pcpath); 593 } 594 default /*REDUCE_FAILED*/: 595 return gx_default_stroke_path(dev, pis, ppath, params, pdevc, pcpath); 596 } 597 } 598 599 private int 600 plane_fill_mask(gx_device *dev, 601 const byte *data, int data_x, int raster, gx_bitmap_id id, 602 int x, int y, int w, int h, 603 const gx_drawing_color *pdcolor, int depth, 604 gs_logical_operation_t lop, const gx_clip_path *pcpath) 605 { 606 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 607 gx_device * const plane_dev = edev->plane_dev; 608 gx_device_color dcolor; 609 610 switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) { 611 case REDUCE_SKIP: 612 return 0; 613 case REDUCE_DRAW: 614 return dev_proc(plane_dev, fill_mask) 615 (plane_dev, data, data_x, raster, gx_no_bitmap_id, x, y, w, h, 616 &dcolor, depth, lop, pcpath); 617 default /*REDUCE_FAILED*/: 618 return gx_default_fill_mask(dev, data, data_x, raster, gx_no_bitmap_id, 619 x, y, w, h, &dcolor, depth, lop, pcpath); 620 } 621 } 622 623 private int 624 plane_fill_parallelogram(gx_device * dev, 625 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, 626 const gx_drawing_color * pdcolor, gs_logical_operation_t lop) 627 { 628 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 629 gx_device * const plane_dev = edev->plane_dev; 630 gx_device_color dcolor; 631 632 switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) { 633 case REDUCE_SKIP: 634 return 0; 635 case REDUCE_DRAW: 636 return dev_proc(plane_dev, fill_parallelogram) 637 (plane_dev, px, py, ax, ay, bx, by, &dcolor, lop); 638 default /*REDUCE_FAILED*/: 639 return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by, 640 pdcolor, lop); 641 } 642 } 643 644 private int 645 plane_fill_triangle(gx_device * dev, 646 fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, 647 const gx_drawing_color * pdcolor, gs_logical_operation_t lop) 648 { 649 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 650 gx_device * const plane_dev = edev->plane_dev; 651 gx_device_color dcolor; 652 653 switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) { 654 case REDUCE_SKIP: 655 return 0; 656 case REDUCE_DRAW: 657 return dev_proc(plane_dev, fill_triangle) 658 (plane_dev, px, py, ax, ay, bx, by, &dcolor, lop); 659 default /*REDUCE_FAILED*/: 660 return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by, 661 pdcolor, lop); 662 } 663 } 664 665 private int 666 plane_strip_tile_rectangle(gx_device *dev, 667 const gx_strip_bitmap *tiles, int x, int y, int w, int h, 668 gx_color_index color0, gx_color_index color1, 669 int phase_x, int phase_y) 670 { 671 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 672 gx_device * const plane_dev = edev->plane_dev; 673 gx_color_index pixel0 = TRANS_COLOR_PIXEL(edev, color0); 674 gx_color_index pixel1 = TRANS_COLOR_PIXEL(edev, color1); 675 676 if (pixel0 == pixel1) { 677 if (pixel0 != gx_no_color_index) 678 return plane_fill_rectangle(dev, x, y, w, h, color0); 679 /* The tile is a pixmap rather than a bitmap. */ 680 /* We should use the default implementation if it is small.... */ 681 { 682 gx_strip_bitmap plane_tile; 683 tiling_state_t state; 684 long buf[TILE_RECTANGLE_BUF_SIZE / sizeof(long)]; 685 int code = begin_tiling(&state, edev, tiles->data, 0, tiles->raster, 686 tiles->size.x, tiles->size.y, 687 (byte *)buf, sizeof(buf), false); 688 689 if (code < 0) 690 return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h, 691 color0, color1, phase_x, phase_y); 692 extract_partial_tile(&state); 693 plane_tile = *tiles; 694 plane_tile.data = state.buffer.data; 695 plane_tile.raster = state.buffer.raster; 696 plane_tile.id = gx_no_bitmap_id; 697 code = dev_proc(plane_dev, strip_tile_rectangle) 698 (plane_dev, &plane_tile, x, y, w, h, pixel0, pixel1, 699 phase_x, phase_y); 700 end_tiling(&state); 701 edev->any_marks = true; 702 return code; 703 } 704 } 705 if ((pixel0 == edev->plane_white || pixel0 == gx_no_color_index) && 706 (pixel1 == edev->plane_white || pixel1 == gx_no_color_index)) { 707 /* This operation will only write white. */ 708 if (!edev->any_marks) 709 return 0; 710 } else 711 edev->any_marks = true; 712 return dev_proc(plane_dev, strip_tile_rectangle) 713 (plane_dev, tiles, x, y, w, h, pixel0, pixel1, phase_x, phase_y); 714 } 715 716 private int 717 plane_strip_copy_rop(gx_device *dev, 718 const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, 719 const gx_color_index *scolors, 720 const gx_strip_bitmap *textures, const gx_color_index *tcolors, 721 int x, int y, int w, int h, 722 int phase_x, int phase_y, gs_logical_operation_t lop) 723 { 724 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 725 gx_device * const plane_dev = edev->plane_dev; 726 gs_rop3_t rop = lop_rop(lop); 727 struct crp_ { 728 gx_color_index pixels[2]; 729 gx_color_index *colors; 730 tiling_state_t state; 731 } source, texture; 732 long sbuf[COPY_ROP_SOURCE_BUF_SIZE / sizeof(long)]; 733 long tbuf[COPY_ROP_TEXTURE_BUF_SIZE / sizeof(long)]; 734 const byte *plane_source; 735 uint plane_raster = 0xbaadf00d; /* Initialize against indeterminizm. */ 736 gx_strip_bitmap plane_texture; 737 const gx_strip_bitmap *plane_textures = NULL; 738 int code; 739 740 /* We should do better than this on transparency.... */ 741 if (lop & (lop_S_transparent | lop_T_transparent)) 742 return gx_default_strip_copy_rop(dev, sdata, sourcex, sraster, id, 743 scolors, textures, tcolors, 744 x, y, w, h, phase_x, phase_y, lop); 745 if (!rop3_uses_S(rop)) { 746 sdata = 0; 747 source.colors = 0; 748 } else if (scolors) { 749 source.pixels[0] = COLOR_PIXEL(edev, scolors[0]); 750 source.pixels[1] = COLOR_PIXEL(edev, scolors[1]); 751 if (source.pixels[0] == source.pixels[1]) 752 sdata = 0; 753 source.colors = source.pixels; 754 } 755 else 756 source.colors = 0; 757 if (!rop3_uses_T(rop)) { 758 textures = 0; 759 texture.colors = 0; 760 } else if (tcolors) { 761 texture.pixels[0] = COLOR_PIXEL(edev, tcolors[0]); 762 texture.pixels[1] = COLOR_PIXEL(edev, tcolors[1]); 763 if (texture.pixels[0] == texture.pixels[1]) 764 textures = 0; 765 texture.colors = texture.pixels; 766 } 767 else 768 texture.colors = 0; 769 if (sdata) { 770 code = begin_tiling(&source.state, edev, sdata, sourcex, sraster, w, y, 771 (byte *)sbuf, sizeof(sbuf), true); 772 if (code < 0) 773 return gx_default_strip_copy_rop(dev, sdata, sourcex, sraster, id, 774 scolors, textures, tcolors, 775 x, y, w, h, phase_x, phase_y, lop); 776 plane_source = source.state.buffer.data; 777 plane_raster = source.state.buffer.raster; 778 } else 779 plane_source = 0; 780 if (textures) { 781 code = begin_tiling(&texture.state, edev, textures->data, 0, 782 textures->raster, textures->size.x, 783 textures->size.y, (byte *)tbuf, sizeof(tbuf), 784 false); 785 if (code < 0) { 786 if (plane_source) 787 end_tiling(&source.state); 788 return code; 789 } 790 plane_texture = *textures; 791 plane_texture.data = texture.state.buffer.data; 792 plane_texture.raster = texture.state.buffer.raster; 793 plane_textures = &plane_texture; 794 } 795 if (textures) 796 extract_partial_tile(&texture.state); 797 do { 798 if (sdata) 799 extract_partial_tile(&source.state); 800 code = dev_proc(plane_dev, strip_copy_rop) 801 (plane_dev, plane_source, sourcex, plane_raster, gx_no_bitmap_id, 802 source.colors, plane_textures, texture.colors, 803 x, y, w, h, phase_x, phase_y, lop); 804 } while (code >= 0 && sdata && next_tile(&source.state)); 805 if (textures) 806 end_tiling(&texture.state); 807 if (sdata) 808 end_tiling(&source.state); 809 return code; 810 } 811 812 /* ---------------- Images ---------------- */ 813 814 /* Define the state for image rendering. */ 815 typedef struct plane_image_enum_s { 816 gx_image_enum_common; 817 gs_memory_t *memory; 818 gx_image_enum_common_t *info; /* plane device enumerator */ 819 const gs_imager_state *pis; /* original imager state */ 820 gs_imager_state *pis_image; /* modified imager state */ 821 } plane_image_enum_t; 822 gs_private_st_suffix_add3(st_plane_image_enum, plane_image_enum_t, 823 "plane_image_enum_t", plane_image_enum_enum_ptrs, 824 plane_image_enum_reloc_ptrs, st_gx_image_enum_common, info, pis, pis_image); 825 826 /* 827 * Reduce drawing colors returned by color mapping. Note that these 828 * assume that the call of reduce_drawing_color will not fail: 829 * plane_begin_typed_image must ensure this. 830 * 831 * In the imager state passed to these procedures, the client data is 832 * the plane_image_enum_t. 833 */ 834 835 private void 836 plane_cmap_gray(frac gray, gx_device_color * pdc, 837 const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select) 838 { 839 const plane_image_enum_t *ppie = 840 (const plane_image_enum_t *)pis_image->client_data; 841 gx_device_plane_extract * const edev = 842 (gx_device_plane_extract *)ppie->dev; 843 gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image); 844 gx_device_color dcolor; 845 846 gx_remap_concrete_gray(gray, &dcolor, ppie->pis, 847 (gx_device *)edev, select); 848 reduce_drawing_color(pdc, edev, &dcolor, &lop); 849 } 850 private void 851 plane_cmap_rgb(frac r, frac g, frac b, gx_device_color * pdc, 852 const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select) 853 { 854 const plane_image_enum_t *ppie = 855 (const plane_image_enum_t *)pis_image->client_data; 856 gx_device_plane_extract * const edev = 857 (gx_device_plane_extract *)ppie->dev; 858 gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image); 859 gx_device_color dcolor; 860 861 gx_remap_concrete_rgb(r, g, b, &dcolor, ppie->pis, 862 (gx_device *)edev, select); 863 reduce_drawing_color(pdc, edev, &dcolor, &lop); 864 } 865 private void 866 plane_cmap_cmyk(frac c, frac m, frac y, frac k, gx_device_color * pdc, 867 const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select) 868 { 869 const plane_image_enum_t *ppie = 870 (const plane_image_enum_t *)pis_image->client_data; 871 gx_device_plane_extract * const edev = 872 (gx_device_plane_extract *)ppie->dev; 873 gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image); 874 gx_device_color dcolor; 875 876 gx_remap_concrete_cmyk(c, m, y, k, &dcolor, ppie->pis, 877 (gx_device *)edev, select); 878 reduce_drawing_color(pdc, edev, &dcolor, &lop); 879 } 880 private void 881 plane_cmap_rgb_alpha(frac r, frac g, frac b, frac alpha, gx_device_color * pdc, 882 const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select) 883 { 884 const plane_image_enum_t *ppie = 885 (const plane_image_enum_t *)pis_image->client_data; 886 gx_device_plane_extract * const edev = 887 (gx_device_plane_extract *)ppie->dev; 888 gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image); 889 gx_device_color dcolor; 890 891 gx_remap_concrete_rgb_alpha(r, g, b, alpha, &dcolor, ppie->pis, 892 (gx_device *)edev, select); 893 reduce_drawing_color(pdc, edev, &dcolor, &lop); 894 } 895 private bool 896 plane_cmap_is_halftoned(const gs_imager_state *pis_image, gx_device *dev) 897 { 898 return false; 899 } 900 901 private const gx_color_map_procs plane_color_map_procs = { 902 plane_cmap_gray, plane_cmap_rgb, plane_cmap_cmyk, plane_cmap_rgb_alpha, 903 NULL, NULL, plane_cmap_is_halftoned 904 }; 905 private const gx_color_map_procs * 906 plane_get_cmap_procs(const gs_imager_state *pis, const gx_device *dev) 907 { 908 return &plane_color_map_procs; 909 } 910 911 /* Define the image processing procedures. */ 912 private image_enum_proc_plane_data(plane_image_plane_data); 913 private image_enum_proc_end_image(plane_image_end_image); 914 private const gx_image_enum_procs_t plane_image_enum_procs = { 915 plane_image_plane_data, plane_image_end_image 916 }; 917 918 private int 919 plane_begin_typed_image(gx_device * dev, 920 const gs_imager_state * pis, const gs_matrix * pmat, 921 const gs_image_common_t * pic, const gs_int_rect * prect, 922 const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, 923 gs_memory_t * memory, gx_image_enum_common_t ** pinfo) 924 { 925 /* 926 * For images, we intercept the imager state's cmap_procs and apply 927 * reduce_drawing_color to the colors as they are returned to the image 928 * processing code. For reasons explained above, we can't do this in 929 * some cases of RasterOp that include transparency. 930 */ 931 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 932 gs_logical_operation_t lop = gs_current_logical_op((const gs_state *)pis); 933 const gs_pixel_image_t *pim; 934 plane_image_enum_t *info = 0; 935 gs_imager_state *pis_image = 0; 936 gx_device_color dcolor; 937 bool uses_color = false; 938 int code; 939 940 /* We can only handle a limited set of image types. */ 941 switch (pic->type->index) { 942 case 1: { 943 const gs_image1_t * const pim1 = (const gs_image1_t *)pic; 944 945 if (pim1->Alpha != gs_image_alpha_none) 946 goto fail; 947 uses_color = pim1->ImageMask; 948 break; 949 } 950 case 3: 951 case 4: 952 break; 953 default: 954 goto fail; 955 } 956 pim = (const gs_pixel_image_t *)pic; 957 if ((lop & lop_S_transparent) || 958 ((uses_color || pim->CombineWithColor) && (lop & lop_T_transparent)) 959 ) 960 goto fail; 961 if (uses_color || (pim->CombineWithColor && lop_uses_T(lop))) { 962 if (reduce_drawing_color(&dcolor, edev, pdcolor, &lop) == 963 REDUCE_FAILED) 964 goto fail; 965 } else { 966 /* 967 * The drawing color won't be used, but if RasterOp is involved, 968 * it may still be accessed in some anomalous cases. 969 */ 970 set_nonclient_dev_color(&dcolor, (gx_color_index)0); 971 } 972 info = gs_alloc_struct(memory, plane_image_enum_t, &st_plane_image_enum, 973 "plane_image_begin_typed(info)"); 974 pis_image = gs_imager_state_copy(pis, memory); 975 if (pis_image == 0 || info == 0) 976 goto fail; 977 *pis_image = *pis; 978 pis_image->client_data = info; 979 pis_image->get_cmap_procs = plane_get_cmap_procs; 980 code = dev_proc(edev->plane_dev, begin_typed_image) 981 (edev->plane_dev, pis_image, pmat, pic, prect, 982 &dcolor, pcpath, memory, &info->info); 983 if (code < 0) 984 goto fail; 985 *((gx_image_enum_common_t *)info) = *info->info; 986 info->procs = &plane_image_enum_procs; 987 info->dev = (gx_device *)edev; 988 info->id = gs_next_ids(memory, 1); 989 info->memory = memory; 990 info->pis = pis; 991 info->pis_image = pis_image; 992 *pinfo = (gx_image_enum_common_t *)info; 993 return code; 994 fail: 995 gs_free_object(memory, pis_image, "plane_image_begin_typed(pis_image)"); 996 gs_free_object(memory, info, "plane_image_begin_typed(info)"); 997 return gx_default_begin_typed_image(dev, pis, pmat, pic, prect, 998 pdcolor, pcpath, memory, pinfo); 999 } 1000 1001 private int 1002 plane_image_plane_data(gx_image_enum_common_t * info, 1003 const gx_image_plane_t * planes, int height, 1004 int *rows_used) 1005 { 1006 plane_image_enum_t * const ppie = (plane_image_enum_t *)info; 1007 1008 return gx_image_plane_data_rows(ppie->info, planes, height, rows_used); 1009 } 1010 1011 private int 1012 plane_image_end_image(gx_image_enum_common_t * info, bool draw_last) 1013 { 1014 plane_image_enum_t * const ppie = (plane_image_enum_t *)info; 1015 int code = gx_image_end(ppie->info, draw_last); 1016 1017 gs_free_object(ppie->memory, ppie->pis_image, 1018 "plane_image_end_image(pis_image)"); 1019 gs_free_object(ppie->memory, info, "plane_image_end_image(info)"); 1020 return code; 1021 } 1022 1023 /* ---------------- Reading back bits ---------------- */ 1024 1025 private int 1026 plane_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, 1027 gs_get_bits_params_t * params, gs_int_rect ** unread) 1028 { 1029 gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev; 1030 gx_device * const plane_dev = edev->plane_dev; 1031 int plane_index = edev->plane.index; 1032 gs_get_bits_options_t options = params->options; 1033 gs_get_bits_params_t plane_params; 1034 int plane; 1035 int code; 1036 1037 /* 1038 * The only real option that this device supports is single-plane 1039 * retrieval. However, for the default case of RasterOp, it must be 1040 * able to return chunky pixels in which the other components are 1041 * arbitrary (but might as well be zero). 1042 */ 1043 if ((options & GB_PACKING_PLANAR) && (options & GB_SELECT_PLANES)) { 1044 if (params->data[plane_index] == 0) 1045 return gx_default_get_bits_rectangle(dev, prect, params, unread); 1046 /* If the caller wants any other plane(s), punt. */ 1047 for (plane = 0; plane < dev->color_info.num_components; ++plane) 1048 if (plane != plane_index && params->data[plane] != 0) 1049 return gx_default_get_bits_rectangle(dev, prect, params, unread); 1050 /* Pass the request on to the plane device. */ 1051 plane_params = *params; 1052 plane_params.options = 1053 (options & ~(GB_PACKING_ALL | GB_SELECT_PLANES)) | 1054 GB_PACKING_CHUNKY; 1055 plane_params.data[0] = params->data[plane_index]; 1056 code = dev_proc(plane_dev, get_bits_rectangle) 1057 (plane_dev, prect, &plane_params, unread); 1058 if (code >= 0) { 1059 *params = plane_params; 1060 params->options = (params->options & ~GB_PACKING_ALL) | 1061 (GB_PACKING_PLANAR | GB_SELECT_PLANES); 1062 params->data[plane_index] = params->data[0]; 1063 for (plane = 0; plane < dev->color_info.num_components; ++plane) 1064 if (plane != plane_index) 1065 params->data[plane] = 0; 1066 } 1067 } else if (!(~options & (GB_COLORS_NATIVE | GB_ALPHA_NONE | 1068 GB_PACKING_CHUNKY | GB_RETURN_COPY | 1069 GB_ALIGN_STANDARD | GB_OFFSET_0 | 1070 GB_RASTER_STANDARD))) { 1071 /* Expand the plane into chunky pixels. */ 1072 bits_plane_t dest, source; 1073 1074 dest.data.write = params->data[0]; 1075 dest.raster = 1076 bitmap_raster((prect->q.x - prect->p.x) * dev->color_info.depth); 1077 dest.depth = edev->color_info.depth; 1078 dest.x = 0; 1079 1080 /* not source.data, source.raster, source.x */ 1081 source.depth = plane_dev->color_info.depth; 1082 1083 plane_params = *params; 1084 plane_params.options = options &= 1085 (~(GB_COLORS_ALL | GB_ALPHA_ALL | GB_PACKING_ALL | 1086 GB_RETURN_ALL | GB_ALIGN_ALL | GB_OFFSET_ALL | GB_RASTER_ALL) | 1087 GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_PACKING_CHUNKY | 1088 /* Try for a pointer return the first time. */ 1089 GB_RETURN_POINTER | 1090 GB_ALIGN_STANDARD | 1091 (GB_OFFSET_0 | GB_OFFSET_ANY) | 1092 (GB_RASTER_STANDARD | GB_RASTER_ANY)); 1093 plane_params.raster = gx_device_raster(plane_dev, true); 1094 code = dev_proc(plane_dev, get_bits_rectangle) 1095 (plane_dev, prect, &plane_params, unread); 1096 if (code >= 0) { 1097 /* Success, expand the plane into pixels. */ 1098 source.data.read = plane_params.data[0]; 1099 source.raster = plane_params.raster; 1100 source.x = params->x_offset; 1101 code = bits_expand_plane(&dest, &source, edev->plane.shift, 1102 prect->q.x - prect->p.x, 1103 prect->q.y - prect->p.y); 1104 } 1105 params->options = (options & ~GB_RETURN_POINTER) | GB_RETURN_COPY; 1106 } else 1107 return gx_default_get_bits_rectangle(dev, prect, params, unread); 1108 return code; 1109 } 1110