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