diff options
author | Igor Melichev <igor.melichev@artifex.com> | 2004-03-13 18:28:52 +0000 |
---|---|---|
committer | Igor Melichev <igor.melichev@artifex.com> | 2004-03-13 18:28:52 +0000 |
commit | b535d8ca48b19eeff379706b4142c2f1a7216584 (patch) | |
tree | 965ef9cc923ad1c0b6aaa9a927619c922b8eec41 | |
parent | f4c7e77604d5078136ebc971f9e4fbbc8d87ca76 (diff) |
Implementing current point with double precision.
DETAILS :
The old code stores the current point in pgs->ppath->position
with the 'fixed' representation in the device space coordinates.
This appears insufficiently precise if a document constructs a path
with multiple 'rlineto' or 'rcurveto'. A significant to error accumulation happens.
We implement the current point with 'double', duplicating pgs->ppath->position
with the new field gs_imager_state::current_point.
We can't replace pgs->ppath->position with the new one due to several reasons :
- Sometimes (in the text processing, in arc processing and in reversepath)
a new current point is computed when imager state is not accessible.
- Don't want to spend processor time for conversion double to fixed,
whenever a fixed is needed.
- Don't want to modify many of low level modules;
Text operation always round the current point to 'fixed'.
Note that the convertion from fixed to double is always precise,
therefore we widely use it with text operations.
Thus this improves the precision of moveto, lineto, curveto,
rmoveto, rlineto, rcurveto, but the precision of other operators
left as it was. Likely there is no strong need to improve text operations
due to pixel rounding, but it would be useful to improve arc, arcn, arct, arcto.
However an improvement of arc operations isn't a high priority,
and after this patch becomes a local change.
We removed ppath->outside_position, because
pgs->current_point now effectively handles this feature.
Due to that the rounded pgs->current_point may be unequal to pgs->ppath->position
when the current point is outside the range.
The configuration flag PRECISE_CURRENTPOINT defined in gxstate.h
helps to debug the new code with raster comparison with the old code.
PRECISE_CURRENTPOINT 0 works same as the old code except the
coordinate clamping. Therefore once tested with the comparison,
the further validation reduced to a validation of the code
swtched by the flag - this part pof code is pretty small.
The mode (PRECISE_CURRENTPOINT 0) **MUST**NOT** go to production
due to the dropped clamping. PRECISE_CURRENTPOINT 1 handles the clamping.
Bug 687359 "Current point is inprecise".
EXPECTED DIFFERENCES :
Almost all comparefiles render differently.
git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@4887 a1074d23-0009-0410-80fe-cf8c14f379e6
-rw-r--r-- | gs/src/gdevpdtc.c | 9 | ||||
-rw-r--r-- | gs/src/gdevpdte.c | 20 | ||||
-rw-r--r-- | gs/src/gdevpdtt.h | 2 | ||||
-rw-r--r-- | gs/src/gscoord.c | 2 | ||||
-rw-r--r-- | gs/src/gspaint.c | 6 | ||||
-rw-r--r-- | gs/src/gspath.c | 309 | ||||
-rw-r--r-- | gs/src/gspath.h | 11 | ||||
-rw-r--r-- | gs/src/gspath1.c | 33 | ||||
-rw-r--r-- | gs/src/gstype1.c | 8 | ||||
-rw-r--r-- | gs/src/gstype2.c | 3 | ||||
-rw-r--r-- | gs/src/gstype42.c | 3 | ||||
-rw-r--r-- | gs/src/gxchar.c | 9 | ||||
-rw-r--r-- | gs/src/gxistate.h | 5 | ||||
-rw-r--r-- | gs/src/gxmatrix.h | 9 | ||||
-rw-r--r-- | gs/src/gxpath.c | 5 | ||||
-rw-r--r-- | gs/src/gxpath.h | 5 | ||||
-rw-r--r-- | gs/src/gxstate.h | 4 | ||||
-rw-r--r-- | gs/src/gzpath.h | 13 | ||||
-rw-r--r-- | gs/src/gzstate.h | 11 | ||||
-rw-r--r-- | gs/src/lib.mak | 2 | ||||
-rw-r--r-- | gs/src/zupath.c | 15 |
21 files changed, 295 insertions, 189 deletions
diff --git a/gs/src/gdevpdtc.c b/gs/src/gdevpdtc.c index 6c4f64ca6..879454dec 100644 --- a/gs/src/gdevpdtc.c +++ b/gs/src/gdevpdtc.c @@ -158,9 +158,7 @@ process_composite_text(gs_text_enum_t *pte, void *vbuf, uint bsize) } if (!return_width) return 0; - return gx_path_add_point(penum->path, - penum->origin.x + float2fixed(total_width.x), - penum->origin.y + float2fixed(total_width.y)); + return pdf_shift_text_currentpoint(penum, &total_width); } /* ---------------- CMap-based composite font ---------------- */ @@ -518,10 +516,7 @@ scan_cmap_text(pdf_text_enum_t *pte) } pte->index = break_index; pte->xy_index = break_xy_index; - - code = gx_path_add_point(pte->path, - pte->origin.x + float2fixed(wxy.x), - pte->origin.y + float2fixed(wxy.y)); + code = pdf_shift_text_currentpoint(pte, &wxy); if (code < 0) return code; } diff --git a/gs/src/gdevpdte.c b/gs/src/gdevpdte.c index b0b56d5cf..66009f307 100644 --- a/gs/src/gdevpdte.c +++ b/gs/src/gdevpdte.c @@ -373,6 +373,22 @@ adjust_first_last_char(pdf_font_resource_t *pdfont, byte *str, int size) } } +int +pdf_shift_text_currentpoint(pdf_text_enum_t *penum, gs_point *wpt) +{ + gs_state *pgs; + extern_st(st_gs_state); + + if (gs_object_type(penum->dev->memory, penum->pis) != &st_gs_state) { + /* Probably never happens. Not sure though. */ + return_error(gs_error_unregistered); + } + pgs = (gs_state *)penum->pis; + return gs_moveto_aux(penum->pis, gx_current_path(pgs), + fixed2float(penum->origin.x) + wpt->x, + fixed2float(penum->origin.y) + wpt->y); +} + /* * Internal procedure to process a string in a non-composite font. * Doesn't use or set pte->{data,size,index}; may use/set pte->xy_index; @@ -530,9 +546,7 @@ finish: penum->returned.total_width.y += p.y; } else penum->returned.total_width = width_pt; - return gx_path_add_point(penum->path, - penum->origin.x + float2fixed(width_pt.x), - penum->origin.y + float2fixed(width_pt.y)); + return pdf_shift_text_currentpoint(penum, &width_pt); } /* diff --git a/gs/src/gdevpdtt.h b/gs/src/gdevpdtt.h index 8ac312126..8c5e6153c 100644 --- a/gs/src/gdevpdtt.h +++ b/gs/src/gdevpdtt.h @@ -283,4 +283,6 @@ pdf_add_ToUnicode(gx_device_pdf *pdev, gs_font *font, pdf_font_resource_t *pdfon int pdf_encode_glyph(gs_font_base *bfont, gs_glyph glyph0, byte *buf, int buf_size, int *char_code_length); +int pdf_shift_text_currentpoint(pdf_text_enum_t *penum, gs_point *wpt); + #endif /* gdevpdtt_INCLUDED */ diff --git a/gs/src/gscoord.c b/gs/src/gscoord.c index 222182b1d..693d68ee9 100644 --- a/gs/src/gscoord.c +++ b/gs/src/gscoord.c @@ -384,6 +384,8 @@ gx_translate_to_fixed(register gs_state * pgs, fixed px, fixed py) trace_matrix_fixed(&pgs->char_tm); } #endif + gx_setcurrentpoint(pgs, fixed2float(pgs->ctm.tx_fixed), fixed2float(pgs->ctm.ty_fixed)); + pgs->current_point_valid = true; return 0; } diff --git a/gs/src/gspaint.c b/gs/src/gspaint.c index 0069d8973..1bba1dab5 100644 --- a/gs/src/gspaint.c +++ b/gs/src/gspaint.c @@ -395,5 +395,9 @@ gs_strokepath(gs_state * pgs) gx_path_free(&spath, "gs_strokepath"); return code; } - return gx_path_assign_free(pgs->path, &spath); + code = gx_path_assign_free(pgs->path, &spath); + if (code < 0) + return code; + gx_setcurrentpoint(pgs, fixed2float(spath.position.x), fixed2float(spath.position.y)); + return 0; } diff --git a/gs/src/gspath.c b/gs/src/gspath.c index 40b9c3fe9..68a8b2136 100644 --- a/gs/src/gspath.c +++ b/gs/src/gspath.c @@ -17,6 +17,7 @@ /* $Id$ */ /* Basic path routines for Ghostscript library */ #include "gx.h" +#include "math_.h" #include "gserrors.h" #include "gxfixed.h" #include "gxmatrix.h" @@ -33,6 +34,7 @@ int gs_newpath(gs_state * pgs) { + pgs->current_point_valid = false; return gx_path_new(pgs->path); } @@ -44,9 +46,7 @@ gs_closepath(gs_state * pgs) if (code < 0) return code; - if (path_start_outside_range(ppath)) - path_set_outside_position(ppath, ppath->outside_start.x, - ppath->outside_start.y); + pgs->current_point = pgs->subpath_start; return code; } @@ -72,7 +72,7 @@ gx_current_path(const gs_state * pgs) */ #define max_coord_fixed (max_fixed - int2fixed(1000)) /* arbitrary */ #define min_coord_fixed (-max_coord_fixed) -private void +private inline void clamp_point(gs_fixed_point * ppt, floatp x, floatp y) { #define clamp_coord(xy)\ @@ -87,190 +87,221 @@ clamp_point(gs_fixed_point * ppt, floatp x, floatp y) int gs_currentpoint(gs_state * pgs, gs_point * ppt) { - gx_path *ppath = pgs->path; - int code; - gs_fixed_point pt; + if (!pgs->current_point_valid) + return_error(gs_error_nocurrentpoint); + return gs_itransform(pgs, pgs->current_point.x, + pgs->current_point.y, ppt); +} + +private inline int +gs_point_transform_compat(floatp x, floatp y, const gs_matrix_fixed *m, gs_point *pt) +{ +#if !PRECISE_CURRENTPOINT + gs_fixed_point p; + int code = gs_point_transform2fixed(m, x, y, &p); - if (path_outside_range(ppath)) - return gs_itransform(pgs, ppath->outside_position.x, - ppath->outside_position.y, ppt); - code = gx_path_current_point(pgs->path, &pt); if (code < 0) return code; - return gs_itransform(pgs, fixed2float(pt.x), fixed2float(pt.y), ppt); + pt->x = fixed2float(p.x); + pt->y = fixed2float(p.y); + return 0; +#else + return gs_point_transform(x, y, (const gs_matrix *)m, pt); +#endif +} + +private inline int +gs_distance_transform_compat(floatp x, floatp y, const gs_matrix_fixed *m, gs_point *pt) +{ +#if !PRECISE_CURRENTPOINT + gs_fixed_point p; + int code = gs_distance_transform2fixed(m, x, y, &p); + + if (code < 0) + return code; + pt->x = fixed2float(p.x); + pt->y = fixed2float(p.y); + return 0; +#else + return gs_distance_transform(x, y, (const gs_matrix *)m, pt); +#endif +} + +#define float2fixed_rounding(f) ((fixed)floor((f)*(float)fixed_scale + 0.5)) + +private inline int +clamp_point_aux(bool clamp_coordinates, gs_fixed_point *ppt, floatp x, floatp y) +{ + if (!f_fits_in_bits(x, fixed_int_bits) || !f_fits_in_bits(y, fixed_int_bits)) { + if (!clamp_coordinates) + return_error(gs_error_limitcheck); + clamp_point(ppt, x, y); + } else { + /* 181-01.ps" fails with no rounding in + "Verify as last element of a userpath and effect on setbbox." */ + ppt->x = float2fixed_rounding(x); + ppt->y = float2fixed_rounding(y); + } + return 0; } int -gs_moveto(gs_state * pgs, floatp x, floatp y) +gs_moveto_aux(gs_imager_state *pis, gx_path *ppath, floatp x, floatp y) { - gx_path *ppath = pgs->path; gs_fixed_point pt; int code; - if ((code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) < 0) { - if (pgs->clamp_coordinates) { /* Handle out-of-range coordinates. */ - gs_point opt; + code = clamp_point_aux(pis->clamp_coordinates, &pt, x, y); + if (code < 0) + return code; + code = gx_path_add_point(ppath, pt.x, pt.y); + if (code < 0) + return code; + ppath->start_flags = ppath->state_flags; + gx_setcurrentpoint(pis, x, y); + pis->subpath_start = pis->current_point; + pis->current_point_valid = true; + return 0; +} - if (code != gs_error_limitcheck || - (code = gs_transform(pgs, x, y, &opt)) < 0 - ) - return code; - clamp_point(&pt, opt.x, opt.y); - code = gx_path_add_point(ppath, pt.x, pt.y); - if (code < 0) - return code; - path_set_outside_position(ppath, opt.x, opt.y); - ppath->outside_start = ppath->outside_position; - ppath->start_flags = ppath->state_flags; - } +int +gs_moveto(gs_state * pgs, floatp x, floatp y) +{ + gs_point pt; + int code = gs_point_transform_compat(x, y, &pgs->ctm, &pt); + + if (code < 0) return code; - } - return gx_path_add_point(ppath, pt.x, pt.y); + return gs_moveto_aux((gs_imager_state *)pgs, pgs->path, pt.x, pt.y); } int gs_rmoveto(gs_state * pgs, floatp x, floatp y) { - gs_fixed_point dpt; - int code; + gs_point dd; + int code; - if ((code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) < 0 || - (code = gx_path_add_relative_point(pgs->path, dpt.x, dpt.y)) < 0 - ) { /* Handle all exceptional conditions here. */ - gs_point upt; - - if ((code = gs_currentpoint(pgs, &upt)) < 0) - return code; - return gs_moveto(pgs, upt.x + x, upt.y + y); - } - return code; + if (!pgs->current_point_valid) + return_error(gs_error_nocurrentpoint); + code = gs_distance_transform_compat(x, y, &pgs->ctm, &dd); + if (code < 0) + return code; + /* fixme : check in range. */ + return gs_moveto_aux((gs_imager_state *)pgs, pgs->path, + dd.x + pgs->current_point.x, dd.y + pgs->current_point.y); } -int -gs_lineto(gs_state * pgs, floatp x, floatp y) +private inline int +gs_lineto_aux(gs_state * pgs, floatp x, floatp y) { gx_path *ppath = pgs->path; - int code; gs_fixed_point pt; + int code; - if ((code = gs_point_transform2fixed(&pgs->ctm, x, y, &pt)) < 0) { - if (pgs->clamp_coordinates) { /* Handle out-of-range coordinates. */ - gs_point opt; + code = clamp_point_aux(pgs->clamp_coordinates, &pt, x, y); + if (code < 0) + return code; + code = gx_path_add_line(ppath, pt.x, pt.y); + if (code < 0) + return code; + gx_setcurrentpoint(pgs, x, y); + return 0; +} - if (code != gs_error_limitcheck || - (code = gs_transform(pgs, x, y, &opt)) < 0 - ) - return code; - clamp_point(&pt, opt.x, opt.y); - code = gx_path_add_line(ppath, pt.x, pt.y); - if (code < 0) - return code; - path_set_outside_position(ppath, opt.x, opt.y); - } +int +gs_lineto(gs_state * pgs, floatp x, floatp y) +{ + gs_point pt; + int code = gs_point_transform_compat(x, y, &pgs->ctm, &pt); + + if (code < 0) return code; - } - return gx_path_add_line(pgs->path, pt.x, pt.y); + return gs_lineto_aux(pgs, pt.x, pt.y); } int gs_rlineto(gs_state * pgs, floatp x, floatp y) { - gx_path *ppath = pgs->path; - gs_fixed_point dpt; - fixed nx, ny; - int code; + gs_point dd; + int code; - if (!path_position_in_range(ppath) || - (code = gs_distance_transform2fixed(&pgs->ctm, x, y, &dpt)) < 0 || - /* Check for overflow in addition. */ - (((nx = ppath->position.x + dpt.x) ^ dpt.x) < 0 && - (ppath->position.x ^ dpt.x) >= 0) || - (((ny = ppath->position.y + dpt.y) ^ dpt.y) < 0 && - (ppath->position.y ^ dpt.y) >= 0) || - (code = gx_path_add_line(ppath, nx, ny)) < 0 - ) { /* Handle all exceptional conditions here. */ - gs_point upt; - - if ((code = gs_currentpoint(pgs, &upt)) < 0) - return code; - return gs_lineto(pgs, upt.x + x, upt.y + y); - } - return code; + if (!pgs->current_point_valid) + return_error(gs_error_nocurrentpoint); + code = gs_distance_transform_compat(x, y, &pgs->ctm, &dd); + if (code < 0) + return code; + /* fixme : check in range. */ + return gs_lineto_aux(pgs, dd.x + pgs->current_point.x, + dd.y + pgs->current_point.y); } /* ------ Curves ------ */ -int -gs_curveto(gs_state * pgs, +private inline int +gs_curveto_aux(gs_state * pgs, floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3) { gs_fixed_point p1, p2, p3; - int code1 = gs_point_transform2fixed(&pgs->ctm, x1, y1, &p1); - int code2 = gs_point_transform2fixed(&pgs->ctm, x2, y2, &p2); - int code3 = gs_point_transform2fixed(&pgs->ctm, x3, y3, &p3); + int code; gx_path *ppath = pgs->path; - if ((code1 | code2 | code3) < 0) { - if (pgs->clamp_coordinates) { /* Handle out-of-range coordinates. */ - gs_point opt1, opt2, opt3; - int code; + code = clamp_point_aux(pgs->clamp_coordinates, &p1, x1, y1); + if (code < 0) + return code; + code = clamp_point_aux(pgs->clamp_coordinates, &p2, x2, y2); + if (code < 0) + return code; + code = clamp_point_aux(pgs->clamp_coordinates, &p3, x3, y3); + if (code < 0) + return code; + code = gx_path_add_curve(ppath, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + if (code < 0) + return code; + gx_setcurrentpoint(pgs, x3, y3); + return 0; +} - if ((code1 < 0 && code1 != gs_error_limitcheck) || - (code1 = gs_transform(pgs, x1, y1, &opt1)) < 0 - ) - return code1; - if ((code2 < 0 && code2 != gs_error_limitcheck) || - (code2 = gs_transform(pgs, x2, y2, &opt2)) < 0 - ) - return code2; - if ((code3 < 0 && code3 != gs_error_limitcheck) || - (code3 = gs_transform(pgs, x3, y3, &opt3)) < 0 - ) - return code3; - clamp_point(&p1, opt1.x, opt1.y); - clamp_point(&p2, opt2.x, opt2.y); - clamp_point(&p3, opt3.x, opt3.y); - code = gx_path_add_curve(ppath, - p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); - if (code < 0) - return code; - path_set_outside_position(ppath, opt3.x, opt3.y); - return code; - } else - return (code1 < 0 ? code1 : code2 < 0 ? code2 : code3); - } - return gx_path_add_curve(ppath, - p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); +int +gs_curveto(gs_state * pgs, + floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3) +{ + gs_point pt1, pt2, pt3; + int code; + + code = gs_point_transform_compat(x1, y1, &pgs->ctm, &pt1); + if (code < 0) + return code; + code = gs_point_transform_compat(x2, y2, &pgs->ctm, &pt2); + if (code < 0) + return code; + code = gs_point_transform_compat(x3, y3, &pgs->ctm, &pt3); + if (code < 0) + return code; + return gs_curveto_aux(pgs, pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y); } int gs_rcurveto(gs_state * pgs, floatp dx1, floatp dy1, floatp dx2, floatp dy2, floatp dx3, floatp dy3) { - gx_path *ppath = pgs->path; - gs_fixed_point p1, p2, p3; - fixed ptx, pty; - int code; + gs_point dd1, dd2, dd3; + int code; -/****** SHOULD CHECK FOR OVERFLOW IN ADDITION ******/ - if (!path_position_in_range(ppath) || - (code = gs_distance_transform2fixed(&pgs->ctm, dx1, dy1, &p1)) < 0 || - (code = gs_distance_transform2fixed(&pgs->ctm, dx2, dy2, &p2)) < 0 || - (code = gs_distance_transform2fixed(&pgs->ctm, dx3, dy3, &p3)) < 0 || - (ptx = ppath->position.x, pty = ppath->position.y, - code = gx_path_add_curve(ppath, ptx + p1.x, pty + p1.y, - ptx + p2.x, pty + p2.y, - ptx + p3.x, pty + p3.y)) < 0 - ) { /* Handle all exceptional conditions here. */ - gs_point upt; - - if ((code = gs_currentpoint(pgs, &upt)) < 0) - return code; - return gs_curveto(pgs, upt.x + dx1, upt.y + dy1, - upt.x + dx2, upt.y + dy2, - upt.x + dx3, upt.y + dy3); - } - return code; + if (!pgs->current_point_valid) + return_error(gs_error_nocurrentpoint); + code = gs_distance_transform_compat(dx1, dy1, &pgs->ctm, &dd1); + if (code < 0) + return code; + code = gs_distance_transform_compat(dx2, dy2, &pgs->ctm, &dd2); + if (code < 0) + return code; + code = gs_distance_transform_compat(dx3, dy3, &pgs->ctm, &dd3); + if (code < 0) + return code; + /* fixme : check in range. */ + return gs_curveto_aux(pgs, dd1.x + pgs->current_point.x, dd1.y + pgs->current_point.y, + dd2.x + pgs->current_point.x, dd2.y + pgs->current_point.y, + dd3.x + pgs->current_point.x, dd3.y + pgs->current_point.y); } /* ------ Clipping ------ */ diff --git a/gs/src/gspath.h b/gs/src/gspath.h index 39f7ef382..11f223ed2 100644 --- a/gs/src/gspath.h +++ b/gs/src/gspath.h @@ -42,7 +42,6 @@ int gs_newpath(gs_state *), gs_rcurveto(gs_state *, floatp, floatp, floatp, floatp, floatp, floatp), gs_closepath(gs_state *); -/* Imager-level procedures */ #ifndef gs_imager_state_DEFINED # define gs_imager_state_DEFINED typedef struct gs_imager_state_s gs_imager_state; @@ -51,15 +50,17 @@ typedef struct gs_imager_state_s gs_imager_state; # define gx_path_DEFINED typedef struct gx_path_s gx_path; #endif +#ifndef gs_matrix_fixed_DEFINED +#define gs_matrix_fixed_DEFINED +typedef struct gs_matrix_fixed_s gs_matrix_fixed; +#endif + +/* Imager-level procedures */ int gs_imager_arc_add(gx_path * ppath, gs_imager_state * pis, bool clockwise, floatp axc, floatp ayc, floatp arad, floatp aang1, floatp aang2, bool add_line); -#define gs_arc_add_inline(pgs, cw, axc, ayc, arad, aa1, aa2, add)\ - gs_imager_arc_add((pgs)->path, (gs_imager_state *)(pgs),\ - cw, axc, ayc, arad, aa1, aa2, add) - /* Add the current path to the path in the previous graphics state. */ int gs_upmergepath(gs_state *); diff --git a/gs/src/gspath1.c b/gs/src/gspath1.c index 068b88b53..cb8825c7a 100644 --- a/gs/src/gspath1.c +++ b/gs/src/gspath1.c @@ -61,6 +61,30 @@ typedef struct arc_curve_params_s { /* Forward declarations */ private int arc_add(const arc_curve_params_t *arc, bool is_quadrant); + +int +gx_setcurrentpoint_from_path(gs_imager_state *pis, gx_path *path) +{ + gs_point pt; + + pt.x = fixed2float(path->position.x); + pt.y = fixed2float(path->position.y); + gx_setcurrentpoint(pis, pt.x, pt.y); + pis->current_point_valid = true; + return 0; +} + +private inline int +gs_arc_add_inline(gs_state *pgs, bool cw, floatp xc, floatp yc, floatp rad, + floatp a1, floatp a2, bool add) +{ + int code = gs_imager_arc_add(pgs->path, (gs_imager_state *)pgs, cw, xc, yc, rad, a1, a2, add); + + if (code < 0) + return code; + return gx_setcurrentpoint_from_path((gs_imager_state *)pgs, pgs->path); +} + int gs_arc(gs_state * pgs, floatp xc, floatp yc, floatp r, floatp ang1, floatp ang2) @@ -321,6 +345,8 @@ floatp ax1, floatp ay1, floatp ax2, floatp ay2, floatp arad, float retxy[4]) arc.pt.x = ax1; arc.pt.y = ay1; code = arc_add(&arc, false); + if (code == 0) + code = gx_setcurrentpoint_from_path((gs_imager_state *)pgs, pgs->path); } } if (retxy != 0) { @@ -463,6 +489,13 @@ gs_reversepath(gs_state * pgs) gx_path_free(&rpath, "gs_reversepath"); return code; } + if (pgs->current_point_valid) { + /* Not empty. */ + gx_setcurrentpoint(pgs, fixed2float(rpath.position.x), + fixed2float(rpath.position.y)); + pgs->subpath_start.x = fixed2float(rpath.segments->contents.subpath_current->pt.x); + pgs->subpath_start.y = fixed2float(rpath.segments->contents.subpath_current->pt.y); + } gx_path_assign_free(ppath, &rpath); return 0; } diff --git a/gs/src/gstype1.c b/gs/src/gstype1.c index 3dc977599..aa917e133 100644 --- a/gs/src/gstype1.c +++ b/gs/src/gstype1.c @@ -253,8 +253,14 @@ gs_type1_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd, code = t1_hinter__endchar(h, (pcis->seac_accent >= 0)); if (code < 0) return code; - if (pcis->seac_accent < 0) + if (pcis->seac_accent < 0) { code = t1_hinter__endglyph(h); + if (code < 0) + return code; + code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path); + if (code < 0) + return code; + } code = gs_type1_endchar(pcis); if (code == 1) { /* do accent of seac */ diff --git a/gs/src/gstype2.c b/gs/src/gstype2.c index a5356dca9..9f27061e3 100644 --- a/gs/src/gstype2.c +++ b/gs/src/gstype2.c @@ -326,6 +326,9 @@ gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd, code = t1_hinter__endglyph(h); if (code < 0) return code; + code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path); + if (code < 0) + return code; } else t1_hinter__setcurrentpoint(h, pcis->save_adxy.x, pcis->save_adxy.y); code = gs_type1_endchar(pcis); diff --git a/gs/src/gstype42.c b/gs/src/gstype42.c index 8cf0036c0..b02664636 100644 --- a/gs/src/gstype42.c +++ b/gs/src/gstype42.c @@ -717,6 +717,9 @@ gs_type42_append(uint glyph_index, gs_imager_state * pis, if (code < 0) return code; + code = gx_setcurrentpoint_from_path(pis, ppath); + if (code < 0) + return code; /* Set the flatness for curve rendering. */ return gs_imager_setflat(pis, gs_char_flatness(pis, 1.0)); } diff --git a/gs/src/gxchar.c b/gs/src/gxchar.c index b639ad71a..2a1577108 100644 --- a/gs/src/gxchar.c +++ b/gs/src/gxchar.c @@ -769,12 +769,9 @@ show_update(gs_show_enum * penum) private int show_fast_move(gs_state * pgs, gs_fixed_point * pwxy) { - int code = gx_path_add_rel_point_inline(pgs->path, pwxy->x, pwxy->y); - - /* If the current position is out of range, don't try to move. */ - if (code == gs_error_limitcheck && pgs->clamp_coordinates) - code = 0; - return code; + return gs_moveto_aux((gs_imager_state *)pgs, pgs->path, + pgs->current_point.x + fixed2float(pwxy->x), + pgs->current_point.y + fixed2float(pwxy->y)); } /* Get the current character code. */ diff --git a/gs/src/gxistate.h b/gs/src/gxistate.h index 1213b931d..d2603ada2 100644 --- a/gs/src/gxistate.h +++ b/gs/src/gxistate.h @@ -211,6 +211,10 @@ typedef struct gs_transparency_source_s { void *client_data;\ gx_line_params line_params;\ gs_matrix_fixed ctm;\ + bool current_point_valid;\ + gs_point current_point;\ + gs_point subpath_start;\ + bool clamp_coordinates;\ gs_logical_operation_t log_op;\ gx_color_value alpha;\ gs_blend_mode_t blend_mode;\ @@ -255,6 +259,7 @@ struct gs_imager_state_s { #define gs_imager_state_initial(scale)\ 0, 0, { gx_line_params_initial },\ { (float)(scale), 0.0, 0.0, (float)(-(scale)), 0.0, 0.0 },\ + false, {0, 0}, {0, 0}, false, \ lop_default, gx_max_color_value, BLEND_MODE_Compatible,\ { 1.0, 0 }, { 1.0, 0 }, 0/*false*/, 0, 0, 0/*false*/, 0, 0, 1.0,\ { fixed_half, fixed_half }, 0/*false*/, 0/*false*/, 0/*false*/, 1.0,\ diff --git a/gs/src/gxmatrix.h b/gs/src/gxmatrix.h index 2fe007732..6baef8049 100644 --- a/gs/src/gxmatrix.h +++ b/gs/src/gxmatrix.h @@ -29,11 +29,16 @@ * tx/ty values may be too large to fit in a fixed values; txy_fixed_valid * is false if this is the case, and true otherwise. */ -typedef struct gs_matrix_fixed_s { +struct gs_matrix_fixed_s { _matrix_body; fixed tx_fixed, ty_fixed; bool txy_fixed_valid; -} gs_matrix_fixed; +}; + +#ifndef gs_matrix_fixed_DEFINED +#define gs_matrix_fixed_DEFINED +typedef struct gs_matrix_fixed_s gs_matrix_fixed; +#endif /* Make a gs_matrix_fixed from a gs_matrix. */ int gs_matrix_fixed_from_matrix(gs_matrix_fixed *, const gs_matrix *); diff --git a/gs/src/gxpath.c b/gs/src/gxpath.c index 34d36c06f..436db0176 100644 --- a/gs/src/gxpath.c +++ b/gs/src/gxpath.c @@ -520,8 +520,6 @@ gz_path_add_point(gx_path * ppath, fixed x, fixed y) private int gz_path_bbox_add_point(gx_path * ppath, fixed x, fixed y) { - ppath->outside_start.x = x; - ppath->outside_start.y = y; gz_path_bbox_move(ppath, x, y); return 0; } @@ -771,7 +769,6 @@ gx_path_add_path(gx_path * ppath, gx_path * ppfrom) } /* Transfer the remaining state. */ ppath->position = ppfrom->position; - ppath->outside_position = ppfrom->outside_position; ppath->state_flags = ppfrom->state_flags; /* Reset the source path. */ gx_path_init_contents(ppfrom); @@ -855,8 +852,6 @@ gz_path_close_subpath_notes(gx_path * ppath, segment_notes notes) private int gz_path_bbox_close_subpath_notes(gx_path * ppath, segment_notes notes) { - gz_path_bbox_move(ppath, (fixed)ppath->outside_start.x, - (fixed)ppath->outside_start.y); return 0; } diff --git a/gs/src/gxpath.h b/gs/src/gxpath.h index d5e21b341..087789610 100644 --- a/gs/src/gxpath.h +++ b/gs/src/gxpath.h @@ -257,6 +257,11 @@ segment_notes gx_path_enum_notes(const gs_path_enum *); bool gx_path_enum_backup(gs_path_enum *); +/* An auxiliary function to add a path point with a specified transformation. */ +int gs_moveto_aux(gs_imager_state *pis, gx_path *ppath, floatp x, floatp y); +int gx_setcurrentpoint_from_path(gs_imager_state *pis, gx_path *path); + + /* ------ Clipping paths ------ */ /* Opaque type for a clipping path */ diff --git a/gs/src/gxstate.h b/gs/src/gxstate.h index b680078d4..cdc46954f 100644 --- a/gs/src/gxstate.h +++ b/gs/src/gxstate.h @@ -81,4 +81,8 @@ void *gs_state_client_data(const gs_state *); /* Accessories. */ gs_id gx_get_clip_path_id(gs_state *); +/* The following switch is for developmenty purpose only. + PRECISE_CURRENTPOINT 0 must not go to production due to no clamping. */ +#define PRECISE_CURRENTPOINT 1 /* Old code compatible with dropped clamping = 0, new code = 1 */ + #endif /* gxstate_INCLUDED */ diff --git a/gs/src/gzpath.h b/gs/src/gzpath.h index 786fe844a..3b412cb1a 100644 --- a/gs/src/gzpath.h +++ b/gs/src/gzpath.h @@ -235,10 +235,6 @@ typedef enum { ((ppath)->state_flags = psf_last_draw) #define path_update_closepath(ppath)\ ((ppath)->state_flags = psf_last_closepath) -#define path_set_outside_position(ppath, px, py)\ - ((ppath)->outside_position.x = (px),\ - (ppath)->outside_position.y = (py),\ - (ppath)->state_flags |= psf_outside_range) /* * In order to be able to reclaim path segments at the right time, we need @@ -320,8 +316,6 @@ struct gx_path_s { int subpath_count; int curve_count; gs_fixed_point position; /* current position */ - gs_point outside_position; /* position if outside_range is set */ - gs_point outside_start; /* outside_position of last moveto */ gx_path_procs *procs; }; @@ -370,13 +364,6 @@ extern_st(st_path_enum); #define gx_path_current_point_inline(ppath,ppt)\ ( !path_position_valid(ppath) ? gs_note_error(gs_error_nocurrentpoint) :\ ((ppt)->x = ppath->position.x, (ppt)->y = ppath->position.y, 0) ) -/* ...rel_point rather than ...relative_point is because */ -/* some compilers dislike identifiers of >31 characters. */ -#define gx_path_add_rel_point_inline(ppath,dx,dy)\ - ( !path_position_in_range(ppath) || ppath->bbox_set ?\ - gx_path_add_relative_point(ppath, dx, dy) :\ - (ppath->position.x += dx, ppath->position.y += dy,\ - path_update_moveto(ppath), 0) ) /* An iterator of flattened segments for a minotonic curve. */ typedef struct gx_flattened_iterator_s gx_flattened_iterator; diff --git a/gs/src/gzstate.h b/gs/src/gzstate.h index bae7985b7..404cd0bad 100644 --- a/gs/src/gzstate.h +++ b/gs/src/gzstate.h @@ -93,16 +93,13 @@ struct gs_state_s { gs_matrix ctm_default; bool ctm_default_set; /* if true, use ctm_default; */ /* if false, ask device */ - /* Paths: */ gx_path *path; gx_clip_path *clip_path; gx_clip_stack_t *clip_stack; /* (LanguageLevel 3 only) */ gx_clip_path *view_clip; /* (may be 0, or have rule = 0) */ - bool clamp_coordinates; /* if true, clamp out-of-range */ - /* coordinates; if false, */ - /* report a limitcheck */ + /* Effective clip path cache */ gs_id effective_clip_id; /* (key) clip path id */ gs_id effective_view_clip_id; /* (key) view clip path id */ @@ -164,4 +161,10 @@ struct gs_state_s { m(12,transparency_group_stack) #define gs_state_num_ptrs 13 +/* The following macro is used for development purpose for designating places + where current point is changed. Clients must not use it. */ +#define gx_setcurrentpoint(pgs, xx, yy)\ + (pgs)->current_point.x = xx;\ + (pgs)->current_point.y = yy; + #endif /* gzstate_INCLUDED */ diff --git a/gs/src/lib.mak b/gs/src/lib.mak index f7987e174..5ec4dc07a 100644 --- a/gs/src/lib.mak +++ b/gs/src/lib.mak @@ -858,7 +858,7 @@ $(GLOBJ)gsparams.$(OBJ) : $(GLSRC)gsparams.c $(GXERR) $(memory__h)\ $(GLCC) $(GLO_)gsparams.$(OBJ) $(C_) $(GLSRC)gsparams.c $(GLOBJ)gspath.$(OBJ) : $(GLSRC)gspath.c $(GXERR)\ - $(gscoord_h) $(gspath_h)\ + $(math__h) $(gscoord_h) $(gspath_h)\ $(gxdevice_h) $(gxdevmem_h) $(gxfixed_h) $(gxmatrix_h)\ $(gzcpath_h) $(gzpath_h) $(gzstate_h) $(GLCC) $(GLO_)gspath.$(OBJ) $(C_) $(GLSRC)gspath.c diff --git a/gs/src/zupath.c b/gs/src/zupath.c index 861da49d9..43ace507f 100644 --- a/gs/src/zupath.c +++ b/gs/src/zupath.c @@ -524,8 +524,8 @@ make_upath(i_ctx_t *i_ctx_p, ref *rupath, gs_state *pgs, gx_path *ppath, /* ------ Internal routines ------ */ /* Append a user path to the current path. */ -private int -upath_append(os_ptr oppath, i_ctx_t *i_ctx_p) +private inline int +upath_append_aux(os_ptr oppath, i_ctx_t *i_ctx_p) { ref opcodes; check_read(*oppath); @@ -638,6 +638,17 @@ upath_append(os_ptr oppath, i_ctx_t *i_ctx_p) } return 0; } +private int +upath_append(os_ptr oppath, i_ctx_t *i_ctx_p) +{ + int code = upath_append_aux(oppath, i_ctx_p); + + if (code < 0) + return code; + igs->current_point.x = fixed2float(igs->path->position.x); + igs->current_point.y = fixed2float(igs->path->position.y); + return 0; +} /* Append a user path to the current path, and then apply or return */ /* a transformation if one is supplied. */ |