From f8d6d7ae42a7b7f720f96ee0ca92d0fda11897e0 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Thu, 4 Jun 2009 14:55:38 +0200 Subject: [PATCH] Implement axial/radial ShadedFill in cairo backend using cairo gradients Fixes bugs #10942 and #14160. --- poppler/CairoOutputDev.cc | 34 ++++++++++++++++++ poppler/CairoOutputDev.h | 8 ++++ poppler/Gfx.cc | 86 ++++++++++++++++++++++++++++++++------------- poppler/OutputDev.h | 1 + 4 files changed, 104 insertions(+), 25 deletions(-) diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index 199e5ea..cb8b286 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -458,6 +458,18 @@ void CairoOutputDev::updateStrokeOpacity(GfxState *state) { LOG(printf ("stroke opacity: %f\n", stroke_opacity)); } +void CairoOutputDev::updateFillColorStop(GfxState *state, double offset) { + state->getFillRGB(&fill_color); + + cairo_pattern_add_color_stop_rgba(fill_pattern, offset, + fill_color.r / 65535.0, + fill_color.g / 65535.0, + fill_color.b / 65535.0, + fill_opacity); + LOG(printf ("fill color stop: %f (%d, %d, %d)\n", + offset, fill_color.r, fill_color.g, fill_color.b)); +} + void CairoOutputDev::updateFont(GfxState *state) { cairo_font_face_t *font_face; cairo_matrix_t matrix, invert_matrix; @@ -586,6 +598,28 @@ void CairoOutputDev::eoFill(GfxState *state) { } +GBool CairoOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { + double x0, y0, x1, y1; + + shading->getCoords(&x0, &y0, &x1, &y1); + cairo_pattern_destroy(fill_pattern); + fill_pattern = cairo_pattern_create_linear (x0, y0, x1, y1); + + // TODO: use the actual stops in the shading in the case + // of linear interpolation (Type 2 Exponential functions with N=1) + return gFalse; +} + +GBool CairoOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) { + double x0, y0, r0, x1, y1, r1; + + shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); + cairo_pattern_destroy(fill_pattern); + fill_pattern = cairo_pattern_create_radial (x0, y0, r0, x1, y1, r1); + + return gFalse; +} + 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 7a9283f..ea72b01 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -98,6 +98,11 @@ public: // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gTrue; } + // Does this device use functionShadedFill(), axialShadedFill(), and + // radialShadedFill()? If this returns false, these shaded fills + // will be reduced to a series of other drawing operations. + virtual GBool useShadedFills() { return gTrue; } + // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gFalse; } @@ -132,6 +137,7 @@ public: virtual void updateStrokeColor(GfxState *state); virtual void updateFillOpacity(GfxState *state); virtual void updateStrokeOpacity(GfxState *state); + virtual void updateFillColorStop(GfxState *state, double offset); //----- update text state virtual void updateFont(GfxState *state); @@ -141,6 +147,8 @@ public: virtual void stroke(GfxState *state); virtual void fill(GfxState *state); virtual void eoFill(GfxState *state); + virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading); + virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading); //----- path clipping virtual void clip(GfxState *state); diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc index e907850..3f6be30 100644 --- a/poppler/Gfx.cc +++ b/poppler/Gfx.cc @@ -2577,7 +2577,10 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { // set the color state->setFillColor(&color0); - out->updateFillColor(state); + if (out->useShadedFills()) + out->updateFillColorStop(state, tt / t1); + else + out->updateFillColor(state); // fill the region state->moveTo(ux0, uy0); @@ -2585,9 +2588,11 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { state->lineTo(vx1, vy1); state->lineTo(ux1, uy1); state->closePath(); - if (!contentIsHidden()) - out->fill(state); - state->clearPath(); + if (!out->useShadedFills()) { + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } // set up for next region ux0 = ux1; @@ -2597,6 +2602,12 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) { color0 = color1; i = next[i]; } + + if (out->useShadedFills()) { + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } } void Gfx::doRadialShFill(GfxRadialShading *shading) { @@ -2606,6 +2617,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { GfxColor colorA, colorB; double xa, ya, xb, yb, ra, rb; double ta, tb, sa, sb; + double tt; double sz, xz, yz, sMin, sMax; GBool enclosed; int ia, ib, k, n; @@ -2751,12 +2763,13 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { ya = y0 + sa * (y1 - y0); ra = r0 + sa * (r1 - r0); if (ta < t0) { - shading->getColor(t0, &colorA); + tt = t0; } else if (ta > t1) { - shading->getColor(t1, &colorA); + tt = t1; } else { - shading->getColor(ta, &colorA); + tt = ta; } + shading->getColor(tt, &colorA); // fill the circles while (ia < radialMaxSplits) { @@ -2771,12 +2784,13 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { sb = sMax; tb = t0 + sb * (t1 - t0); if (tb < t0) { - shading->getColor(t0, &colorB); + tt = t0; } else if (tb > t1) { - shading->getColor(t1, &colorB); + tt = t1; } else { - shading->getColor(tb, &colorB); + tt = tb; } + shading->getColor(tt, &colorB); while (ib - ia > 1) { for (k = 0; k < nComps; ++k) { if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { @@ -2790,12 +2804,13 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); tb = t0 + sb * (t1 - t0); if (tb < t0) { - shading->getColor(t0, &colorB); + tt = t0; } else if (tb > t1) { - shading->getColor(t1, &colorB); + tt = t1; } else { - shading->getColor(tb, &colorB); + tt = tb; } + shading->getColor(tt, &colorB); } // compute center and radius of the circle @@ -2808,7 +2823,10 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2; } state->setFillColor(&colorA); - out->updateFillColor(state); + if (out->useShadedFills()) + out->updateFillColorStop(state, tt / t1); + else + out->updateFillColor(state); if (enclosed) { @@ -2862,9 +2880,11 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } // fill the path - if (!contentIsHidden()) - out->fill(state); - state->clearPath(); + if (!out->useShadedFills()) { + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } // step to the next value of t ia = ib; @@ -2893,16 +2913,21 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } shading->getColor(ta, &colorA); state->setFillColor(&colorA); - out->updateFillColor(state); + if (out->useShadedFills()) + out->updateFillColorStop(state, ta / t1); + else + out->updateFillColor(state); 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(); - if (!contentIsHidden()) - out->fill(state); - state->clearPath(); + if (!out->useShadedFills()) { + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } } // extend the larger circle @@ -2921,7 +2946,10 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { } shading->getColor(ta, &colorA); state->setFillColor(&colorA); - out->updateFillColor(state); + if (out->useShadedFills()) + out->updateFillColorStop(state, ta / t1); + else + out->updateFillColor(state); state->moveTo(xMin, yMin); state->lineTo(xMin, yMax); state->lineTo(xMax, yMax); @@ -2933,11 +2961,19 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) { state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); } state->closePath(); - if (!contentIsHidden()) - out->fill(state); - state->clearPath(); + if (!out->useShadedFills()) { + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } } } + + if (out->useShadedFills()) { + if (!contentIsHidden()) + out->fill(state); + state->clearPath(); + } } void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) { diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h index 4866631..07a2d86 100644 --- a/poppler/OutputDev.h +++ b/poppler/OutputDev.h @@ -168,6 +168,7 @@ public: virtual void updateFillOverprint(GfxState * /*state*/) {} virtual void updateStrokeOverprint(GfxState * /*state*/) {} virtual void updateTransfer(GfxState * /*state*/) {} + virtual void updateFillColorStop(GfxState * /*state*/, double /*offset*/) {} //----- update text state virtual void updateFont(GfxState * /*state*/) {} -- 1.6.0.4