/* Someday we'll find a way to merge them. */ static int common_viewclip(gs_state * pgs, int rule) { gs_fixed_rect bbox; gx_clip_path rpath; int code; gx_clip_path *pcpath = pgs->view_clip; if (pcpath == 0) { pcpath = gx_cpath_alloc(pgs->memory, "gs_[eo]viewclip"); if (pcpath == 0) return_error(gs_error_VMerror); pgs->view_clip = pcpath; } if ((code = gx_path_bbox(pgs->path, &bbox)) < 0) return code; gx_cpath_init_local(&rpath, pgs->memory); code = gx_cpath_from_rectangle(&rpath, &bbox); if (code >= 0) code = gx_cpath_clip(pgs, &rpath, pgs->path, rule); if (code < 0) { gx_cpath_free(&rpath, "gs_[eo]viewclip"); return code; } rpath.rule = rule; gx_cpath_assign_free(pcpath, &rpath); gs_newpath(pgs); return 0; }
/* A variation of gs_path_bbox, to be used by the patbbox operator */ int gx_path_bbox_set(gx_path * ppath, gs_fixed_rect * pbox) { if (ppath->bbox_set) { /* The bounding box was set by setbbox. */ *pbox = ppath->bbox; return 0; } else return gx_path_bbox(ppath, pbox); }
/* relatives. */ int gx_path_add_char_path(gx_path * to_path, gx_path * from_path, gs_char_path_mode mode) { int code; gs_fixed_rect bbox; switch (mode) { default: /* shouldn't happen! */ gx_path_new(from_path); return 0; case cpm_charwidth: { gs_fixed_point cpt; code = gx_path_current_point(from_path, &cpt); if (code < 0) break; return gx_path_add_point(to_path, cpt.x, cpt.y); } case cpm_true_charpath: case cpm_false_charpath: return gx_path_add_path(to_path, from_path); case cpm_true_charboxpath: gx_path_bbox(from_path, &bbox); code = gx_path_add_rectangle(to_path, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y); break; case cpm_false_charboxpath: gx_path_bbox(from_path, &bbox); code = gx_path_add_point(to_path, bbox.p.x, bbox.p.y); if (code >= 0) code = gx_path_add_line(to_path, bbox.q.x, bbox.q.y); break; } if (code < 0) return code; gx_path_new(from_path); return 0; }
/* This is very inefficient right now. */ int gx_clip_to_path(gs_state * pgs) { gs_fixed_rect bbox; int code; if ((code = gx_path_bbox(pgs->path, &bbox)) < 0 || (code = gx_clip_to_rectangle(pgs, &bbox)) < 0 || (code = gs_clip(pgs)) < 0 ) return code; note_set_clip_path(pgs); return 0; }
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; }
/* Set the bounding box for the current path. */ int gs_setbbox(gs_state * pgs, floatp llx, floatp lly, floatp urx, floatp ury) { gs_rect ubox, dbox; gs_fixed_rect obox, bbox; gx_path *ppath = pgs->path; int code; if (llx > urx || lly > ury) return_error(gs_error_rangecheck); /* Transform box to device coordinates. */ ubox.p.x = llx; ubox.p.y = lly; ubox.q.x = urx; ubox.q.y = ury; if ((code = gs_bbox_transform(&ubox, &ctm_only(pgs), &dbox)) < 0) return code; /* Round the corners in opposite directions. */ /* Because we can't predict the magnitude of the dbox values, */ /* we add/subtract the slop after fixing. */ if (dbox.p.x < fixed2float(min_fixed + box_rounding_slop_fixed) || dbox.p.y < fixed2float(min_fixed + box_rounding_slop_fixed) || dbox.q.x >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon) || dbox.q.y >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon) ) return_error(gs_error_limitcheck); bbox.p.x = (fixed) floor(dbox.p.x * fixed_scale) - box_rounding_slop_fixed; bbox.p.y = (fixed) floor(dbox.p.y * fixed_scale) - box_rounding_slop_fixed; bbox.q.x = (fixed) ceil(dbox.q.x * fixed_scale) + box_rounding_slop_fixed; bbox.q.y = (fixed) ceil(dbox.q.y * fixed_scale) + box_rounding_slop_fixed; if (gx_path_bbox(ppath, &obox) >= 0) { /* Take the union of the bboxes. */ ppath->bbox.p.x = min(obox.p.x, bbox.p.x); ppath->bbox.p.y = min(obox.p.y, bbox.p.y); ppath->bbox.q.x = max(obox.q.x, bbox.q.x); ppath->bbox.q.y = max(obox.q.y, bbox.q.y); } else { /* empty path *//* Just set the bbox. */ ppath->bbox = bbox; } ppath->bbox_set = 1; 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; }
static int bbox_stroke_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath, const gx_stroke_params * params, const gx_drawing_color * pdevc, const gx_clip_path * pcpath) { gx_device_bbox *const bdev = (gx_device_bbox *) dev; gx_device *tdev = bdev->target; /* Skip the call if there is no target. */ int code = (tdev == 0 ? 0 : dev_proc(tdev, stroke_path)(tdev, pis, ppath, params, pdevc, pcpath)); if (!GX_DC_IS_TRANSPARENT(pdevc, bdev)) { gs_fixed_rect ibox; gs_fixed_point expand; if (gx_stroke_path_expansion(pis, ppath, &expand) == 0 && gx_path_bbox(ppath, &ibox) >= 0 ) { /* The fast result is exact. */ adjust_box(&ibox, expand); } else { /* * The result is not exact. Compute an exact result using * strokepath. */ gx_path *spath = gx_path_alloc(pis->memory, "bbox_stroke_path"); int code = 0; if (spath) code = gx_imager_stroke_add(ppath, spath, dev, pis); else code = -1; if (code >= 0) code = gx_path_bbox(spath, &ibox); if (code < 0) { ibox.p.x = ibox.p.y = min_fixed; ibox.q.x = ibox.q.y = max_fixed; } if (spath) gx_path_free(spath, "bbox_stroke_path"); } if (pcpath != NULL && !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y) ) { /* Let the target do the drawing, but break down the */ /* fill path into pieces for computing the bounding box. */ gx_drawing_color devc; set_nonclient_dev_color(&devc, bdev->black); /* any non-white color will do */ bdev->target = NULL; gx_default_stroke_path(dev, pis, ppath, params, &devc, pcpath); bdev->target = tdev; } else { /* Just use the path bounding box. */ BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); } } return code; }
static int bbox_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath, const gx_fill_params * params, const gx_device_color * pdevc, const gx_clip_path * pcpath) { gx_device_bbox *const bdev = (gx_device_bbox *) dev; gx_device *tdev = bdev->target; dev_proc_fill_path((*fill_path)) = (tdev == 0 ? dev_proc(&gs_null_device, fill_path) : dev_proc(tdev, fill_path)); int code; if (ppath == NULL) { /* A special handling of shfill with no path. */ gs_fixed_rect ibox; gs_fixed_point adjust; if (pcpath == NULL) return 0; gx_cpath_inner_box(pcpath, &ibox); adjust = params->adjust; adjust_box(&ibox, adjust); BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); return 0; } else if (!GX_DC_IS_TRANSPARENT(pdevc, bdev) && !gx_path_is_void(ppath)) { gs_fixed_rect ibox; gs_fixed_point adjust; if (gx_path_bbox(ppath, &ibox) < 0) return 0; adjust = params->adjust; adjust_box(&ibox, adjust); /* * If the path lies within the already accumulated box, just draw * on the target. */ if (BBOX_IN_RECT(bdev, &ibox)) return fill_path(tdev, pis, ppath, params, pdevc, pcpath); /* * If the target uses the default algorithm, just draw on the * bbox device. */ if (tdev != 0 && fill_path == gx_default_fill_path) return fill_path(dev, pis, ppath, params, pdevc, pcpath); /* Draw on the target now. */ code = fill_path(tdev, pis, ppath, params, pdevc, pcpath); if (code < 0) return code; if (pcpath != NULL && !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y) ) { /* * Let the target do the drawing, but break down the * fill path into pieces for computing the bounding box. */ gx_drawing_color devc; set_nonclient_dev_color(&devc, bdev->black); /* any non-white color will do */ bdev->target = NULL; code = gx_default_fill_path(dev, pis, ppath, params, &devc, pcpath); bdev->target = tdev; } else { /* Just use the path bounding box. */ BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); } return code; } else return fill_path(tdev, pis, ppath, params, pdevc, pcpath); }