diff --git a/debian/changelog b/debian/changelog index d611187..6402268 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,63 @@ +ghostscript (10.05.1~dfsg-3deepin11) unstable; urgency=medium + + * fix(cve): CVE-2017-8908 + + -- deepin-ci-robot Tue, 28 Jul 2026 08:31:59 +0800 + +ghostscript (10.05.1~dfsg-3deepin10) unstable; urgency=medium + + * fix(cve): CVE-2025-59800 + + -- deepin-ci-robot Tue, 28 Jul 2026 07:30:01 +0800 + +ghostscript (10.05.1~dfsg-3deepin9) unstable; urgency=medium + + * fix(cve): CVE-2018-16539 + + -- deepin-ci-robot Tue, 28 Jul 2026 07:03:30 +0800 + +ghostscript (10.05.1~dfsg-3deepin8) unstable; urgency=medium + + * fix(cve): CVE-2025-59798 + + -- deepin-ci-robot Tue, 28 Jul 2026 06:29:20 +0800 + +ghostscript (10.05.1~dfsg-3deepin7) unstable; urgency=medium + + * fix(cve): CVE-2025-59799 + + -- deepin-ci-robot Tue, 28 Jul 2026 06:09:47 +0800 + +ghostscript (10.05.1~dfsg-3deepin6) unstable; urgency=medium + + * fix(cve): CVE-2025-59801 + + -- deepin-ci-robot Tue, 28 Jul 2026 04:32:35 +0800 + +ghostscript (10.05.1~dfsg-3deepin5) unstable; urgency=medium + + * fix(cve): CVE-2017-7948 + + -- deepin-ci-robot Tue, 28 Jul 2026 03:05:30 +0800 + +ghostscript (10.05.1~dfsg-3deepin4) unstable; urgency=medium + + * fix(cve): CVE-2018-17183 + + -- deepin-ci-robot Tue, 28 Jul 2026 00:59:46 +0800 + +ghostscript (10.05.1~dfsg-3deepin3) unstable; urgency=medium + + * fix(cve): CVE-2017-9619 + + -- deepin-ci-robot Tue, 28 Jul 2026 00:28:47 +0800 + +ghostscript (10.05.1~dfsg-3deepin2) unstable; urgency=medium + + * fix(cve): CVE-2010-1628 + + -- deepin-ci-robot Mon, 27 Jul 2026 22:08:22 +0800 + ghostscript (10.05.1~dfsg-3deepin1) unstable; urgency=medium * Add libgs9-common transitional package for smooth upgrading diff --git a/debian/patches/CVE-2010-1628.patch b/debian/patches/CVE-2010-1628.patch new file mode 100644 index 0000000..937df68 --- /dev/null +++ b/debian/patches/CVE-2010-1628.patch @@ -0,0 +1,40 @@ +Description: CVE-2010-1628 - 安全修复 +Author: Alex Cherepanov +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/e833acd440c5ff694cec3237eeed45cef69eb02e +Bug: https://nvd.nist.gov/vuln/detail/CVE-2010-1628 +Last-Update: 2007-02-12 +--- +diff --git a/psi/ialloc.c b/psi/ialloc.c +index 40216e4..708ddce 100644 +--- a/psi/ialloc.c ++++ b/psi/ialloc.c +@@ -218,11 +218,6 @@ gs_alloc_ref_array(gs_ref_memory_t * mem, ref * parr, uint attrs, + alloc_change_t *cp = 0; + int code = 0; + +- if ((gs_memory_t *)mem != mem->stable_memory) { +- code = alloc_save_change_alloc(mem, "gs_alloc_ref_array", &cp); +- if (code < 0) +- return code; +- } + obj = gs_alloc_struct_array((gs_memory_t *) mem, num_refs + 1, + ref, &st_refs, cname); + if (obj == 0) { +@@ -257,9 +252,14 @@ gs_alloc_ref_array(gs_ref_memory_t * mem, ref * parr, uint attrs, + gs_abort((gs_memory_t *) mem); + } + } +- if (cp) { +- mem->changes = cp; +- cp->where = (ref_packed *)obj; ++ if ((gs_memory_t *)mem != mem->stable_memory) { ++ code = alloc_save_change_alloc(mem, "gs_alloc_ref_array", &cp); ++ if (code < 0) ++ return code; ++ if (cp) { ++ mem->changes = cp; ++ cp->where = (ref_packed *)obj; ++ } + } + } + for (i = 0; i < num_refs; i++) { diff --git a/debian/patches/CVE-2017-7948.patch b/debian/patches/CVE-2017-7948.patch new file mode 100644 index 0000000..82a3475 --- /dev/null +++ b/debian/patches/CVE-2017-7948.patch @@ -0,0 +1,2896 @@ +Description: CVE-2017-7948 - 安全修复 +Author: Robin Watts +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/8210a2864372723b49c526e2b102fdc00c9c4699 +Bug: https://nvd.nist.gov/vuln/detail/CVE-2017-7948 +Last-Update: 2017-04-19 +--- +diff --git a/base/gxscanc.c b/base/gxscanc.c +index 2fbe2aaf0..13ece3afc 100644 +--- a/base/gxscanc.c ++++ b/base/gxscanc.c +@@ -1,16 +1,14 @@ +-/* Copyright (C) 2001-2023 Artifex Software, Inc. ++/* Copyright (C) 2001-2016 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + +- This software is distributed under license and may not be copied, +- modified or distributed except as expressly authorized under the terms +- of the license contained in the file LICENSE in this distribution. +- +- Refer to licensing information at http://www.artifex.com or contact +- Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +- CA 94129, USA, for further information. ++ This software is distributed under license and may not be copied, modified ++ or distributed except as expressly authorized under the terms of that ++ license. Refer to licensing information at http://www.artifex.com/ ++ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, ++ San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. + */ + + /* Path stroking procedures for Ghostscript library */ +@@ -39,7 +37,6 @@ + #include "gxdcolor.h" + #include "assert_.h" + #include /* for qsort */ +-#include /* For INT_MAX */ + + /* Overview of the scan conversion algorithm. + * +@@ -141,8 +138,6 @@ + #undef DEBUG_SCAN_CONVERTER + #undef DEBUG_OUTPUT_SC_AS_PS + +-typedef int64_t fixed64; +- + enum + { + DIRN_UNSET = -1, +@@ -197,130 +192,9 @@ static void coord(const char *str, fixed x, fixed y) + } + #endif + +-typedef void (zero_filler_fn)(int *, const fixed *); +- +-static void mark_line_zero(fixed sx, fixed ex, fixed *zf) +-{ +- if (sx < zf[0]) +- zf[0] = sx; +- if (ex < zf[0]) +- zf[0] = ex; +- if (sx > zf[1]) +- zf[1] = sx; +- if (ex > zf[1]) +- zf[1] = ex; +-} +- +-static void mark_curve_zero(fixed sx, fixed c1x, fixed c2x, fixed ex, int depth, fixed *zf) +-{ +- fixed ax = (sx + c1x)>>1; +- fixed bx = (c1x + c2x)>>1; +- fixed cx = (c2x + ex)>>1; +- fixed dx = (ax + bx)>>1; +- fixed fx = (bx + cx)>>1; +- fixed gx = (dx + fx)>>1; +- +- assert(depth >= 0); +- if (depth == 0) +- mark_line_zero(sx, ex, zf); +- else { +- depth--; +- mark_curve_zero(sx, ax, dx, gx, depth, zf); +- mark_curve_zero(gx, fx, cx, ex, depth, zf); +- } +-} +- +-static void mark_curve_big_zero(fixed64 sx, fixed64 c1x, fixed64 c2x, fixed64 ex, int depth, fixed *zf) +-{ +- fixed64 ax = (sx + c1x)>>1; +- fixed64 bx = (c1x + c2x)>>1; +- fixed64 cx = (c2x + ex)>>1; +- fixed64 dx = (ax + bx)>>1; +- fixed64 fx = (bx + cx)>>1; +- fixed64 gx = (dx + fx)>>1; +- +- assert(depth >= 0); +- if (depth == 0) +- mark_line_zero((fixed)sx, (fixed)ex, zf); +- else { +- depth--; +- mark_curve_big_zero(sx, ax, dx, gx, depth, zf); +- mark_curve_big_zero(gx, fx, cx, ex, depth, zf); +- } +-} +- +-static void mark_curve_top_zero(fixed sx, fixed c1x, fixed c2x, fixed ex, int depth, fixed *zf) +-{ +- fixed test = (sx^(sx<<1))|(c1x^(c1x<<1))|(c2x^(c2x<<1))|(ex^(ex<<1)); +- +- if (test < 0) +- mark_curve_big_zero(sx, c1x, c2x, ex, depth, zf); +- else +- mark_curve_zero(sx, c1x, c2x, ex, depth, zf); +-} +- +-static int +-zero_case(gx_device * gs_restrict pdev, +- gx_path * gs_restrict path, +- gs_fixed_rect * gs_restrict ibox, +- int * gs_restrict index, +- int * gs_restrict table, +- fixed fixed_flat, +- zero_filler_fn * fill) +-{ +- const subpath *psub; +- fixed zf[2]; +- +- /* Step 2 continued: Now we run through the path, filling in the real +- * values. */ +- for (psub = path->first_subpath; psub != 0;) { +- const segment *pseg = (const segment *)psub; +- fixed ex = pseg->pt.x; +- fixed sy = pseg->pt.y; +- fixed ix = ex; +- int iy = fixed2int(pseg->pt.y); +- +- zf[0] = ex; +- zf[1] = ex; +- +- while ((pseg = pseg->next) != 0 && +- pseg->type != s_start +- ) { +- fixed sx = ex; +- ex = pseg->pt.x; +- +- switch (pseg->type) { +- default: +- case s_start: /* Should never happen */ +- case s_dash: /* We should never be seeing a dash here */ +- assert("This should never happen" == NULL); +- break; +- case s_curve: { +- const curve_segment *const pcur = (const curve_segment *)pseg; +- int k = gx_curve_log2_samples(sx, sy, pcur, fixed_flat); +- +- mark_curve_top_zero(sx, pcur->p1.x, pcur->p2.x, ex, k, zf); +- break; +- } +- case s_gap: +- case s_line: +- case s_line_close: +- mark_line_zero(sx, ex, zf); +- break; +- } +- } +- /* And close any open segments */ +- mark_line_zero(ex, ix, zf); +- fill(&table[index[iy-ibox->p.y]], zf); +- psub = (const subpath *)pseg; +- } +- +- return 0; +-} +- + static void mark_line(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int height, int *table, int *index) + { +- int64_t delta; ++ int delta; + int iy, ih; + fixed clip_sy, clip_ey; + int dirn = DIRN_UP; +@@ -360,26 +234,25 @@ static void mark_line(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int he + clip_ey = int2fixed(base_y + height - 1) + fixed_half; + if (sy > clip_ey) + return; +- delta = (int64_t)clip_sy - (int64_t)sy; ++ delta = clip_sy - sy; + if (delta > 0) + { +- int64_t dx = (int64_t)ex - (int64_t)sx; +- int64_t dy = (int64_t)ey - (int64_t)sy; +- int advance = (int)((dx * delta + (dy>>1)) / dy); ++ int dx = ex - sx; ++ int dy = ey - sy; ++ int advance = (int)(((int64_t)dx * delta + (dy>>1)) / dy); + sx += advance; + sy += delta; + } +- delta = (int64_t)ey - (int64_t)clip_ey; ++ ex -= sx; ++ ey -= sy; ++ clip_ey -= clip_sy; ++ delta = ey - clip_ey; + if (delta > 0) + { +- int64_t dx = (int64_t)ex - (int64_t)sx; +- int64_t dy = (int64_t)ey - (int64_t)sy; +- int advance = (int)((dx * delta + (dy>>1)) / dy); ++ int advance = (int)(((int64_t)ex * delta + (ey>>1)) / ey); + ex -= advance; + ey -= delta; + } +- ex -= sx; +- ey -= sy; + ih = fixed2int(ey); + assert(ih >= 0); + iy = fixed2int(sy) - base_y; +@@ -471,24 +344,24 @@ static void mark_curve(fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixe + } + } + +-static void mark_curve_big(fixed64 sx, fixed64 sy, fixed64 c1x, fixed64 c1y, fixed64 c2x, fixed64 c2y, fixed64 ex, fixed64 ey, fixed base_y, fixed height, int *table, int *index, int depth) ++static void mark_curve_big(fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, fixed base_y, fixed height, int *table, int *index, int depth) + { +- fixed64 ax = (sx + c1x)>>1; +- fixed64 ay = (sy + c1y)>>1; +- fixed64 bx = (c1x + c2x)>>1; +- fixed64 by = (c1y + c2y)>>1; +- fixed64 cx = (c2x + ex)>>1; +- fixed64 cy = (c2y + ey)>>1; +- fixed64 dx = (ax + bx)>>1; +- fixed64 dy = (ay + by)>>1; +- fixed64 fx = (bx + cx)>>1; +- fixed64 fy = (by + cy)>>1; +- fixed64 gx = (dx + fx)>>1; +- fixed64 gy = (dy + fy)>>1; ++ fixed ax = (sx>>1) + (c1x>>1); ++ fixed ay = (sy>>1) + (c1y>>1); ++ fixed bx = (c1x>>1) + (c2x>>1); ++ fixed by = (c1y>>1) + (c2y>>1); ++ fixed cx = (c2x>>1) + (ex>>1); ++ fixed cy = (c2y>>1) + (ey>>1); ++ fixed dx = (ax>>1) + (bx>>1); ++ fixed dy = (ay>>1) + (by>>1); ++ fixed fx = (bx>>1) + (cx>>1); ++ fixed fy = (by>>1) + (cy>>1); ++ fixed gx = (dx>>1) + (fx>>1); ++ fixed gy = (dy>>1) + (fy>>1); + + assert(depth >= 0); + if (depth == 0) +- mark_line((fixed)sx, (fixed)sy, (fixed)ex, (fixed)ey, base_y, height, table, index); ++ mark_line(sx, sy, ex, ey, base_y, height, table, index); + else { + depth--; + mark_curve_big(sx, sy, ax, ay, dx, dy, gx, gy, base_y, height, table, index, depth); +@@ -508,91 +381,60 @@ static void mark_curve_top(fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, + + static int make_bbox(gx_path * path, + const gs_fixed_rect * clip, +- gs_fixed_rect * bbox, + gs_fixed_rect * ibox, + fixed adjust) + { ++ gs_fixed_rect bbox; + int code; +- int ret = 0; + + /* Find the bbox - fixed */ +- code = gx_path_bbox(path, bbox); ++ code = gx_path_bbox(path, &bbox); + if (code < 0) + return code; + +- if (bbox->p.y == bbox->q.y) { +- /* Zero height path */ +- if (!clip || +- (bbox->p.y >= clip->p.y && bbox->q.y <= clip->q.y)) { +- /* Either we're not clipping, or we are vertically inside the clip */ +- if (clip) { +- if (bbox->p.x < clip->p.x) +- bbox->p.x = clip->p.x; +- if (bbox->q.x > clip->q.x) +- bbox->q.x = clip->q.x; +- } +- if (bbox->p.x <= bbox->q.x) { +- /* Zero height rectangle, not clipped completely away */ +- ret = 1; +- } +- } +- } +- + if (clip) { +- if (bbox->p.y < clip->p.y) +- bbox->p.y = clip->p.y; +- if (bbox->q.y > clip->q.y) +- bbox->q.y = clip->q.y; ++ if (bbox.p.y < clip->p.y) ++ bbox.p.y = clip->p.y; ++ if (bbox.q.y > clip->q.y) ++ bbox.q.y = clip->q.y; + } + + /* Convert to bbox - int */ +- ibox->p.x = fixed2int(bbox->p.x+adjust-(adjust?1:0)); +- ibox->p.y = fixed2int(bbox->p.y+adjust-(adjust?1:0)); +- ibox->q.x = fixed2int(bbox->q.x-adjust+fixed_1); +- ibox->q.y = fixed2int(bbox->q.y-adjust+fixed_1); ++ ibox->p.x = fixed2int(bbox.p.x-adjust); ++ ibox->p.y = fixed2int(bbox.p.y-adjust); ++ ibox->q.x = fixed2int(bbox.q.x-adjust+fixed_1); ++ ibox->q.y = fixed2int(bbox.q.y-adjust+fixed_1); + +- return ret; ++ return 0; + } + + static inline int + make_table_template(gx_device * pdev, + gx_path * path, +- gs_fixed_rect * ibox, ++ const gs_fixed_rect * ibox, + int intersection_size, +- int adjust, ++ fixed adjust, + int * scanlinesp, + int ** indexp, + int ** tablep) + { + int scanlines; +- const subpath * gs_restrict psub; +- int * gs_restrict index; +- int * gs_restrict table; ++ const subpath * restrict psub; ++ int * restrict index; ++ int * restrict table; + int i; +- int64_t offset; +- int delta; +- fixed base_y; ++ int offset, delta; ++ fixed base_y = ibox->p.y; + + *scanlinesp = 0; + *indexp = NULL; + *tablep = NULL; + +- if (pdev->max_fill_band != 0) +- ibox->p.y &= ~(pdev->max_fill_band-1); +- base_y = ibox->p.y; +- +- /* Previously we took adjust as a fixed distance to add to miny/maxy +- * to allow for the expansion due to 'any part of a pixel'. This causes +- * problems with over/underflow near INT_MAX/INT_MIN, so instead we +- * take adjust as boolean telling us whether to expand y by 1 or not, and +- * then adjust the assignments into the index as appropriate. This +- * solves Bug 697970. */ +- + /* Step 1: Make us a table */ + scanlines = ibox->q.y-base_y; +- /* +1+adjust simplifies the loop below */ ++ /* +1 simplifies the loop below */ + index = (int *)gs_alloc_bytes(pdev->memory, +- (scanlines+1+adjust) * sizeof(*index), ++ (scanlines+1) * sizeof(*index), + "scanc index buffer"); + if (index == NULL) + return_error(gs_error_VMerror); +@@ -602,8 +444,8 @@ make_table_template(gx_device * pdev, + + /* Step 1 continued: Run through the path, filling in the index */ + for (psub = path->first_subpath; psub != 0;) { +- const segment * gs_restrict pseg = (const segment *)psub; +- fixed ey = pseg->pt.y; ++ const segment * restrict pseg = (const segment *)psub; ++ fixed ey = pseg->pt.y + adjust; + fixed iy = ey; + int iey = fixed2int(iy) - base_y; + +@@ -622,7 +464,7 @@ make_table_template(gx_device * pdev, + pseg->type != s_start + ) { + fixed sy = ey; +- ey = pseg->pt.y; ++ ey = pseg->pt.y + adjust; + + switch (pseg->type) { + default: +@@ -631,9 +473,9 @@ make_table_template(gx_device * pdev, + assert("This should never happen" == NULL); + break; + case s_curve: { +- const curve_segment *const gs_restrict pcur = (const curve_segment *)pseg; +- fixed c1y = pcur->p1.y; +- fixed c2y = pcur->p2.y; ++ const curve_segment *const restrict pcur = (const curve_segment *)pseg; ++ fixed c1y = pcur->p1.y + adjust; ++ fixed c2y = pcur->p2.y + adjust; + fixed maxy = sy, miny = sy; + int imaxy, iminy; + if (miny > c1y) +@@ -653,10 +495,8 @@ make_table_template(gx_device * pdev, + dlprintf2("Curve (%x->%x) ", miny, maxy); + #endif + iminy = fixed2int(miny) - base_y; +- if (iminy <= 0) ++ if (iminy < 0) + iminy = 0; +- else +- iminy -= adjust; + if (iminy < scanlines) { + imaxy = fixed2int(maxy) - base_y; + if (imaxy >= 0) { +@@ -665,13 +505,12 @@ make_table_template(gx_device * pdev, + dlprintf1("+%x ", iminy); + #endif + index[iminy]+=3; +- if (imaxy < scanlines) { ++ if (imaxy < scanlines) + #ifdef DEBUG_SCAN_CONVERTER + if (debugging_scan_converter) + dlprintf1("-%x ", imaxy+1); + #endif +- index[imaxy+1+adjust]-=3; +- } ++ index[imaxy+1]-=3; + } + } + #ifdef DEBUG_SCAN_CONVERTER +@@ -701,10 +540,8 @@ make_table_template(gx_device * pdev, + dlprintf2("Line (%x->%x) ", miny, maxy); + #endif + iminy = fixed2int(miny) - base_y; +- if (iminy <= 0) ++ if (iminy < 0) + iminy = 0; +- else +- iminy -= adjust; + if (iminy < scanlines) { + imaxy = fixed2int(maxy) - base_y; + if (imaxy >= 0) { +@@ -718,7 +555,7 @@ make_table_template(gx_device * pdev, + if (debugging_scan_converter) + dlprintf1("-%x ", imaxy+1); + #endif +- index[imaxy+1+adjust]--; ++ index[imaxy+1]--; + } + } + } +@@ -744,10 +581,8 @@ make_table_template(gx_device * pdev, + dlprintf2("Close (%x->%x) ", miny, maxy); + #endif + iminy = fixed2int(miny) - base_y; +- if (iminy <= 0) ++ if (iminy < 0) + iminy = 0; +- else +- iminy -= adjust; + if (iminy < scanlines) { + imaxy = fixed2int(maxy) - base_y; + if (imaxy >= 0) { +@@ -761,7 +596,7 @@ make_table_template(gx_device * pdev, + if (debugging_scan_converter) + dlprintf1("-%x ", imaxy+1); + #endif +- index[imaxy+1+adjust]--; ++ index[imaxy+1]--; + } + } + } +@@ -780,47 +615,26 @@ make_table_template(gx_device * pdev, + /* Step 1 continued: index now contains a list of deltas (how the + * number of intersects on line x differs from the number on line x-1). + * First convert them to be the real number of intersects on that line. +- * Sum these values to get us the total number of intersects. Then ++ * Sum these values to get us the total nunber of intersects. Then + * convert the table to be a list of offsets into the real intersect + * buffer. */ + offset = 0; + delta = 0; +- for (i=0; i < scanlines+adjust; i++) { ++ for (i=0; i < scanlines; i++) { + delta += intersection_size*index[i]; /* delta = Num ints on this scanline. */ + index[i] = offset; /* Offset into table for this lines data. */ + offset += delta+1; /* Adjust offset for next line. */ + } +- /* Ensure we always have enough room for our zero height rectangle hack. */ +- if (offset < 2*intersection_size) +- offset += 2*intersection_size; +- offset *= sizeof(*table); +- +- /* Try to keep the size to 1Meg. This is enough for the vast majority +- * of files. Allow us to grow above this if it would mean dropping +- * the height below a suitably small number (set to be larger than +- * any max_fill_band we might meet). */ +- if (scanlines > 16 && offset > 1024*1024) { /* Arbitrary */ +- gs_free_object(pdev->memory, index, "scanc index buffer"); +- return offset/(1024*1024) + 1; +- } +- +- /* In the case where we have let offset be large, at least make sure +- * it's not TOO large for us to malloc. */ +- if (offset != (int64_t)(uint)offset) +- { +- gs_free_object(pdev->memory, index, "scanc index buffer"); +- return_error(gs_error_VMerror); +- } + + /* End of step 1: index[i] = offset into table 2 for scanline i's + * intersection data. offset = Total number of int entries required for + * table. */ + + /* Step 2: Collect the real intersections */ +- table = (int *)gs_alloc_bytes(pdev->memory, offset, ++ table = (int *)gs_alloc_bytes(pdev->memory, offset * sizeof(*table), + "scanc intersects buffer"); + if (table == NULL) { +- gs_free_object(pdev->memory, index, "scanc index buffer"); ++ gs_free_object(pdev->memory, table, "scanc index buffer"); + return_error(gs_error_VMerror); + } + +@@ -840,37 +654,27 @@ make_table_template(gx_device * pdev, + + static int make_table(gx_device * pdev, + gx_path * path, +- gs_fixed_rect * ibox, ++ const gs_fixed_rect * ibox, + int * scanlines, + int ** index, + int ** table) + { +- return make_table_template(pdev, path, ibox, 1, 1, scanlines, index, table); +-} +- +-static void +-fill_zero(int *row, const fixed *x) +-{ +- int n = *row = (*row)+2; /* Increment the count */ +- row[n-1] = (x[0]&~1); +- row[n ] = (x[1]|1); ++ return make_table_template(pdev, path, ibox, 1, fixed_half-1, scanlines, index, table); + } + +-int gx_scan_convert(gx_device * gs_restrict pdev, +- gx_path * gs_restrict path, +- const gs_fixed_rect * gs_restrict clip, +- gx_edgebuffer * gs_restrict edgebuffer, +- fixed fixed_flat) ++int gx_scan_convert(gx_device * restrict pdev, ++ gx_path * restrict path, ++ const gs_fixed_rect * restrict clip, ++ gx_edgebuffer * restrict edgebuffer, ++ fixed fixed_flat) + { + gs_fixed_rect ibox; +- gs_fixed_rect bbox; + int scanlines; + const subpath *psub; + int *index; + int *table; + int i; + int code; +- int zero; + + edgebuffer->index = NULL; + edgebuffer->table = NULL; +@@ -879,24 +683,17 @@ int gx_scan_convert(gx_device * gs_restrict pdev, + if (path->first_subpath == NULL) + return 0; + +- zero = make_bbox(path, clip, &bbox, &ibox, fixed_half); +- if (zero < 0) +- return zero; ++ code = make_bbox(path, clip, &ibox, fixed_half); ++ if (code < 0) ++ return code; + + if (ibox.q.y <= ibox.p.y) + return 0; + + code = make_table(pdev, path, &ibox, &scanlines, &index, &table); +- if (code != 0) /* >0 means "retry with smaller height" */ ++ if (code < 0) + return code; + +- if (scanlines == 0) +- return 0; +- +- if (zero) { +- code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero); +- } else { +- + /* Step 2 continued: Now we run through the path, filling in the real + * values. */ + for (psub = path->first_subpath; psub != 0;) { +@@ -940,7 +737,6 @@ int gx_scan_convert(gx_device * gs_restrict pdev, + mark_line(ex, ey, ix, iy, ibox.p.y, scanlines, table, index); + psub = (const subpath *)pseg; + } +- } + + /* Step 2 complete: We now have a complete list of intersection data in + * table, indexed by index. */ +@@ -985,8 +781,8 @@ int gx_scan_convert(gx_device * gs_restrict pdev, + + /* Step 5: Filter the intersections according to the rules */ + int +-gx_filter_edgebuffer(gx_device * gs_restrict pdev, +- gx_edgebuffer * gs_restrict edgebuffer, ++gx_filter_edgebuffer(gx_device * restrict pdev, ++ gx_edgebuffer * restrict edgebuffer, + int rule) + { + int i; +@@ -1041,9 +837,9 @@ gx_filter_edgebuffer(gx_device * gs_restrict pdev, + + /* Step 6: Fill the edgebuffer */ + int +-gx_fill_edgebuffer(gx_device * gs_restrict pdev, +- const gx_device_color * gs_restrict pdevc, +- gx_edgebuffer * gs_restrict edgebuffer, ++gx_fill_edgebuffer(gx_device * restrict pdev, ++ const gx_device_color * restrict pdevc, ++ gx_edgebuffer * restrict edgebuffer, + int log_op) + { + int i, code; +@@ -1154,7 +950,7 @@ typedef struct + } cursor; + + static inline void +-cursor_output(cursor * gs_restrict cr, int iy) ++cursor_output(cursor * restrict cr, int iy) + { + int *row; + int count; +@@ -1167,21 +963,21 @@ cursor_output(cursor * gs_restrict cr, int iy) + cr->save_iy = iy; + cr->save_d = cr->d; + cr->saved = 1; +- } else if (cr->d != DIRN_UNSET) { ++ } else { + /* Enter it into the table */ ++ assert(cr->d != DIRN_UNSET); ++ + row = &cr->table[cr->index[iy]]; + *row = count = (*row)+1; /* Increment the count */ + row[2 * count - 1] = (cr->left&~1) | cr->d; + row[2 * count ] = cr->right; +- } else { +- assert(cr->left == max_fixed && cr->right == min_fixed); + } + } + cr->first = 0; + } + + static inline void +-cursor_output_inrange(cursor * gs_restrict cr, int iy) ++cursor_output_inrange(cursor * restrict cr, int iy) + { + int *row; + int count; +@@ -1208,7 +1004,7 @@ cursor_output_inrange(cursor * gs_restrict cr, int iy) + + /* Step the cursor in y, allowing for maybe crossing a scanline */ + static inline void +-cursor_step(cursor * gs_restrict cr, fixed dy, fixed x, int skip) ++cursor_step(cursor * restrict cr, fixed dy, fixed x) + { + int new_iy; + int iy = fixed2int(cr->y) - cr->base; +@@ -1216,8 +1012,7 @@ cursor_step(cursor * gs_restrict cr, fixed dy, fixed x, int skip) + cr->y += dy; + new_iy = fixed2int(cr->y) - cr->base; + if (new_iy != iy) { +- if (!skip) +- cursor_output(cr, iy); ++ cursor_output(cr, iy); + cr->left = x; + cr->right = x; + } else { +@@ -1230,7 +1025,7 @@ cursor_step(cursor * gs_restrict cr, fixed dy, fixed x, int skip) + + /* Step the cursor in y, never by enough to cross a scanline. */ + static inline void +-cursor_never_step_vertical(cursor * gs_restrict cr, fixed dy, fixed x) ++cursor_never_step_vertical(cursor * restrict cr, fixed dy, fixed x) + { + assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); + +@@ -1241,7 +1036,7 @@ cursor_never_step_vertical(cursor * gs_restrict cr, fixed dy, fixed x) + * knowing that we are moving left, and that the right edge + * has already been accounted for. */ + static inline void +-cursor_never_step_left(cursor * gs_restrict cr, fixed dy, fixed x) ++cursor_never_step_left(cursor * restrict cr, fixed dy, fixed x) + { + assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); + +@@ -1254,7 +1049,7 @@ cursor_never_step_left(cursor * gs_restrict cr, fixed dy, fixed x) + * knowing that we are moving right, and that the left edge + * has already been accounted for. */ + static inline void +-cursor_never_step_right(cursor * gs_restrict cr, fixed dy, fixed x) ++cursor_never_step_right(cursor * restrict cr, fixed dy, fixed x) + { + assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); + +@@ -1265,12 +1060,11 @@ cursor_never_step_right(cursor * gs_restrict cr, fixed dy, fixed x) + + /* Step the cursor in y, always by enough to cross a scanline. */ + static inline void +-cursor_always_step(cursor * gs_restrict cr, fixed dy, fixed x, int skip) ++cursor_always_step(cursor * restrict cr, fixed dy, fixed x) + { + int iy = fixed2int(cr->y) - cr->base; + +- if (!skip) +- cursor_output(cr, iy); ++ cursor_output(cr, iy); + cr->y += dy; + cr->left = x; + cr->right = x; +@@ -1280,7 +1074,7 @@ cursor_always_step(cursor * gs_restrict cr, fixed dy, fixed x, int skip) + * part of a vertical line, knowing that we are moving from a + * position guaranteed to be in the valid y range. */ + static inline void +-cursor_always_step_inrange_vertical(cursor * gs_restrict cr, fixed dy, fixed x) ++cursor_always_step_inrange_vertical(cursor * restrict cr, fixed dy, fixed x) + { + int iy = fixed2int(cr->y) - cr->base; + +@@ -1292,7 +1086,7 @@ cursor_always_step_inrange_vertical(cursor * gs_restrict cr, fixed dy, fixed x) + * part of a left moving line, knowing that we are moving from a + * position guaranteed to be in the valid y range. */ + static inline void +-cursor_always_inrange_step_left(cursor * gs_restrict cr, fixed dy, fixed x) ++cursor_always_inrange_step_left(cursor * restrict cr, fixed dy, fixed x) + { + int iy = fixed2int(cr->y) - cr->base; + +@@ -1305,7 +1099,7 @@ cursor_always_inrange_step_left(cursor * gs_restrict cr, fixed dy, fixed x) + * part of a right moving line, knowing that we are moving from a + * position guaranteed to be in the valid y range. */ + static inline void +-cursor_always_inrange_step_right(cursor * gs_restrict cr, fixed dy, fixed x) ++cursor_always_inrange_step_right(cursor * restrict cr, fixed dy, fixed x) + { + int iy = fixed2int(cr->y) - cr->base; + +@@ -1314,7 +1108,7 @@ cursor_always_inrange_step_right(cursor * gs_restrict cr, fixed dy, fixed x) + cr->left = x; + } + +-static inline void cursor_init(cursor * gs_restrict cr, fixed y, fixed x) ++static inline void cursor_init(cursor * restrict cr, fixed y, fixed x) + { + assert(y >= int2fixed(cr->base) && y <= int2fixed(cr->base + cr->scanlines)); + +@@ -1324,45 +1118,40 @@ static inline void cursor_init(cursor * gs_restrict cr, fixed y, fixed x) + cr->d = DIRN_UNSET; + } + +-static inline void cursor_left_merge(cursor * gs_restrict cr, fixed x) ++static inline void cursor_left_merge(cursor * restrict cr, fixed x) + { + if (x < cr->left) + cr->left = x; + } + +-static inline void cursor_left(cursor * gs_restrict cr, fixed x) ++static inline void cursor_left(cursor * restrict cr, fixed x) + { + cr->left = x; + } + +-static inline void cursor_right_merge(cursor * gs_restrict cr, fixed x) ++static inline void cursor_right_merge(cursor * restrict cr, fixed x) + { + if (x > cr->right) + cr->right = x; + } + +-static inline void cursor_right(cursor * gs_restrict cr, fixed x) ++static inline void cursor_right(cursor * restrict cr, fixed x) + { + cr->right = x; + } + +-static inline int cursor_down(cursor * gs_restrict cr, fixed x) ++static inline void cursor_down(cursor * restrict cr, fixed x) + { +- int skip = 0; +- if ((cr->y & 0xff) == 0) +- skip = 1; + if (cr->d == DIRN_UP) + { +- if (!skip) +- cursor_output(cr, fixed2int(cr->y) - cr->base); ++ cursor_output(cr, fixed2int(cr->y) - cr->base); + cr->left = x; + cr->right = x; + } + cr->d = DIRN_DOWN; +- return skip; + } + +-static inline void cursor_up(cursor * gs_restrict cr, fixed x) ++static inline void cursor_up(cursor * restrict cr, fixed x) + { + if (cr->d == DIRN_DOWN) + { +@@ -1374,7 +1163,7 @@ static inline void cursor_up(cursor * gs_restrict cr, fixed x) + } + + static inline void +-cursor_flush(cursor * gs_restrict cr, fixed x) ++cursor_flush(cursor * restrict cr, fixed x) + { + int iy; + +@@ -1383,11 +1172,6 @@ cursor_flush(cursor * gs_restrict cr, fixed x) + * rectangle from the start point. */ + if (cr->first) { + int iy = fixed2int(cr->y) - cr->base; +- /* Any zero height rectangle counts as filled, except +- * those on the baseline of a pixel. */ +- if (cr->d == DIRN_UNSET && (cr->y & 0xff) == 0) +- return; +- assert(cr->left != max_fixed && cr->right != min_fixed); + if (iy >= 0 && iy < cr->scanlines) { + int *row = &cr->table[cr->index[iy]]; + int count = *row = (*row)+2; /* Increment the count */ +@@ -1423,17 +1207,10 @@ cursor_flush(cursor * gs_restrict cr, fixed x) + } + } + +-static inline void +-cursor_null(cursor *cr) +-{ +- cr->right = min_fixed; +- cr->left = max_fixed; +- cr->d = DIRN_UNSET; +-} +- +-static void mark_line_app(cursor * gs_restrict cr, fixed sx, fixed sy, fixed ex, fixed ey) ++static void mark_line_app(cursor * restrict cr, fixed sx, fixed sy, fixed ex, fixed ey) + { + int isy, iey; ++ fixed y_steps; + fixed saved_sy = sy; + fixed saved_ex = ex; + fixed saved_ey = ey; +@@ -1455,45 +1232,34 @@ static void mark_line_app(cursor * gs_restrict cr, fixed sx, fixed sy, fixed ex, + dlprintf("stroke %%PS\n"); + #endif + +- /* Horizontal motion at the bottom of a pixel is ignored */ +- if (sy == ey && (sy & 0xff) == 0) +- return; +- +- assert(cr->y == sy && +- ((cr->left <= sx && cr->right >= sx) || ((sy & 0xff) == 0)) && +- cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); ++ assert(cr->y == sy && cr->left <= sx && cr->right >= sx && cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); + + if (isy < iey) { + /* Rising line */ + if (iey < 0 || isy >= cr->scanlines) { + /* All line is outside. */ +- if ((ey & 0xff) == 0) +- cursor_null(cr); +- else { +- cr->left = ex; +- cr->right = ex; +- } + cr->y = ey; ++ cr->left = ex; ++ cr->right = ex; + cr->first = 0; + return; + } + if (isy < 0) { + /* Move sy up */ +- int64_t y = (int64_t)ey - (int64_t)sy; +- fixed new_sy = int2fixed(cr->base); +- int64_t dy = (int64_t)new_sy - (int64_t)sy; ++ int y = ey - sy; ++ int new_sy = int2fixed(cr->base); ++ int dy = new_sy - sy; + sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; +- cursor_null(cr); +- cr->y = sy; ++ cursor_init(cr, sy, sx); + isy = 0; + } + truncated = iey > cr->scanlines; + if (truncated) { + /* Move ey down */ +- int64_t y = ey - sy; +- fixed new_ey = int2fixed(cr->base + cr->scanlines); +- int64_t dy = (int64_t)ey - (int64_t)new_ey; ++ int y = ey - sy; ++ int new_ey = int2fixed(cr->base + cr->scanlines); ++ int dy = ey - new_ey; + saved_ex = ex; + saved_ey = ey; + ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); +@@ -1504,42 +1270,34 @@ static void mark_line_app(cursor * gs_restrict cr, fixed sx, fixed sy, fixed ex, + /* Falling line */ + if (isy < 0 || iey >= cr->scanlines) { + /* All line is outside. */ +- if ((ey & 0xff) == 0) +- cursor_null(cr); +- else { +- cr->left = ex; +- cr->right = ex; +- } + cr->y = ey; ++ cr->left = ex; ++ cr->right = ex; + cr->first = 0; + return; + } + truncated = iey < 0; + if (truncated) { + /* Move ey up */ +- int64_t y = (int64_t)ey - (int64_t)sy; +- fixed new_ey = int2fixed(cr->base); +- int64_t dy = (int64_t)ey - (int64_t)new_ey; ++ int y = ey - sy; ++ int new_ey = int2fixed(cr->base); ++ int dy = ey - new_ey; + ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); + ey = new_ey; + iey = 0; + } + if (isy >= cr->scanlines) { + /* Move sy down */ +- int64_t y = (int64_t)ey - (int64_t)sy; +- fixed new_sy = int2fixed(cr->base + cr->scanlines); +- int64_t dy = (int64_t)new_sy - (int64_t)sy; ++ int y = ey - sy; ++ int new_sy = int2fixed(cr->base + cr->scanlines); ++ int dy = new_sy - sy; + sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; +- cursor_null(cr); +- cr->y = sy; ++ cursor_init(cr, sy, sx); + isy = cr->scanlines; + } + } + +- cursor_left_merge(cr, sx); +- cursor_right_merge(cr, sx); +- + assert(cr->left <= sx); + assert(cr->right >= sx); + assert(cr->y == sy); +@@ -1567,42 +1325,24 @@ static void mark_line_app(cursor * gs_restrict cr, fixed sx, fixed sy, fixed ex, + if (isy == iey) { + if (saved_sy == saved_ey) { + /* Horizontal line. Don't change cr->d, don't flush. */ +- if ((ey & 0xff) == 0) +- goto no_merge; + } else if (saved_sy > saved_ey) { + /* Falling line, flush if previous was rising */ +- int skip = cursor_down(cr, sx); +- if ((ey & 0xff) == 0) { +- /* We are falling to the baseline of a subpixel, so output +- * for the current pixel, and leave the cursor nulled. */ +- if (sx <= ex) { +- cursor_right_merge(cr, ex); +- } else { +- cursor_left_merge(cr, ex); +- } +- if (!skip) +- cursor_output(cr, fixed2int(cr->y) - cr->base); +- cursor_null(cr); +- goto no_merge; +- } ++ cursor_down(cr, sx); + } else { + /* Rising line, flush if previous was falling */ + cursor_up(cr, sx); +- if ((ey & 0xff) == 0) { +- cursor_null(cr); +- goto no_merge; +- } + } + if (sx <= ex) { ++ cursor_left_merge(cr, sx); + cursor_right_merge(cr, ex); + } else { + cursor_left_merge(cr, ex); ++ cursor_right_merge(cr, sx); + } +-no_merge: + cr->y = ey; + if (sy > saved_ey) + goto endFalling; +- } else if (iey > isy) { ++ } else if ((y_steps = ey - sy) > 0) { + /* We want to change from sy to ey, which are guaranteed to be on + * different scanlines. We do this in 3 phases. + * Phase 1 gets us from sy to the next scanline boundary. +@@ -1617,7 +1357,6 @@ no_merge: + */ + int phase1_y_steps = (-sy) & (fixed_1 - 1); + int phase3_y_steps = ey & (fixed_1 - 1); +- ufixed y_steps = (ufixed)ey - (ufixed)sy; + + cursor_up(cr, sx); + +@@ -1625,16 +1364,16 @@ no_merge: + /* Vertical line. (Rising) */ + + /* Phase 1: */ ++ cursor_left_merge(cr, sx); ++ cursor_right_merge(cr, sx); + if (phase1_y_steps) { + /* If phase 1 will move us into a new scanline, then we must + * flush it before we move. */ +- cursor_step(cr, phase1_y_steps, sx, 0); ++ cursor_step(cr, phase1_y_steps, sx); + sy += phase1_y_steps; + y_steps -= phase1_y_steps; +- if (y_steps == 0) { +- cursor_null(cr); ++ if (y_steps == 0) + goto end; +- } + } + + /* Phase 3: precalculation */ +@@ -1644,7 +1383,7 @@ no_merge: + y_steps = fixed2int(y_steps); + assert(y_steps >= 0); + if (y_steps > 0) { +- cursor_always_step(cr, fixed_1, sx, 0); ++ cursor_always_step(cr, fixed_1, sx); + y_steps--; + while (y_steps) { + cursor_always_step_inrange_vertical(cr, fixed_1, sx); +@@ -1654,28 +1393,24 @@ no_merge: + + /* Phase 3 */ + assert(cr->left == sx && cr->right == sx); +- if (phase3_y_steps == 0) +- cursor_null(cr); +- else +- cr->y += phase3_y_steps; ++ cr->y += phase3_y_steps; + } else if (sx < ex) { + /* Lines increasing in x. (Rightwards, rising) */ + int phase1_x_steps, phase3_x_steps; + fixed x_steps = ex - sx; + + /* Phase 1: */ ++ cursor_left_merge(cr, sx); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + sx += phase1_x_steps; + cursor_right_merge(cr, sx); + x_steps -= phase1_x_steps; +- cursor_step(cr, phase1_y_steps, sx, 0); ++ cursor_step(cr, phase1_y_steps, sx); + sy += phase1_y_steps; + y_steps -= phase1_y_steps; +- if (y_steps == 0) { +- cursor_null(cr); ++ if (y_steps == 0) + goto end; +- } + } + + /* Phase 3: precalculation */ +@@ -1702,7 +1437,7 @@ no_merge: + if (f < 0) + f += d, sx++; + cursor_right_merge(cr, sx); +- cursor_always_step(cr, fixed_1, sx, 0); ++ cursor_always_step(cr, fixed_1, sx); + y_steps--; + + while (y_steps) { +@@ -1718,30 +1453,25 @@ no_merge: + + /* Phase 3 */ + assert(cr->left <= ex && cr->right >= sx); +- if (phase3_y_steps == 0) +- cursor_null(cr); +- else { +- cursor_right(cr, ex); +- cr->y += phase3_y_steps; +- } ++ cursor_right(cr, ex); ++ cr->y += phase3_y_steps; + } else { + /* Lines decreasing in x. (Leftwards, rising) */ + int phase1_x_steps, phase3_x_steps; + fixed x_steps = sx - ex; + + /* Phase 1: */ ++ cursor_right_merge(cr, sx); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + x_steps -= phase1_x_steps; + sx -= phase1_x_steps; + cursor_left_merge(cr, sx); +- cursor_step(cr, phase1_y_steps, sx, 0); ++ cursor_step(cr, phase1_y_steps, sx); + sy += phase1_y_steps; + y_steps -= phase1_y_steps; +- if (y_steps == 0) { +- cursor_null(cr); ++ if (y_steps == 0) + goto end; +- } + } + + /* Phase 3: precalculation */ +@@ -1768,7 +1498,7 @@ no_merge: + if (f < 0) + f += d, sx--; + cursor_left_merge(cr, sx); +- cursor_always_step(cr, fixed_1, sx, 0); ++ cursor_always_step(cr, fixed_1, sx); + y_steps--; + + while (y_steps) { +@@ -1784,12 +1514,8 @@ no_merge: + + /* Phase 3 */ + assert(cr->right >= ex && cr->left <= sx); +- if (phase3_y_steps == 0) +- cursor_null(cr); +- else { +- cursor_left(cr, ex); +- cr->y += phase3_y_steps; +- } ++ cursor_left(cr, ex); ++ cr->y += phase3_y_steps; + } + } else { + /* So lines decreasing in y. */ +@@ -1801,21 +1527,34 @@ no_merge: + */ + int phase1_y_steps = sy & (fixed_1 - 1); + int phase3_y_steps = (-ey) & (fixed_1 - 1); +- ufixed y_steps = (ufixed)sy - (ufixed)ey; + +- int skip = cursor_down(cr, sx); ++ y_steps = -y_steps; ++ /* Cope with the awkward 0x80000000 case. */ ++ if (y_steps < 0) ++ { ++ int mx, my; ++ mx = sx + ((ex-sx)>>1); ++ my = sy + ((ey-sy)>>1); ++ mark_line_app(cr, sx, sy, mx, my); ++ mark_line_app(cr, mx, my, ex, ey); ++ return; ++ } ++ ++ cursor_down(cr, sx); + + if (sx == ex) { + /* Vertical line. (Falling) */ + + /* Phase 1: */ ++ cursor_left_merge(cr, sx); ++ cursor_right_merge(cr, sx); + if (phase1_y_steps) { + /* Phase 1 in a falling line never moves us into a new scanline. */ + cursor_never_step_vertical(cr, -phase1_y_steps, sx); + sy -= phase1_y_steps; + y_steps -= phase1_y_steps; + if (y_steps == 0) +- goto endFallingLeftOnEdgeOfPixel; ++ goto endFalling; + } + + /* Phase 3: precalculation */ +@@ -1826,8 +1565,7 @@ no_merge: + y_steps = fixed2int(y_steps); + assert(y_steps >= 0); + if (y_steps) { +- cursor_always_step(cr, -fixed_1, sx, skip); +- skip = 0; ++ cursor_always_step(cr, -fixed_1, sx); + y_steps--; + while (y_steps) { + cursor_always_step_inrange_vertical(cr, -fixed_1, sx); +@@ -1836,12 +1574,8 @@ no_merge: + } + + /* Phase 3 */ +- if (phase3_y_steps == 0) { +-endFallingLeftOnEdgeOfPixel: +- cursor_always_step_inrange_vertical(cr, 0, sx); +- cursor_null(cr); +- } else { +- cursor_step(cr, -phase3_y_steps, sx, skip); ++ if (phase3_y_steps > 0) { ++ cursor_step(cr, -phase3_y_steps, sx); + assert(cr->left == sx && cr->right == sx); + } + } else if (sx < ex) { +@@ -1850,6 +1584,7 @@ endFallingLeftOnEdgeOfPixel: + fixed x_steps = ex - sx; + + /* Phase 1: */ ++ cursor_left_merge(cr, sx); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + x_steps -= phase1_x_steps; +@@ -1859,8 +1594,9 @@ endFallingLeftOnEdgeOfPixel: + sy -= phase1_y_steps; + y_steps -= phase1_y_steps; + if (y_steps == 0) +- goto endFallingRightOnEdgeOfPixel; +- } ++ goto endFalling; ++ } else ++ cursor_right_merge(cr, sx); + + /* Phase 3: precalculation */ + phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); +@@ -1879,8 +1615,7 @@ endFallingLeftOnEdgeOfPixel: + int f = y_steps/2; + int d = y_steps; + +- cursor_always_step(cr, -fixed_1, sx, skip); +- skip = 0; ++ cursor_always_step(cr, -fixed_1, sx); + sx += x_inc; + f -= n_inc; + if (f < 0) +@@ -1900,12 +1635,8 @@ endFallingLeftOnEdgeOfPixel: + } + + /* Phase 3 */ +- if (phase3_y_steps == 0) { +-endFallingRightOnEdgeOfPixel: +- cursor_always_step_inrange_vertical(cr, 0, sx); +- cursor_null(cr); +- } else { +- cursor_step(cr, -phase3_y_steps, sx, skip); ++ if (phase3_y_steps > 0) { ++ cursor_step(cr, -phase3_y_steps, sx); + cursor_right(cr, ex); + assert(cr->left == sx && cr->right == ex); + } +@@ -1915,6 +1646,7 @@ endFallingRightOnEdgeOfPixel: + fixed x_steps = sx - ex; + + /* Phase 1: */ ++ cursor_right_merge(cr, sx); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + x_steps -= phase1_x_steps; +@@ -1924,8 +1656,9 @@ endFallingRightOnEdgeOfPixel: + sy -= phase1_y_steps; + y_steps -= phase1_y_steps; + if (y_steps == 0) +- goto endFallingVerticalOnEdgeOfPixel; +- } ++ goto endFalling; ++ } else ++ cursor_left_merge(cr, sx); + + /* Phase 3: precalculation */ + phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); +@@ -1944,8 +1677,7 @@ endFallingRightOnEdgeOfPixel: + int f = y_steps/2; + int d = y_steps; + +- cursor_always_step(cr, -fixed_1, sx, skip); +- skip = 0; ++ cursor_always_step(cr, -fixed_1, sx); + sx -= x_inc; + f -= n_inc; + if (f < 0) +@@ -1965,17 +1697,15 @@ endFallingRightOnEdgeOfPixel: + } + + /* Phase 3 */ +- if (phase3_y_steps == 0) { +-endFallingVerticalOnEdgeOfPixel: +- cursor_always_step_inrange_vertical(cr, 0, sx); +- cursor_null(cr); +- } else { +- cursor_step(cr, -phase3_y_steps, sx, skip); ++ if (phase3_y_steps > 0) { ++ cursor_step(cr, -phase3_y_steps, sx); + cursor_left(cr, ex); + assert(cr->left == ex && cr->right == sx); + } + } +-endFalling: {} ++endFalling: ++ if (truncated) ++ cursor_output(cr, fixed2int(cr->y) - cr->base); + } + + end: +@@ -2011,24 +1741,24 @@ static void mark_curve_app(cursor *cr, fixed sx, fixed sy, fixed c1x, fixed c1y, + } + } + +-static void mark_curve_big_app(cursor *cr, fixed64 sx, fixed64 sy, fixed64 c1x, fixed64 c1y, fixed64 c2x, fixed64 c2y, fixed64 ex, fixed64 ey, int depth) ++static void mark_curve_big_app(cursor *cr, fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, int depth) + { +- fixed64 ax = (sx + c1x)>>1; +- fixed64 ay = (sy + c1y)>>1; +- fixed64 bx = (c1x + c2x)>>1; +- fixed64 by = (c1y + c2y)>>1; +- fixed64 cx = (c2x + ex)>>1; +- fixed64 cy = (c2y + ey)>>1; +- fixed64 dx = (ax + bx)>>1; +- fixed64 dy = (ay + by)>>1; +- fixed64 fx = (bx + cx)>>1; +- fixed64 fy = (by + cy)>>1; +- fixed64 gx = (dx + fx)>>1; +- fixed64 gy = (dy + fy)>>1; ++ fixed ax = (sx>>1) + (c1x>>1); ++ fixed ay = (sy>>1) + (c1y>>1); ++ fixed bx = (c1x>>1) + (c2x>>1); ++ fixed by = (c1y>>1) + (c2y>>1); ++ fixed cx = (c2x>>1) + (ex>>1); ++ fixed cy = (c2y>>1) + (ey>>1); ++ fixed dx = (ax>>1) + (bx>>1); ++ fixed dy = (ay>>1) + (by>>1); ++ fixed fx = (bx>>1) + (cx>>1); ++ fixed fy = (by>>1) + (cy>>1); ++ fixed gx = (dx>>1) + (fx>>1); ++ fixed gy = (dy>>1) + (fy>>1); + + assert(depth >= 0); + if (depth == 0) +- mark_line_app(cr, (fixed)sx, (fixed)sy, (fixed)ex, (fixed)ey); ++ mark_line_app(cr, sx, sy, ex, ey); + else { + depth--; + mark_curve_big_app(cr, sx, sy, ax, ay, dx, dy, gx, gy, depth); +@@ -2048,7 +1778,7 @@ static void mark_curve_top_app(cursor *cr, fixed sx, fixed sy, fixed c1x, fixed + + static int make_table_app(gx_device * pdev, + gx_path * path, +- gs_fixed_rect * ibox, ++ const gs_fixed_rect * ibox, + int * scanlines, + int ** index, + int ** table) +@@ -2056,24 +1786,13 @@ static int make_table_app(gx_device * pdev, + return make_table_template(pdev, path, ibox, 2, 0, scanlines, index, table); + } + +-static void +-fill_zero_app(int *row, const fixed *x) +-{ +- int n = *row = (*row)+2; /* Increment the count */ +- row[2*n-3] = (x[0]&~1); +- row[2*n-2] = (x[1]&~1); +- row[2*n-1] = (x[1]&~1)|1; +- row[2*n ] = x[1]; +-} +- +-int gx_scan_convert_app(gx_device * gs_restrict pdev, +- gx_path * gs_restrict path, +- const gs_fixed_rect * gs_restrict clip, +- gx_edgebuffer * gs_restrict edgebuffer, ++int gx_scan_convert_app(gx_device * restrict pdev, ++ gx_path * restrict path, ++ const gs_fixed_rect * restrict clip, ++ gx_edgebuffer * restrict edgebuffer, + fixed fixed_flat) + { + gs_fixed_rect ibox; +- gs_fixed_rect bbox; + int scanlines; + const subpath *psub; + int *index; +@@ -2081,7 +1800,6 @@ int gx_scan_convert_app(gx_device * gs_restrict pdev, + int i; + cursor cr; + int code; +- int zero; + + edgebuffer->index = NULL; + edgebuffer->table = NULL; +@@ -2090,24 +1808,17 @@ int gx_scan_convert_app(gx_device * gs_restrict pdev, + if (path->first_subpath == NULL) + return 0; + +- zero = make_bbox(path, clip, &bbox, &ibox, 0); +- if (zero < 0) +- return zero; ++ code = make_bbox(path, clip, &ibox, 0); ++ if (code < 0) ++ return code; + + if (ibox.q.y <= ibox.p.y) + return 0; + + code = make_table_app(pdev, path, &ibox, &scanlines, &index, &table); +- if (code != 0) /* > 0 means "retry with smaller height" */ ++ if (code < 0) + return code; + +- if (scanlines == 0) +- return 0; +- +- if (zero) { +- code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero_app); +- } else { +- + /* Step 2 continued: Now we run through the path, filling in the real + * values. */ + cr.scanlines = scanlines; +@@ -2122,12 +1833,7 @@ int gx_scan_convert_app(gx_device * gs_restrict pdev, + fixed iy = ey; + fixed sx, sy; + +- if ((ey & 0xff) == 0) { +- cr.left = max_fixed; +- cr.right = min_fixed; +- } else { +- cr.left = cr.right = ex; +- } ++ cr.left = cr.right = ex; + cr.y = ey; + cr.d = DIRN_UNSET; + cr.first = 1; +@@ -2166,7 +1872,6 @@ int gx_scan_convert_app(gx_device * gs_restrict pdev, + cursor_flush(&cr, ex); + psub = (const subpath *)pseg; + } +- } + + /* Step 2 complete: We now have a complete list of intersection data in + * table, indexed by index. */ +@@ -2195,9 +1900,9 @@ int gx_scan_convert_app(gx_device * gs_restrict pdev, + if (rowlen <= 6) { + int j, k; + for (j = 0; j < rowlen-1; j++) { +- int * gs_restrict t = &row[j<<1]; ++ int * restrict t = &row[j<<1]; + for (k = j+1; k < rowlen; k++) { +- int * gs_restrict s = &row[k<<1]; ++ int * restrict s = &row[k<<1]; + int tmp; + if (t[0] < s[0]) + continue; +@@ -2221,8 +1926,8 @@ swap01: + + /* Step 5: Filter the intersections according to the rules */ + int +-gx_filter_edgebuffer_app(gx_device * gs_restrict pdev, +- gx_edgebuffer * gs_restrict edgebuffer, ++gx_filter_edgebuffer_app(gx_device * restrict pdev, ++ gx_edgebuffer * restrict edgebuffer, + int rule) + { + int i; +@@ -2242,7 +1947,7 @@ gx_filter_edgebuffer_app(gx_device * gs_restrict pdev, + int ll, lr, rl, rr, wind, marked_to; + + /* Avoid double setting pixels, by keeping where we have marked to. */ +- marked_to = INT_MIN; ++ marked_to = 0; + while (rowlen > 0) { + if (rule == gx_rule_even_odd) { + /* Even Odd */ +@@ -2293,7 +1998,7 @@ gx_filter_edgebuffer_app(gx_device * gs_restrict pdev, + } + } + +- if (lr >= ll) { ++ if (lr > ll) { + *rowout++ = ll; + *rowout++ = lr; + marked_to = lr; +@@ -2306,9 +2011,9 @@ gx_filter_edgebuffer_app(gx_device * gs_restrict pdev, + + /* Step 6: Fill */ + int +-gx_fill_edgebuffer_app(gx_device * gs_restrict pdev, +- const gx_device_color * gs_restrict pdevc, +- gx_edgebuffer * gs_restrict edgebuffer, ++gx_fill_edgebuffer_app(gx_device * restrict pdev, ++ const gx_device_color * restrict pdevc, ++ gx_edgebuffer * restrict edgebuffer, + int log_op) + { + int i, code; +@@ -2380,7 +2085,7 @@ gx_edgebuffer_print_tr(gx_edgebuffer * edgebuffer) + + static void mark_line_tr(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int height, int *table, int *index, int id) + { +- int64_t delta; ++ int delta; + int iy, ih; + fixed clip_sy, clip_ey; + int dirn = DIRN_UP; +@@ -2420,26 +2125,25 @@ static void mark_line_tr(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int + clip_ey = int2fixed(base_y + height - 1) + fixed_half; + if (sy > clip_ey) + return; +- delta = (int64_t)clip_sy - (int64_t)sy; ++ delta = clip_sy - sy; + if (delta > 0) + { +- int64_t dx = (int64_t)ex - (int64_t)sx; +- int64_t dy = (int64_t)ey - (int64_t)sy; +- int advance = (int)((dx * delta + (dy>>1)) / dy); ++ int dx = ex - sx; ++ int dy = ey - sy; ++ int advance = (int)(((int64_t)dx * delta + (dy>>1)) / dy); + sx += advance; + sy += delta; + } +- delta = (int64_t)ey - (int64_t)clip_ey; ++ ex -= sx; ++ ey -= sy; ++ clip_ey -= clip_sy; ++ delta = ey - clip_ey; + if (delta > 0) + { +- int64_t dx = (int64_t)ex - (int64_t)sx; +- int64_t dy = (int64_t)ey - (int64_t)sy; +- int advance = (int)((dx * delta + (dy>>1)) / dy); ++ int advance = (int)(((int64_t)ex * delta + (ey>>1)) / ey); + ex -= advance; + ey -= delta; + } +- ex -= sx; +- ey -= sy; + ih = fixed2int(ey); + assert(ih >= 0); + iy = fixed2int(sy) - base_y; +@@ -2538,25 +2242,25 @@ static void mark_curve_tr(fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, f + } + } + +-static void mark_curve_big_tr(fixed64 sx, fixed64 sy, fixed64 c1x, fixed64 c1y, fixed64 c2x, fixed64 c2y, fixed64 ex, fixed64 ey, fixed base_y, fixed height, int *table, int *index, int *id, int depth) ++static void mark_curve_big_tr(fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, fixed base_y, fixed height, int *table, int *index, int *id, int depth) + { +- fixed64 ax = (sx + c1x)>>1; +- fixed64 ay = (sy + c1y)>>1; +- fixed64 bx = (c1x + c2x)>>1; +- fixed64 by = (c1y + c2y)>>1; +- fixed64 cx = (c2x + ex)>>1; +- fixed64 cy = (c2y + ey)>>1; +- fixed64 dx = (ax + bx)>>1; +- fixed64 dy = (ay + by)>>1; +- fixed64 fx = (bx + cx)>>1; +- fixed64 fy = (by + cy)>>1; +- fixed64 gx = (dx + fx)>>1; +- fixed64 gy = (dy + fy)>>1; ++ fixed ax = (sx>>1) + (c1x>>1); ++ fixed ay = (sy>>1) + (c1y>>1); ++ fixed bx = (c1x>>1) + (c2x>>1); ++ fixed by = (c1y>>1) + (c2y>>1); ++ fixed cx = (c2x>>1) + (ex>>1); ++ fixed cy = (c2y>>1) + (ey>>1); ++ fixed dx = (ax>>1) + (bx>>1); ++ fixed dy = (ay>>1) + (by>>1); ++ fixed fx = (bx>>1) + (cx>>1); ++ fixed fy = (by>>1) + (cy>>1); ++ fixed gx = (dx>>1) + (fx>>1); ++ fixed gy = (dy>>1) + (fy>>1); + + assert(depth >= 0); + if (depth == 0) { + *id += 1; +- mark_line_tr((fixed)sx, (fixed)sy, (fixed)ex, (fixed)ey, base_y, height, table, index, *id); ++ mark_line_tr(sx, sy, ex, ey, base_y, height, table, index, *id); + } else { + depth--; + mark_curve_big_tr(sx, sy, ax, ay, dx, dy, gx, gy, base_y, height, table, index, id, depth); +@@ -2576,32 +2280,21 @@ static void mark_curve_top_tr(fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2 + + static int make_table_tr(gx_device * pdev, + gx_path * path, +- gs_fixed_rect * ibox, ++ const gs_fixed_rect * ibox, + int * scanlines, + int ** index, + int ** table) + { +- return make_table_template(pdev, path, ibox, 2, 1, scanlines, index, table); +-} +- +-static void +-fill_zero_tr(int *row, const fixed *x) +-{ +- int n = *row = (*row)+2; /* Increment the count */ +- row[2*n-3] = x[0]; +- row[2*n-2] = 0; +- row[2*n-1] = x[1]; +- row[2*n ] = 1; ++ return make_table_template(pdev, path, ibox, 2, fixed_half-1, scanlines, index, table); + } + +-int gx_scan_convert_tr(gx_device * gs_restrict pdev, +- gx_path * gs_restrict path, +- const gs_fixed_rect * gs_restrict clip, +- gx_edgebuffer * gs_restrict edgebuffer, ++int gx_scan_convert_tr(gx_device * restrict pdev, ++ gx_path * restrict path, ++ const gs_fixed_rect * restrict clip, ++ gx_edgebuffer * restrict edgebuffer, + fixed fixed_flat) + { + gs_fixed_rect ibox; +- gs_fixed_rect bbox; + int scanlines; + const subpath *psub; + int *index; +@@ -2609,7 +2302,6 @@ int gx_scan_convert_tr(gx_device * gs_restrict pdev, + int i; + int code; + int id = 0; +- int zero; + + edgebuffer->index = NULL; + edgebuffer->table = NULL; +@@ -2618,24 +2310,17 @@ int gx_scan_convert_tr(gx_device * gs_restrict pdev, + if (path->first_subpath == NULL) + return 0; + +- zero = make_bbox(path, clip, &bbox, &ibox, fixed_half); +- if (zero < 0) +- return zero; ++ code = make_bbox(path, clip, &ibox, fixed_half); ++ if (code < 0) ++ return code; + + if (ibox.q.y <= ibox.p.y) + return 0; + + code = make_table_tr(pdev, path, &ibox, &scanlines, &index, &table); +- if (code != 0) /* > 0 means "retry with smaller height" */ ++ if (code < 0) + return code; + +- if (scanlines == 0) +- return 0; +- +- if (zero) { +- code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero_tr); +- } else { +- + /* Step 3: Now we run through the path, filling in the real + * values. */ + for (psub = path->first_subpath; psub != 0;) { +@@ -2679,18 +2364,6 @@ int gx_scan_convert_tr(gx_device * gs_restrict pdev, + mark_line_tr(ex, ey, ix, iy, ibox.p.y, scanlines, table, index, ++id); + psub = (const subpath *)pseg; + } +- } +- +- //if (zero) { +- // if (table[0] == 0) { +- // /* Zero height rectangle fills a span */ +- // table[0] = 2; +- // table[1] = int2fixed(fixed2int(bbox.p.x + fixed_half)); +- // table[2] = 0; +- // table[3] = int2fixed(fixed2int(bbox.q.x + fixed_half)); +- // table[4] = 1; +- // } +- //} + + /* Step 2 complete: We now have a complete list of intersection data in + * table, indexed by index. */ +@@ -2719,9 +2392,9 @@ int gx_scan_convert_tr(gx_device * gs_restrict pdev, + if (rowlen <= 6) { + int j, k; + for (j = 0; j < rowlen-1; j++) { +- int * gs_restrict t = &row[j<<1]; ++ int * restrict t = &row[j<<1]; + for (k = j+1; k < rowlen; k++) { +- int * gs_restrict s = &row[k<<1]; ++ int * restrict s = &row[k<<1]; + int tmp; + if (t[0] < s[0]) + continue; +@@ -2742,9 +2415,9 @@ int gx_scan_convert_tr(gx_device * gs_restrict pdev, + + /* Step 5: Filter the intersections according to the rules */ + int +-gx_filter_edgebuffer_tr(gx_device * gs_restrict pdev, +- gx_edgebuffer * gs_restrict edgebuffer, +- int rule) ++gx_filter_edgebuffer_tr(gx_device * restrict pdev, ++ gx_edgebuffer * restrict edgebuffer, ++ int rule) + { + int i; + +@@ -2801,13 +2474,12 @@ gx_filter_edgebuffer_tr(gx_device * gs_restrict pdev, + + /* Step 6: Fill the edgebuffer */ + int +-gx_fill_edgebuffer_tr(gx_device * gs_restrict pdev, +- const gx_device_color * gs_restrict pdevc, +- gx_edgebuffer * gs_restrict edgebuffer, ++gx_fill_edgebuffer_tr(gx_device * restrict pdev, ++ const gx_device_color * restrict pdevc, ++ gx_edgebuffer * restrict edgebuffer, + int log_op) + { + int i, j, code; +- int mfb = pdev->max_fill_band; + + #ifdef DEBUG_SCAN_CONVERTER + if (debugging_scan_converter) { +@@ -2822,18 +2494,9 @@ gx_fill_edgebuffer_tr(gx_device * gs_restrict pdev, + int *row2; + int *rowptr; + int *row2ptr; +- int y_band_max; +- +- if (mfb) { +- y_band_max = (i & ~(mfb-1)) + mfb; +- if (y_band_max > edgebuffer->height) +- y_band_max = edgebuffer->height; +- } else { +- y_band_max = edgebuffer->height; +- } + + /* See how many scanlines match i */ +- for (j = i+1; j < y_band_max; j++) { ++ for (j = i+1; j < edgebuffer->height; j++) { + int row2len; + + row2 = &edgebuffer->table[edgebuffer->index[j]]; +@@ -2931,6 +2594,8 @@ rowdifferent:{} + row2 += 4; + rowlen -= 2; + ++ assert(le.start.x >= 0); ++ assert(le.end.x >= 0); + assert(re.start.x >= le.start.x); + assert(re.end.x >= le.end.x); + +@@ -3074,7 +2739,7 @@ typedef struct + } cursor_tr; + + static inline void +-cursor_output_tr(cursor_tr * gs_restrict cr, int iy) ++cursor_output_tr(cursor_tr * restrict cr, int iy) + { + int *row; + int count; +@@ -3089,23 +2754,23 @@ cursor_output_tr(cursor_tr * gs_restrict cr, int iy) + cr->save_iy = iy; + cr->save_d = cr->d; + cr->saved = 1; +- } else if (cr->d != DIRN_UNSET) { ++ } else { + /* Enter it into the table */ ++ assert(cr->d != DIRN_UNSET); ++ + row = &cr->table[cr->index[iy]]; + *row = count = (*row)+1; /* Increment the count */ + row[4 * count - 3] = cr->left; + row[4 * count - 2] = cr->d | (cr->lid<<1); + row[4 * count - 1] = cr->right; + row[4 * count ] = cr->rid; +- } else { +- assert(cr->left == max_fixed && cr->right == min_fixed); + } + } + cr->first = 0; + } + + static inline void +-cursor_output_inrange_tr(cursor_tr * gs_restrict cr, int iy) ++cursor_output_inrange_tr(cursor_tr * restrict cr, int iy) + { + int *row; + int count; +@@ -3136,7 +2801,7 @@ cursor_output_inrange_tr(cursor_tr * gs_restrict cr, int iy) + + /* Step the cursor in y, allowing for maybe crossing a scanline */ + static inline void +-cursor_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id, int skip) ++cursor_step_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + int new_iy; + int iy = fixed2int(cr->y) - cr->base; +@@ -3144,18 +2809,19 @@ cursor_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id, int skip) + cr->y += dy; + new_iy = fixed2int(cr->y) - cr->base; + if (new_iy != iy) { +- if (!skip) +- cursor_output_tr(cr, iy); ++ cursor_output_tr(cr, iy); + cr->left = x; + cr->lid = id; + cr->right = x; + cr->rid = id; + } else { +- if (x < cr->left) { ++ if (x < cr->left) ++ { + cr->left = x; + cr->lid = id; + } +- if (x > cr->right) { ++ if (x > cr->right) ++ { + cr->right = x; + cr->rid = id; + } +@@ -3164,7 +2830,7 @@ cursor_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id, int skip) + + /* Step the cursor in y, never by enough to cross a scanline. */ + static inline void +-cursor_never_step_vertical_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) ++cursor_never_step_vertical_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); + +@@ -3175,7 +2841,7 @@ cursor_never_step_vertical_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int + * knowing that we are moving left, and that the right edge + * has already been accounted for. */ + static inline void +-cursor_never_step_left_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) ++cursor_never_step_left_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); + +@@ -3191,7 +2857,7 @@ cursor_never_step_left_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) + * knowing that we are moving right, and that the left edge + * has already been accounted for. */ + static inline void +-cursor_never_step_right_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) ++cursor_never_step_right_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + assert(fixed2int(cr->y+dy) == fixed2int(cr->y)); + +@@ -3205,12 +2871,11 @@ cursor_never_step_right_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id + + /* Step the cursor in y, always by enough to cross a scanline. */ + static inline void +-cursor_always_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id, int skip) ++cursor_always_step_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + int iy = fixed2int(cr->y) - cr->base; + +- if (!skip) +- cursor_output_tr(cr, iy); ++ cursor_output_tr(cr, iy); + cr->y += dy; + cr->left = x; + cr->lid = id; +@@ -3222,7 +2887,7 @@ cursor_always_step_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id, int + * part of a vertical line, knowing that we are moving from a + * position guaranteed to be in the valid y range. */ + static inline void +-cursor_always_step_inrange_vertical_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) ++cursor_always_step_inrange_vertical_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + int iy = fixed2int(cr->y) - cr->base; + +@@ -3234,7 +2899,7 @@ cursor_always_step_inrange_vertical_tr(cursor_tr * gs_restrict cr, fixed dy, fix + * part of a left moving line, knowing that we are moving from a + * position guaranteed to be in the valid y range. */ + static inline void +-cursor_always_inrange_step_left_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) ++cursor_always_inrange_step_left_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + int iy = fixed2int(cr->y) - cr->base; + +@@ -3248,7 +2913,7 @@ cursor_always_inrange_step_left_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x + * part of a right moving line, knowing that we are moving from a + * position guaranteed to be in the valid y range. */ + static inline void +-cursor_always_inrange_step_right_tr(cursor_tr * gs_restrict cr, fixed dy, fixed x, int id) ++cursor_always_inrange_step_right_tr(cursor_tr * restrict cr, fixed dy, fixed x, int id) + { + int iy = fixed2int(cr->y) - cr->base; + +@@ -3258,7 +2923,7 @@ cursor_always_inrange_step_right_tr(cursor_tr * gs_restrict cr, fixed dy, fixed + cr->lid = id; + } + +-static inline void cursor_init_tr(cursor_tr * gs_restrict cr, fixed y, fixed x, int id) ++static inline void cursor_init_tr(cursor_tr * restrict cr, fixed y, fixed x, int id) + { + assert(y >= int2fixed(cr->base) && y <= int2fixed(cr->base + cr->scanlines)); + +@@ -3270,7 +2935,7 @@ static inline void cursor_init_tr(cursor_tr * gs_restrict cr, fixed y, fixed x, + cr->d = DIRN_UNSET; + } + +-static inline void cursor_left_merge_tr(cursor_tr * gs_restrict cr, fixed x, int id) ++static inline void cursor_left_merge_tr(cursor_tr * restrict cr, fixed x, int id) + { + if (x < cr->left) { + cr->left = x; +@@ -3278,13 +2943,13 @@ static inline void cursor_left_merge_tr(cursor_tr * gs_restrict cr, fixed x, int + } + } + +-static inline void cursor_left_tr(cursor_tr * gs_restrict cr, fixed x, int id) ++static inline void cursor_left_tr(cursor_tr * restrict cr, fixed x, int id) + { + cr->left = x; + cr->lid = id; + } + +-static inline void cursor_right_merge_tr(cursor_tr * gs_restrict cr, fixed x, int id) ++static inline void cursor_right_merge_tr(cursor_tr * restrict cr, fixed x, int id) + { + if (x > cr->right) { + cr->right = x; +@@ -3292,31 +2957,26 @@ static inline void cursor_right_merge_tr(cursor_tr * gs_restrict cr, fixed x, in + } + } + +-static inline void cursor_right_tr(cursor_tr * gs_restrict cr, fixed x, int id) ++static inline void cursor_right_tr(cursor_tr * restrict cr, fixed x, int id) + { + cr->right = x; + cr->rid = id; + } + +-static inline int cursor_down_tr(cursor_tr * gs_restrict cr, fixed x, int id) ++static inline void cursor_down_tr(cursor_tr * restrict cr, fixed x, int id) + { +- int skip = 0; +- if ((cr->y & 0xff) == 0) +- skip = 1; + if (cr->d == DIRN_UP) + { +- if (!skip) +- cursor_output_tr(cr, fixed2int(cr->y) - cr->base); ++ cursor_output_tr(cr, fixed2int(cr->y) - cr->base); + cr->left = x; + cr->lid = id; + cr->right = x; + cr->rid = id; + } + cr->d = DIRN_DOWN; +- return skip; + } + +-static inline void cursor_up_tr(cursor_tr * gs_restrict cr, fixed x, int id) ++static inline void cursor_up_tr(cursor_tr * restrict cr, fixed x, int id) + { + if (cr->d == DIRN_DOWN) + { +@@ -3330,7 +2990,7 @@ static inline void cursor_up_tr(cursor_tr * gs_restrict cr, fixed x, int id) + } + + static inline void +-cursor_flush_tr(cursor_tr * gs_restrict cr, fixed x, int id) ++cursor_flush_tr(cursor_tr * restrict cr, fixed x, int id) + { + int iy; + +@@ -3339,11 +2999,6 @@ cursor_flush_tr(cursor_tr * gs_restrict cr, fixed x, int id) + * rectangle from the start point. */ + if (cr->first) { + int iy = fixed2int(cr->y) - cr->base; +- /* Any zero height rectangle counts as filled, except +- * those on the baseline of a pixel. */ +- if (cr->d == DIRN_UNSET && (cr->y & 0xff) == 0) +- return; +- assert(cr->left != max_fixed && cr->right != min_fixed); + if (iy >= 0 && iy < cr->scanlines) { + int *row = &cr->table[cr->index[iy]]; + int count = *row = (*row)+2; /* Increment the count */ +@@ -3389,23 +3044,16 @@ cursor_flush_tr(cursor_tr * gs_restrict cr, fixed x, int id) + } + } + +-static inline void +-cursor_null_tr(cursor_tr *cr) +-{ +- cr->right = min_fixed; +- cr->left = max_fixed; +- cr->d = DIRN_UNSET; +-} +- +-static void mark_line_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fixed ex, fixed ey, int id) ++static void mark_line_tr_app(cursor_tr * restrict cr, fixed sx, fixed sy, fixed ex, fixed ey, int id) + { + int isy, iey; ++ fixed y_steps; + fixed saved_sy = sy; + fixed saved_ex = ex; + fixed saved_ey = ey; + int truncated; + +- if (sy == ey && sx == ex) ++ if (sx == ex && sy == ey) + return; + + isy = fixed2int(sy) - cr->base; +@@ -3422,50 +3070,39 @@ static void mark_line_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fix + dlprintf("stroke %%PS\n"); + #endif + +- /* Horizontal motion at the bottom of a pixel is ignored */ +- if (sy == ey && (sy & 0xff) == 0) +- return; +- +- assert(cr->y == sy && +- ((cr->left <= sx && cr->right >= sx) || ((sy & 0xff) == 0)) && +- cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); ++ assert(cr->y == sy && cr->left <= sx && cr->right >= sx && cr->d >= DIRN_UNSET && cr->d <= DIRN_DOWN); + + if (isy < iey) { + /* Rising line */ + if (iey < 0 || isy >= cr->scanlines) { + /* All line is outside. */ +- if ((ey & 0xff) == 0) { +- cursor_null_tr(cr); +- } else { +- cr->left = ex; +- cr->lid = id; +- cr->right = ex; +- cr->rid = id; +- } + cr->y = ey; ++ cr->left = ex; ++ cr->lid = id; ++ cr->right = ex; ++ cr->rid = id; + cr->first = 0; + return; + } + if (isy < 0) { + /* Move sy up */ +- int64_t y = (int64_t)ey - (int64_t)sy; +- fixed new_sy = int2fixed(cr->base); +- int64_t dy = (int64_t)new_sy - (int64_t)sy; +- sx += (int)(((((int64_t)ex-sx))*dy + y/2)/y); ++ int y = ey - sy; ++ int new_sy = int2fixed(cr->base); ++ int dy = new_sy - sy; ++ sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; +- cursor_null_tr(cr); +- cr->y = sy; ++ cursor_init_tr(cr, sy, sx, id); + isy = 0; + } + truncated = iey > cr->scanlines; + if (truncated) { + /* Move ey down */ +- int64_t y = (int64_t)ey - (int64_t)sy; +- fixed new_ey = int2fixed(cr->base + cr->scanlines); +- int64_t dy = (int64_t)ey - (int64_t)new_ey; ++ int y = ey - sy; ++ int new_ey = int2fixed(cr->base + cr->scanlines); ++ int dy = ey - new_ey; + saved_ex = ex; + saved_ey = ey; +- ex -= (int)(((((int64_t)ex-sx))*dy + y/2)/y); ++ ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); + ey = new_ey; + iey = cr->scanlines; + } +@@ -3473,44 +3110,36 @@ static void mark_line_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fix + /* Falling line */ + if (isy < 0 || iey >= cr->scanlines) { + /* All line is outside. */ +- if ((ey & 0xff) == 0) { +- cursor_null_tr(cr); +- } else { +- cr->left = ex; +- cr->lid = id; +- cr->right = ex; +- cr->rid = id; +- } + cr->y = ey; ++ cr->left = ex; ++ cr->lid = id; ++ cr->right = ex; ++ cr->rid = id; + cr->first = 0; + return; + } + truncated = iey < 0; + if (truncated) { + /* Move ey up */ +- int64_t y = (int64_t)ey - (int64_t)sy; +- fixed new_ey = int2fixed(cr->base); +- int64_t dy = (int64_t)ey - (int64_t)new_ey; +- ex -= (int)(((((int64_t)ex-sx))*dy + y/2)/y); ++ int y = ey - sy; ++ int new_ey = int2fixed(cr->base); ++ int dy = ey - new_ey; ++ ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); + ey = new_ey; + iey = 0; + } + if (isy >= cr->scanlines) { + /* Move sy down */ +- int64_t y = (int64_t)ey - (int64_t)sy; +- fixed new_sy = int2fixed(cr->base + cr->scanlines); +- int64_t dy = (int64_t)new_sy - (int64_t)sy; +- sx += (int)(((((int64_t)ex-sx))*dy + y/2)/y); ++ int y = ey - sy; ++ int new_sy = int2fixed(cr->base + cr->scanlines); ++ int dy = new_sy - sy; ++ sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; +- cursor_null_tr(cr); +- cr->y = sy; ++ cursor_init_tr(cr, sy, sx, id); + isy = cr->scanlines; + } + } + +- cursor_left_merge_tr(cr, sx, id); +- cursor_right_merge_tr(cr, sx, id); +- + assert(cr->left <= sx); + assert(cr->right >= sx); + assert(cr->y == sy); +@@ -3538,44 +3167,24 @@ static void mark_line_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fix + if (isy == iey) { + if (saved_sy == saved_ey) { + /* Horizontal line. Don't change cr->d, don't flush. */ +- if ((ey & 0xff) == 0) { +- cursor_null_tr(cr); +- goto no_merge; +- } + } else if (saved_sy > saved_ey) { + /* Falling line, flush if previous was rising */ +- int skip = cursor_down_tr(cr, sx, id); +- if ((ey & 0xff) == 0) { +- /* We are falling to the baseline of a subpixel, so output +- * for the current pixel, and leave the cursor nulled. */ +- if (sx <= ex) { +- cursor_right_merge_tr(cr, ex, id); +- } else { +- cursor_left_merge_tr(cr, ex, id); +- } +- if (!skip) +- cursor_output_tr(cr, fixed2int(cr->y) - cr->base); +- cursor_null_tr(cr); +- goto no_merge; +- } ++ cursor_down_tr(cr, sx, id); + } else { + /* Rising line, flush if previous was falling */ + cursor_up_tr(cr, sx, id); +- if ((ey & 0xff) == 0) { +- cursor_null_tr(cr); +- goto no_merge; +- } + } + if (sx <= ex) { ++ cursor_left_merge_tr(cr, sx, id); + cursor_right_merge_tr(cr, ex, id); + } else { + cursor_left_merge_tr(cr, ex, id); ++ cursor_right_merge_tr(cr, sx, id); + } +-no_merge: + cr->y = ey; + if (sy > saved_ey) + goto endFalling; +- } else if (iey > isy) { ++ } else if ((y_steps = ey - sy) > 0) { + /* So lines increasing in y. */ + /* We want to change from sy to ey, which are guaranteed to be on + * different scanlines. We do this in 3 phases. +@@ -3585,7 +3194,6 @@ no_merge: + */ + int phase1_y_steps = (-sy) & (fixed_1 - 1); + int phase3_y_steps = ey & (fixed_1 - 1); +- ufixed y_steps = (ufixed)ey - (ufixed)sy; + + cursor_up_tr(cr, sx, id); + +@@ -3593,16 +3201,16 @@ no_merge: + /* Vertical line. (Rising) */ + + /* Phase 1: */ ++ cursor_left_merge_tr(cr, sx, id); ++ cursor_right_merge_tr(cr, sx, id); + if (phase1_y_steps) { + /* If phase 1 will move us into a new scanline, then we must + * flush it before we move. */ +- cursor_step_tr(cr, phase1_y_steps, sx, id, 0); ++ cursor_step_tr(cr, phase1_y_steps, sx, id); + sy += phase1_y_steps; + y_steps -= phase1_y_steps; +- if (y_steps == 0) { +- cursor_null_tr(cr); ++ if (y_steps == 0) + goto end; +- } + } + + /* Phase 3: precalculation */ +@@ -3612,7 +3220,7 @@ no_merge: + y_steps = fixed2int(y_steps); + assert(y_steps >= 0); + if (y_steps > 0) { +- cursor_always_step_tr(cr, fixed_1, sx, id, 0); ++ cursor_always_step_tr(cr, fixed_1, sx, id); + y_steps--; + while (y_steps) { + cursor_always_step_inrange_vertical_tr(cr, fixed_1, sx, id); +@@ -3622,30 +3230,24 @@ no_merge: + + /* Phase 3 */ + assert(cr->left == sx && cr->right == sx && cr->lid == id && cr->rid == id); +- if (phase3_y_steps == 0) +- cursor_null_tr(cr); +- else +- cr->y += phase3_y_steps; ++ cr->y += phase3_y_steps; + } else if (sx < ex) { + /* Lines increasing in x. (Rightwards, rising) */ + int phase1_x_steps, phase3_x_steps; +- /* Use unsigned int here, to allow for extreme cases like +- * ex = 0x7fffffff, sx = 0x80000000 */ +- unsigned int x_steps = ex - sx; ++ fixed x_steps = ex - sx; + + /* Phase 1: */ ++ cursor_left_merge_tr(cr, sx, id); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + sx += phase1_x_steps; + cursor_right_merge_tr(cr, sx, id); + x_steps -= phase1_x_steps; +- cursor_step_tr(cr, phase1_y_steps, sx, id, 0); ++ cursor_step_tr(cr, phase1_y_steps, sx, id); + sy += phase1_y_steps; + y_steps -= phase1_y_steps; +- if (y_steps == 0) { +- cursor_null_tr(cr); ++ if (y_steps == 0) + goto end; +- } + } + + /* Phase 3: precalculation */ +@@ -3672,7 +3274,7 @@ no_merge: + if (f < 0) + f += d, sx++; + cursor_right_merge_tr(cr, sx, id); +- cursor_always_step_tr(cr, fixed_1, sx, id, 0); ++ cursor_always_step_tr(cr, fixed_1, sx, id); + y_steps--; + + while (y_steps) { +@@ -3688,32 +3290,25 @@ no_merge: + + /* Phase 3 */ + assert(cr->left <= ex && cr->lid == id && cr->right >= sx); +- if (phase3_y_steps == 0) +- cursor_null_tr(cr); +- else { +- cursor_right_tr(cr, ex, id); +- cr->y += phase3_y_steps; +- } ++ cursor_right_tr(cr, ex, id); ++ cr->y += phase3_y_steps; + } else { + /* Lines decreasing in x. (Leftwards, rising) */ + int phase1_x_steps, phase3_x_steps; +- /* Use unsigned int here, to allow for extreme cases like +- * sx = 0x7fffffff, ex = 0x80000000 */ +- unsigned int x_steps = sx - ex; ++ fixed x_steps = sx - ex; + + /* Phase 1: */ ++ cursor_right_merge_tr(cr, sx, id); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + x_steps -= phase1_x_steps; + sx -= phase1_x_steps; + cursor_left_merge_tr(cr, sx, id); +- cursor_step_tr(cr, phase1_y_steps, sx, id, 0); ++ cursor_step_tr(cr, phase1_y_steps, sx, id); + sy += phase1_y_steps; + y_steps -= phase1_y_steps; +- if (y_steps == 0) { +- cursor_null_tr(cr); ++ if (y_steps == 0) + goto end; +- } + } + + /* Phase 3: precalculation */ +@@ -3723,7 +3318,7 @@ no_merge: + assert((y_steps & (fixed_1 - 1)) == 0); + + /* Phase 2: */ +- y_steps = fixed2int((unsigned int)y_steps); ++ y_steps = fixed2int(y_steps); + assert(y_steps >= 0); + if (y_steps) { + /* We want to change sx by x_steps in y_steps steps. +@@ -3740,7 +3335,7 @@ no_merge: + if (f < 0) + f += d, sx--; + cursor_left_merge_tr(cr, sx, id); +- cursor_always_step_tr(cr, fixed_1, sx, id, 0); ++ cursor_always_step_tr(cr, fixed_1, sx, id); + y_steps--; + + while (y_steps) { +@@ -3756,12 +3351,8 @@ no_merge: + + /* Phase 3 */ + assert(cr->right >= ex && cr->rid == id && cr->left <= sx); +- if (phase3_y_steps == 0) +- cursor_null_tr(cr); +- else { +- cursor_left_tr(cr, ex, id); +- cr->y += phase3_y_steps; +- } ++ cursor_left_tr(cr, ex, id); ++ cr->y += phase3_y_steps; + } + } else { + /* So lines decreasing in y. */ +@@ -3773,21 +3364,34 @@ no_merge: + */ + int phase1_y_steps = sy & (fixed_1 - 1); + int phase3_y_steps = (-ey) & (fixed_1 - 1); +- ufixed y_steps = (ufixed)sy - (ufixed)ey; + +- int skip = cursor_down_tr(cr, sx, id); ++ y_steps = -y_steps; ++ /* Cope with the awkward 0x80000000 case. */ ++ if (y_steps < 0) ++ { ++ int mx, my; ++ mx = sx + ((ex-sx)>>1); ++ my = sy + ((ey-sy)>>1); ++ mark_line_tr_app(cr, sx, sy, mx, my, id); ++ mark_line_tr_app(cr, mx, my, ex, ey, id); ++ return; ++ } ++ ++ cursor_down_tr(cr, sx, id); + + if (sx == ex) { + /* Vertical line. (Falling) */ + + /* Phase 1: */ ++ cursor_left_merge_tr(cr, sx, id); ++ cursor_right_merge_tr(cr, sx, id); + if (phase1_y_steps) { + /* Phase 1 in a falling line never moves us into a new scanline. */ + cursor_never_step_vertical_tr(cr, -phase1_y_steps, sx, id); + sy -= phase1_y_steps; + y_steps -= phase1_y_steps; + if (y_steps == 0) +- goto endFallingLeftOnEdgeOfPixel; ++ goto endFalling; + } + + /* Phase 3: precalculation */ +@@ -3798,8 +3402,7 @@ no_merge: + y_steps = fixed2int(y_steps); + assert(y_steps >= 0); + if (y_steps) { +- cursor_always_step_tr(cr, -fixed_1, sx, id, skip); +- skip = 0; ++ cursor_always_step_tr(cr, -fixed_1, sx, id); + y_steps--; + while (y_steps) { + cursor_always_step_inrange_vertical_tr(cr, -fixed_1, sx, id); +@@ -3808,22 +3411,17 @@ no_merge: + } + + /* Phase 3 */ +- if (phase3_y_steps == 0) { +-endFallingLeftOnEdgeOfPixel: +- cursor_always_step_inrange_vertical_tr(cr, 0, sx, id); +- cursor_null_tr(cr); +- } else { +- cursor_step_tr(cr, -phase3_y_steps, sx, id, skip); ++ if (phase3_y_steps > 0) { ++ cursor_step_tr(cr, -phase3_y_steps, sx, id); + assert(cr->left == sx && cr->lid == id && cr->right == sx && cr->rid == id); + } + } else if (sx < ex) { + /* Lines increasing in x. (Rightwards, falling) */ + int phase1_x_steps, phase3_x_steps; +- /* Use unsigned int here, to allow for extreme cases like +- * ex = 0x7fffffff, sx = 0x80000000 */ +- unsigned int x_steps = ex - sx; ++ fixed x_steps = ex - sx; + + /* Phase 1: */ ++ cursor_left_merge_tr(cr, sx, id); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + x_steps -= phase1_x_steps; +@@ -3833,8 +3431,9 @@ endFallingLeftOnEdgeOfPixel: + sy -= phase1_y_steps; + y_steps -= phase1_y_steps; + if (y_steps == 0) +- goto endFallingRightOnEdgeOfPixel; +- } ++ goto endFalling; ++ } else ++ cursor_right_merge_tr(cr, sx, id); + + /* Phase 3: precalculation */ + phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); +@@ -3853,8 +3452,7 @@ endFallingLeftOnEdgeOfPixel: + int f = y_steps/2; + int d = y_steps; + +- cursor_always_step_tr(cr, -fixed_1, sx, id, skip); +- skip = 0; ++ cursor_always_step_tr(cr, -fixed_1, sx, id); + sx += x_inc; + f -= n_inc; + if (f < 0) +@@ -3874,23 +3472,18 @@ endFallingLeftOnEdgeOfPixel: + } + + /* Phase 3 */ +- if (phase3_y_steps == 0) { +-endFallingRightOnEdgeOfPixel: +- cursor_always_step_inrange_vertical_tr(cr, 0, sx, id); +- cursor_null_tr(cr); +- } else { +- cursor_step_tr(cr, -phase3_y_steps, sx, id, skip); ++ if (phase3_y_steps > 0) { ++ cursor_step_tr(cr, -phase3_y_steps, sx, id); + cursor_right_tr(cr, ex, id); + assert(cr->left == sx && cr->lid == id && cr->right == ex && cr->rid == id); + } + } else { + /* Lines decreasing in x. (Falling) */ + int phase1_x_steps, phase3_x_steps; +- /* Use unsigned int here, to allow for extreme cases like +- * sx = 0x7fffffff, ex = 0x80000000 */ +- unsigned int x_steps = sx - ex; ++ fixed x_steps = sx - ex; + + /* Phase 1: */ ++ cursor_right_merge_tr(cr, sx, id); + if (phase1_y_steps) { + phase1_x_steps = (int)(((int64_t)x_steps * phase1_y_steps + y_steps/2) / y_steps); + x_steps -= phase1_x_steps; +@@ -3900,8 +3493,9 @@ endFallingRightOnEdgeOfPixel: + sy -= phase1_y_steps; + y_steps -= phase1_y_steps; + if (y_steps == 0) +- goto endFallingVerticalOnEdgeOfPixel; +- } ++ goto endFalling; ++ } else ++ cursor_left_merge_tr(cr, sx, id); + + /* Phase 3: precalculation */ + phase3_x_steps = (int)(((int64_t)x_steps * phase3_y_steps + y_steps/2) / y_steps); +@@ -3920,8 +3514,7 @@ endFallingRightOnEdgeOfPixel: + int f = y_steps/2; + int d = y_steps; + +- cursor_always_step_tr(cr, -fixed_1, sx, id, skip); +- skip = 0; ++ cursor_always_step_tr(cr, -fixed_1, sx, id); + sx -= x_inc; + f -= n_inc; + if (f < 0) +@@ -3941,17 +3534,17 @@ endFallingRightOnEdgeOfPixel: + } + + /* Phase 3 */ +- if (phase3_y_steps == 0) { +-endFallingVerticalOnEdgeOfPixel: +- cursor_always_step_inrange_vertical_tr(cr, 0, sx, id); +- cursor_null_tr(cr); +- } else { +- cursor_step_tr(cr, -phase3_y_steps, sx, id, skip); ++ if (phase3_y_steps > 0) { ++ cursor_step_tr(cr, -phase3_y_steps, sx, id); + cursor_left_tr(cr, ex, id); + assert(cr->left == ex && cr->lid == id && cr->right == sx && cr->rid == id); + } + } +-endFalling: {} ++endFalling: ++ if (truncated) ++ { ++ cursor_output_tr(cr, fixed2int(cr->y) - cr->base); ++ } + } + + end: +@@ -3964,7 +3557,7 @@ end: + } + } + +-static void mark_curve_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, int depth, int * gs_restrict id) ++static void mark_curve_tr_app(cursor_tr * restrict cr, fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, int depth, int * restrict id) + { + int ax = (sx + c1x)>>1; + int ay = (sy + c1y)>>1; +@@ -3990,25 +3583,25 @@ static void mark_curve_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fi + } + } + +-static void mark_curve_big_tr_app(cursor_tr * gs_restrict cr, fixed64 sx, fixed64 sy, fixed64 c1x, fixed64 c1y, fixed64 c2x, fixed64 c2y, fixed64 ex, fixed64 ey, int depth, int * gs_restrict id) ++static void mark_curve_big_tr_app(cursor_tr * restrict cr, fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, int depth, int * restrict id) + { +- fixed64 ax = (sx + c1x)>>1; +- fixed64 ay = (sy + c1y)>>1; +- fixed64 bx = (c1x + c2x)>>1; +- fixed64 by = (c1y + c2y)>>1; +- fixed64 cx = (c2x + ex)>>1; +- fixed64 cy = (c2y + ey)>>1; +- fixed64 dx = (ax + bx)>>1; +- fixed64 dy = (ay + by)>>1; +- fixed64 fx = (bx + cx)>>1; +- fixed64 fy = (by + cy)>>1; +- fixed64 gx = (dx + fx)>>1; +- fixed64 gy = (dy + fy)>>1; ++ fixed ax = (sx>>1) + (c1x>>1); ++ fixed ay = (sy>>1) + (c1y>>1); ++ fixed bx = (c1x>>1) + (c2x>>1); ++ fixed by = (c1y>>1) + (c2y>>1); ++ fixed cx = (c2x>>1) + (ex>>1); ++ fixed cy = (c2y>>1) + (ey>>1); ++ fixed dx = (ax>>1) + (bx>>1); ++ fixed dy = (ay>>1) + (by>>1); ++ fixed fx = (bx>>1) + (cx>>1); ++ fixed fy = (by>>1) + (cy>>1); ++ fixed gx = (dx>>1) + (fx>>1); ++ fixed gy = (dy>>1) + (fy>>1); + + assert(depth >= 0); + if (depth == 0) { + *id += 1; +- mark_line_tr_app(cr, (fixed)sx, (fixed)sy, (fixed)ex, (fixed)ey, *id); ++ mark_line_tr_app(cr, sx, sy, ex, ey, *id); + } else { + depth--; + mark_curve_big_tr_app(cr, sx, sy, ax, ay, dx, dy, gx, gy, depth, id); +@@ -4016,7 +3609,7 @@ static void mark_curve_big_tr_app(cursor_tr * gs_restrict cr, fixed64 sx, fixed6 + } + } + +-static void mark_curve_top_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, int depth, int * gs_restrict id) ++static void mark_curve_top_tr_app(cursor_tr * restrict cr, fixed sx, fixed sy, fixed c1x, fixed c1y, fixed c2x, fixed c2y, fixed ex, fixed ey, int depth, int * restrict id) + { + fixed test = (sx^(sx<<1))|(sy^(sy<<1))|(c1x^(c1x<<1))|(c1y^(c1y<<1))|(c2x^(c2x<<1))|(c2y^(c2y<<1))|(ex^(ex<<1))|(ey^(ey<<1)); + +@@ -4028,7 +3621,7 @@ static void mark_curve_top_tr_app(cursor_tr * gs_restrict cr, fixed sx, fixed sy + + static int make_table_tr_app(gx_device * pdev, + gx_path * path, +- gs_fixed_rect * ibox, ++ const gs_fixed_rect * ibox, + int * scanlines, + int ** index, + int ** table) +@@ -4036,28 +3629,13 @@ static int make_table_tr_app(gx_device * pdev, + return make_table_template(pdev, path, ibox, 4, 0, scanlines, index, table); + } + +-static void +-fill_zero_app_tr(int *row, const fixed *x) +-{ +- int n = *row = (*row)+2; /* Increment the count */ +- row[4*n-7] = x[0]; +- row[4*n-6] = 0; +- row[4*n-5] = x[1]; +- row[4*n-4] = 0; +- row[4*n-3] = x[1]; +- row[4*n-2] = (1<<1)|1; +- row[4*n-1] = x[1]; +- row[4*n ] = 1; +-} +- +-int gx_scan_convert_tr_app(gx_device * gs_restrict pdev, +- gx_path * gs_restrict path, +- const gs_fixed_rect * gs_restrict clip, +- gx_edgebuffer * gs_restrict edgebuffer, ++int gx_scan_convert_tr_app(gx_device * restrict pdev, ++ gx_path * restrict path, ++ const gs_fixed_rect * restrict clip, ++ gx_edgebuffer * restrict edgebuffer, + fixed fixed_flat) + { + gs_fixed_rect ibox; +- gs_fixed_rect bbox; + int scanlines; + const subpath *psub; + int *index; +@@ -4066,7 +3644,6 @@ int gx_scan_convert_tr_app(gx_device * gs_restrict pdev, + cursor_tr cr; + int code; + int id = 0; +- int zero; + + edgebuffer->index = NULL; + edgebuffer->table = NULL; +@@ -4075,24 +3652,17 @@ int gx_scan_convert_tr_app(gx_device * gs_restrict pdev, + if (path->first_subpath == NULL) + return 0; + +- zero = make_bbox(path, clip, &bbox, &ibox, 0); +- if (zero < 0) +- return zero; ++ code = make_bbox(path, clip, &ibox, 0); ++ if (code < 0) ++ return code; + + if (ibox.q.y <= ibox.p.y) + return 0; + + code = make_table_tr_app(pdev, path, &ibox, &scanlines, &index, &table); +- if (code != 0) /* > 0 means "retry with smaller height" */ ++ if (code < 0) + return code; + +- if (scanlines == 0) +- return 0; +- +- if (zero) { +- code = zero_case(pdev, path, &ibox, index, table, fixed_flat, fill_zero_app_tr); +- } else { +- + /* Step 2 continued: Now we run through the path, filling in the real + * values. */ + cr.scanlines = scanlines; +@@ -4107,12 +3677,7 @@ int gx_scan_convert_tr_app(gx_device * gs_restrict pdev, + fixed iy = ey; + fixed sx, sy; + +- if ((ey & 0xff) == 0) { +- cr.left = max_fixed; +- cr.right = min_fixed; +- } else { +- cr.left = cr.right = ex; +- } ++ cr.left = cr.right = ex; + cr.lid = cr.rid = id+1; + cr.y = ey; + cr.d = DIRN_UNSET; +@@ -4152,7 +3717,6 @@ int gx_scan_convert_tr_app(gx_device * gs_restrict pdev, + cursor_flush_tr(&cr, ex, id); + psub = (const subpath *)pseg; + } +- } + + /* Step 2 complete: We now have a complete list of intersection data in + * table, indexed by index. */ +@@ -4181,9 +3745,9 @@ int gx_scan_convert_tr_app(gx_device * gs_restrict pdev, + if (rowlen <= 6) { + int j, k; + for (j = 0; j < rowlen-1; j++) { +- int * gs_restrict t = &row[j<<2]; ++ int * restrict t = &row[j<<2]; + for (k = j+1; k < rowlen; k++) { +- int * gs_restrict s = &row[k<<2]; ++ int * restrict s = &row[k<<2]; + int tmp; + if (t[0] < s[0]) + continue; +@@ -4219,8 +3783,8 @@ swap13: + + /* Step 5: Filter the intersections according to the rules */ + int +-gx_filter_edgebuffer_tr_app(gx_device * gs_restrict pdev, +- gx_edgebuffer * gs_restrict edgebuffer, ++gx_filter_edgebuffer_tr_app(gx_device * restrict pdev, ++ gx_edgebuffer * restrict edgebuffer, + int rule) + { + int i; +@@ -4241,7 +3805,7 @@ gx_filter_edgebuffer_tr_app(gx_device * gs_restrict pdev, + int ll, llid, lr, lrid, rlid, rr, rrid, wind, marked_to; + + /* Avoid double setting pixels, by keeping where we have marked to. */ +- marked_to = INT_MIN; ++ marked_to = 0; + while (rowlen > 0) { + if (rule == gx_rule_even_odd) { + /* Even Odd */ +@@ -4250,18 +3814,24 @@ gx_filter_edgebuffer_tr_app(gx_device * gs_restrict pdev, + lr = *row++; + lrid = *row++; + rowlen--; ++ wind = 1; + + /* We will fill solidly from ll to at least lr, possibly further */ + assert(rowlen > 0); +- (void)row++; /* rl not needed here */ +- (void)row++; +- rr = *row++; +- rrid = *row++; +- rowlen--; +- if (rr > lr) { +- lr = rr; +- lrid = rrid; +- } ++ do { ++ (void)row++; /* rl not needed here */ ++ rlid = *row++>>1; ++ rr = *row++; ++ rrid = *row++; ++ rowlen--; ++ if (rr > lr) { ++ lr = rr; ++ lrid = rrid; ++ } ++ wind ^= 1; ++ if (wind == 0) ++ break; ++ } while (rowlen > 0); + } else { + /* Non-Zero */ + int w; +@@ -4296,7 +3866,7 @@ gx_filter_edgebuffer_tr_app(gx_device * gs_restrict pdev, + if (lr < marked_to) + continue; + +- if (marked_to >= ll) { ++ if (marked_to > ll) { + if (rowout == rowstart) { + ll = marked_to; + llid = --marked_id; +@@ -4307,7 +3877,7 @@ gx_filter_edgebuffer_tr_app(gx_device * gs_restrict pdev, + } + } + +- if (lr >= ll) { ++ if (lr > ll) { + *rowout++ = ll; + *rowout++ = llid; + *rowout++ = lr; +@@ -4322,13 +3892,12 @@ gx_filter_edgebuffer_tr_app(gx_device * gs_restrict pdev, + + /* Step 6: Fill */ + int +-gx_fill_edgebuffer_tr_app(gx_device * gs_restrict pdev, +- const gx_device_color * gs_restrict pdevc, +- gx_edgebuffer * gs_restrict edgebuffer, ++gx_fill_edgebuffer_tr_app(gx_device * restrict pdev, ++ const gx_device_color * restrict pdevc, ++ gx_edgebuffer * restrict edgebuffer, + int log_op) + { + int i, j, code; +- int mfb = pdev->max_fill_band; + + #ifdef DEBUG_SCAN_CONVERTER + if (debugging_scan_converter) { +@@ -4343,18 +3912,9 @@ gx_fill_edgebuffer_tr_app(gx_device * gs_restrict pdev, + int *row2; + int *rowptr; + int *row2ptr; +- int y_band_max; +- +- if (mfb) { +- y_band_max = (i & ~(mfb-1)) + mfb; +- if (y_band_max > edgebuffer->height) +- y_band_max = edgebuffer->height; +- } else { +- y_band_max = edgebuffer->height; +- } + + /* See how many scanlines match i */ +- for (j = i+1; j < y_band_max; j++) { ++ for (j = i+1; j < edgebuffer->height; j++) { + int row2len; + + row2 = &edgebuffer->table[edgebuffer->index[j]]; +@@ -4473,6 +4033,8 @@ rowdifferent:{} + offset += 4; + rowlen--; + ++ assert(le.start.x >= -fixed_half); ++ assert(le.end.x >= -fixed_half); + assert(re.start.x >= le.start.x); + assert(re.end.x >= le.end.x); + assert(le.start.y <= ybot + fixed_half); +@@ -4558,97 +4120,3 @@ gx_edgebuffer_fin(gx_device * pdev, + edgebuffer->index = NULL; + edgebuffer->table = NULL; + } +- +-gx_scan_converter_t gx_scan_converter = +-{ +- gx_scan_convert, +- gx_filter_edgebuffer, +- gx_fill_edgebuffer +-}; +- +-gx_scan_converter_t gx_scan_converter_app = +-{ +- gx_scan_convert_app, +- gx_filter_edgebuffer_app, +- gx_fill_edgebuffer_app +-}; +- +-gx_scan_converter_t gx_scan_converter_tr = +-{ +- gx_scan_convert_tr, +- gx_filter_edgebuffer_tr, +- gx_fill_edgebuffer_tr +-}; +- +-gx_scan_converter_t gx_scan_converter_tr_app = +-{ +- gx_scan_convert_tr_app, +- gx_filter_edgebuffer_tr_app, +- gx_fill_edgebuffer_tr_app +-}; +- +-int +-gx_scan_convert_and_fill(const gx_scan_converter_t *sc, +- gx_device *dev, +- gx_path *ppath, +- const gs_fixed_rect *ibox, +- fixed flat, +- int rule, +- const gx_device_color *pdevc, +- int lop) +-{ +- int code; +- gx_edgebuffer eb; +- gs_fixed_rect ibox2 = *ibox; +- int height; +- int mfb = dev->max_fill_band; +- +- if (mfb != 0) { +- ibox2.p.y &= ~(mfb-1); +- ibox2.q.y = (ibox2.q.y+mfb-1) & ~(mfb-1); +- } +- height = ibox2.q.y - ibox2.p.y; +- +- do { +- gx_edgebuffer_init(&eb); +- while (1) { +- ibox2.q.y = ibox2.p.y + height; +- if (ibox2.q.y > ibox->q.y) +- ibox2.q.y = ibox->q.y; +- code = sc->scan_convert(dev, +- ppath, +- &ibox2, +- &eb, +- flat); +- if (code <= 0) +- break; +- /* Let's shrink the ibox and try again */ +- if (mfb && height == mfb) { +- /* Can't shrink the height any more! */ +- code = gs_error_rangecheck; +- break; +- } +- height = height/code; +- if (mfb) +- height = (height + mfb-1) & ~(mfb-1); +- if (height < (mfb ? mfb : 1)) { +- code = gs_error_VMerror; +- break; +- } +- } +- if (code >= 0) +- code = sc->filter(dev, +- &eb, +- rule); +- if (code >= 0) +- code = sc->fill(dev, +- pdevc, +- &eb, +- lop); +- gx_edgebuffer_fin(dev,&eb); +- ibox2.p.y += height; +- } +- while (ibox2.p.y < ibox->q.y); +- +- return code; +-} diff --git a/debian/patches/CVE-2017-8908.patch b/debian/patches/CVE-2017-8908.patch new file mode 100644 index 0000000..1086fd4 --- /dev/null +++ b/debian/patches/CVE-2017-8908.patch @@ -0,0 +1,166 @@ +Description: CVE-2017-8908 - 安全修复 +Author: Ray Johnston +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/9f9daedfdf98bab590eba53e34fba76b96307ec0 +Bug: https://nvd.nist.gov/vuln/detail/CVE-2017-8908 +Last-Update: 2018-02-13 +--- +diff --git a/base/gxscanc.c b/base/gxscanc.c +index 13ece3afc..db8ab1213 100644 +--- a/base/gxscanc.c ++++ b/base/gxscanc.c +@@ -194,7 +194,7 @@ static void coord(const char *str, fixed x, fixed y) + + static void mark_line(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int height, int *table, int *index) + { +- int delta; ++ int64_t delta; + int iy, ih; + fixed clip_sy, clip_ey; + int dirn = DIRN_UP; +@@ -234,7 +234,7 @@ static void mark_line(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int he + clip_ey = int2fixed(base_y + height - 1) + fixed_half; + if (sy > clip_ey) + return; +- delta = clip_sy - sy; ++ delta = (int64_t)clip_sy - (int64_t)sy; + if (delta > 0) + { + int dx = ex - sx; +@@ -246,7 +246,7 @@ static void mark_line(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int he + ex -= sx; + ey -= sy; + clip_ey -= clip_sy; +- delta = ey - clip_ey; ++ delta = (int64_t)ey - (int64_t)clip_ey; + if (delta > 0) + { + int advance = (int)(((int64_t)ex * delta + (ey>>1)) / ey); +@@ -1246,9 +1246,9 @@ static void mark_line_app(cursor * restrict cr, fixed sx, fixed sy, fixed ex, fi + } + if (isy < 0) { + /* Move sy up */ +- int y = ey - sy; +- int new_sy = int2fixed(cr->base); +- int dy = new_sy - sy; ++ int64_t y = (int64_t)ey - (int64_t)sy; ++ fixed new_sy = int2fixed(cr->base); ++ int64_t dy = (int64_t)new_sy - (int64_t)sy; + sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; + cursor_init(cr, sy, sx); +@@ -1257,9 +1257,9 @@ static void mark_line_app(cursor * restrict cr, fixed sx, fixed sy, fixed ex, fi + truncated = iey > cr->scanlines; + if (truncated) { + /* Move ey down */ +- int y = ey - sy; +- int new_ey = int2fixed(cr->base + cr->scanlines); +- int dy = ey - new_ey; ++ int64_t y = ey - sy; ++ fixed new_ey = int2fixed(cr->base + cr->scanlines); ++ int64_t dy = (int64_t)ey - (int64_t)new_ey; + saved_ex = ex; + saved_ey = ey; + ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); +@@ -1279,18 +1279,18 @@ static void mark_line_app(cursor * restrict cr, fixed sx, fixed sy, fixed ex, fi + truncated = iey < 0; + if (truncated) { + /* Move ey up */ +- int y = ey - sy; +- int new_ey = int2fixed(cr->base); +- int dy = ey - new_ey; ++ int64_t y = (int64_t)ey - (int64_t)sy; ++ fixed new_ey = int2fixed(cr->base); ++ int64_t dy = (int64_t)ey - (int64_t)new_ey; + ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); + ey = new_ey; + iey = 0; + } + if (isy >= cr->scanlines) { + /* Move sy down */ +- int y = ey - sy; +- int new_sy = int2fixed(cr->base + cr->scanlines); +- int dy = new_sy - sy; ++ int64_t y = (int64_t)ey - (int64_t)sy; ++ fixed new_sy = int2fixed(cr->base + cr->scanlines); ++ int64_t dy = (int64_t)new_sy - (int64_t)sy; + sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; + cursor_init(cr, sy, sx); +@@ -2085,7 +2085,7 @@ gx_edgebuffer_print_tr(gx_edgebuffer * edgebuffer) + + static void mark_line_tr(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int height, int *table, int *index, int id) + { +- int delta; ++ int64_t delta; + int iy, ih; + fixed clip_sy, clip_ey; + int dirn = DIRN_UP; +@@ -2125,7 +2125,7 @@ static void mark_line_tr(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int + clip_ey = int2fixed(base_y + height - 1) + fixed_half; + if (sy > clip_ey) + return; +- delta = clip_sy - sy; ++ delta = (int64_t)clip_sy - (int64_t)sy; + if (delta > 0) + { + int dx = ex - sx; +@@ -2137,7 +2137,7 @@ static void mark_line_tr(fixed sx, fixed sy, fixed ex, fixed ey, int base_y, int + ex -= sx; + ey -= sy; + clip_ey -= clip_sy; +- delta = ey - clip_ey; ++ delta = (int64_t)ey - (int64_t)clip_ey; + if (delta > 0) + { + int advance = (int)(((int64_t)ex * delta + (ey>>1)) / ey); +@@ -3086,9 +3086,9 @@ static void mark_line_tr_app(cursor_tr * restrict cr, fixed sx, fixed sy, fixed + } + if (isy < 0) { + /* Move sy up */ +- int y = ey - sy; +- int new_sy = int2fixed(cr->base); +- int dy = new_sy - sy; ++ int64_t y = (int64_t)ey - (int64_t)sy; ++ fixed new_sy = int2fixed(cr->base); ++ int64_t dy = (int64_t)new_sy - (int64_t)sy; + sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; + cursor_init_tr(cr, sy, sx, id); +@@ -3097,9 +3097,9 @@ static void mark_line_tr_app(cursor_tr * restrict cr, fixed sx, fixed sy, fixed + truncated = iey > cr->scanlines; + if (truncated) { + /* Move ey down */ +- int y = ey - sy; +- int new_ey = int2fixed(cr->base + cr->scanlines); +- int dy = ey - new_ey; ++ int64_t y = (int64_t)ey - (int64_t)sy; ++ fixed new_ey = int2fixed(cr->base + cr->scanlines); ++ int64_t dy = (int64_t)ey - (int64_t)new_ey; + saved_ex = ex; + saved_ey = ey; + ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); +@@ -3121,18 +3121,18 @@ static void mark_line_tr_app(cursor_tr * restrict cr, fixed sx, fixed sy, fixed + truncated = iey < 0; + if (truncated) { + /* Move ey up */ +- int y = ey - sy; +- int new_ey = int2fixed(cr->base); +- int dy = ey - new_ey; ++ int64_t y = (int64_t)ey - (int64_t)sy; ++ fixed new_ey = int2fixed(cr->base); ++ int64_t dy = (int64_t)ey - (int64_t)new_ey; + ex -= (int)((((int64_t)(ex-sx))*dy + y/2)/y); + ey = new_ey; + iey = 0; + } + if (isy >= cr->scanlines) { + /* Move sy down */ +- int y = ey - sy; +- int new_sy = int2fixed(cr->base + cr->scanlines); +- int dy = new_sy - sy; ++ int64_t y = (int64_t)ey - (int64_t)sy; ++ fixed new_sy = int2fixed(cr->base + cr->scanlines); ++ int64_t dy = (int64_t)new_sy - (int64_t)sy; + sx += (int)((((int64_t)(ex-sx))*dy + y/2)/y); + sy = new_sy; + cursor_init_tr(cr, sy, sx, id); diff --git a/debian/patches/CVE-2017-9619.patch b/debian/patches/CVE-2017-9619.patch new file mode 100644 index 0000000..f058930 --- /dev/null +++ b/debian/patches/CVE-2017-9619.patch @@ -0,0 +1,41 @@ +Description: CVE-2017-9619 - 安全修复 +Author: Ken Sharp +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/690ac215a57039c7202fd1ffdae12f52829f625d +Bug: https://nvd.nist.gov/vuln/detail/CVE-2017-9619 +Last-Update: 2025-09-09 08:01:56 +0100 +--- +diff --git a/xps/xpsttf.c b/xps/xpsttf.c +index 70ae184..e8eb0de 100644 +--- a/xps/xpsttf.c ++++ b/xps/xpsttf.c +@@ -143,7 +143,7 @@ xps_true_callback_glyph_name(gs_font *pfont, gs_glyph glyph, gs_const_string *ps + ulong format; + int numGlyphs; + uint glyph_name_index; +- const byte *postp; /* post table pointer */ ++ const byte *postp, *indexp; /* post table pointer */ + xps_font_t *font = pfont->client_data; + + if (glyph >= GS_MIN_GLYPH_INDEX) { +@@ -217,7 +217,11 @@ xps_true_callback_glyph_name(gs_font *pfont, gs_glyph glyph, gs_const_string *ps + } + + /* glyph name index starts at post + 34 each entry is 2 bytes */ +- glyph_name_index = u16(postp + 34 + (glyph * 2)); ++ indexp = postp + 34 + (glyph * 2); ++ if (indexp > (postp + table_length - 2)) ++ return gs_throw(-1, "post table format error"); ++ ++ glyph_name_index = u16(indexp); + + /* this shouldn't happen */ + if ( glyph_name_index > 0x7fff ) +@@ -249,6 +253,8 @@ xps_true_callback_glyph_name(gs_font *pfont, gs_glyph glyph, gs_const_string *ps + { + pascal_stringp += ((int)(*pascal_stringp)+1); + glyph_name_index--; ++ if (pascal_stringp >= postp + table_length) ++ return gs_throw(-1, "data out of range"); + } + + /* length byte */ diff --git a/debian/patches/CVE-2018-16539.patch b/debian/patches/CVE-2018-16539.patch new file mode 100644 index 0000000..90e3fea --- /dev/null +++ b/debian/patches/CVE-2018-16539.patch @@ -0,0 +1,84 @@ +Description: CVE-2018-16539 - 安全修复 +Author: Chris Liddell +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/e0174f4d743782e7cb949c90e955ff912c11d592 +Bug: https://nvd.nist.gov/vuln/detail/CVE-2018-16539 +Last-Update: 2026-02-23 14:59:01 +0000 +--- +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index c7051622b..4d6c9e828 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -2369,20 +2369,6 @@ readonly def + //systemdict /SAFERUndefinePostScriptOperators .forceundef + } .forcebind def % must be bound and hidden for .forceundef + +-/tempfilepaths +-[ +- (TMPDIR) getenv not +- { +- (TEMP) getenv not +- { +- (TMP) getenv not +- { +- (/temp) (/tmp) +- } if +- } if +- } if +-] def +- + /.lockfileaccess { + .currentpathcontrolstate + { +@@ -2394,7 +2380,6 @@ readonly def + } + { + [ +- //tempfilepaths (*) .generate_dir_list_templates + /FONTPATH .systemvar (*) .generate_dir_list_templates + /level2dict where { + pop +@@ -2408,14 +2393,6 @@ readonly def + } if + ] {/PermitFileReading exch .addcontrolpath} forall + +- [ +- //tempfilepaths (*) .generate_dir_list_templates +- ] {/PermitFileWriting exch .addcontrolpath} forall +- +- [ +- //tempfilepaths (*) .generate_dir_list_templates +- ] {/PermitFileControl exch .addcontrolpath} forall +- + .activatepathcontrol + } ifelse + } .internalbind def +@@ -2425,7 +2402,6 @@ readonly def + << + /PermitFileReading [ + currentuserparams /PermitFileReading get aload pop +- //tempfilepaths (*) .generate_dir_list_templates + /FONTPATH .systemvar (*) .generate_dir_list_templates + % Library files : + /LIBPATH .systemvar (*) .generate_dir_list_templates +@@ -2445,21 +2421,12 @@ readonly def + .generate_dir_list_templates + } if + ] +- /PermitFileWriting [ +- currentuserparams /PermitFileWriting get aload pop +- //tempfilepaths (*) .generate_dir_list_templates +- ] +- /PermitFileControl [ +- currentuserparams /PermitFileControl get aload pop +- //tempfilepaths (*) .generate_dir_list_templates +- ] + /LockFilePermissions //true + >> setuserparams + } + if + } .forcebind def + +-currentdict /tempfilepaths undef + + %% --- These are documented extensions --- + /.locksafe { diff --git a/debian/patches/CVE-2018-17183.patch b/debian/patches/CVE-2018-17183.patch new file mode 100644 index 0000000..b3dad21 --- /dev/null +++ b/debian/patches/CVE-2018-17183.patch @@ -0,0 +1,66 @@ +Description: CVE-2018-17183 - 安全修复 +Author: Chris Liddell +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/fb713b3818b52d8a6cf62c951eba2e1795ff9624 +Bug: https://nvd.nist.gov/vuln/detail/CVE-2018-17183 +Last-Update: 2018-09-06 +--- +diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps +index 239596f63..c7051622b 100644 +--- a/Resource/Init/gs_init.ps ++++ b/Resource/Init/gs_init.ps +@@ -1400,7 +1400,11 @@ errordict begin + } .internalbind def + end % errordict + +-gserrordict /unknownerror errordict /unknownerror get put ++% Put all the default handlers in gserrordict ++gserrordict ++errordict {2 index 3 1 roll put} forall ++noaccess pop ++% remove the non-standard errors from errordict + errordict /unknownerror .undef + + /.SAFERERRORLIST ErrorNames def +diff --git a/psi/interp.c b/psi/interp.c +index 187d3fbb4..3c0c25173 100644 +--- a/psi/interp.c ++++ b/psi/interp.c +@@ -683,18 +683,27 @@ again: + if (gs_errorname(i_ctx_p, code, &error_name) < 0) + return code; /* out-of-range error code! */ + +- /* We refer to gserrordict first, which is not accessible to Postcript jobs +- * If we're running with SAFERERRORS all the handlers are copied to gserrordict +- * so we'll always find the default one. If not SAFERERRORS, only gs specific +- * errors are in gserrordict. ++ /* If LockFilePermissions is true, we only refer to gserrordict, which ++ * is not accessible to Postcript jobs + */ +- if ((dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || +- !r_has_type(perrordict, t_dictionary) || +- dict_find(perrordict, &error_name, &epref) <= 0) && +- (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || +- !r_has_type(perrordict, t_dictionary) || +- dict_find(perrordict, &error_name, &epref) <= 0)) +- return code; /* error name not in errordict??? */ ++ if (i_ctx_p->LockFilePermissions) { ++ if (((dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || ++ dict_find(perrordict, &error_name, &epref) <= 0)) ++ ) ++ return code; /* error name not in errordict??? */ ++ } ++ else { ++ /* ++ * For greater Adobe compatibility, only the standard PostScript errors ++ * are defined in errordict; the rest are in gserrordict. ++ */ ++ if (dict_find_string(systemdict, "errordict", &perrordict) <= 0 || ++ (dict_find(perrordict, &error_name, &epref) <= 0 && ++ (dict_find_string(systemdict, "gserrordict", &perrordict) <= 0 || ++ dict_find(perrordict, &error_name, &epref) <= 0)) ++ ) ++ return code; /* error name not in errordict??? */ ++ } + + if (code == gs_error_execstackoverflow + && obj_eq(imemory, &doref, epref)) { diff --git a/debian/patches/CVE-2025-59798.patch b/debian/patches/CVE-2025-59798.patch new file mode 100644 index 0000000..3443af7 --- /dev/null +++ b/debian/patches/CVE-2025-59798.patch @@ -0,0 +1,106 @@ +Description: CVE-2025-59798 - 安全修复 +Author: Ken Sharp +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/0cae41b23a9669e801211dd4cf97b6dadd6dbdd7 +Bug: https://nvd.nist.gov/vuln/detail/CVE-2025-59798 +Last-Update: 2025-05-22 +--- +diff --git a/devices/vector/gdevpdtw.c b/devices/vector/gdevpdtw.c +index ced15c9b2..fe24dd73a 100644 +--- a/devices/vector/gdevpdtw.c ++++ b/devices/vector/gdevpdtw.c +@@ -703,7 +703,8 @@ static int + pdf_write_cid_system_info_to_stream(gx_device_pdf *pdev, stream *s, + const gs_cid_system_info_t *pcidsi, gs_id object_id) + { +- byte *Registry, *Ordering; ++ byte *Registry = NULL, *Ordering = NULL; ++ int code = 0; + + Registry = gs_alloc_bytes(pdev->pdf_memory, pcidsi->Registry.size, "temporary buffer for Registry"); + if (!Registry) +@@ -734,14 +735,19 @@ pdf_write_cid_system_info_to_stream(gx_device_pdf *pdev, stream *s, + } + s_arcfour_process_buffer(&sarc4, Ordering, pcidsi->Ordering.size); + } +- stream_puts(s, "<<\n/Registry"); ++ code = stream_puts(s, "<<\n/Registry"); ++ if (code < 0) ++ goto error; + s_write_ps_string(s, Registry, pcidsi->Registry.size, PRINT_HEX_NOT_OK); +- stream_puts(s, "\n/Ordering"); ++ code = stream_puts(s, "\n/Ordering"); ++ if(code < 0) ++ goto error; + s_write_ps_string(s, Ordering, pcidsi->Ordering.size, PRINT_HEX_NOT_OK); ++error: + pprintd1(s, "\n/Supplement %d\n>>\n", pcidsi->Supplement); + gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer"); + gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer"); +- return 0; ++ return code; + } + + int +@@ -786,31 +792,55 @@ pdf_write_cmap(gx_device_pdf *pdev, const gs_cmap_t *pcmap, + *ppres = writer.pres; + writer.pres->where_used = 0; /* CMap isn't a PDF resource. */ + if (!pcmap->ToUnicode) { +- byte buf[200]; ++ byte *buf = NULL; ++ uint64_t buflen = 0; + cos_dict_t *pcd = (cos_dict_t *)writer.pres->object; + stream s; + ++ /* We use 'buf' for the stream 's' below and that needs to have some extra ++ * space for the CIDSystemInfo. We also need an extra byte for the leading '/' ++ * 100 bytes is ample for the overhead. ++ */ ++ buflen = pcmap->CIDSystemInfo->Registry.size + pcmap->CIDSystemInfo->Ordering.size + pcmap->CMapName.size + 100; ++ if (buflen > max_uint) ++ return_error(gs_error_limitcheck); ++ ++ buf = gs_alloc_bytes(pdev->memory, buflen, "pdf_write_cmap"); ++ if (buf == NULL) ++ return_error(gs_error_VMerror); ++ + code = cos_dict_put_c_key_int(pcd, "/WMode", pcmap->WMode); +- if (code < 0) ++ if (code < 0) { ++ gs_free_object(pdev->memory, buf, "pdf_write_cmap"); + return code; ++ } + buf[0] = '/'; + memcpy(buf + 1, pcmap->CMapName.data, pcmap->CMapName.size); + code = cos_dict_put_c_key_string(pcd, "/CMapName", + buf, pcmap->CMapName.size + 1); +- if (code < 0) ++ if (code < 0) { ++ gs_free_object(pdev->memory, buf, "pdf_write_cmap"); + return code; ++ } + s_init(&s, pdev->memory); +- swrite_string(&s, buf, sizeof(buf)); ++ swrite_string(&s, buf, buflen); + code = pdf_write_cid_system_info_to_stream(pdev, &s, pcmap->CIDSystemInfo, 0); +- if (code < 0) ++ if (code < 0) { ++ gs_free_object(pdev->memory, buf, "pdf_write_cmap"); + return code; ++ } + code = cos_dict_put_c_key_string(pcd, "/CIDSystemInfo", + buf, stell(&s)); +- if (code < 0) ++ if (code < 0) { ++ gs_free_object(pdev->memory, buf, "pdf_write_cmap"); + return code; ++ } + code = cos_dict_put_string_copy(pcd, "/Type", "/CMap"); +- if (code < 0) ++ if (code < 0) { ++ gs_free_object(pdev->memory, buf, "pdf_write_cmap"); + return code; ++ } ++ gs_free_object(pdev->memory, buf, "pdf_write_cmap"); + } + if (pcmap->CMapName.size == 0) { + /* Create an arbitrary name (for ToUnicode CMap). */ diff --git a/debian/patches/CVE-2025-59799.patch b/debian/patches/CVE-2025-59799.patch new file mode 100644 index 0000000..3566ef0 --- /dev/null +++ b/debian/patches/CVE-2025-59799.patch @@ -0,0 +1,28 @@ +Description: CVE-2025-59799 - 安全修复 +Author: Piotr Kajda +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/6dab38fb211f15226c242ab7a83fa53e4b0ff781 +Bug: https://nvd.nist.gov/vuln/detail/CVE-2025-59799 +Last-Update: 2025-05-08 +--- +diff --git a/devices/vector/gdevpdfm.c b/devices/vector/gdevpdfm.c +index d1237c91a..c120ba1ae 100644 +--- a/devices/vector/gdevpdfm.c ++++ b/devices/vector/gdevpdfm.c +@@ -199,6 +199,8 @@ pdfmark_coerce_dest(gs_param_string *dstr, char dest[MAX_DEST_STRING]) + { + const byte *data = dstr->data; + uint size = dstr->size; ++ if (size > MAX_DEST_STRING) ++ return_error(gs_error_limitcheck); + if (size == 0 || data[0] != '(') + return 0; + /****** HANDLE ESCAPES ******/ +@@ -859,6 +861,8 @@ pdfmark_put_ao_pairs(gx_device_pdf * pdev, cos_dict_t *pcd, + char buf[30]; + int d0, d1; + ++ if (Action[1].size > 29) ++ return_error(gs_error_rangecheck); + memcpy(buf, Action[1].data, Action[1].size); + buf[Action[1].size] = 0; + if (sscanf(buf, "%d %d R", &d0, &d1) == 2) diff --git a/debian/patches/CVE-2025-59800.patch b/debian/patches/CVE-2025-59800.patch new file mode 100644 index 0000000..202f281 --- /dev/null +++ b/debian/patches/CVE-2025-59800.patch @@ -0,0 +1,25 @@ +Description: CVE-2025-59800 - 安全修复 +Author: Ken Sharp +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/176cf0188a2294bc307b8caec876f39412e58350 +Bug: https://nvd.nist.gov/vuln/detail/CVE-2025-59800 +Last-Update: 2025-07-01 +--- +diff --git a/devices/gdevpdfocr.c b/devices/gdevpdfocr.c +index 1c1e8eab8..7c9c12f8c 100644 +--- a/devices/gdevpdfocr.c ++++ b/devices/gdevpdfocr.c +@@ -521,9 +521,12 @@ ocr_line32(gx_device_pdf_image *dev, void *row) + static int + ocr_begin_page(gx_device_pdf_image *dev, int w, int h, int bpp) + { +- int raster = (w+3)&~3; ++ int64_t raster = (w + 3) & ~3; + +- dev->ocr.data = gs_alloc_bytes(dev->memory, raster * h, "ocr_begin_page"); ++ raster = raster * (int64_t)h; ++ if (raster < 0 || raster > max_size_t) ++ return gs_note_error(gs_error_VMerror); ++ dev->ocr.data = gs_alloc_bytes(dev->memory, raster, "ocr_begin_page"); + if (dev->ocr.data == NULL) + return_error(gs_error_VMerror); + dev->ocr.w = w; diff --git a/debian/patches/CVE-2025-59801.patch b/debian/patches/CVE-2025-59801.patch new file mode 100644 index 0000000..bd49abb --- /dev/null +++ b/debian/patches/CVE-2025-59801.patch @@ -0,0 +1,26 @@ +Description: CVE-2025-59801 - 安全修复 +Author: Ken Sharp +Origin: https://github.com/ArtifexSoftware/ghostpdl/commit/99727069197d548a8db69ba5d63f766bff40eaab +Bug: https://nvd.nist.gov/vuln/detail/CVE-2025-59801 +Last-Update: 2025-09-09 +--- +diff --git a/xps/xpstiff.c b/xps/xpstiff.c +index 484ed5b3a..83cb913d1 100644 +--- a/xps/xpstiff.c ++++ b/xps/xpstiff.c +@@ -1175,6 +1175,15 @@ xps_decode_tiff(xps_context_t *ctx, byte *buf, int len, xps_image_t *image) + if (tiff->rowsperstrip > tiff->imagelength) + tiff->rowsperstrip = tiff->imagelength; + ++ if (tiff->bitspersample != 1 && tiff->bitspersample != 4 && tiff->bitspersample != 8 && tiff->bitspersample != 16) ++ return gs_rethrow(error, "Illegal BitsPerSample in TIFF header"); ++ ++ if (tiff->samplesperpixel != 1 && tiff->samplesperpixel != 3 && tiff->samplesperpixel != 4 && tiff->samplesperpixel != 5) ++ return gs_rethrow(error, "Illegal SamplesPerPixel in TIFF header"); ++ ++ if (tiff->compression < 1 || (tiff->compression > 5 && (tiff->compression != 7 && tiff->compression != 32773))) ++ return gs_rethrow(error, "Illegal Compression in TIFF header"); ++ + error = xps_decode_tiff_strips(ctx, tiff, image); + if (error) + return gs_rethrow(error, "could not decode image data"); diff --git a/debian/patches/series b/debian/patches/series index 2d3f9ca..760d327 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -14,3 +14,13 @@ 2010_add_build_timestamp_setting.patch 2011_disable_google_analytics.patch 2012_additional_gcc_15_fixes.patch +CVE-2010-1628.patch +CVE-2017-9619.patch +CVE-2018-17183.patch +CVE-2017-7948.patch +CVE-2025-59801.patch +CVE-2025-59799.patch +CVE-2025-59798.patch +CVE-2018-16539.patch +CVE-2025-59800.patch +CVE-2017-8908.patch