diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index 565ac1c..0776571 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -624,6 +624,34 @@ GBool CairoOutputDev::axialShadedSupportExtend(GfxState *state, GfxAxialShading return (shading->getExtend0() == shading->getExtend1()); } +GBool CairoOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) { + double x0, y0, r0, x1, y1, r1; + double dx, dy, dr; + + shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); + dx = x1 - x0; + dy = y1 - y0; + dr = r1 - r0; + cairo_pattern_destroy(fill_pattern); + fill_pattern = cairo_pattern_create_radial (x0 + sMin * dx, + y0 + sMin * dy, + r0 + sMin * dr, + x0 + sMax * dx, + y0 + sMax * dy, + r0 + sMax * dr); + if (shading->getExtend0() && shading->getExtend1()) + cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_PAD); + else + cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_NONE); + + return gFalse; +} + +GBool CairoOutputDev::radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading) +{ + return (shading->getExtend0() == shading->getExtend1()); +} + void CairoOutputDev::clip(GfxState *state) { doPath (cairo, state, state->getPath()); cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING); diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h index afff7ea..540d9e4 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -152,6 +152,8 @@ public: virtual void eoFill(GfxState *state); virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax); virtual GBool axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading); + virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax); + virtual GBool radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading); //----- path clipping virtual void clip(GfxState *state); diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index 284a124..a4fac4e 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -2651,11 +2651,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { int ia, ib, k, n; double *ctm; double theta, alpha, angle, t; - - if (out->useShadedFills() && - out->radialShadedFill(state, shading)) { - return; - } + GBool needExtend = gTrue; // get the shading info shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); @@ -2752,6 +2748,11 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } } + if (out->useShadedFills() && + out->radialShadedFill(state, shading, sMin, sMax)) { + return; + } + // compute the number of steps into which circles must be divided to // achieve a curve flatness of 0.1 pixel in device space for the // largest circle (note that "device space" is 72 dpi when generating @@ -2798,6 +2799,8 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { shading->getColor(ta, &colorA); } + needExtend = !out->radialShadedSupportExtend(state, shading); + // fill the circles while (ia < radialMaxSplits) { @@ -2848,63 +2851,67 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2; } state->setFillColor(&colorA); - out->updateFillColor(state); - - if (enclosed) { - - // construct path for first circle (counterclockwise) - state->moveTo(xa + ra, ya); - for (k = 1; k < n; ++k) { - angle = ((double)k / (double)n) * 2 * M_PI; - state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); - } - state->closePath(); - - // construct and append path for second circle (clockwise) - state->moveTo(xb + rb, yb); - for (k = 1; k < n; ++k) { - angle = -((double)k / (double)n) * 2 * M_PI; - state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); - } - state->closePath(); - - } else { + if (out->useFillColorStop()) + out->updateFillColorStop(state, (sa - sMin)/(sMax - sMin)); + else + out->updateFillColor(state); - // construct the first subpath (clockwise) - state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), - ya + ra * sin(alpha + theta + 0.5 * M_PI)); - for (k = 0; k < n; ++k) { - angle = alpha + theta + 0.5 * M_PI - - ((double)k / (double)n) * (2 * theta + M_PI); - state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); - } - for (k = 0; k < n; ++k) { - angle = alpha - theta - 0.5 * M_PI - + ((double)k / (double)n) * (2 * theta - M_PI); - state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); - } - state->closePath(); + if (needExtend) { + if (enclosed) { + // construct path for first circle (counterclockwise) + state->moveTo(xa + ra, ya); + for (k = 1; k < n; ++k) { + angle = ((double)k / (double)n) * 2 * M_PI; + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); - // construct the second subpath (counterclockwise) - state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), - ya + ra * sin(alpha + theta + 0.5 * M_PI)); - for (k = 0; k < n; ++k) { - angle = alpha + theta + 0.5 * M_PI - + ((double)k / (double)n) * (-2 * theta + M_PI); - state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); - } - for (k = 0; k < n; ++k) { - angle = alpha - theta - 0.5 * M_PI - + ((double)k / (double)n) * (2 * theta + M_PI); - state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + // construct and append path for second circle (clockwise) + state->moveTo(xb + rb, yb); + for (k = 1; k < n; ++k) { + angle = -((double)k / (double)n) * 2 * M_PI; + state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); + } + state->closePath(); + } else { + // construct the first subpath (clockwise) + state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), + ya + ra * sin(alpha + theta + 0.5 * M_PI)); + for (k = 0; k < n; ++k) { + angle = alpha + theta + 0.5 * M_PI + - ((double)k / (double)n) * (2 * theta + M_PI); + state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); + } + for (k = 0; k < n; ++k) { + angle = alpha - theta - 0.5 * M_PI + + ((double)k / (double)n) * (2 * theta - M_PI); + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); + + // construct the second subpath (counterclockwise) + state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), + ya + ra * sin(alpha + theta + 0.5 * M_PI)); + for (k = 0; k < n; ++k) { + angle = alpha + theta + 0.5 * M_PI + + ((double)k / (double)n) * (-2 * theta + M_PI); + state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); + } + for (k = 0; k < n; ++k) { + angle = alpha - theta - 0.5 * M_PI + + ((double)k / (double)n) * (2 * theta + M_PI); + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); } - state->closePath(); } - // fill the path - if (!contentIsHidden()) - out->fill(state); - state->clearPath(); + if (!out->useFillColorStop()) { + // fill the path + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } // step to the next value of t ia = ib; @@ -2916,6 +2923,26 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { colorA = colorB; } + if (out->useFillColorStop()) { + // make sure we add stop color when sb = sMax + state->setFillColor(&colorA); + out->updateFillColorStop(state, (sb - sMin)/(sMax - sMin)); + + // fill the path + state->moveTo(xMin, yMin); + state->lineTo(xMin, yMax); + state->lineTo(xMax, yMax); + state->lineTo(xMax, yMin); + state->closePath(); + + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } + + if (!needExtend) + return; + if (enclosed) { // extend the smaller circle if ((shading->getExtend0() && r0 <= r1) || diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h index d1cb2b0..d7fb10f 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -201,7 +201,7 @@ public: { return gFalse; } virtual GBool axialShadedSupportExtend(GfxState * /*state*/, GfxAxialShading * /*shading*/) { return gFalse; } - virtual GBool radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/) + virtual GBool radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/, double /*sMin*/, double /*sMax*/) { return gFalse; } virtual GBool radialShadedSupportExtend(GfxState * /*state*/, GfxRadialShading * /*shading*/) { return gFalse; }