[gs-cvs] gs/src

Igor Melichev igor at ghostscript.com
Thu May 13 04:40:21 PDT 2004


Update of /cvs/ghostscript/gs/src
In directory casper:/tmp/cvs-serv8810/gs/src

Modified Files:
	gxshade1.c gxshade6.c gxshade4.h 
Log Message:
A new implementation of shadings, step 74.

DETAILS :

In the enabled code :

1. Non-linear color quadrangles are subdivided into quadrangles.
   This complies the color approximation with the specified smoothness.
2. Skipped quadrangles and triangles outside the clipping area.
3. Fixed the 'midpoint' formula. It was wrong and coused excessive subdivision.

In the disabled code (NEW_RADIAL_SHADINGS 0 in gxshade4.h) :

1. Debugged Extensions.
2. mesh_padding and wedges with zero length sides were tested.
3. Skipped painting outside the clipping area.
4. Optimized for constant color.

Known problems left :
1. With self-intersecting patches, outer wedges may paint in a wrong order.
This can cause such dropout that a lower part of the patch penetrates
through the upper part in single pixels.

EXPECTED DIFFERENCES :

"442-01.ps"
"446-01.ps"
"464-01.ps"
"483-01.ps"
"483-05-fixed.ps"
"483-05.ps"
"chilis_black.pdf"
"Clarke Tate Manns Chinese.ai"
"gradmesh.ai"
"Openhuis_pdf_zw.pdf"
"self-intersect2.ps"
"SmoothShading.pdf"
"STEUER-RollingMesh 1(linear).ai"
"STEUER-RollingMesh 3(Final).ai"
"Testform.v1.0.2.pdf"


Index: gxshade1.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxshade1.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- a/gxshade1.c	12 May 2004 21:33:40 -0000	1.30
+++ b/gxshade1.c	13 May 2004 11:40:17 -0000	1.31
@@ -917,6 +917,8 @@
     double d = hypot(dx, dy);
     gs_point p0, p1, pc0, pc1;
     int k, j, code;
+    bool inside = 0;
+
     pc0.x = x0, pc0.y = y0; 
     pc1.x = x1, pc1.y = y1;
     if (r0 + d <= r1 || r1 + d <= r0) {
@@ -924,6 +926,8 @@
 	   Use any subdivision, 
 	   but don't depend on dx, dy, which may be too small. */
 	p0.x = 0, p0.y = -1;
+	/* Align stripes along radii for faster triangulation : */
+	inside = 1;
     } else {
         /* Must generate canonic quadrangle arcs,
 	   because we approximate them with curves. */
@@ -939,7 +943,8 @@
 		p0.x = -1, p0.y = 0;
 	}
     }
-    /* fixme: wish: cut invisible parts off. */
+    /* fixme: wish: cut invisible parts off. 
+       Note : when r0 != r1 the invisible part is not a half circle. */
     for (k = 0; k < 4; k++, p0 = p1) {
 	gs_point p[12];
 	patch_curve_t curve[4];
@@ -960,24 +965,27 @@
 	p[10].y = (p[9].y * 2 + p[0].y) / 3;
 	p[11].x = (p[9].x + p[0].x * 2) / 3;
 	p[11].y = (p[9].y + p[0].y * 2) / 3;
-	/* fixme : truncate by 'rect'. */
 	for (j = 0; j < 4; j++) {
+	    int jj = (j + inside) % 4;
+
 	    code = gs_point_transform2fixed(&pfs->pis->ctm, 
-			p[j * 3 + 0].x, p[j * 3 + 0].y, &curve[j].vertex.p);
+			p[j * 3 + 0].x, p[j * 3 + 0].y, &curve[jj].vertex.p);
 	    if (code < 0)
 		return code;
 	    code = gs_point_transform2fixed(&pfs->pis->ctm, 
-			p[j * 3 + 1].x, p[j * 3 + 1].y, &curve[j].control[0]);
+			p[j * 3 + 1].x, p[j * 3 + 1].y, &curve[jj].control[0]);
 	    if (code < 0)
 		return code;
 	    code = gs_point_transform2fixed(&pfs->pis->ctm, 
-			p[j * 3 + 2].x, p[j * 3 + 2].y, &curve[j].control[1]);
+			p[j * 3 + 2].x, p[j * 3 + 2].y, &curve[jj].control[1]);
 	    if (code < 0)
 		return code;
 	}
 #	if NEW_RADIAL_SHADINGS
