/* Get the default clipping box. */ int gx_default_clip_box(const gs_state * pgs, gs_fixed_rect * pbox) { register gx_device *dev = gs_currentdevice(pgs); gs_rect bbox; gs_matrix imat; int code; if (dev->ImagingBBox_set) { /* Use the ImagingBBox, relative to default user space. */ gs_defaultmatrix(pgs, &imat); bbox.p.x = dev->ImagingBBox[0]; bbox.p.y = dev->ImagingBBox[1]; bbox.q.x = dev->ImagingBBox[2]; bbox.q.y = dev->ImagingBBox[3]; } else { /* Use the MediaSize indented by the HWMargins, */ /* relative to unrotated user space adjusted by */ /* the Margins. (We suspect this isn't quite right, */ /* but the whole issue of "margins" is such a mess that */ /* we don't think we can do any better.) */ (*dev_proc(dev, get_initial_matrix)) (dev, &imat); /* Adjust for the Margins. */ imat.tx += dev->Margins[0] * dev->HWResolution[0] / dev->MarginsHWResolution[0]; imat.ty += dev->Margins[1] * dev->HWResolution[1] / dev->MarginsHWResolution[1]; bbox.p.x = dev->HWMargins[0]; bbox.p.y = dev->HWMargins[1]; bbox.q.x = dev->MediaSize[0] - dev->HWMargins[2]; bbox.q.y = dev->MediaSize[1] - dev->HWMargins[3]; } code = gs_bbox_transform(&bbox, &imat, &bbox); if (code < 0) return code; /* Round the clipping box so that it doesn't get ceilinged. */ pbox->p.x = fixed_rounded(float2fixed(bbox.p.x)); pbox->p.y = fixed_rounded(float2fixed(bbox.p.y)); pbox->q.x = fixed_rounded(float2fixed(bbox.q.x)); pbox->q.y = fixed_rounded(float2fixed(bbox.q.y)); return 0; }
/* We should swap axes to get best accuracy, but we don't. */ int gz_fill_pgram_fixed(fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, const gx_device_color *pdevc, gs_state *pgs) { fixed t; fixed qx, dx, wx, pax, qax; int code; #define swap(r, s) (t = r, r = s, s = t) /* Reorder the points so that 0 <= ay <= by. */ if ( ay < 0 ) px += ax, py += ay, ax = -ax, ay = -ay; if ( by < 0 ) px += bx, py += by, bx = -bx, by = -by; if ( ay > by ) swap(ax, bx), swap(ay, by); if ( by == 0 ) return 0; /* degenerate (line) */ qx = px + ax + bx; /* Compute the distance from p to the point on the line (p, p+b) */ /* whose Y coordinate is equal to ay. */ dx = (fixed)((double)bx * ay / by); if ( dx < ax ) pax = px + dx, qax = qx - ax, wx = ax - dx; else pax = px + ax, qax = qx - dx, wx = dx - ax; if ( ay >= fixed_1 || fixed_rounded(py) != fixed_rounded(py + ay) ) { code = gz_fill_trapezoid_fixed(px, fixed_0, py, pax, wx, ay, 0, pdevc, pgs); if ( code < 0 ) return code; } code = gz_fill_trapezoid_fixed(pax, wx, py + ay, qax, wx, by - ay, 0, pdevc, pgs); if ( code < 0 ) return code; py += by; if ( ay >= fixed_1 || fixed_rounded(py) != fixed_rounded(py + ay) ) return gz_fill_trapezoid_fixed(qax, wx, py, qx, fixed_0, ay, 0, pdevc, pgs); #undef swap return 0; }
int gz_fill_trapezoid_fixed(fixed fx0, fixed fw0, fixed fy0, fixed fx1, fixed fw1, fixed fh, int swap_axes, const gx_device_color *pdevc, gs_state *pgs) { const fixed ymin = fixed_rounded(fy0) + fixed_half; const fixed ymax = fixed_rounded(fy0 + fh); int iy = fixed2int_var(ymin); const int iy1 = fixed2int_var(ymax); if ( iy >= iy1 ) return 0; /* no scan lines to sample */ { trap_line l, r; int rxl, rxr, ry; const fixed dxl = fx1 - fx0; const fixed dxr = dxl + fw1 - fw0; const fixed yline = ymin - fy0; /* partial pixel offset to */ /* first line to sample */ int fill_direct = color_is_pure(pdevc); gx_color_index cindex; gx_device *dev; dev_proc_fill_rectangle((*fill_rect)); int code; if_debug2('z', "[z]y=[%d,%d]\n", iy, iy1); if ( fill_direct ) cindex = pdevc->color1, dev = pgs->device->info, fill_rect = dev->procs->fill_rectangle; gp_check_interrupts(); r.x = (l.x = fx0 + fixed_half) + fw0; ry = iy; /* If the rounded X values are the same on both sides, */ /* we can save ourselves a *lot* of work. */ if ( fixed_truncated(l.x) == fixed_rounded(fx1) && fixed_truncated(r.x) == fixed_rounded(fx1 + fw1) ) { rxl = fixed2int_var(l.x); rxr = fixed2int_var(r.x); iy = iy1; if_debug2('z', "[z]rectangle, x=[%d,%d]\n", rxl, rxr); goto last; } #define fill_trap_rect(x,y,w,h)\ (fill_direct ?\ (swap_axes ? (*fill_rect)(dev, y, x, h, w, cindex) :\ (*fill_rect)(dev, x, y, w, h, cindex)) :\ swap_axes ? gz_fill_rectangle(y, x, h, w, pdevc, pgs) :\ gz_fill_rectangle(x, y, w, h, pdevc, pgs)) /* Compute the dx/dy ratios. */ /* dx# = dx#i + (dx#f / fh). */ #define compute_dx(tl, d)\ if ( d >= 0 )\ { if ( d < fh ) tl.di = 0, tl.df = d;\ else tl.di = (int)(d / fh), tl.df = d - tl.di * fh, tl.x += yline * tl.di;\ }\ else\ { if ( (tl.df = d + fh) >= 0 /* d >= -fh */ ) tl.di = -1, tl.x -= yline;\ else tl.di = (int)-((fh - 1 - d) / fh), tl.df = d - tl.di * fh, tl.x += yline * tl.di;\ } /* Compute the x offsets at the first scan line to sample. */ /* We need to be careful in computing yline * dx#f {/,%} fh */ /* because the multiplication may overflow. We know that */ /* all the quantities involved are non-negative, and that */ /* yline is less than 1 (as a fixed, of course); this gives us */ /* a cheap conservative check for overflow in the multiplication. */ #define ymult_limit (max_fixed / fixed_1) #define ymult_quo(yl, dxxf)\ (dxxf < ymult_limit ? yl * dxxf / fh : fixed_mult_quo(yl, dxxf, fh)) #define ymult_rem(yl, dxxf)\ (dxxf < ymult_limit ? yl * dxxf % fh : fixed_mult_rem(yl, dxxf, fh)) /* It's worth checking for dxl == dxr, since this is the case */ /* for parallelograms (including stroked lines). */ compute_dx(l, dxl); if ( dxr == dxl ) { fixed fx = ymult_quo(yline, l.df); l.x += fx; if ( l.di == 0 ) r.di = 0, r.df = l.df; else /* too hard to do adjustments right */ compute_dx(r, dxr); r.x += fx; } else { l.x += ymult_quo(yline, l.df); compute_dx(r, dxr); r.x += ymult_quo(yline, r.df); } rxl = fixed2int_var(l.x); rxr = fixed2int_var(r.x); /* Compute one line's worth of dx/dy. */ /* dx# * fixed_1 = ld#i + (ld#f / fh). */ /* We don't have to bother with this if */ /* we're only sampling a single scan line. */ if ( iy1 - iy == 1 ) { iy++; goto last; } #define compute_ldx(tl)\ if ( tl.df < ymult_limit )\ tl.ldi = int2fixed(tl.di) + int2fixed(tl.df) / fh,\ tl.ldf = int2fixed(tl.df) % fh,\ tl.xf = yline * tl.df % fh - fh;\ else\ tl.ldi = int2fixed(tl.di) + fixed_mult_quo(fixed_1, tl.df, fh),\ tl.ldf = fixed_mult_rem(fixed_1, tl.df, fh),\ tl.xf = fixed_mult_rem(yline, tl.df, fh) - fh compute_ldx(l); if ( dxr == dxl ) r.ldi = l.ldi, r.ldf = l.ldf, r.xf = l.xf; else { compute_ldx(r); } #undef compute_ldx while ( ++iy != iy1 ) { int ixl, ixr; #define step_line(tl)\ tl.x += tl.ldi;\ if ( (tl.xf += tl.ldf) >= 0 ) tl.xf -= fh, tl.x++; step_line(l); step_line(r); #undef step_line ixl = fixed2int_var(l.x); ixr = fixed2int_var(r.x); if ( ixl != rxl || ixr != rxr ) { code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry); if ( code < 0 ) goto xit; rxl = ixl, rxr = ixr, ry = iy; } } last: code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry); xit: gp_check_interrupts(); if ( code < 0 && fill_direct ) return_error(code); 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 = 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; }