[gs-cvs] rev 7983 - in branches/gs-esp-gpl-merger: lib src
till at ghostscript.com
till at ghostscript.com
Wed May 16 15:16:07 PDT 2007
Author: till
Date: 2007-05-16 15:16:06 -0700 (Wed, 16 May 2007)
New Revision: 7983
Modified:
branches/gs-esp-gpl-merger/lib/pdf_font.ps
branches/gs-esp-gpl-merger/lib/pdf_main.ps
branches/gs-esp-gpl-merger/src/gxshade1.c
Log:
Merged in changes from trunk up to rev 7982.
Modified: branches/gs-esp-gpl-merger/lib/pdf_font.ps
===================================================================
--- branches/gs-esp-gpl-merger/lib/pdf_font.ps 2007-05-16 21:04:35 UTC (rev 7982)
+++ branches/gs-esp-gpl-merger/lib/pdf_font.ps 2007-05-16 22:16:06 UTC (rev 7983)
@@ -855,11 +855,10 @@
% filepos fontres stream
1 index /FontDescriptor oget % filepos fontres stream fd
/Flags get 4 and 0 ne % filepos fontres stream is_symbolic
- dup {
- 2 index null exch getencoding % filepos fontres stream is_symbolic Encoding
- } {
- 2 index StandardEncoding exch getencoding
- } ifelse
+ dup { //null } { StandardEncoding } ifelse
+ 3 index /Encoding known {
+ 3 index getencoding
+ } if % filepos fontres stream is_symbolic Encoding
dup 4 index exch % filepos fontres stream is_symbolic Encoding fontres Encoding
/prebuilt_encoding exch put % filepos fontres stream is_symbolic Encoding
.loadpdfttfont
Modified: branches/gs-esp-gpl-merger/lib/pdf_main.ps
===================================================================
--- branches/gs-esp-gpl-merger/lib/pdf_main.ps 2007-05-16 21:04:35 UTC (rev 7982)
+++ branches/gs-esp-gpl-merger/lib/pdf_main.ps 2007-05-16 22:16:06 UTC (rev 7983)
@@ -1598,9 +1598,7 @@
% device supports OutputIntent parameter
Trailer /Root oget /OutputIntents knownoget {
{ % process all output profiles present
- dup xcheck {
- exec
- } if
+ oforce
dup length dict .copydict
dup /DestOutputProfile knownoget {
PDFfile fileposition exch
Modified: branches/gs-esp-gpl-merger/src/gxshade1.c
===================================================================
--- branches/gs-esp-gpl-merger/src/gxshade1.c 2007-05-16 21:04:35 UTC (rev 7982)
+++ branches/gs-esp-gpl-merger/src/gxshade1.c 2007-05-16 22:16:06 UTC (rev 7983)
@@ -639,7 +639,364 @@
return 0;
}
+typedef struct radial_shading_attrs_s {
+ double x0, y0;
+ double x1, y1;
+ double span[2][2];
+ double apex;
+ bool have_apex;
+ bool have_root[2]; /* ongoing contact, outgoing contact. */
+ bool outer_contact[2];
+ gs_point p[6]; /* 4 corners of the rectangle, p[4] = p[0], p[5] = p[1] */
+} radial_shading_attrs_t;
+
+#define Pw2(a) ((a)*(a))
+
+private void
+radial_shading_external_contact(radial_shading_attrs_t *rsa, int point_index, double t, double r0, double r1, bool at_corner, int root_index)
+{
+ double cx = rsa->x0 + (rsa->x1 - rsa->x0) * t;
+ double cy = rsa->y0 + (rsa->y1 - rsa->y0) * t;
+ double rx = rsa->p[point_index].x - cx;
+ double ry = rsa->p[point_index].y - cy;
+ double dx = rsa->p[point_index - 1].x - rsa->p[point_index].x;
+ double dy = rsa->p[point_index - 1].y - rsa->p[point_index].y;
+
+ if (at_corner) {
+ double Dx = rsa->p[point_index + 1].x - rsa->p[point_index].x;
+ double Dy = rsa->p[point_index + 1].y - rsa->p[point_index].y;
+ bool b1 = (dx * rx + dy * ry >= 0);
+ bool b2 = (Dx * rx + Dy * ry >= 0);
+
+ if (b1 & b2)
+ rsa->outer_contact[root_index] = true;
+ } else {
+ if (rx * dy - ry * dx < 0)
+ rsa->outer_contact[root_index] = true;
+ }
+}
+
+private void
+store_roots(radial_shading_attrs_t *rsa, const bool have_root[2], const double t[2], double r0, double r1, int point_index, bool at_corner)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ bool good_root;
+
+ if (!have_root[i])
+ continue;
+ good_root = (!rsa->have_apex || (rsa->apex <= 0 || r0 == 0 ? t[i] >= rsa->apex : t[i] <= rsa->apex));
+ if (good_root) {
+ radial_shading_external_contact(rsa, point_index, t[i], r0, r1, at_corner, i);
+ if (!rsa->have_root[i]) {
+ rsa->span[i][0] = rsa->span[i][1] = t[i];
+ rsa->have_root[i] = true;
+ } else {
+ if (rsa->span[i][0] > t[i])
+ rsa->span[i][0] = t[i];
+ if (rsa->span[i][1] < t[i])
+ rsa->span[i][1] = t[i];
+ }
+ }
+ }
+}
+
+private void
+compute_radial_shading_span_extended_side(radial_shading_attrs_t *rsa, double r0, double r1, int point_index)
+{
+ double cc, c;
+ bool have_root[2] = {false, false};
+ double t[2];
+ bool by_x = (rsa->p[point_index].x == rsa->p[point_index + 1].x);
+ int i;
+
+ /* Assuming x0 = y0 = 0 :
+ cc * t +- (r0 + (r1 - r0) * t) == c
+ t0 := (c - r0) / (cc + (r1 - r0))
+ t1 := (c + r0) / (cc - (r1 - r0))
+ */
+
+ if (by_x) {
+ c = rsa->p[point_index].x - rsa->x0;
+ cc = rsa->x1 - rsa->x0;
+ } else {
+ c = rsa->p[point_index].y - rsa->y0;
+ cc = rsa->y1 - rsa->y0;
+ }
+ t[0] = (c - r0) / (cc + r1 - r0);
+ t[1] = (c + r0) / (cc - r1 + r0);
+ if (t[0] > t[1]) {
+ t[0] = t[1];
+ t[1] = (c - r0) / (cc + r1 - r0);
+ }
+ for (i = 0; i < 2; i++) {
+ double d, d0, d1;
+
+ if (by_x) {
+ d = rsa->y1 - rsa->y0 + r0 + (r1 - r0) * t[i];
+ d0 = rsa->p[point_index].y;
+ d1 = rsa->p[point_index + 1].y;
+ } else {
+ d = rsa->x1 - rsa->x0 + r0 + (r1 - r0) * t[i];
+ d0 = rsa->p[point_index].x;
+ d1 = rsa->p[point_index + 1].x;
+ }
+ if (d1 > d0 ? d0 <= d && d <= d1 : d1 <= d && d <= d0)
+ have_root[i] = true;
+ }
+ store_roots(rsa, have_root, t, r0, r1, point_index, false);
+}
+
private int
+compute_radial_shading_span_extended_point(radial_shading_attrs_t *rsa, double r0, double r1, int point_index)
+{
+ double p1x = rsa->x1 - rsa->x0;
+ double p1y = rsa->y1 - rsa->y0;
+ double qx = rsa->p[point_index].x - rsa->x0;
+ double qy = rsa->p[point_index].y - rsa->y0;
+ double div = (Pw2(p1x) + Pw2(p1y) - Pw2(r0 - r1));
+ bool have_root[2] = {false, false};
+ double t[2];
+
+ if (fabs(div) < 1e-8) {
+ /* Linear equation. */
+ /* This case is always the ongoing eclipese contact. */
+ double cx = rsa->x0 - (rsa->x1 - rsa->x0) * r0 / (r1 - r0);
+ double cy = rsa->y0 - (rsa->y1 - rsa->y0) * r0 / (r1 - r0);
+
+ t[0] = (Pw2(qx) + Pw2(qy))/(cx*qx + cy*qy) / 2;
+ have_root[0] = true;
+ } else {
+ /* Square equation. */
+ double desc2 = -((Pw2(qx) + Pw2(qy) - Pw2(r0))*(Pw2(p1x) + Pw2(p1y) - Pw2(r0 - r1))) + Pw2(p1x*qx + p1y*qy + r0*(-r0 + r1));
+
+ if (desc2 < 0) {
+ return -1; /* The point is outside the shading coverage.
+ Do not shorten, because we didn't observe it in practice. */
+ } else {
+ double desc1 = sqrt(desc2);
+
+ if (div > 0) {
+ t[0] = (p1x*qx + p1y*qy + r0*(-r0 + r1) - desc1) / div;
+ t[1] = (p1x*qx + p1y*qy + r0*(-r0 + r1) + desc1) / div;
+ } else {
+ t[0] = (p1x*qx + p1y*qy + r0*(-r0 + r1) + desc1) / div;
+ t[1] = (p1x*qx + p1y*qy + r0*(-r0 + r1) - desc1) / div;
+ }
+ have_root[0] = have_root[1] = true;
+ }
+ }
+ store_roots(rsa, have_root, t, r0, r1, point_index, true);
+ if (have_root[0] && have_root[1])
+ return 15;
+ if (have_root[0])
+ return 15 - 4;
+ if (have_root[1])
+ return 15 - 2;
+ return -1;
+}
+
+#undef Pw2
+
+private int
+compute_radial_shading_span_extended(radial_shading_attrs_t *rsa, double r0, double r1)
+{
+ int span_type0, span_type1;
+
+ span_type0 = compute_radial_shading_span_extended_point(rsa, r0, r1, 1);
+ if (span_type0 == -1)
+ return -1;
+ span_type1 = compute_radial_shading_span_extended_point(rsa, r0, r1, 2);
+ if (span_type0 != span_type1)
+ return -1;
+ span_type1 = compute_radial_shading_span_extended_point(rsa, r0, r1, 3);
+ if (span_type0 != span_type1)
+ return -1;
+ span_type1 = compute_radial_shading_span_extended_point(rsa, r0, r1, 4);
+ if (span_type0 != span_type1)
+ return -1;
+ compute_radial_shading_span_extended_side(rsa, r0, r1, 1);
+ compute_radial_shading_span_extended_side(rsa, r0, r1, 2);
+ compute_radial_shading_span_extended_side(rsa, r0, r1, 3);
+ compute_radial_shading_span_extended_side(rsa, r0, r1, 4);
+ return span_type0;
+}
+
+private int
+compute_radial_shading_span(radial_shading_attrs_t *rsa, float x0, float y0, floatp r0, float x1, float y1, floatp r1, const gs_rect * rect)
+{
+ /* If the shading area is much larger than the path bbox,
+ we want to shorten the shading for a faster rendering.
+ If any point of the path bbox falls outside the shading area,
+ our math is not applicable, and we render entire shading.
+ If the path bbox is inside the shading area,
+ we compute 1 or 2 'spans' - the shading parameter intervals,
+ which covers the bbox. For doing that we need to resolve
+ a square eqation by the shading parameter
+ for each corner of the bounding box,
+ and for each side of the shading bbox.
+ Note the equation to be solved in the user space.
+ Since each equation gives 2 roots (because the points are
+ strongly inside the shading area), we will get 2 parameter intervals -
+ the 'lower' one corresponds to the first (ongoing) contact of
+ the running circle, and the second one corresponds to the last (outgoing) contact
+ (like in a sun eclipse; well our sun is rectangular).
+
+ Here are few exceptions.
+
+ First, the equation degenerates when the distance sqrt((x1-x0)^2 + (y1-y0)^2)
+ appears equal to r0-r1. In this case the base circles do contact,
+ and the running circle does contact at the same point.
+ The equation degenerates to a linear one.
+ Since we don't want float precision noize to affect the result,
+ we compute this condition in 'fixed' coordinates.
+
+ Second, Postscript approximates any circle with 3d order beziers.
+ This approximation may give a 2% error.
+ Therefore using the precise roots may cause a dropout.
+ To prevetn them, we slightly modify the base radii.
+ However the sign of modification smartly depends
+ on the relative sizes of the base circles,
+ and on the contact number. Currently we don't want to
+ define and debug the smart optimal logic for that,
+ so we simply try all 4 variants for each source equation,
+ and use the union of intervals.
+
+ Third, we could compute which quarter of the circle
+ really covers the path bbox. Using it we could skip
+ rendering of uncovering quarters. Currently we do not
+ implement this optimization. The general tensor patch algorithm
+ will skip uncovering parts.
+
+ Fourth, when one base circle is (almost) inside the other,
+ the parameter interval must include the shading apex.
+ To know that, we determine whether the contacting circle
+ is outside the rectangle (the "outer" contact),
+ or it is (partially) inside the rectangle.
+
+ At last, a small shortening of a shading won't give a
+ sensible speedup, but it may replace a symmetric function domain
+ with an assymmetric one, so that the rendering
+ would be asymmetyric for a symmetric shading.
+ Therefore we do not perform a small sortening.
+ Instead we shorten only if the shading span
+ is much smaller that the shading domain.
+ */
+ const double extent = 1.02;
+ int span_type0, span_type1, span_type;
+
+ memset(rsa, 0, sizeof(*rsa));
+ rsa->x0 = x0;
+ rsa->y0 = y0;
+ rsa->x1 = x1;
+ rsa->y1 = y1;
+ rsa->p[0] = rsa->p[4] = rect->p;
+ rsa->p[1].x = rsa->p[5].x = rect->p.x;
+ rsa->p[1].y = rsa->p[5].y = rect->q.y;
+ rsa->p[2] = rect->q;
+ rsa->p[3].x = rect->q.x;
+ rsa->p[3].y = rect->p.y;
+ rsa->have_apex = any_abs(r1 - r0) > 1e-7 * any_abs(r1 + r0);
+ rsa->apex = (rsa->have_apex ? -r0 / (r1 - r0) : 0);
+ span_type0 = compute_radial_shading_span_extended(rsa, r0 / extent, r1 * extent);
+ if (span_type0 == -1)
+ return -1;
+ span_type1 = compute_radial_shading_span_extended(rsa, r0 / extent, r1 / extent);
+ if (span_type0 != span_type1)
+ return -1;
+ span_type1 = compute_radial_shading_span_extended(rsa, r0 * extent, r1 * extent);
+ if (span_type0 != span_type1)
+ return -1;
+ span_type1 = compute_radial_shading_span_extended(rsa, r0 * extent, r1 / extent);
+ if (span_type1 == -1)
+ return -1;
+ if (r0 < r1) {
+ if (rsa->have_root[0] && !rsa->outer_contact[0])
+ rsa->span[0][0] = rsa->apex; /* Likely never happens. Remove ? */
+ if (rsa->have_root[1] && !rsa->outer_contact[1])
+ rsa->span[1][0] = rsa->apex;
+ } else if (r0 > r1) {
+ if (rsa->have_root[0] && !rsa->outer_contact[0])
+ rsa->span[0][1] = rsa->apex;
+ if (rsa->have_root[1] && !rsa->outer_contact[1])
+ rsa->span[1][1] = rsa->apex; /* Likely never happens. Remove ? */
+ }
+ span_type = 0;
+ if (rsa->have_root[0] && rsa->span[0][0] < 0)
+ span_type |= 1;
+ if (rsa->have_root[1] && rsa->span[1][0] < 0)
+ span_type |= 1;
+ if (rsa->have_root[0] && rsa->span[0][1] > 0 && rsa->span[0][0] < 1)
+ span_type |= 2;
+ if (rsa->have_root[1] && rsa->span[1][1] > 0 && rsa->span[1][0] < 1)
+ span_type |= 4;
+ if (rsa->have_root[0] && rsa->span[0][1] > 1)
+ span_type |= 8;
+ if (rsa->have_root[1] && rsa->span[1][1] > 1)
+ span_type |= 8;
+ return span_type;
+}
+
+private bool
+shorten_radial_shading(float *x0, float *y0, floatp *r0, float *d0, float *x1, float *y1, floatp *r1, float *d1, double span_[2])
+{
+ double s0 = span_[0], s1 = span_[1], w;
+
+ if (s0 < 0)
+ s0 = 0;
+ if (s1 < 0)
+ s1 = 0;
+ if (s0 > 1)
+ s0 = 1;
+ if (s1 > 1)
+ s1 = 1;
+ w = s1 - s0;
+ if (w == 0)
+ return false; /* Don't pass a degenerate shading. */
+ if (w > 0.3)
+ return false; /* The span is big, don't shorten it. */
+ { /* Do shorten. */
+ double R0 = *r0, X0 = *x0, Y0 = *y0, D0 = *d0;
+ double R1 = *r1, X1 = *x1, Y1 = *y1, D1 = *d1;
+
+ *r0 = R0 + (R1 - R0) * s0;
+ *x0 = X0 + (X1 - X0) * s0;
+ *y0 = Y0 + (Y1 - Y0) * s0;
+ *d0 = D0 + (D1 - D0) * s0;
+ *r1 = R0 + (R1 - R0) * s1;
+ *x1 = X0 + (X1 - X0) * s1;
+ *y1 = Y0 + (Y1 - Y0) * s1;
+ *d1 = D0 + (D1 - D0) * s1;
+ }
+ return true;
+}
+
+private bool inline
+is_radial_shading_large(double x0, double y0, double r0, double d0, double x1, double y1, double r1, const gs_rect * rect)
+{
+ const double d = hypot(x1 - x0, y1 - y0);
+ const double area0 = M_PI * r0 * r0 / 2;
+ const double area1 = M_PI * r1 * r1 / 2;
+ const double area2 = (r0 + r1) / 2 * d;
+ const double arbitrary = 8;
+ double areaX, areaY;
+
+ /* The shading area is not equal to area0 + area1 + area2
+ when one circle is (almost) inside the other.
+ We believe that the 'arbitrary' coefficient recovers that
+ when it is set greater than 2. */
+ /* If one dimension is large enough, the shading parameter span is wide. */
+ areaX = (rect->q.x - rect->p.x) * (rect->q.x - rect->p.x);
+ if (areaX * arbitrary < area0 + area1 + area2)
+ return true;
+ areaY = (rect->q.y - rect->p.y) * (rect->q.y - rect->p.y);
+ if (areaY * arbitrary < area0 + area1 + area2)
+ return true;
+ return false;
+}
+
+private int
gs_shading_R_fill_rectangle_aux(const gs_shading_t * psh0, const gs_rect * rect,
const gs_fixed_rect *clip_rect,
gx_device * dev, gs_imager_state * pis)
@@ -650,6 +1007,8 @@
floatp r0 = psh->params.Coords[2];
float x1 = psh->params.Coords[3], y1 = psh->params.Coords[4];
floatp r1 = psh->params.Coords[5];
+ radial_shading_attrs_t rsa;
+ int span_type; /* <0 - don't shorten, 1 - extent0, 2 - first contact, 4 - last contact, 8 - extent1. */
int code;
patch_fill_state_t pfs1;
@@ -663,11 +1022,51 @@
pfs1.function_arg_shift = 1;
pfs1.rect = *clip_rect;
pfs1.maybe_self_intersecting = false;
- code = R_extensions(&pfs1, psh, rect, d0, d1, psh->params.Extend[0], false);
- if (code >= 0)
- code = R_tensor_annulus(&pfs1, rect, x0, y0, r0, d0, x1, y1, r1, d1);
- if (code >= 0)
- code = R_extensions(&pfs1, psh, rect, d0, d1, false, psh->params.Extend[1]);
+ if (is_radial_shading_large(x0, y0, r0, d0, x1, y1, r1, rect))
+ span_type = compute_radial_shading_span(&rsa, x0, y0, r0, x1, y1, r1, rect);
+ else
+ span_type = -1;
+ if (span_type < 0) {
+ code = R_extensions(&pfs1, psh, rect, d0, d1, psh->params.Extend[0], false);
+ if (code >= 0)
+ code = R_tensor_annulus(&pfs1, rect, x0, y0, r0, d0, x1, y1, r1, d1);
+ if (code >= 0)
+ code = R_extensions(&pfs1, psh, rect, d0, d1, false, psh->params.Extend[1]);
+ } else {
+ bool second_interval = true;
+
+ code = 0;
+ if (span_type & 1)
+ code = R_extensions(&pfs1, psh, rect, d0, d1, psh->params.Extend[0], false);
+ if (code >= 0) {
+ float X0 = x0, Y0 = y0, D0 = d0, X1 = x1, Y1 = y1, D1 = d1;
+ floatp R0 = r0, R1 = r1;
+
+ if ((span_type & 2) && (span_type & 4) && rsa.span[0][1] >= rsa.span[1][0]) {
+ double united[2];
+
+ united[0] = rsa.span[0][0];
+ united[1] = rsa.span[1][1];
+ shorten_radial_shading(&X0, &Y0, &R0, &D0, &X1, &Y1, &R1, &D1, united);
+ second_interval = false;
+ code = R_tensor_annulus(&pfs1, rect, X0, Y0, R0, D0, X1, Y1, R1, D1);
+ } else if (span_type & 2) {
+ second_interval = shorten_radial_shading(&X0, &Y0, &R0, &D0, &X1, &Y1, &R1, &D1, rsa.span[0]);
+ code = R_tensor_annulus(&pfs1, rect, X0, Y0, R0, D0, X1, Y1, R1, D1);
+ }
+ }
+ if (code >= 0 && second_interval) {
+ if (span_type & 4) {
+ float X0 = x0, Y0 = y0, D0 = d0, X1 = x1, Y1 = y1, D1 = d1;
+ floatp R0 = r0, R1 = r1;
+
+ shorten_radial_shading(&X0, &Y0, &R0, &D0, &X1, &Y1, &R1, &D1, rsa.span[1]);
+ code = R_tensor_annulus(&pfs1, rect, X0, Y0, R0, D0, X1, Y1, R1, D1);
+ }
+ }
+ if (code >= 0 && (span_type & 8))
+ code = R_extensions(&pfs1, psh, rect, d0, d1, false, psh->params.Extend[1]);
+ }
if (term_patch_fill_state(&pfs1))
return_error(gs_error_unregistered); /* Must not happen. */
return code;
More information about the gs-cvs
mailing list