-	    curve[0].vertex.cc[0] = curve[1].vertex.cc[0] = t0;
-	    curve[2].vertex.cc[0] = curve[3].vertex.cc[0] = t1;
+	    curve[(0 + inside) % 4].vertex.cc[0] = t0;
+	    curve[(1 + inside) % 4].vertex.cc[0] = t0;
+	    curve[(2 + inside) % 4].vertex.cc[0] = t1;
+	    curve[(3 + inside) % 4].vertex.cc[0] = t1;
 #	else
 	    curve[0].vertex.cc[0] = curve[1].vertex.cc[0] = 0; /* stub. */
 	    curve[2].vertex.cc[0] = curve[3].vertex.cc[0] = 0; /* stub. */
@@ -998,7 +1006,6 @@
 	double x1, double y1, double r1, 
 	double *x2, double *y2, double *r2)
 {
-    double ax, ay, a0, a1;
     double dx = x1 - x0, dy = y1 - y0;
     double sp, sq, s;
 
@@ -1087,7 +1094,7 @@
     double dx0 = p0->x - ax, dy0 = p0->y - ay;
     double dx1 = p1->x - ax, dy1 = p1->y - ay;
     double dx = p->x - ax, dy = p->y - ay;
-    double vp0 = dx * dy0 - dy * dx0;
+    double vp0 = dx0 * dy - dy0 * dx;
     double vp1 = dx * dy1 - dy * dx1;
 
     return vp0 >= 0 && vp1 >= 0;
@@ -1112,12 +1119,12 @@
     ax = x0 + (x1 - x0) * as;
     ay = y0 + (y1 - y0) * as;
 
-    if (any_abs(d - dr) < 1e-7) {
+    if (any_abs(d - dr) < 1e-7 * (d + dr)) {
 	/* Nearly degenerate, replace with half-plane. */
 	p0.x = ax - dy * r / d;
-	p0.y = ax + dx * r / d;
+	p0.y = ay + dx * r / d;
 	p1.x = ax + dy * r / d;
-	p1.y = ax - dx * r / d;
+	p1.y = ay - dx * r / d;
     } else {
 	/* Tangent limits by proportional triangles. */
 	double da = hypot(ax - x0, ay - y0);
@@ -1125,10 +1132,10 @@
 
 	assert(h <= r);
 	g = sqrt(r * r - h * h);
-	p0.x = ax - dy * h / d;
-	p0.y = ax + dx * g / d;
-	p0.x = ax + dy * h / d;
-	p0.y = ax - dx * g / d;
+	p0.x = ax - dx * g / d - dy * h / d;
+	p0.y = ay - dy * g / d + dx * h / d;
+	p1.x = ax - dx * g / d + dy * h / d;
+	p1.y = ay - dy * g / d - dx * h / d;
     }
     /* Now we have 2 limited tangents, and 4 corners of the rect. 
        Need to know what corners are covered. */
@@ -1171,8 +1178,21 @@
 }
 
 private int
+R_tensor_cone_apex(patch_fill_state_t *pfs, const gs_rect *rect,
+	double x0, double y0, double r0, 
+	double x1, double y1, double r1, double t)
+{
+    double as = r0 / (r0 - r1);
+    double ax = x0 + (x1 - x0) * as;
+    double ay = y0 + (y1 - y0) * as;
+
+    return R_tensor_annulus(pfs, rect, x1, y1, r1, t, ax, ay, 0, t);
+}
+
+
+private int
 R_extensions(patch_fill_state_t *pfs, const gs_shading_R_t *psh, const gs_rect *rect, 
-	double t0, double t1)
+	double t0, double t1, bool Extend0, bool Extend1)
 {
     float x0 = psh->params.Coords[0], y0 = psh->params.Coords[1];
     floatp r0 = psh->params.Coords[2];
@@ -1182,65 +1202,69 @@
     double d = hypot(dx, dy), r;
     int code;
 
-    if (dr >= d) {
+    if (dr >= d - 1e-7 * (d + dr)) {
 	/* Nested circles, or degenerate. */
 	if (r0 > r1) {
-	    if (psh->params.Extend[0]) {
+	    if (Extend0) {
 		r = R_rect_radius(rect, x0, y0);
-		code = R_tensor_annulus(pfs, rect, x0, y0, r, t0, x0, y0, r0, t0);
-		if (code < 0)
-		    return code;
+		if (r > r0) {
+		    code = R_tensor_annulus(pfs, rect, x0, y0, r, t0, x0, y0, r0, t0);
+		    if (code < 0)
+			return code;
+		}
 	    }
-	    if (psh->params.Extend[1])
+	    if (Extend1 && r1 > 0)
 		return R_tensor_annulus(pfs, rect, x1, y1, r1, t1, x1, y1, 0, t1);
 	} else {
-	    if (psh->params.Extend[1]) {
+	    if (Extend1) {
 		r = R_rect_radius(rect, x1, y1);
-		code = R_tensor_annulus(pfs, rect, x1, y1, r, t1, x1, y1, r1, t1);
-		if (code < 0)
-		    return code;
+		if (r > r1) {
+		    code = R_tensor_annulus(pfs, rect, x1, y1, r, t1, x1, y1, r1, t1);
+		    if (code < 0)
+			return code;
+		}
 	    }
-	    if (psh->params.Extend[0])
+	    if (Extend0 && r0 > 0)
 		return R_tensor_annulus(pfs, rect, x0, y0, r0, t0, x0, y0, 0, t0);
 	}
     } else if (dr > d / 3) {
 	/* Obtuse cone. */
 	if (r0 > r1) {
-	    if (psh->params.Extend[0]) {
+	    if (Extend0) {
 		r = R_rect_radius(rect, x0, y0);
 		code = R_obtuse_cone(pfs, rect, x0, y0, r0, x1, y1, r1, t0, r);
 		if (code < 0)
 		    return code;
 	    }
-	    if (psh->params.Extend[1] && r1 != 0)
-		return R_tensor_annulus(pfs, rect, x1, y1, r1, t1, x1, y1, 0, t1);
+	    if (Extend1 && r1 != 0)
+		return R_tensor_cone_apex(pfs, rect, x0, y0, r0, x1, y1, r1, t1);
 	    return 0;
 	} else {
-	    if (psh->params.Extend[1]) {
+	    if (Extend1) {
 		r = R_rect_radius(rect, x1, y1);
 		code = R_obtuse_cone(pfs, rect, x1, y1, r1, x0, y0, r0, t1, r);
 		if (code < 0)
 		    return code;
 	    }
-	    if (psh->params.Extend[0] && r0 != 0)
-		return R_tensor_annulus(pfs, rect, x0, y0, r0, t0, x0, y0, 0, t0);
+	    if (Extend0 && r0 != 0)
+		return R_tensor_cone_apex(pfs, rect, x1, y1, r1, x0, y0, r0, t0);
 	}
     } else {
 	/* Acute cone or cylinder. */
 	double x2, y2, r2, x3, y3, r3;
 
-	if (psh->params.Extend[0]) {
-	    R_outer_circle(pfs, rect, x0, y0, r0, x1, y1, r1, &x2, &y2, &r2);
-	    if (x2 != x0 || y2 != y0) {
-		code = R_tensor_annulus(pfs, rect, x1, y1, r1, t1, x2, y2, r2, t1);
+	if (Extend0) {
+	    R_outer_circle(pfs, rect, x1, y1, r1, x0, y0, r0, &x3, &y3, &r3);
+	    if (x3 != x1 || y3 != y1) {
+		code = R_tensor_annulus(pfs, rect, x0, y0, r0, t0, x3, y3, r3, t0);
 		if (code < 0)
 		    return code;
 	    }
 	}
-	if (psh->params.Extend[1]) {
-	    R_outer_circle(pfs, rect, x1, y1, r1, x0, y0, r0, &x3, &y3, &r3);
-	    if (x3 != x1 || y3 != y1) {
-		code = R_tensor_annulus(pfs, rect, x0, y0, r0, t0, x3, y3, r3, t0);
+	if (Extend1) {
+	    R_outer_circle(pfs, rect, x0, y0, r0, x1, y1, r1, &x2, &y2, &r2);
+	    if (x2 != x0 || y2 != y0) {
+		code = R_tensor_annulus(pfs, rect, x1, y1, r1, t1, x2, y2, r2, t1);
 		if (code < 0)
 		    return code;
 	    }
@@ -1414,7 +1438,7 @@
 	shade_bbox_transform2fixed(rect, pis, &pfs1.rect);
 	pfs1.maybe_self_intersecting = false;
 
-	code = R_extensions(&pfs1, psh, rect, t[0], t[1]);
+	code = R_extensions(&pfs1, psh, rect, t[0], t[1], psh->params.Extend[0], false);
 	if (code < 0)
 	    return code;
 	{
@@ -1424,7 +1448,10 @@
 	    floatp r1 = psh->params.Coords[5];
 	    
 	    code = R_tensor_annulus(&pfs1, rect, x0, y0, r0, t[0], x1, y1, r1, t[1]);
+	    if (code < 0)
+		return code;
 	}
+	code = R_extensions(&pfs1, psh, rect, t[0], t[1], false, psh->params.Extend[1]);
     } else {
 	/*
 	    For a faster painting, we apply fill adjustment to outer annula only.

Index: gxshade6.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxshade6.c,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -d -r1.69 -r1.70
--- a/gxshade6.c	12 May 2004 21:33:40 -0000	1.69
+++ b/gxshade6.c	13 May 2004 11:40:18 -0000	1.70
@@ -153,6 +153,7 @@
     pfs->vectorization = false; /* A stub for a while. Will use with pclwrite. */
     pfs->maybe_self_intersecting = true;
     pfs->monotonic_color = (pfs->Function == NULL);
+    pfs->inside = false;
     pfs->n_color_args = 1;
     pfs->fixed_flat = float2fixed(pfs->pis->flatness);
     pfs->smoothness = pfs->pis->smoothness;
@@ -1362,23 +1363,28 @@
 private inline bool
 is_color_linear(const patch_fill_state_t *pfs, const patch_color_t *c0, const patch_color_t *c1)
 {
-    gs_direct_color_space *cs = 
-		(gs_direct_color_space *)pfs->direct_space; /* break 'const'. */
-    int code;
-    float smoothness = max(pfs->smoothness, 1.0 / min_linear_grades);
-    /* Restrict the smoothness with 1/min_linear_grades, because cs_is_linear
-       can't provide a better precision due to the color
-       representation with integers.
-     */
-    float s = function_linearity(pfs, c0, c1);
 
-    if (s > smoothness)
-	return false;
-    code = cs_is_linear(cs, pfs->pis, pfs->dev, 
-	    &c0->cc, &c1->cc, NULL, NULL, smoothness - s);
-    if (code <= 0)
-	return false;
-    return true;
+    if (pfs->unlinear)
+	return true; /* Disable this check. */
+    else {
+	gs_direct_color_space *cs = 
+		    (gs_direct_color_space *)pfs->direct_space; /* break 'const'. */
+	int code;
+	float smoothness = max(pfs->smoothness, 1.0 / min_linear_grades);
+	/* Restrict the smoothness with 1/min_linear_grades, because cs_is_linear
+	   can't provide a better precision due to the color
+	   representation with integers.
+	 */
+	float s = function_linearity(pfs, c0, c1);
+
+	if (s > smoothness)
+	    return false;
+	code = cs_is_linear(cs, pfs->pis, pfs->dev, 
+		&c0->cc, &c1->cc, NULL, NULL, smoothness - s);
+	if (code <= 0)
+	    return false;
+	return true;
+    }
 }
 
 private int
@@ -1402,52 +1408,51 @@
 	bool monotonic_color_save = pfs->monotonic_color;
 
 	if (!pfs->monotonic_color)
-	    pfs->monotonic_color = is_color_monotonic(pfs, c0, c1);
+	    pfs->monotonic_color = is_color_monotonic(pfs, c0, c1) &&
+				   is_color_linear(pfs, c0, c1);
 	if (!pfs->unlinear && pfs->monotonic_color) {
-	    if (is_color_linear(pfs, c0, c1)) {
-		gx_device *pdev = pfs->dev;
-		frac31 fc[2][GX_DEVICE_COLOR_MAX_COMPONENTS];
-		gs_fill_attributes fa;
-		gx_device_color dc[2];
-		gs_fixed_rect clip;
-		int code;
+	    gx_device *pdev = pfs->dev;
+	    frac31 fc[2][GX_DEVICE_COLOR_MAX_COMPONENTS];
+	    gs_fill_attributes fa;
+	    gx_device_color dc[2];
+	    gs_fixed_rect clip;
+	    int code;
 
-		clip = pfs->rect;
-		if (swap_axes) {
-		    fixed v;
+	    clip = pfs->rect;
+	    if (swap_axes) {
+		fixed v;
 
-		    v = clip.p.x; clip.p.x = clip.p.y; clip.p.y = v;
-		    v = clip.q.x; clip.q.x = clip.q.y; clip.q.y = v;
-		}
-		clip.p.y = max(clip.p.y, ybot);
-		clip.q.y = min(clip.q.y, ytop);
-		fa.clip = &clip; 
-		fa.ht = NULL;
-		fa.swap_axes = swap_axes;
-		fa.lop = 0;
-		fa.ystart = ybot;
-		fa.yend = ytop;
-		code = patch_color_to_device_color(pfs, c0, &dc[0]);
+		v = clip.p.x; clip.p.x = clip.p.y; clip.p.y = v;
+		v = clip.q.x; clip.q.x = clip.q.y; clip.q.y = v;
+	    }
+	    clip.p.y = max(clip.p.y, ybot);
+	    clip.q.y = min(clip.q.y, ytop);
+	    fa.clip = &clip; 
+	    fa.ht = NULL;
+	    fa.swap_axes = swap_axes;
+	    fa.lop = 0;
+	    fa.ystart = ybot;
+	    fa.yend = ytop;
+	    code = patch_color_to_device_color(pfs, c0, &dc[0]);
+	    if (code < 0)
+		return code;
+	    if (dc[0].type == &gx_dc_type_data_pure) {
+		dc2fc(pfs, dc[0].colors.pure, fc[0]);
+		code = patch_color_to_device_color(pfs, c1, &dc[1]);
 		if (code < 0)
 		    return code;
-		if (dc[0].type == &gx_dc_type_data_pure) {
-		    dc2fc(pfs, dc[0].colors.pure, fc[0]);
-		    code = patch_color_to_device_color(pfs, c1, &dc[1]);
-		    if (code < 0)
-			return code;
-		    dc2fc(pfs, dc[1].colors.pure, fc[1]);
-		    code = dev_proc(pdev, fill_linear_color_trapezoid)(pdev, &fa, 
-				    &le->start, &le->end, &re->start, &re->end, 
-				    fc[0], fc[1], NULL, NULL);
-		    if (code == 1) {
-			pfs->monotonic_color = monotonic_color_save;
-			return 0; /* The area is filled. */
-		    }
-		    if (code < 0)
-			return code;
-		    else /* code == 0, the device requested to decompose the area. */ 
-			return_error(gs_error_unregistered); /* Must not happen. */
+		dc2fc(pfs, dc[1].colors.pure, fc[1]);
+		code = dev_proc(pdev, fill_linear_color_trapezoid)(pdev, &fa, 
+				&le->start, &le->end, &re->start, &re->end, 
+				fc[0], fc[1], NULL, NULL);
+		if (code == 1) {
+		    pfs->monotonic_color = monotonic_color_save;
+		    return 0; /* The area is filled. */
 		}
+		if (code < 0)
+		    return code;
+		else /* code == 0, the device requested to decompose the area. */ 
+		    return_error(gs_error_unregistered); /* Must not happen. */
 	    }
 	}
 	if (!pfs->monotonic_color || !pfs->unlinear ||
@@ -1538,7 +1543,8 @@
 split_curve_s(const gs_fixed_point *pole, gs_fixed_point *q0, gs_fixed_point *q1, int pole_step)
 {
     /*	This copies a code fragment from split_curve_midpoint,
-        substituting another data type.
+        substituting another data type. 
+	Also fixed a bug in the macro "midpoint".
      */				
     /*
      * We have to define midpoint carefully to avoid overflow.
@@ -1546,7 +1552,7 @@
      * on, but we could get infinite recursion that way....)
      */
 #define midpoint(a,b)\
-  (arith_rshift_1(a) + arith_rshift_1(b) + ((a) & (b) & 1) + 1)
+  (arith_rshift_1(a) + arith_rshift_1(b) + (((a) | (b)) & 1))
     fixed x12 = midpoint(pole[1 * pole_step].x, pole[2 * pole_step].x);
     fixed y12 = midpoint(pole[1 * pole_step].y, pole[2 * pole_step].y);
 
@@ -2517,7 +2523,7 @@
     code = is_color_linear(pfs, &p->c[0][1], &p->c[1][1]);
     if (code <= 0)
 	return false;
-    return 1;
+    return true;
 }
 
 private inline bool
@@ -2581,6 +2587,45 @@
     patch_interpolate_color(&p->c, &p0->c, &p1->c, pfs, (double)(radix - 1) / radix);
 }
 
+private inline void
+bbox_of_points(gs_fixed_rect *r, 
+	const gs_fixed_point *p0, const gs_fixed_point *p1,
+	const gs_fixed_point *p2, const gs_fixed_point *p3)
+{
+    r->p.x = r->q.x = p0->x;
+    r->p.y = r->q.y = p0->y;
+
+    if (r->p.x > p1->x)
+	r->p.x = p1->x;
+    if (r->q.x < p1->x)
+	r->q.x = p1->x;
+    if (r->p.y > p1->y)
+	r->p.y = p1->y;
+    if (r->q.y < p1->y)
+	r->q.y = p1->y;
+
+    if (r->p.x > p2->x)
+	r->p.x = p2->x;
+    if (r->q.x < p2->x)
+	r->q.x = p2->x;
+    if (r->p.y > p2->y)
+	r->p.y = p2->y;
+    if (r->q.y < p2->y)
+	r->q.y = p2->y;
+
+    if (p3 == NULL)
+	return;
+
+    if (r->p.x > p3->x)
+	r->p.x = p3->x;
+    if (r->q.x < p3->x)
+	r->q.x = p3->x;
+    if (r->p.y > p3->y)
+	r->p.y = p3->y;
+    if (r->q.y < p3->y)
+	r->q.y = p3->y;
+}
+
 private int 
 triangle_by_4(patch_fill_state_t *pfs, 
 	const shading_vertex_t *p0, const shading_vertex_t *p1, const shading_vertex_t *p2, 
@@ -2589,8 +2634,17 @@
 {
     shading_vertex_t p01, p12, p20;
     wedge_vertex_list_t L01, L12, L20, L[3];
+    bool inside_save = pfs->inside;
+    gs_fixed_rect r, r1;
     int code;
     
+    if (!pfs->inside) {
+	bbox_of_points(&r, &p0->p, &p1->p, &p2->p, NULL);
+	r1 = r;
+	rect_intersect(r, pfs->rect);
+	if (r.q.x <= r.p.x || r.q.y <= r.p.y)
+	    return 0; /* Outside. */
+    }
     code = try_device_linear_color(pfs, false, p0, p1, p2);
     switch(code) {
 	case 0: /* The area is filled. */
@@ -2617,6 +2671,11 @@
 	default: /* Error. */
 	    return code;
     }
+    if (!pfs->inside) {
+	if (r.p.x == r1.p.x && r.p.y == r1.p.y && 
+	    r.q.x == r1.q.x && r.q.y == r1.q.y)
+	    pfs->inside = true;
+    }
     divide_bar(pfs, p0, p1, 2, &p01);
     divide_bar(pfs, p1, p2, 2, &p12);
     divide_bar(pfs, p2, p0, 2, &p20);
@@ -2675,6 +2734,7 @@
 	if (code < 0)
 	    return code;
     }
+    pfs->inside = inside_save;
     return 0;
 }
 
@@ -2836,6 +2896,26 @@
     q->l1000 = &l[3];
 }
 
+private inline bool
+is_quadrangle_color_linear(const patch_fill_state_t *pfs, const quadrangle_patch *p)
+{
+    if (pfs->unlinear)
+	return true; /* Disable this check. */
+    if (!is_color_linear(pfs, &p->p[0][0]->c, &p->p[0][1]->c))
+	return false;
+    if (!is_color_linear(pfs, &p->p[1][0]->c, &p->p[1][1]->c))
+	return false;
+    if (!is_color_linear(pfs, &p->p[0][0]->c, &p->p[1][0]->c))
+	return false;
+    if (!is_color_linear(pfs, &p->p[0][1]->c, &p->p[1][1]->c))
+	return false;
+    if (!is_color_linear(pfs, &p->p[0][0]->c, &p->p[1][1]->c))
+	return false;
+    if (!is_color_linear(pfs, &p->p[0][1]->c, &p->p[1][0]->c))
+	return false;
+    return true;
+}
+
 typedef enum {
     color_change_small,
     color_change_gradient,
@@ -2858,12 +2938,11 @@
     D0111 = color_span(pfs, &p->p[0][1]->c, &p->p[1][1]->c);
     D0011 = color_span(pfs, &p->p[0][0]->c, &p->p[1][1]->c);
     D0110 = color_span(pfs, &p->p[0][1]->c, &p->p[1][0]->c);
-    if (pfs->unlinear)
+    if (pfs->unlinear) {
 	if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness &&
 	    D0010 <= pfs->smoothness && D0111 <= pfs->smoothness &&
 	    D0011 <= pfs->smoothness && D0110 <= pfs->smoothness)
 	    return color_change_small;
-    if (pfs->unlinear) {
 	if (D0001 <= pfs->smoothness && D1011 <= pfs->smoothness) {
 	    *uv = false;
 	    return color_change_gradient;
@@ -2875,10 +2954,12 @@
     }
     color_diff(pfs, &d0001, &d1011, &d);
     D = color_norm(pfs, &d);
-    if (D <= pfs->smoothness)
-	return color_change_linear;
     Du = max(D0001, D1011);
     Dv = max(D0010, D0111);
+    if (Du <= pfs->smoothness / 8 && Dv <= pfs->smoothness / 8)
+	return color_change_small;
+    if (D <= pfs->smoothness)
+	return color_change_linear;
     *uv = Du > Dv;
     return color_change_general;
 }
@@ -2895,8 +2976,17 @@
     bool divide_u = false, divide_v = false, big1 = big;
     shading_vertex_t q[2];
     bool monotonic_color_save = pfs->monotonic_color;
+    bool inside_save = pfs->inside;
+    gs_fixed_rect r, r1;
     /* Warning : pfs->monotonic_color is not restored on error. */
 
+    if (!pfs->inside) {
+	bbox_of_points(&r, &p->p[0][0]->p, &p->p[0][1]->p, &p->p[1][0]->p, &p->p[1][1]->p);
+	r1 = r;
+	rect_intersect(r, pfs->rect);
+	if (r.q.x <= r.p.x || r.q.y <= r.p.y)
+	    return 0; /* Outside. */
+    }
     if (big) {
 	/* Likely 'big' is an unuseful rudiment due to curve_samples
 	   restricts lengthes. We keep it for a while because its implementation 
@@ -2943,7 +3033,8 @@
 			constant_color_quadrangle : triangles)(pfs, p, 
 			    pfs->maybe_self_intersecting);
 	if (!pfs->monotonic_color)
-	    pfs->monotonic_color = is_quadrangle_color_monotonic(pfs, p, &color_u);
+	    pfs->monotonic_color = is_quadrangle_color_monotonic(pfs, p, &color_u)
+				&& is_quadrangle_color_linear(pfs, p);
 	if (!pfs->monotonic_color) {
 	    /* go to divide. */
 	} else switch(quadrangle_color_change(pfs, p, &color_u)) {
@@ -2967,6 +3058,11 @@
 	    divide_v = is_big_v; /* Unused. Just for a clarity. */
 	}
     }
+    if (!pfs->inside) {
+	if (r.p.x == r1.p.x && r.p.y == r1.p.y && 
+	    r.q.x == r1.q.x && r.q.y == r1.q.y)
+	    pfs->inside = true;
+    }
     if (LAZY_WEDGES)
 	init_wedge_vertex_list(&l0, 1);
     if (divide_v) {
@@ -3047,6 +3143,7 @@
 	}
     }
     pfs->monotonic_color = monotonic_color_save;
+    pfs->inside = inside_save;
     return code;
 }
 

Index: gxshade4.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxshade4.h,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- a/gxshade4.h	12 May 2004 21:33:40 -0000	1.33
+++ b/gxshade4.h	13 May 2004 11:40:18 -0000	1.34
@@ -115,6 +115,7 @@
     bool maybe_self_intersecting;
     bool monotonic_color;
     bool unlinear;
+    bool inside;
 #endif
 } patch_fill_state_t;
 #endif



More information about the gs-cvs mailing list