/* Create an image enumerator given image parameters and a graphics state. */ int gs_image_begin_typed(const gs_image_common_t * pic, gs_state * pgs, bool uses_color, gx_image_enum_common_t ** ppie) { gx_device *dev = gs_currentdevice(pgs); gx_clip_path *pcpath; int code = gx_effective_clip_path(pgs, &pcpath); gx_device *dev2 = dev; gx_device_color dc_temp, *pdevc = pgs->dev_color; if (code < 0) return code; /* Processing an image object operation */ gs_set_object_tag(pgs, GS_IMAGE_TAG); if (uses_color) { gx_set_dev_color(pgs); code = gs_state_color_load(pgs); if (code < 0) return code; } /* Imagemask with shading color needs a special optimization with converting the image into a clipping. Check for such case after gs_state_color_load is done, because it can cause interpreter callout. */ if (pic->type->begin_typed_image == &gx_begin_image1) { gs_image_t *image = (gs_image_t *)pic; if(image->ImageMask) { code = gx_image_fill_masked_start(dev, pgs->dev_color, pcpath, pgs->memory, &dev2); if (code < 0) return code; } if (dev2 != dev) { set_nonclient_dev_color(&dc_temp, 1); pdevc = &dc_temp; } } code = gx_device_begin_typed_image(dev2, (const gs_imager_state *)pgs, NULL, pic, NULL, pdevc, pcpath, pgs->memory, ppie); if (code < 0) return code; code = is_image_visible(pic, pgs, pcpath); if (code < 0) return code; if (!code) (*ppie)->skipping = true; return 0; }
void xps_bounds_in_user_space(xps_context_t *ctx, gs_rect *ubox) { gx_clip_path *clip_path; gs_rect dbox; int code; code = gx_effective_clip_path(ctx->pgs, &clip_path); if (code < 0) gs_warn("gx_effective_clip_path failed"); dbox.p.x = fixed2float(clip_path->outer_box.p.x); dbox.p.y = fixed2float(clip_path->outer_box.p.y); dbox.q.x = fixed2float(clip_path->outer_box.q.x); dbox.q.y = fixed2float(clip_path->outer_box.q.y); gs_bbox_transform_inverse(&dbox, &ctm_only(ctx->pgs), ubox); }
/* We take the trouble to do this efficiently in the simple cases. */ int gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count) { const gs_rect *rlist = pr; gx_clip_path *pcpath; uint rcount = count; int code; gx_device * pdev = pgs->device; gx_device_color *pdc = gs_currentdevicecolor_inline(pgs); const gs_imager_state *pis = (const gs_imager_state *)pgs; bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc); bool hl_color = (hl_color_available && dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_hlcolor, NULL, 0)); bool center_of_pixel = (pgs->fill_adjust.x == 0 && pgs->fill_adjust.y == 0); /* Processing a fill object operation */ dev_proc(pgs->device, set_graphics_type_tag)(pgs->device, GS_PATH_TAG); code = gx_set_dev_color(pgs); if (code != 0) return code; if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) || is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) && gx_effective_clip_path(pgs, &pcpath) >= 0 && clip_list_is_rectangle(gx_cpath_list(pcpath)) && (hl_color || pdc->type == gx_dc_type_pure || pdc->type == gx_dc_type_ht_binary || pdc->type == gx_dc_type_ht_colored) && gs_state_color_load(pgs) >= 0 && (*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics) <= 1 && (!pgs->overprint || !pgs->effective_overprint_mode) ) { uint i; gs_fixed_rect clip_rect; gx_cpath_inner_box(pcpath, &clip_rect); /* We should never plot anything for an empty clip rectangle */ if ((clip_rect.p.x >= clip_rect.q.x) && (clip_rect.p.y >= clip_rect.q.y)) return 0; for (i = 0; i < count; ++i) { gs_fixed_point p, q; gs_fixed_rect draw_rect; if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 || gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0 ) { /* Switch to the slow algorithm. */ goto slow; } draw_rect.p.x = min(p.x, q.x); draw_rect.p.y = min(p.y, q.y); draw_rect.q.x = max(p.x, q.x); draw_rect.q.y = max(p.y, q.y); if (hl_color) { rect_intersect(draw_rect, clip_rect); /* We do pass on 0 extant rectangles to high level devices. It isn't clear how a client and an output device should interact if one uses a center of pixel algorithm and the other uses any part of pixel. For now we punt and just pass the high level rectangle on without adjustment. */ if (draw_rect.p.x <= draw_rect.q.x && draw_rect.p.y <= draw_rect.q.y) { code = dev_proc(pdev, fill_rectangle_hl_color)(pdev, &draw_rect, pis, pdc, pcpath); if (code < 0) return code; } } else { int x, y, w, h; rect_intersect(draw_rect, clip_rect); if (center_of_pixel) { draw_rect.p.x = fixed_rounded(draw_rect.p.x); draw_rect.p.y = fixed_rounded(draw_rect.p.y); draw_rect.q.x = fixed_rounded(draw_rect.q.x); draw_rect.q.y = fixed_rounded(draw_rect.q.y); } else { /* any part of pixel rule - touched */ draw_rect.p.x = fixed_floor(draw_rect.p.x); draw_rect.p.y = fixed_floor(draw_rect.p.y); draw_rect.q.x = fixed_ceiling(draw_rect.q.x); draw_rect.q.y = fixed_ceiling(draw_rect.q.y); } x = fixed2int(draw_rect.p.x); y = fixed2int(draw_rect.p.y); w = fixed2int(draw_rect.q.x) - x; h = fixed2int(draw_rect.q.y) - y; /* clients that use the "any part of pixel" rule also fill 0 areas. This is true of current graphics library clients but not a general rule. */ if (!center_of_pixel) { if (w == 0) w = 1; /* yes Adobe Acrobat 8, seems to back up the y coordinate when the width is 0, sigh. */ if (h == 0) { y--; h = 1; } } if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0) goto slow; } } return 0; slow:rlist = pr + i; rcount = count - i; } { bool do_save = !gx_path_is_null(pgs->path); if (do_save) { if ((code = gs_gsave(pgs)) < 0) return code; gs_newpath(pgs); } if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 || (code = gs_fill(pgs)) < 0 ) DO_NOTHING; if (do_save) gs_grestore(pgs); else if (code < 0) gs_newpath(pgs); } return code; }
/* We take the trouble to do this efficiently in the simple cases. */ int gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count) { const gs_rect *rlist = pr; gx_clip_path *pcpath; uint rcount = count; int code; gx_device * pdev = pgs->device; gx_device_color *pdc = pgs->dev_color; const gs_imager_state *pis = (const gs_imager_state *)pgs; bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc); gs_fixed_rect empty = {{0, 0}, {0, 0}}; bool hl_color = (hl_color_available && dev_proc(pdev, fill_rectangle_hl_color)(pdev, &empty, pis, pdc, NULL) == 0); gx_set_dev_color(pgs); if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) || is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) && gx_effective_clip_path(pgs, &pcpath) >= 0 && clip_list_is_rectangle(gx_cpath_list(pcpath)) && (hl_color || pdc->type == gx_dc_type_pure || pdc->type == gx_dc_type_ht_binary || pdc->type == gx_dc_type_ht_colored /* DeviceN todo: add wts case */) && gs_state_color_load(pgs) >= 0 && (*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics) <= 1 && (!pgs->overprint || !pgs->effective_overprint_mode) ) { uint i; gs_fixed_rect clip_rect; gx_cpath_inner_box(pcpath, &clip_rect); for (i = 0; i < count; ++i) { gs_fixed_point p, q; gs_fixed_rect draw_rect; if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 || gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0 ) { /* Switch to the slow algorithm. */ goto slow; } draw_rect.p.x = min(p.x, q.x); draw_rect.p.y = min(p.y, q.y); draw_rect.q.x = max(p.x, q.x); draw_rect.q.y = max(p.y, q.y); if (hl_color) { rect_intersect(draw_rect, clip_rect); if (draw_rect.p.x < draw_rect.q.x && draw_rect.p.y < draw_rect.q.y) { code = dev_proc(pdev, fill_rectangle_hl_color)(pdev, &draw_rect, pis, pdc, pcpath); if (code < 0) return code; } } else { int x, y, w, h; draw_rect.p.x -= pgs->fill_adjust.x; draw_rect.p.y -= pgs->fill_adjust.x; draw_rect.q.x += pgs->fill_adjust.x; draw_rect.q.y += pgs->fill_adjust.x; rect_intersect(draw_rect, clip_rect); x = fixed2int_pixround(draw_rect.p.x); y = fixed2int_pixround(draw_rect.p.y); w = fixed2int_pixround(draw_rect.q.x) - x; h = fixed2int_pixround(draw_rect.q.y) - y; if (w > 0 && h > 0) if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0) goto slow; } } return 0; slow:rlist = pr + i; rcount = count - i; } { bool do_save = !gx_path_is_null(pgs->path); if (do_save) { if ((code = gs_gsave(pgs)) < 0) return code; gs_newpath(pgs); } if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 || (code = gs_fill(pgs)) < 0 ) DO_NOTHING; if (do_save) gs_grestore(pgs); else if (code < 0) gs_newpath(pgs); } return code; }