Commit 53c3d636 authored by Carlos Garcia Campos's avatar Carlos Garcia Campos

[cairo] Implement radialShadedFill in cairo backend using cairo gradients

Fixes bugs #10942, #14160
parent 2ba93754
......@@ -683,6 +683,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);
......
......@@ -153,6 +153,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);
......
......@@ -2652,11 +2652,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);
......@@ -2753,6 +2749,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
......@@ -2799,6 +2800,8 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
shading->getColor(ta, &colorA);
}
needExtend = !out->radialShadedSupportExtend(state, shading);
// fill the circles
while (ia < radialMaxSplits) {
......@@ -2849,63 +2852,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;
......@@ -2917,6 +2924,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) ||
......
......@@ -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; }
......
......@@ -3944,8 +3944,7 @@ GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, do
return gTrue;
}
GBool PSOutputDev::radialShadedFill(GfxState *state,
GfxRadialShading *shading) {
GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/) {
double xMin, yMin, xMax, yMax;
double x0, y0, r0, x1, y1, r1, t0, t1;
double xa, ya, ra;
......
......@@ -216,7 +216,7 @@ public:
virtual GBool functionShadedFill(GfxState *state,
GfxFunctionShading *shading);
virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/);
virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/);
//----- path clipping
virtual void clip(GfxState *state);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment