/* * Compress a bitmap, skipping extra padding bytes at the end of each row if * necessary. We require height >= 1, raster >= bitmap_raster(width_bits). */ static int cmd_compress_bitmap(stream_state * st, const byte * data, uint width_bits, uint raster, uint height, stream_cursor_write * pw) { uint width_bytes = bitmap_raster(width_bits); int status = 0; stream_cursor_read r; r.ptr = data - 1; if (raster == width_bytes) { r.limit = r.ptr + raster * height; status = (*st->templat->process) (st, &r, pw, true); } else { /* Compress row-by-row. */ uint y; for (y = 1; (r.limit = r.ptr + width_bytes), y < height; ++y) { status = (*st->templat->process) (st, &r, pw, false); if (status) break; if (r.ptr != r.limit) { /* We don't attempt to handle compressors that */ /* require >1 input byte to make progress. */ status = -1; break; } r.ptr += raster - width_bytes; } if (status == 0) status = (*st->templat->process) (st, &r, pw, true); } if (st->templat->release) (*st->templat->release) (st); return status; }
/* This is the first half of gs_screen_init_accurate. */ int gs_screen_order_alloc(gx_ht_order *porder, gs_memory_t *mem) { uint num_levels = porder->params.W * porder->params.D; int code; if (!FORCE_STRIP_HALFTONES && ((ulong)porder->params.W1 * bitmap_raster(porder->params.W) + num_levels * sizeof(*porder->levels) + porder->params.W * porder->params.W1 * sizeof(gx_ht_bit)) <= porder->screen_params.max_size) { /* * Allocate an order for the entire tile, but only sample one * strip. Note that this causes the order parameters to be * self-inconsistent until gx_ht_construct_spot_order fixes them * up: see gxdht.h for more information. */ code = gx_ht_alloc_order(porder, porder->params.W, porder->params.W1, 0, num_levels, mem); porder->height = porder->orig_height = porder->params.D; porder->shift = porder->orig_shift = porder->params.S; } else { /* Just allocate the order for a single strip. */ code = gx_ht_alloc_order(porder, porder->params.W, porder->params.D, porder->params.S, num_levels, mem); } return code; }
static void clist_render_thread(void *data) { clist_render_thread_control_t *thread = (clist_render_thread_control_t *)data; gx_device *dev = thread->cdev; gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_clist_reader *crdev = &cldev->reader; gx_device *bdev = thread->bdev; gs_int_rect band_rect; byte *mdata = crdev->data + crdev->page_tile_cache_size; uint raster = bitmap_raster(dev->width * dev->color_info.depth); int code; int band_height = crdev->page_band_height; int band = thread->band; int band_begin_line = band * band_height; int band_end_line = band_begin_line + band_height; int band_num_lines; #ifdef DEBUG long starttime[2], endtime[2]; gp_get_usertime(starttime); /* thread start time */ #endif if (band_end_line > dev->height) band_end_line = dev->height; band_num_lines = band_end_line - band_begin_line; code = crdev->buf_procs.setup_buf_device (bdev, mdata, raster, NULL, 0, band_num_lines, band_num_lines); band_rect.p.x = 0; band_rect.p.y = band_begin_line; band_rect.q.x = dev->width; band_rect.q.y = band_end_line; if (code >= 0) code = clist_render_rectangle(cldev, &band_rect, bdev, NULL, true); /* Reset the band boundaries now */ crdev->ymin = band_begin_line; crdev->ymax = band_end_line; crdev->offset_map = NULL; if (code < 0) thread->status = code; /* shouldn't happen */ else thread->status = RENDER_THREAD_DONE; /* OK */ #ifdef DEBUG gp_get_usertime(endtime); thread->cputime += (endtime[0] - starttime[0]) * 1000 + (endtime[1] - starttime[1]) / 1000000; #endif /* * Signal the semaphores. We signal the 'group' first since even if * the waiter is released on the group, it still needs to check * status on the thread */ gx_semaphore_signal(thread->sema_group); gx_semaphore_signal(thread->sema_this); }
static int alpha_buffer_init(gs_state * pgs, fixed extra_x, fixed extra_y, int alpha_bits, bool devn) { gx_device *dev = gs_currentdevice_inline(pgs); int log2_alpha_bits = ilog2(alpha_bits); gs_fixed_rect bbox; gs_int_rect ibox; uint width, raster, band_space; uint height; gs_log2_scale_point log2_scale; gs_memory_t *mem; gx_device_memory *mdev; log2_scale.x = log2_scale.y = log2_alpha_bits; gx_path_bbox(pgs->path, &bbox); ibox.p.x = fixed2int(bbox.p.x - extra_x) - 1; ibox.p.y = fixed2int(bbox.p.y - extra_y) - 1; ibox.q.x = fixed2int_ceiling(bbox.q.x + extra_x) + 1; ibox.q.y = fixed2int_ceiling(bbox.q.y + extra_y) + 1; width = (ibox.q.x - ibox.p.x) << log2_scale.x; raster = bitmap_raster(width); band_space = raster << log2_scale.y; height = (abuf_nominal / band_space) << log2_scale.y; if (height == 0) height = 1 << log2_scale.y; mem = pgs->memory; mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory, "alpha_buffer_init"); if (mdev == 0) return 0; /* if no room, don't buffer */ /* We may have to update the marking parameters if we have a pdf14 device as our target. Need to do while dev is still active in pgs */ if (dev_proc(dev, dev_spec_op)(dev, gxdso_is_pdf14_device, NULL, 0) > 0) { gs_update_trans_marking_params(pgs); } gs_make_mem_abuf_device(mdev, mem, dev, &log2_scale, alpha_bits, ibox.p.x << log2_scale.x, devn); mdev->width = width; mdev->height = height; mdev->bitmap_memory = mem; if ((*dev_proc(mdev, open_device)) ((gx_device *) mdev) < 0) { /* No room for bits, punt. */ gs_free_object(mem, mdev, "alpha_buffer_init"); return 0; } gx_set_device_only(pgs, (gx_device *) mdev); scale_paths(pgs, log2_scale.x, log2_scale.y, true); return 1; }
/* Determine the space needed by a planar buffer device. */ int gdev_prn_size_buf_planar(gx_device_buf_space_t *space, gx_device *target, const gx_render_plane_t *render_plane, int height, bool for_band) { gx_device_memory mdev; if (render_plane && render_plane->index >= 0) return gx_default_size_buf_device(space, target, render_plane, height, for_band); mdev.color_info = target->color_info; gdev_prn_set_planar(&mdev, target); if (gdev_mem_bits_size(&mdev, target->width, height, &(space->bits)) < 0) return_error(gs_error_VMerror); space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height); space->raster = bitmap_raster(target->width * mdev.planes[0].depth); return 0; }
static int alpha_buffer_init(gs_state * pgs, fixed extra_x, fixed extra_y, int alpha_bits) { gx_device *dev = gs_currentdevice_inline(pgs); int log2_alpha_bits = ilog2(alpha_bits); gs_fixed_rect bbox; gs_int_rect ibox; uint width, raster, band_space; uint height; gs_log2_scale_point log2_scale; gs_memory_t *mem; gx_device_memory *mdev; log2_scale.x = log2_scale.y = log2_alpha_bits; gx_path_bbox(pgs->path, &bbox); ibox.p.x = fixed2int(bbox.p.x - extra_x) - 1; ibox.p.y = fixed2int(bbox.p.y - extra_y) - 1; ibox.q.x = fixed2int_ceiling(bbox.q.x + extra_x) + 1; ibox.q.y = fixed2int_ceiling(bbox.q.y + extra_y) + 1; width = (ibox.q.x - ibox.p.x) << log2_scale.x; raster = bitmap_raster(width); band_space = raster << log2_scale.y; height = (abuf_nominal / band_space) << log2_scale.y; if (height == 0) height = 1 << log2_scale.y; mem = pgs->memory; mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory, "alpha_buffer_init"); if (mdev == 0) return 0; /* if no room, don't buffer */ gs_make_mem_abuf_device(mdev, mem, dev, &log2_scale, alpha_bits, ibox.p.x << log2_scale.x); mdev->width = width; mdev->height = height; mdev->bitmap_memory = mem; if ((*dev_proc(mdev, open_device)) ((gx_device *) mdev) < 0) { /* No room for bits, punt. */ gs_free_object(mem, mdev, "alpha_buffer_init"); return 0; } gx_set_device_only(pgs, (gx_device *) mdev); scale_paths(pgs, log2_scale.x, log2_scale.y, true); return 1; }
/* * Determine the (possibly unpadded) width in bytes for writing a bitmap, * per the algorithm in gxcldev.h. If compression_mask has any of the * cmd_mask_compress_any bits set, we assume the bitmap will be compressed. * Return the total size of the bitmap. */ uint clist_bitmap_bytes(uint width_bits, uint height, int compression_mask, uint * width_bytes, uint * raster) { uint full_raster = *raster = bitmap_raster(width_bits); uint short_raster = (width_bits + 7) >> 3; uint width_bytes_last; if (compression_mask & cmd_mask_compress_any) *width_bytes = width_bytes_last = full_raster; else if (short_raster <= cmd_max_short_width_bytes || height <= 1 || (compression_mask & decompress_spread) != 0 ) *width_bytes = width_bytes_last = short_raster; else *width_bytes = full_raster, width_bytes_last = short_raster; return (height == 0 ? 0 : *width_bytes * (height - 1) + width_bytes_last); }
/* rendering adjacent to the first band (forward or backward) */ static int clist_get_bits_rect_mt(gx_device *dev, const gs_int_rect * prect, gs_get_bits_params_t *params, gs_int_rect **unread) { gx_device_printer *pdev = (gx_device_printer *)dev; gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_clist_common *cdev = (gx_device_clist_common *)dev; gx_device_clist_reader *crdev = &cldev->reader; gs_memory_t *mem = cdev->bandlist_memory; gs_get_bits_options_t options = params->options; int y = prect->p.y; int end_y = prect->q.y; int line_count = end_y - y; int band_height = crdev->page_info.band_params.BandHeight; int band = y / band_height; gs_int_rect band_rect; int lines_rasterized; gx_device *bdev; byte *mdata; uint raster = bitmap_raster(dev->width * dev->color_info.depth); int my; int code = 0; /* This page might not want multiple threads */ /* Also we don't support plane extraction using multiple threads */ if (pdev->num_render_threads_requested < 1 || (options & GB_SELECT_PLANES)) return clist_get_bits_rectangle(dev, prect, params, unread); if (prect->p.x < 0 || prect->q.x > dev->width || y < 0 || end_y > dev->height ) return_error(gs_error_rangecheck); if (line_count <= 0 || prect->p.x >= prect->q.x) return 0; if (crdev->ymin < 0) { if ((code = clist_close_writer_and_init_reader(cldev)) < 0) return code; if (clist_setup_render_threads(dev, y) < 0) /* problem setting up the threads, revert to single threaded */ return clist_get_bits_rectangle(dev, prect, params, unread); } else { if (crdev->render_threads == NULL) { /* If we get here with with ymin >=0, it's because we closed the threads */ /* while doing a page due to an error. Use single threaded mode. */ return clist_get_bits_rectangle(dev, prect, params, unread); } } /* If we already have the band's data, just return it */ if (y < crdev->ymin || end_y > crdev->ymax) code = clist_get_band_from_thread(dev, band); if (code < 0) goto free_thread_out; mdata = crdev->data + crdev->page_tile_cache_size; if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &bdev, cdev->target, y, NULL, mem, clist_get_band_complexity(dev,y))) < 0 || (code = crdev->buf_procs.setup_buf_device(bdev, mdata, raster, NULL, y - crdev->ymin, line_count, crdev->ymax - crdev->ymin)) < 0) goto free_thread_out; lines_rasterized = min(band_height, line_count); /* Return as much of the rectangle as falls within the rasterized lines. */ band_rect = *prect; band_rect.p.y = 0; band_rect.q.y = lines_rasterized; code = dev_proc(bdev, get_bits_rectangle) (bdev, &band_rect, params, unread); cdev->buf_procs.destroy_buf_device(bdev); if (code < 0) goto free_thread_out; /* Note that if called via 'get_bits', the line count will always be 1 */ if (lines_rasterized == line_count) { return code; } /***** TODO: Handle the below with data from the threads *****/ /* * We'll have to return the rectangle in pieces. Force GB_RETURN_COPY * rather than GB_RETURN_POINTER, and require all subsequent pieces to * use the same values as the first piece for all of the other format * options. If copying isn't allowed, or if there are any unread * rectangles, punt. */ if (!(options & GB_RETURN_COPY) || code > 0) return gx_default_get_bits_rectangle(dev, prect, params, unread); options = params->options; if (!(options & GB_RETURN_COPY)) { /* Redo the first piece with copying. */ params->options = options = (params->options & ~GB_RETURN_ALL) | GB_RETURN_COPY; lines_rasterized = 0; } { gs_get_bits_params_t band_params; uint raster = gx_device_raster(bdev, true); code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &bdev, cdev->target, y, NULL, mem, clist_get_band_complexity(dev, y)); if (code < 0) return code; band_params = *params; while ((y += lines_rasterized) < end_y) { /* Increment data pointer by lines_rasterized. */ if (band_params.data) band_params.data[0] += raster * lines_rasterized; line_count = end_y - y; code = clist_rasterize_lines(dev, y, line_count, bdev, NULL, &my); if (code < 0) break; lines_rasterized = min(code, line_count); band_rect.p.y = my; band_rect.q.y = my + lines_rasterized; code = dev_proc(bdev, get_bits_rectangle) (bdev, &band_rect, &band_params, unread); if (code < 0) break; params->options = options = band_params.options; if (lines_rasterized == line_count) break; } cdev->buf_procs.destroy_buf_device(bdev); } return code; /* Free up thread stuff */ free_thread_out: clist_teardown_render_threads(dev); return code; }
irender_proc_t gs_image_class_1_simple(gx_image_enum * penum) { irender_proc_t rproc; fixed ox = dda_current(penum->dda.pixel0.x); fixed oy = dda_current(penum->dda.pixel0.y); if (penum->use_rop || penum->spp != 1 || penum->bps != 1) return 0; switch (penum->posture) { case image_portrait: { /* Use fast portrait algorithm. */ long dev_width = fixed2long_pixround(ox + penum->x_extent.x) - fixed2long_pixround(ox); if (dev_width != penum->rect.w) { /* * Add an extra align_bitmap_mod of padding so that * we can align scaled rows with the device. */ long line_size = bitmap_raster(any_abs(dev_width)) + align_bitmap_mod; if (penum->adjust != 0 || line_size > max_uint) return 0; /* Must buffer a scan line. */ penum->line_width = any_abs(dev_width); penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *)penum, false); return 0; } } if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n", penum->rect.w, dev_width); rproc = image_render_simple; break; } case image_landscape: { /* Use fast landscape algorithm. */ long dev_width = fixed2long_pixround(oy + penum->x_extent.y) - fixed2long_pixround(oy); long line_size = (dev_width = any_abs(dev_width), bitmap_raster(dev_width) * 8 + ROUND_UP(dev_width, 8) * align_bitmap_mod); if ((dev_width != penum->rect.w && penum->adjust != 0) || line_size > max_uint ) return 0; /* Must buffer a group of 8N scan lines. */ penum->line_width = dev_width; penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *) penum, false); return 0; } penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox); if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n", penum->rect.w, dev_width, line_size); rproc = image_render_landscape; /* Precompute values needed for rasterizing. */ penum->dxy = float2fixed(penum->matrix.xy + fixed2float(fixed_epsilon) / 2); break; } default: return 0; } /* Precompute values needed for rasterizing. */ penum->dxx = float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2); /* * We don't want to spread the samples, but we have to reset unpack_bps * to prevent the buffer pointer from being incremented by 8 bytes per * input byte. */ penum->unpack = sample_unpack_copy; penum->unpack_bps = 8; if (penum->use_mask_color) { /* * Set the masked color as 'no_color' to make it transparent * according to the mask color range and the decoding. */ penum->masked = true; if (penum->mask_color.values[0] == 1) { /* if v0 == 1, 1 is transparent since v1 must be == 1 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor0 : penum->icolor1, gx_no_color_index); } else if (penum->mask_color.values[1] == 0) { /* if v1 == 0, 0 is transparent since v0 must be == 0 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor1 : penum->icolor0, gx_no_color_index); } else { /* * The only other possible in-range value is v0 = 0, v1 = 1. * The image is completely transparent! */ rproc = image_render_skip; } penum->map[0].decoding = sd_none; } return rproc; }
/* the routine sets ph->actual_frequency and ph->actual_angle. */ static int pick_cell_size(gs_screen_halftone * ph, const gs_matrix * pmat, ulong max_size, uint min_levels, bool accurate, gx_ht_cell_params_t * phcp) { const bool landscape = (pmat->xy != 0.0 || pmat->yx != 0.0); /* Account for a possibly reflected coordinate system. */ /* See gxstroke.c for the algorithm. */ const bool reflected = pmat->xy * pmat->yx > pmat->xx * pmat->yy; const int reflection = (reflected ? -1 : 1); const int rotation = (landscape ? (pmat->yx < 0 ? 90 : -90) : pmat->xx < 0 ? 180 : 0); const double f0 = ph->frequency, a0 = ph->angle; const double T = fabs((landscape ? pmat->yx / pmat->xy : pmat->xx / pmat->yy)); gs_point uv0; #define u0 uv0.x #define v0 uv0.y int rt = 1; double f = 0, a = 0; double e_best = 1000; bool better; /* * We need to find a vector in device space whose length is * 1 inch / ph->frequency and whose angle is ph->angle. * Because device pixels may not be square, we can't simply * map the length to device space and then rotate it; * instead, since we know that user space is uniform in X and Y, * we calculate the correct angle in user space before rotation. */ /* Compute trial values of u and v. */ { gs_matrix rmat; gs_make_rotation(a0 * reflection + rotation, &rmat); gs_distance_transform(72.0 / f0, 0.0, &rmat, &uv0); gs_distance_transform(u0, v0, pmat, &uv0); if_debug10('h', "[h]Requested: f=%g a=%g mat=[%g %g %g %g] max_size=%lu min_levels=%u =>\n u=%g v=%g\n", ph->frequency, ph->angle, pmat->xx, pmat->xy, pmat->yx, pmat->yy, max_size, min_levels, u0, v0); } /* Adjust u and v to reasonable values. */ if (u0 == 0 && v0 == 0) return_error(gs_error_rangecheck); while ((fabs(u0) + fabs(v0)) * rt < 4) ++rt; try_size: better = false; { double fm0 = u0 * rt; double fn0 = v0 * rt; int m0 = (int)floor(u0 * rt + 0.0001); int n0 = (int)floor(v0 * rt + 0.0001); gx_ht_cell_params_t p; p.R = p.R1 = rt; for (p.M = m0 + 1; p.M >= m0; p.M--) for (p.N = n0 + 1; p.N >= n0; p.N--) { long raster, wt, wt_size; double fr, ar, ft, at, f_diff, a_diff, f_err, a_err; p.M1 = (int)floor(p.M / T + 0.5); p.N1 = (int)floor(p.N * T + 0.5); gx_compute_cell_values(&p); if_debug3('h', "[h]trying m=%d, n=%d, r=%d\n", p.M, p.N, rt); wt = p.W; if (wt >= max_short) continue; /* Check the strip size, not the full tile size, */ /* against max_size. */ raster = bitmap_raster(wt); if (raster > max_size / p.D || raster > max_long / wt) continue; wt_size = raster * wt; /* Compute the corresponding values of F and A. */ if (landscape) ar = atan2(p.M * pmat->xy, p.N * pmat->yx), fr = 72.0 * (p.M == 0 ? pmat->xy / p.N * cos(ar) : pmat->yx / p.M * sin(ar)); else ar = atan2(p.N * pmat->xx, p.M * pmat->yy), fr = 72.0 * (p.M == 0 ? pmat->yy / p.N * sin(ar) : pmat->xx / p.M * cos(ar)); ft = fabs(fr) * rt; /* Normalize the angle to the requested quadrant. */ at = (ar * radians_to_degrees - rotation) * reflection; at -= floor(at / 180.0) * 180.0; at += floor(a0 / 180.0) * 180.0; f_diff = fabs(ft - f0); a_diff = fabs(at - a0); f_err = f_diff / fabs(f0); /* * We used to compute the percentage difference here: * a_err = (a0 == 0 ? a_diff : a_diff / fabs(a0)); * but using the angle difference makes more sense: */ a_err = a_diff; if_debug5('h', " ==> d=%d, wt=%ld, wt_size=%ld, f=%g, a=%g\n", p.D, wt, bitmap_raster(wt) * wt, ft, at); { /* * Compute the error in position between ideal location. * and the current integer location. */ double error = (fn0 - p.N) * (fn0 - p.N) + (fm0 - p.M) * (fm0 - p.M); /* * Adjust the error by the length of the vector. This gives * a slight bias toward larger cell sizzes. */ error /= p.N * p.N + p.M * p.M; error = sqrt(error); /* The previous calcs. gave value squared */ if (error > e_best) continue; e_best = error; } *phcp = p; f = ft, a = at; better = true; if_debug3('h', "*** best wt_size=%ld, f_diff=%g, a_diff=%g\n", wt_size, f_diff, a_diff); /* * We want a maximum relative frequency error of 1% and a * maximum angle error of 1% (of 90 degrees). */ if (f_err <= 0.01 && a_err <= 0.9 /*degrees*/) goto done; } } if (phcp->C < min_levels) { /* We don't have enough levels yet. Keep going. */ ++rt; goto try_size; } if (better) { /* If we want accurate screens, continue till we fail. */ if (accurate) { ++rt; goto try_size; } } else { /* * We couldn't find an acceptable M and N. If R > 1, * take what we've got; if R = 1, give up. */ if (rt == 1) return_error(gs_error_rangecheck); } /* Deliver the results. */ done: if_debug5('h', "[h]Chosen: f=%g a=%g M=%d N=%d R=%d\n", f, a, phcp->M, phcp->N, phcp->R); ph->actual_frequency = f; ph->actual_angle = a; return 0; #undef u0 #undef v0 }
/* * The default implementation for non-memory devices uses get_bits_rectangle * to read out the pixels, the memory device implementation to do the * operation, and copy_color to write the pixels back. */ int gx_default_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) { int depth = dev->color_info.depth; gs_memory_t *mem = dev->memory; const gx_device_memory *mdproto = gdev_mem_device_for_bits(depth); gx_device_memory mdev; uint draster; byte *row = 0; gs_int_rect rect; int max_height; int block_height; int code; int py; #ifdef DEBUG if (gs_debug_c('b')) trace_copy_rop("gx_default_strip_copy_rop", dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, x, y, width, height, phase_x, phase_y, lop); #endif if (mdproto == 0) return_error(gs_error_rangecheck); if (sdata == 0) { fit_fill(dev, x, y, width, height); } else { fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height); } draster = bitmap_raster(width * depth); max_height = max_rop_bitmap / draster; if (max_height == 0) max_height = 1; block_height = min(height, max_height); gs_make_mem_device(&mdev, mdproto, mem, -1, dev); gx_device_retain((gx_device *)&mdev, true); /* prevent freeing */ mdev.width = width; mdev.height = block_height; mdev.bitmap_memory = mem; mdev.color_info = dev->color_info; code = (*dev_proc(&mdev, open_device))((gx_device *)&mdev); if (code < 0) return code; if (rop3_uses_D(gs_transparent_rop(lop))) { row = gs_alloc_bytes(mem, draster * block_height, "copy_rop row"); if (row == 0) { code = gs_note_error(gs_error_VMerror); goto out; } } rect.p.x = x; rect.q.x = x + width; for (py = y; py < y + height; py += block_height) { if (block_height > y + height - py) block_height = y + height - py; rect.p.y = py; rect.q.y = py + block_height; if (row /*uses_d*/) { gs_get_bits_params_t bit_params; bit_params.options = GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_DEPTH_ALL | GB_PACKING_CHUNKY | GB_RETURN_ALL | GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD; bit_params.data[0] = row; bit_params.x_offset = 0; code = (*dev_proc(dev, get_bits_rectangle)) (dev, &rect, &bit_params, NULL); if (code < 0) break; code = (*dev_proc(&mdev, copy_color)) ((gx_device *)&mdev, bit_params.data[0], bit_params.x_offset, draster, gx_no_bitmap_id, 0, 0, width, block_height); if (code < 0) return code; } code = (*dev_proc(&mdev, strip_copy_rop)) ((gx_device *)&mdev, sdata + (py - y) * sraster, sourcex, sraster, gx_no_bitmap_id, scolors, textures, tcolors, 0, 0, width, block_height, phase_x + x, phase_y + py, lop); if (code < 0) break; code = (*dev_proc(dev, copy_color)) (dev, scan_line_base(&mdev, 0), 0, draster, gx_no_bitmap_id, x, py, width, block_height); if (code < 0) break; } out: gs_free_object(mem, row, "copy_rop row"); (*dev_proc(&mdev, close_device))((gx_device *)&mdev); return code; }