Am 09.01.2011 23:48, schrieb Albert Astals Cid:
A Diumenge, 9 de gener de 2011, Thomas Freitag va escriure:
Am 08.01.2011 00:56, schrieb Albert Astals Cid:
A Dilluns, 3 de gener de 2011, Thomas Freitag va escriure:
Am 03.01.2011 00:28, schrieb Albert Astals Cid:
A Diumenge, 2 de gener de 2011, Thomas Freitag va escriure:
Am 01.01.2011 22:34, schrieb Albert Astals Cid:
A Dissabte, 1 de gener de 2011, Thomas Freitag va escriure:
Please regtest this new patch. What I've done in the meantime:
a) speed up the implemenation but have enough quality left.
b) implement the shading extend in a correct way, test it against
the samples from the PDF spec (appendix L)
c) test it against all samples from Andrea, including bug 32349&
30887. d) test it against ducks& roses and all the PDF You send
me because of regressions with former patches.
So I'm think I'm quite near of finishing the implementation, just
waiting for the result of Your regtest.
There are a few empty pixels in the border of
http://bugsfiles.kde.org/attachment.cgi?id=20680
Sorry, I made such a lot changes in the last three days, that I forgot
to remove a test case where I wanted to see where normal shading stops
and extending shading starts, so the last circle of normal shading was
no more painted :-(
Please try the new patch.
There is a regression on page 25 of
http://download.tuxfamily.org/magnum/doc/magnum04.pdf
See attached files.
This was not really a bug in the new feature "radial shading": when I
introduced the dynamic pattern in axial shading, and the ability to
return gFalse in getColor() if nothing should be paint, I forgot to
increase some pipe pointers in pipeRun, i.e. if softmask is used the
softmask pointers must be increased, too.
Please try the new patch.
BTW, Albert: I start working again, and because this is almost a private
pleasure, I can probably look only on weekend into new regressions. And
because I think we are really quite near, could You please run the
regression test over all PDF and send me them all or links to it instead
stopping the test if You first regression? Then I can look at all
regressions next weekend...
It seems as if I was a little bit to optimistic:
The image generated by the new implementation is still considerably
"blockier" than the generated by the old one in page 25 of that pdf.
Solved, and the new routines are faster!
There is a regression in page 8 of
http://launchpadlibrarian.net/17355619/2008SPYSupplement.pdf
Solved, new and old routines need nearly the same time
There is a regression on the top left bubble of
https://bugs.freedesktop.org/attachment.cgi?id=32823
Solved, new and old routines need nearly the same time.
There is a regression in the alfa romeo logo of one of the files you sent
for https://bugs.freedesktop.org/show_bug.cgi?id=27482 (if you don't
have it anymore ask and i'll send it to you)
Solved, new and old routines need nearly the same time.
The pdf at https://bugs.freedesktop.org/attachment.cgi?id=40344 turned to
grayscale
Solved, new and old routines need nearly the same time.
https://bugs.freedesktop.org/attachment.cgi?id=41060 looks really blocky
too with the new patch
Better, but still a little bit blockier. Seems to be the Bresenham
routines.
https://bugs.freedesktop.org/attachment.cgi?id=6858 is considerably
slower with the new patch than with the old code (takes more than the
six times the old code and then stopped trying so no sure if the
rendering is
better/worse/the same)
I've optimized it, but I still need a little bit less than six times
than with the old routines. Reason for this (a PDF with round about 600
radial shadings!) are some radial shadings with a radius of more than
10.000.00 pts and then pick a partial square with 256 pts. With
Bresenham I have to calculate als the 10.000.000 circle points before I
can intersect :-(
There is another circle that got very blocky, i'll send you the file.
No solution 'til now. It's hard to look into it, it need more than 15
minutes on my not so slow laptop for rendering until it reaches the
first radial shading, so I give up for today.
Seems as if I need to spend at least one additional weekend for it. I
have an idea to combine old drawing circles with only 66 points instead
of using Bresenham algorithm to get it faster, but I've to make some
more tests on this.
If You think I can upload a new patch with the actual resuts, just to
look for new / other regressions. Otherwise we can of course wait after
I finish it.
I think i prefer to wait until you have a patch that fixes all the known
regressions until doing another regression test run.
Thanks :-)
Albert
I think, I'm through. Here the new optimized patch. Now I'm mostly
faster then the old implementation, only when the corrected
implementation of larger extension circle is needed, I need sometimes
more time. See for example the european map You sent me in private,
where the ships were very blocky: with the new implementation this is
solved and the square around the ships are away (which is correct, they
should not be there!). Even in the corrected implementation of larger
extension circles I made a lot of optimization steps, see i.e.
https://bugs.freedesktop.org/attachment.cgi?id=41506 from Andrea, which
is now rendered correctly and in time. I'm also able to render now the
PDFs in http://people.freedesktop.org/~ranma42/cairo/radial/ from
Andrea, I think, I found a good compromise between speed and quality there.
Only https://bugs.freedesktop.org/attachment.cgi?id=41060 still looks a
little bit uglier (blockier) than with the old routines, but because
this is more or less an artificial radial shading, I would accept this
case. What are You thinking about that?
Last but not least, even if You'll find new regressions with the new
patch, I want really to thank Andrea Canciani for his samples. Not only
that it's easier testing complete new code with PDF files, which only
contain radial shadings and nothing else, they also gives me a deeper
understanding how radial shading is specified in comparision what I
understood reading the Adobe PDF spec.
Please test the new patch,
Thomas
Thomas
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
.
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 0b3722a..cc0af1a 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -153,6 +153,476 @@ void SplashGouraudPattern::getParameterizedColor(double
colorinterp, SplashColor
}
//------------------------------------------------------------------------
+// SplashRadialPattern
+//------------------------------------------------------------------------
+// Min number of splits along the t axis for a radial shading fill.
+#define radialMinSplits 256
+
+// Max number of splits along the t axis for a radial shading fill.
+#define radialMaxSplits 32768
+
+// Max delta allowed in any color component for a radial shading fill.
+#define radialColorDelta (dblToCol(1.0 / 256.0))
+
+// Max size of pattern bitmap of min (width, height)
+#define radialMaxSize 256
+
+SplashRadialPattern::SplashRadialPattern(GfxState *stateA, GfxRadialShading
*shadingA,
+
double sMinA, double sMaxA, SplashColorMode colorModeA) {
+ double width, height, sa;
+ Matrix ctm;
+
+ state = stateA;
+ shading = shadingA;
+ // ignore sMin ans sMax from Gfx (they include already extends!):
+ sMax = 1;
+ sMin = 0;
+ colorMode = colorModeA;
+ state->getCTM(&ctm);
+ ctm.invertTo(&ictm);
+ splash = NULL;
+ bitmap = NULL;
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ if (shading->getHasBBox())
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ else
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ width = xMax - xMin;
+ height = yMax - yMin;
+ if (splashFloor(xMax) - splashFloor(xMin) > width)
+ width = splashFloor(xMax) - splashFloor(xMin);
+ if (splashFloor(yMax) - splashFloor(yMin) > height)
+ height = splashFloor(yMax) - splashFloor(yMin);
+ if (radialMaxSize > 0 && width > 0 && height > 0) {
+ if ( width > height)
+ scale = radialMaxSize / height;
+ else
+ scale = radialMaxSize / width;
+ } else
+ scale = 1;
+ if (scale < .5 && radialMaxSize > 0 && (r1 > 0 || r0 > 0)) {
+ if ( r1 > r0)
+ scale = radialMaxSize / r1;
+ else
+ scale = radialMaxSize / r0;
+ } else if (scale < .5)
+ scale = 1;
+
+ // calculate sMax for larger extend circle
+ sMaxExtend = sMax;
+ sMinExtend = sMin;
+ maxSplitsExtend = radialMinSplits;
+ if ((shading->getExtend0() && r0 > r1) ||
+ (shading->getExtend1() && r1 >= r0)) {
+ // solve for x(s) + r(s) = xMin or x(s) + r(s) = xMax
+ if ((x1 + r1) - (x0 + r0) != 0) {
+ sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ sa = (xMax - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ }
+ // solve for x(s) - r(s) = xMax and x(s) - r(s) = xMin
+ if ((x1 - r1) - (x0 - r0) != 0) {
+ sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ sa = (xMin - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ }
+ // solve for y(s) + r(s) = yMin or y(s) + r(s) = yMax
+ if ((y1 + r1) - (y0 + r0) != 0) {
+ sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ sa = (yMax - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ }
+ // solve for y(s) - r(s) = yMax or y(s) - r(s) = yMin
+ if ((y1 - r1) - (y0 - r0) != 0) {
+ sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ sa = (yMin - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+ if (sa < sMinExtend) {
+ sMinExtend = sa;
+ } else if (sa > sMaxExtend) {
+ sMaxExtend = sa;
+ }
+ }
+ if (abs(sMinExtend) > abs(sMaxExtend))
+ sMaxExtend = (sMinExtend < 0) ? -sMinExtend :
sMinExtend;
+ else
+ sMinExtend = (sMaxExtend > 0) ? -sMaxExtend :
sMaxExtend;
+
+ sMaxExtend *= 4;
+ sMinExtend *= 4;
+ // limit sMin/MaxExtend by memory (need for Bresenham pts)
+ if (r1 != r0) {
+ sa = 15000000 / scale - r0;
+ if (r1 > r0)
+ sa = sa / (r1 - r0);
+ else
+ sa = sa / (r0 - r1);
+ if (sMinExtend < -sa) {
+ sMinExtend = -sa;
+ maxSplitsExtend = 16;
+ }
+ if (sMaxExtend > sa) {
+ sMaxExtend = sa;
+ maxSplitsExtend = 16;
+ }
+ }
+ }
+
+ xMin *= scale;
+ xMax *= scale;
+ yMin *= scale;
+ yMax *= scale;
+ width *= scale;
+ height *= scale;
+ if (width > 0 && height > 0) {
+ bitmap = new SplashBitmap(splashRound(width), splashRound(height),
colorMode != splashModeMono1, colorMode, gTrue);
+ splash = new Splash(bitmap, gFalse /* AntiAlias in shading Dict! */);
+
+ // show only what is painted, delete alpha channel
+ Guchar *bitmapAlpha = bitmap->getAlphaPtr();
+ int size = bitmap->getWidth() * bitmap->getHeight();
+ for (int i = 0; i < size; ++i)
+ bitmapAlpha[i] = 0;
+ }
+
+ // change transfer matrix to fit to scaled bitmap
+ ictm.m[0] *= scale;
+ ictm.m[1] *= scale;
+ ictm.m[2] *= scale;
+ ictm.m[3] *= scale;
+ ictm.m[4] *= scale;
+ ictm.m[5] *= scale;
+ ictm.m[4] -= xMin;
+ ictm.m[5] -= yMin;
+ maxSplits = splashRound((r0 - r1) * scale / 5);
+ if (maxSplits < 0) maxSplits = -maxSplits;
+ if (maxSplits < radialMinSplits)
+ maxSplits = radialMinSplits;
+ if (maxSplits > radialMaxSplits)
+ maxSplits = radialMaxSplits;
+}
+
+SplashRadialPattern::~SplashRadialPattern() {
+ if (splash) {
+ delete splash;
+ }
+ if (bitmap) {
+ delete bitmap;
+ }
+}
+
+GBool SplashRadialPattern::getColor(int x, int y, SplashColorPtr c) {
+ double xc, yc;
+ int xs, ys, xMin, yMin, xMax, yMax;
+ Guchar *bitmapAlpha;
+ Gulong superCell[splashMaxColorComps];
+ SplashColor cell;
+ int cp = 0, i, ca = 0;
+
+ for (i = 0; i < splashMaxColorComps; i++)
+ superCell[i] = 0;
+ bitmapAlpha = bitmap->getAlphaPtr();
+ ictm.transform(x, y, &xc, &yc);
+ xMin = splashFloor(xc);
+ yMin = splashFloor(yc);
+ if (xMin < 0) xMin = 0;
+ if (xMin >= bitmap->getWidth()) xMin = bitmap->getWidth() - 1;
+ if (yMin < 0) yMin = 0;
+ if (yMin >= bitmap->getHeight()) yMin = bitmap->getHeight() - 1;
+ ictm.transform(x + 1, y + 1, &xc, &yc);
+ xMax = splashFloor(xc);
+ yMax = splashFloor(yc);
+ if (xMax < 0) xMax = 0;
+ if (xMax >= bitmap->getWidth()) xMax = bitmap->getWidth() - 1;
+ if (yMax < 0) yMax = 0;
+ if (yMax >= bitmap->getHeight()) yMax = bitmap->getHeight() - 1;
+ if (xMax < xMin) { i = xMax; xMax = xMin; xMin = i; }
+ if (yMax < yMin) { i = yMax; yMax = yMin; yMin = i; }
+ for (ys = yMin; ys <= yMax; ys++) {
+ for (xs = xMin; xs <= xMax; xs++) {
+ // Because of rounding problems, coordinates could be
+ // outside the bitmap. Reset them on the outer bound now
+ // and let it up to the alpha channel if they are shown:
+ cp++;
+ if (bitmapAlpha[ys * bitmap->getWidth() + xs]) {
+ bitmap->getPixel(xs, ys, cell);
+ for (i = 0; i < splashMaxColorComps; i++)
+ superCell[i] += cell[i];
+ } else {
+ ca++;
+ }
+ }
+ }
+ if (ca < cp) {
+ for (i = 0; i < splashMaxColorComps; i++)
+ c[i] = (Guchar) (superCell[i] / (cp - ca));
+ return gTrue;
+ }
+ return gFalse;
+}
+
+static inline void getShadingColorRadialHelper(double t0, double t1, double t,
GfxRadialShading *shading, GfxColor *color)
+{
+ if (t0 < t1) {
+ if (t < t0) {
+ shading->getColor(t0, color);
+ } else if (t > t1) {
+ shading->getColor(t1, color);
+ } else {
+ shading->getColor(t, color);
+ }
+ } else {
+ if (t > t0) {
+ shading->getColor(t0, color);
+ } else if (t < t1) {
+ shading->getColor(t1, color);
+ } else {
+ shading->getColor(t, color);
+ }
+ }
+}
+
+void SplashRadialPattern::getStartCircle(SplashCoord *xsc, SplashCoord *ysc,
+
SplashCoord *radius,
+
SplashColorPtr c) {
+ GfxColor colorA;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ ia = 0;
+ sa = sMin;
+ ta = t0 + sa * (t1 - t0);
+ xa = x0 + sa * (x1 - x0);
+ ya = y0 + sa * (y1 - y0);
+ ra = r0 + sa * (r1 - r0);
+ getShadingColorRadialHelper(t0, t1, ta, shading, &colorA);
+ *radius = splashFloor(ra * scale);
+ *xsc = splashFloor(xa * scale - xMin); *ysc = splashFloor(ya * scale -
yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorA);
+}
+
+static inline GBool isSameGfxColor(const GfxColor &colorA, const GfxColor
&colorB, Guint nComps, double delta) {
+ for (Guint k = 0; k < nComps; ++k) {
+ if (abs(colorA.c[k] - colorB.c[k]) > delta) {
+ return false;
+ }
+ }
+ return true;
+}
+
+GBool SplashRadialPattern::getNextCircle(SplashCoord *xsc, SplashCoord *ysc,
+
SplashCoord *radius,
+
SplashColorPtr c) {
+ GfxColor colorA, colorB;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ double sb, tb, factor;
+ int ib, nComps;
+ nComps = shading->getColorSpace()->getNComps();
+ if (ia >= maxSplits)
+ return gFalse;
+ getShadingColorRadialHelper(t0, t1, ta, shading, &colorA);
+ ib = maxSplits;
+ sb = sMax;
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ while (ib - ia > 1) {
+ if (isSameGfxColor(colorB, colorA, nComps, radialColorDelta)) {
+ // The shading is not necessarily lineal so having two points with the
+ // same color does not mean all the areas in between have the same
color too
+ int ic = ia + 1;
+ for (; ic <= ib; ic++) {
+ GfxColor colorC;
+ factor = (double)ic / (double)maxSplits;
+ double sc = sMin + factor * (sMax - sMin);
+ double tc = t0 + sc * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tc, shading,
&colorC);
+ if (!isSameGfxColor(colorC, colorA, nComps,
radialColorDelta)) {
+ break;
+ }
+ }
+ ib = (ic > ia + 1)? ic - 1 : ia + 1;
+ factor = (double)ib / (double)maxSplits;
+ sb = sMin + factor * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ break;
+ }
+ ib = (ia + ib) / 2;
+ factor = (double)ib / (double)maxSplits;
+ sb = sMin + factor * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ getShadingColorRadialHelper(t0, t1, tb, shading, &colorB);
+ }
+ // compute center and radius of the circle
+ xa = x0 + sb * (x1 - x0);
+ ya = y0 + sb * (y1 - y0);
+ ra = r0 + sb * (r1 - r0);
+ *radius = splashFloor(ra * scale);
+ *xsc = splashFloor(xa * scale - xMin); *ysc = splashFloor(ya * scale -
yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorB);
+ ia = (maxSplits > radialMinSplits && (*xsc < -100 || *ysc < -100) && ib + 32
< maxSplits) ? ib + 32 : ib;
+ ta = tb;
+ return gTrue;
+}
+
+GBool SplashRadialPattern::getLargerExtendCircle(SplashCoord *xsc, SplashCoord
*ysc,
+
SplashCoord *radius, SplashColorPtr c) {
+ GfxColor colorA;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ if ((shading->getExtend0() && r0 > r1) ||
+ (shading->getExtend1() && r1 >= r0)) {
+ if (r0 >= r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ shading->getColor(ta, &colorA);
+ *radius = splashFloor(ra * scale);
+ *xsc = splashFloor(xa * scale - xMin); *ysc = splashFloor(ya
* scale - yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorA);
+ ia = 0;
+ return gTrue;
+ }
+ return gFalse;
+}
+
+GBool SplashRadialPattern::getNextLargerExtendCircle(SplashCoord *xsc,
SplashCoord *ysc,
+
SplashCoord *radius, GBool fExtend) {
+ double sb, factor;
+ double sStart, sEnd;
+ if (ia++ + 1 >= maxSplitsExtend)
+ return gFalse;
+ if (x0 == x1 && y0 == y1)
+ ia = maxSplitsExtend;
+ sStart = (r0 > r1) ? sMin : sMax;
+ // buest guess:
+ sEnd = (fExtend) ? sMaxExtend : -sMaxExtend;
+ factor = (double)ia / (double)maxSplitsExtend;
+ sb = sStart + factor * (sEnd - sStart);
+ // compute center and radius of the circle
+ xa = x0 + sb * (x1 - x0);
+ ya = y0 + sb * (y1 - y0);
+ ra = r0 + sb * (r1 - r0);
+ ra = ra * scale;
+ xa = xa * scale - xMin;
+ ya = ya * scale - yMin;
+ *radius = splashFloor(ra);
+ *xsc = splashFloor(xa); *ysc = splashFloor(ya);
+ return gTrue;
+}
+
+GBool SplashRadialPattern::getSmallerExtendCircle(SplashCoord *xsc,
SplashCoord *ysc,
+
SplashCoord *radius, SplashColorPtr c, GBool fExtend) {
+ GfxColor colorA;
+ GfxColorSpace* srcColorSpace = shading->getColorSpace();
+ if ((shading->getExtend0() && r0 <= r1 && r0 > 0) ||
+ (shading->getExtend1() && r1 < r0 && r1 > 0)) {
+ double sStart, sEnd;
+ sEnd = (r1 > r0) ? sMin : sMax;
+ sStart = (r1!= r0) ? -r0 / (r1 - r0) : 0;
+ double sb = (fExtend) ? sStart : sEnd;
+ xa = x0 + sb * (x1 - x0);
+ ya = y0 + sb * (y1 - y0);
+ ra = r0 + sb * (r1 - r0);
+ if (r0 < r1) {
+ ta = t0;
+ } else {
+ ta = t1;
+ }
+ shading->getColor(ta, &colorA);
+ *radius = splashFloor(ra * scale);
+ *xsc = splashFloor(xa * scale - xMin); *ysc = splashFloor(ya
* scale - yMin);
+ convertGfxColor(c, colorMode, srcColorSpace, &colorA);
+ ia = 0;
+ return gTrue;
+ }
+ return gFalse;
+}
+
+GBool SplashRadialPattern::getNextSmallerExtendCircle(SplashCoord *xsc,
SplashCoord *ysc,
+
SplashCoord *radius, GBool fExtend) {
+ double sb, factor;
+ double sStart, sEnd;
+ if (ia++ + 1 >= maxSplits)
+ return gFalse;
+ sEnd = (r1 > r0) ? sMax : sMin;
+ sStart = (r1!= r0) ? -r0 / (r1 - r0) : sMax * 16;
+ if (!fExtend) {
+ sEnd = sStart;
+ sStart = (r1 > r0) ? sMin : sMax;
+ }
+ factor = (double)ia / (double)maxSplits;
+ sb = sStart + factor * (sEnd - sStart);
+ // compute center and radius of the circle
+ xa = x0 + sb * (x1 - x0);
+ ya = y0 + sb * (y1 - y0);
+ ra = r0 + sb * (r1 - r0);
+ *radius = splashFloor(ra * scale);
+ *xsc = splashFloor(xa * scale - xMin); *ysc = splashFloor(ya * scale -
yMin);
+ return gTrue;
+}
+
+SplashClipResult SplashRadialPattern::testClip(SplashCoord x, SplashCoord y,
SplashCoord r) {
+ if (x + r < 0 || y + r < 0 || x - r >= bitmap->getWidth() || y - r >=
bitmap->getHeight())
+ return splashClipAllOutside;
+ double rs = r * r;
+ double xls = x * x;
+ double xrs = (x - bitmap->getWidth()) * (x - bitmap->getWidth());
+ double yls = y * y;
+ double yus = (y - bitmap->getHeight()) * (y - bitmap->getHeight());
+ if (xls + yus < rs && xrs + yus < rs &&
+ xls + yls < rs && xrs + yls < rs)
+ return splashClipAllInside;
+ return splashClipPartial;
+}
+
+GBool SplashRadialPattern::encloseCircle(SplashCoord x1, SplashCoord y1,
SplashCoord r1,
+
SplashCoord x2, SplashCoord y2, SplashCoord r2) {
+ if (x1 == x2 && y1 == y2)
+ return r2 < r1;
+ double dist = sqrt((x1 -x2) * (x1 -x2) + (y1 - y2) * (y1 - y2));
+ return dist + r2 < r1;
+}
+
+//------------------------------------------------------------------------
// SplashAxialPattern
//------------------------------------------------------------------------
@@ -3011,14 +3481,14 @@ void SplashOutputDev::beginTransparencyGroup(GfxState
*state, double *bbox,
tx = (int)floor(xMin);
if (tx < 0) {
tx = 0;
- } else if (tx > bitmap->getWidth()) {
- tx = bitmap->getWidth();
+ } else if (tx > bitmap->getWidth() - 1) {
+ tx = bitmap->getWidth() - 1;
}
ty = (int)floor(yMin);
if (ty < 0) {
ty = 0;
- } else if (ty > bitmap->getHeight()) {
- ty = bitmap->getHeight();
+ } else if (ty > bitmap->getHeight() - 1) {
+ ty = bitmap->getHeight() - 1;
}
w = (int)ceil(xMax) - tx + 1;
if (tx + w > bitmap->getWidth()) {
@@ -3379,3 +3849,37 @@ GBool SplashOutputDev::axialShadedFill(GfxState *state,
GfxAxialShading *shading
return retVal;
}
+
+GBool SplashOutputDev::radialShadedFill(GfxState *state, GfxRadialShading
*shading, double sMin, double sMax) {
+ double xMin, yMin, xMax, yMax;
+ SplashPath *path;
+
+ GBool retVal = gFalse;
+ // get the clip region bbox
+ if (shading->getHasBBox())
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ else
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ // fill the region
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ path = convertPath(state, state->getPath());
+
+ SplashRadialColor *pattern = new SplashRadialPattern(state, shading, sMin,
sMax, colorMode);
+ if (pattern->isOk()) {
+ // first draw the radial shading in its own bitmap
+ retVal = (pattern->getSplash()->radialShadedFill(pattern) ==
splashOk);
+ // now use this bitmap as dynamic pattern:
+ if (retVal) {
+ retVal = (splash->shadedFill(path, shading->getHasBBox(),
pattern) == splashOk);
+ }
+ }
+ state->clearPath();
+ delete pattern;
+ delete path;
+
+ return retVal;
+}
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index 570d036..5be95b5 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -105,6 +105,52 @@ private:
GBool bDirectColorTranslation;
};
+// see GfxState.h, GfxRadialShading
+class SplashRadialPattern: public SplashRadialColor {
+public:
+
+ SplashRadialPattern(GfxState *state, GfxRadialShading *shading, double sMin,
double sMax, SplashColorMode colorMode);
+
+ GBool isOk() { return (bitmap != NULL); }
+
+ Splash *getSplash() { return splash; }
+
+ SplashBitmap *getBitmap() { return bitmap; }
+
+ virtual SplashPattern *copy() { return new SplashRadialPattern(state,
shading, sMin, sMax, colorMode); }
+
+ virtual ~SplashRadialPattern();
+
+ virtual GBool getColor(int x, int y, SplashColorPtr c);
+
+ virtual GBool isStatic() { return gFalse; }
+
+ virtual void getStartCircle(SplashCoord *x0, SplashCoord *y0, SplashCoord
*radius, SplashColorPtr c);
+ virtual GBool getNextCircle(SplashCoord *x0, SplashCoord *y0, SplashCoord
*radius, SplashColorPtr c);
+ virtual GBool getLargerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c);
+ virtual GBool getNextLargerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, GBool fExtend);
+ virtual GBool getSmallerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c, GBool fExtend);
+ virtual GBool getNextSmallerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, GBool fExtend);
+ virtual GBool enlargeCircles() { return r1 > r0; }
+ virtual SplashClipResult testClip(SplashCoord x, SplashCoord y, SplashCoord
r);
+ virtual GBool encloseCircle(SplashCoord x0, SplashCoord y0, SplashCoord r0,
+ SplashCoord x1, SplashCoord y1, SplashCoord r1);
+private:
+ GfxRadialShading *shading;
+ GfxState *state;
+ Matrix ictm;
+ double sMin, sMax, sMaxExtend, sMinExtend;
+ double xMin, xMax, yMin, yMax;
+ double scale;
+ double xa, ya, ra, ta, sa;
+ int ia;
+ int maxSplits, maxSplitsExtend;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ Splash *splash;
+ SplashBitmap *bitmap;
+ SplashColorMode colorMode;
+};
+
//------------------------------------------------------------------------
// number of Type 3 fonts to cache
@@ -132,7 +178,7 @@ public:
// radialShadedFill()? If this returns false, these shaded fills
// will be reduced to a series of other drawing operations.
virtual GBool useShadedFills(int type)
- { return (type == 2 || type == 4 || type == 5 ) ? gTrue : gFalse; }
+ { return (type >= 2 && type <= 5) ? gTrue : gFalse; }
// Does this device use upside-down coordinates?
// (Upside-down means (0,0) is the top left corner of the page.)
@@ -186,6 +232,7 @@ public:
virtual void fill(GfxState *state);
virtual void eoFill(GfxState *state);
virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading,
double tMin, double tMax);
+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading,
double sMin, double sMax);
virtual GBool gouraudTriangleShadedFill(GfxState *state,
GfxGouraudTriangleShading *shading);
//----- path clipping
diff --git a/splash/Splash.cc b/splash/Splash.cc
index bc317a6..0d9f5a8 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -253,30 +253,8 @@ inline void Splash::pipeRun(SplashPipe *pipe) {
// dynamic pattern
if (pipe->pattern) {
if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) {
- switch (bitmap->mode) {
- case splashModeMono1:
- if (!(pipe->destColorMask >>= 1))
- ++pipe->destColorPtr;
- break;
- case splashModeMono8:
- ++pipe->destColorPtr;
- break;
- case splashModeBGR8:
- case splashModeRGB8:
- pipe->destColorPtr += 3;
- break;
- case splashModeXBGR8:
-#if SPLASH_CMYK
- case splashModeCMYK8:
-#endif
- pipe->destColorPtr += 4;
- break;
- }
- if (pipe->destAlphaPtr) {
- ++pipe->destAlphaPtr;
- }
- ++pipe->x;
- return;
+ pipeIncX(pipe);
+ return;
}
}
@@ -3531,6 +3509,697 @@ GBool
Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
return gTrue;
}
+SplashPath *Splash::getBresenhamPoints(SplashCoord xc, SplashCoord yc,
SplashCoord rc) {
+ int radius = splashRound(rc);
+ int x0 = splashRound(xc);
+ int y0 = splashRound(yc);
+ int f = 1 - radius;
+ int ddF_x = 1;
+ int ddF_y = -2 * radius;
+ int x = 0, lastX = x;
+ int y = radius, lastY = y;
+ Guchar dummy;
+ SplashPath *splashPath = new SplashPath();
+
+ if (radius == 0) {
+ splashPath->moveTo(lastX, lastY);
+ return splashPath;
+ }
+
+ while(x < y)
+ {
+ if(f >= 0)
+ {
+ y--;
+ ddF_y += 2;
+ f += ddF_y;
+ }
+ x++;
+ ddF_x += 2;
+ f += ddF_x;
+ if (lastY != y) {
+ if (splashPath->getLength())
+ splashPath->lineTo(lastX, lastY);
+ else
+ splashPath->moveTo(lastX, lastY);
+ lastY = y;
+ }
+ lastX = x;
+ }
+ for (int i = splashPath->getLength() -1; i >= 0; i--) {
+ SplashCoord curX, curY;
+ splashPath->getPoint(i, &curY, &curX, &dummy);
+ for (SplashCoord j = lastY; j >= curY; j--)
+ splashPath->lineTo(curX, j);
+ lastY = splashRound(curY - 1);
+ }
+ while (lastY >= 0)
+ splashPath->lineTo(rc, lastY--);
+ return splashPath;
+}
+
+static inline void getBCircleLine(SplashPath *bresPoints, SplashCoord y,
SplashCoord y0, SplashCoord r, SplashCoord *x) {
+ SplashCoord curX, curY;
+ Guchar dummy;
+ int i = (y > y0) ? splashRound(r - (y - y0)) : splashRound(r - (y0 -
y));
+ if (i < bresPoints->getLength()) {
+ bresPoints->getPoint(i, &curX, &curY, &dummy);
+ *x = curX;
+ }
+}
+
+void Splash::drawPartCircleLine(SplashPipe *pipe,
+ SplashCoord
y,
+ SplashCoord
xMin, SplashCoord xMax) {
+ int yI, xmaxI, xminI;
+ int height = bitmap->getHeight();
+ int width = bitmap->getWidth();
+ Guchar *bitmapAlpha = bitmap->getAlphaPtr();
+ yI = splashRound(y);
+ xmaxI = splashRound(xMax);
+ xminI = splashRound(xMin);
+ if (yI >= 0 && yI < height && xMax >= 0) {
+ if (xminI < 0)
+ xminI = 0;
+ if (xminI < width) {
+ if (xmaxI > width - 1)
+ xmaxI = width - 1;
+ drawSpan(pipe, xminI, xmaxI, yI, gTrue);
+ }
+ }
+}
+
+void Splash::drawBCircleLine(SplashPipe *pipe, SplashPath *bresInnerPoints,
+ SplashCoord
y, SplashCoord yiMin, SplashCoord yiMax,
+ SplashCoord
yi, SplashCoord xi, SplashCoord iradius,
+ SplashCoord
xMin, SplashCoord xMax, int lineWidth) {
+ if (y > yiMax || y < yiMin)
+ drawPartCircleLine(pipe, y, xMin, xMax);
+ else {
+ SplashCoord xiMin, xiMax;
+ getBCircleLine(bresInnerPoints, y, yi, iradius, &xiMin);
+ xiMax = xi + xiMin;
+ xiMin = xi - xiMin;
+ if (xiMin >= xMin || xiMax <= xMax) {
+ if (xiMax < xMin || xiMin > xMax)
+ drawPartCircleLine(pipe, y, xMin, xMax);
+ else if (xiMin <= xMin && xiMax < xMax) {
+ if (xiMin != xMin)
+ drawPartCircleLine(pipe, y, xMin, xMin
+ lineWidth);
+ drawPartCircleLine(pipe, y, (xMax - xiMax >
lineWidth) ? xiMax : xMax - lineWidth, xMax);
+ } else if (xiMin >= xMin && xiMax <= xMax) {
+ if (xiMin != xMin)
+ drawPartCircleLine(pipe, y, xMin, xiMin
- 1);
+ if (xiMax != xMax)
+ drawPartCircleLine(pipe, y, xiMax+ 1,
xMax);
+ } else {
+ if (xiMin != xMin)
+ drawPartCircleLine(pipe, y, xMin,
(xiMin - xMin > lineWidth) ? xiMin : xMin + lineWidth);
+ drawPartCircleLine(pipe, y, xMax - lineWidth,
xMax);
+ }
+ }
+ }
+}
+
+SplashPath *Splash::drawCircle(SplashCoord xo, SplashCoord yo, SplashCoord
oradius, SplashColorPtr cur, SplashPath *bresOuterPoints,
+ SplashCoord xi, SplashCoord yi,
SplashCoord iradius, SplashColorPtr curNext, GBool fExtend,
+ SplashPipe *pipe) {
+ SplashPath *bresInnerPoints = getBresenhamPoints(xi, yi, iradius);
+ if (bresInnerPoints == NULL)
+ return bresInnerPoints;
+
+ if (!fExtend) {
+ SplashCoord yiMax = yi + iradius, yiMin = yi - iradius;
+ SplashCoord yoMax = yo + oradius, yoMin = yo - oradius;
+ Guchar dummy;
+ int lineWidth = splashRound(oradius - iradius);
+ if (lineWidth > 3) lineWidth = 3;
+ // draw upper half
+ int startPoint = 0;
+ if (yoMax >= bitmap->getHeight()) {
+ startPoint = splashRound(yoMax - bitmap->getHeight() +
1);
+ }
+ int endPoint = startPoint + bitmap->getHeight();
+ if (endPoint > bresOuterPoints->getLength())
+ endPoint = bresOuterPoints->getLength();
+ for (int i = startPoint; i < endPoint; i++) {
+ SplashCoord curX, curY;
+ SplashCoord xMin, xMax;
+ bresOuterPoints->getPoint(i, &curX, &curY, &dummy);
+ xMax = xo + curX;
+ xMin = xo - curX;
+ curY = yo + curY;
+ drawBCircleLine(pipe, bresInnerPoints,
+ curY, yiMin, yiMax, yi, xi, iradius, xMin,
xMax, lineWidth);
+ }
+ // draw lower half
+ endPoint = splashRound(bitmap->getHeight() - yoMin);
+ startPoint = endPoint - bitmap->getHeight();
+ if (endPoint > bresOuterPoints->getLength())
+ endPoint = bresOuterPoints->getLength();
+ if (startPoint < 0)
+ startPoint = 0;
+ for (int i = startPoint; i < endPoint; i++) {
+ SplashCoord curX, curY;
+ SplashCoord xMin, xMax;
+ bresOuterPoints->getPoint(i, &curX, &curY, &dummy);
+ xMax = xo + curX;
+ xMin = xo - curX;
+ curY = yo - curY;
+ drawBCircleLine(pipe, bresInnerPoints,
+ curY, yiMin, yiMax, yi, xi, iradius, xMin,
xMax, lineWidth);
+ }
+ splashColorCopy(cur, curNext);
+ } else {
+ SplashCoord yoMax = yo + oradius, yoMin = yo - oradius;
+ SplashCoord yiMax = yi + iradius, yiMin = yi - iradius;
+ Guchar dummy;
+ int lineWidth = splashRound(iradius - oradius);
+ if (lineWidth > 3) lineWidth = 3;
+ splashColorCopy(cur, curNext);
+ // draw upper half
+ int startPoint = 0;
+ if (yiMax >= bitmap->getHeight()) {
+ startPoint = splashRound(yiMax - bitmap->getHeight() +
1);
+ }
+ int endPoint = startPoint + bitmap->getHeight();
+ if (endPoint > bresInnerPoints->getLength())
+ endPoint = bresInnerPoints->getLength();
+ for (int i = startPoint; i < endPoint; i++) {
+ SplashCoord curX, curY;
+ SplashCoord xMin, xMax;
+ bresInnerPoints->getPoint(i, &curX, &curY, &dummy);
+ xMax = xi + curX;
+ xMin = xi - curX;
+ curY = yi + curY;
+ drawBCircleLine(pipe, bresOuterPoints,
+ curY, yoMin, yoMax, yo, xo, oradius, xMin,
xMax, lineWidth);
+ }
+ // draw lower half
+ endPoint = splashRound(bitmap->getHeight() - yiMin);
+ startPoint = endPoint - bitmap->getHeight();
+ if (endPoint > bresInnerPoints->getLength())
+ endPoint = bresInnerPoints->getLength();
+ if (startPoint < 0)
+ startPoint = 0;
+ for (int i = startPoint; i < endPoint; i++) {
+ SplashCoord curX, curY;
+ SplashCoord xMin, xMax;
+ bresInnerPoints->getPoint(i, &curX, &curY, &dummy);
+ xMax = xi + curX;
+ xMin = xi - curX;
+ curY = yi - curY;
+ drawBCircleLine(pipe, bresOuterPoints,
+ curY, yoMin, yoMax, yo, xo, oradius, xMin,
xMax, lineWidth);
+ }
+ }
+// fprintf(stderr, "Not drawn: %d\n", notdrawn);
+ return bresInnerPoints;
+}
+
+SplashError Splash::radialShadedFill(SplashRadialColor *shading) {
+ SplashPipe pipe;
+ SplashColor cSrcVal, cNextVal;
+ SplashColorPtr cur = cSrcVal, curNext = cNextVal;
+ SplashCoord xo, yo, oradius;
+ SplashCoord xi, yi, iradius;
+ int tl, tr, tu, td, enclosure;
+ SplashCoord ydl, yul, xll, xrl;
+ GBool fExtend = shading->enlargeCircles();
+
+ pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha, gFalse,
gFalse);
+ pipe.cSrc = cur;
+
+ // extend starting circle
+ if (fExtend && shading->getSmallerExtendCircle(&xo, &yo, &oradius, cur,
fExtend)) {
+ SplashPath *bresOuterPoints = getBresenhamPoints(xo, yo,
oradius);
+ if (bresOuterPoints == NULL)
+ return splashErrEmptyPath;
+ if (oradius == 0)
+ drawPartCircleLine(&pipe, yo, xo, xo);
+ while (shading->getNextSmallerExtendCircle(&xi, &yi, &iradius,
fExtend)) {
+ if (xi == xo && yi == yo && iradius == oradius) {
+ continue;
+ }
+ SplashPath *bresInnerPoints = drawCircle(xo, yo,
oradius, cur, bresOuterPoints,
+ xi, yi, iradius, cur, fExtend, &pipe);
+ if (bresInnerPoints == NULL)
+ break;
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ yo = yi; xo = xi; oradius = iradius;
+ }
+ delete bresOuterPoints;
+ }
+ if (!fExtend && shading->getLargerExtendCircle(&xo, &yo, &oradius,
cur)) {
+ SplashPath *bresOuterPoints = getBresenhamPoints(xo, yo,
oradius);
+ if (bresOuterPoints == NULL)
+ return splashErrEmptyPath;
+ // start with filling the circle
+ SplashCoord xMin, xMax;
+ Guchar dummy;
+ tl = tr = tu = td = enclosure = 0;
+ ydl = xll = yul = xrl = -1;
+ // draw upper half
+ int startPoint = 0;
+ if (yo + oradius >= bitmap->getHeight()) {
+ startPoint = splashRound(yo + oradius -
bitmap->getHeight() + 1);
+ }
+ int endPoint = startPoint + bitmap->getHeight();
+ if (endPoint > bresOuterPoints->getLength())
+ endPoint = bresOuterPoints->getLength();
+ for (int i = startPoint; i < endPoint; i++) {
+ SplashCoord curX, curY;
+ bresOuterPoints->getPoint(i, &curX, &curY, &dummy);
+ curY = yo - curY;
+ xMax = xo + curX;
+ xMin = xo - curX;
+ drawPartCircleLine(&pipe, curY, xMin, xMax);
+ }
+ // draw lower half
+ endPoint = splashRound(bitmap->getHeight() - (yo - oradius));
+ startPoint = endPoint - bitmap->getHeight();
+ if (endPoint > bresOuterPoints->getLength())
+ endPoint = bresOuterPoints->getLength();
+ if (startPoint < 0)
+ startPoint = 0;
+ for (int i = startPoint; i < endPoint; i++) {
+ SplashCoord curX, curY;
+ bresOuterPoints->getPoint(i, &curX, &curY, &dummy);
+ curY += yo;
+ xMax = xo + curX;
+ xMin = xo - curX;
+ drawPartCircleLine(&pipe, curY, xMin, xMax);
+ }
+ while (shading->getNextLargerExtendCircle(&xi, &yi, &iradius,
fExtend)) {
+ if (xi == xo && yi == yo && iradius == oradius) {
+ continue;
+ }
+ SplashPath *bresInnerPoints = drawCircle(xo, yo,
oradius, cur, bresOuterPoints,
+ xi, yi, iradius, cur, gTrue, &pipe);
+ if (bresInnerPoints == NULL)
+ break;
+ // test for enclosure
+ if (shading->encloseCircle(xi, yi, iradius, xo, yo,
oradius))
+ enclosure++;
+ else
+ enclosure = 0;
+ // test for tangents
+ if (yo == yi && abs(xi - xo + oradius - iradius) < 2) {
+ if (xll == -1)
+ xll = xi - iradius;
+ if (abs(xll - xo + oradius) < 2)
+ tl++;
+ else {
+ tl = 0;
+ xll = xi - iradius;
+ }
+ }
+ if (yo == yi && abs(xi - xo + iradius - oradius) < 2) {
+ if (xrl == -1)
+ xrl = xi + iradius;
+ if (abs(xrl - xo - oradius) < 2)
+ tr++;
+ else {
+ tr = 0;
+ xrl = xi + iradius;
+ }
+ }
+ if (xo == xi && abs(yi - yo + oradius - iradius) < 2) {
+ if (ydl == -1)
+ ydl = yi - iradius;
+ if (abs(ydl - yo + oradius) < 2)
+ td++;
+ else {
+ td = 0;
+ ydl = yi - iradius;
+ }
+ }
+ if (xo == xi && abs(yi - yo + iradius - oradius) < 2) {
+ if (yul == -1)
+ yul = yi + iradius;
+ if (abs(yul - yo - oradius) < 2)
+ tu++;
+ else {
+ tu = 0;
+ yul = yi + iradius;
+ }
+ }
+ // do enclosure
+ if (enclosure == 6) {
+ SplashCoord curX, curY;
+ SplashCoord xMin, xMax;
+ Guchar dummy;
+ xll = (tl >= 6) ? xi - iradius : 0;
+ xrl = (tr >= 6) ? xi + iradius :
bitmap->getWidth() - 1;
+ ydl = (td >= 6) ? yi - iradius : 0;
+ yul = (tu >= 6) ? yi + iradius :
bitmap->getHeight() - 1;
+ bresOuterPoints->getPoint(0, &curX, &curY,
&dummy);
+ curY += yo;
+ for (int i = splashRound(curY) + 1; i <
bitmap->getHeight(); i++)
+ if (i >= ydl && i <= yul)
+ drawPartCircleLine(&pipe, i,
xll, xrl);
+ for (int i = 0; i <
bresOuterPoints->getLength(); i++) {
+ bresOuterPoints->getPoint(i, &curX,
&curY, &dummy);
+ curY += yo;
+ xMax = xo + curX;
+ xMin = xo - curX;
+ if (curY >= ydl && curY <= yul) {
+ if (xMin > 0)
+
drawPartCircleLine(&pipe, curY, xll, xMin);
+ if (xMax < bitmap->getWidth())
+
drawPartCircleLine(&pipe, curY, xMax, xrl);
+ }
+ curY = 2 * yo - curY;
+ if (curY >= ydl && curY <= yul) {
+ if (xMin > 0)
+
drawPartCircleLine(&pipe, curY, xll, xMin);
+ if (xMax < bitmap->getWidth())
+
drawPartCircleLine(&pipe, curY, xMax, xrl);
+ }
+ }
+ bresOuterPoints->getPoint(0, &curX, &curY,
&dummy);
+ curY = yo - curY;
+ for (int i = 0; i < curY; i++)
+ if (i >= ydl && i <= yul)
+ drawPartCircleLine(&pipe, i,
xll, xrl);
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ break;
+ }
+ // do tangents if other side is completely outside
+ if (tl >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, 0, 0)) {
+ for (int i = 0; i <
bitmap->getHeight(); i++)
+
drawPartCircleLine(&pipe, i, xi - iradius, xi - iradius);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ if (tr >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius, 0,
bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
0, 0, 0)) {
+ for (int i = 0; i <
bitmap->getHeight(); i++)
+
drawPartCircleLine(&pipe, i, xi + iradius, xi + iradius);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ if (tu >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, 0, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
0, 0, 0)) {
+ drawPartCircleLine(&pipe, yi +
iradius, 0, bitmap->getWidth() - 1);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ if (td >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
0, bitmap->getHeight() - 1, 0)) {
+ drawPartCircleLine(&pipe, yi -
iradius, 0, bitmap->getWidth() - 1);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ yo = yi; xo = xi; oradius = iradius;
+ }
+ delete bresOuterPoints;
+ }
+
+ shading->getStartCircle(&xo, &yo, &oradius, cur);
+ if (oradius == 0)
+ drawPartCircleLine(&pipe, yo, xo, xo);
+ SplashPath *bresOuterPoints = getBresenhamPoints(xo, yo, oradius);
+ if (bresOuterPoints == NULL)
+ return splashErrEmptyPath;
+ tl = tr = tu = td = 0;
+ ydl = xll = yul = xrl = -1;
+ while (shading->getNextCircle(&xi, &yi, &iradius, curNext)) {
+ if (xi == xo && yi == yo && iradius == oradius) {
+ splashColorCopy(cur, curNext);
+ continue;
+ }
+ // test for tangents
+ if (yo == yi && abs(xi - xo + oradius - iradius) < 2) {
+ if (xll == -1)
+ xll = xi - iradius;
+ if (abs(xll - xo + oradius) < 2)
+ tl++;
+ else {
+ tl = 0;
+ xll = xi - iradius;
+ }
+ }
+ if (yo == yi && abs(xi - xo + iradius - oradius) < 2) {
+ if (xrl == -1)
+ xrl = xi + iradius;
+ if (abs(xrl - xo - oradius) < 2)
+ tr++;
+ else {
+ tr = 0;
+ xrl = xi + iradius;
+ }
+ }
+ if (xo == xi && abs(yi - yo + oradius - iradius) < 2) {
+ if (ydl == -1)
+ ydl = yi - iradius;
+ if (abs(ydl - yo + oradius) < 2)
+ td++;
+ else {
+ td = 0;
+ ydl = yi - iradius;
+ }
+ }
+ if (xo == xi && abs(yi - yo + iradius - oradius) < 2) {
+ if (yul == -1)
+ yul = yi + iradius;
+ if (abs(yul - yo - oradius) < 2)
+ tu++;
+ else {
+ tu = 0;
+ yul = yi + iradius;
+ }
+ }
+ if (shading->testClip(xi, yi, iradius) != splashClipAllOutside)
{
+ SplashPath *bresInnerPoints = drawCircle(xo, yo,
oradius, cur, bresOuterPoints,
+ xi, yi, iradius, curNext, fExtend, &pipe);
+ if (bresInnerPoints == NULL)
+ break;
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ }
+ if (shading->testClip(xi, yi, iradius) == splashClipAllInside
&& iradius >= oradius)
+ break;
+ // do tangents if other side is completely outside
+ if (tl >= 256 && fExtend) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, 0, 0)) {
+ break;
+ }
+ }
+ if (tr >= 256 && fExtend) {
+ if (shading->encloseCircle(xi, yi, iradius, 0,
bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius, 0, 0,
0)) {
+ break;
+ }
+ }
+ if (tu >= 256 && fExtend) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, 0, 0) &&
+ shading->encloseCircle(xi, yi, iradius, 0, 0,
0)) {
+ break;
+ }
+ }
+ if (td >= 256 && fExtend) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius, 0,
bitmap->getHeight() - 1, 0)) {
+ break;
+ }
+ }
+ yo = yi; xo = xi; oradius = iradius;
+ }
+ delete bresOuterPoints;
+
+ // extend ending circle
+ if (!fExtend && shading->getSmallerExtendCircle(&xo, &yo, &oradius,
cur, fExtend)) {
+ SplashPath *bresOuterPoints = getBresenhamPoints(xo, yo,
oradius);
+ if (bresOuterPoints == NULL)
+ return splashErrEmptyPath;
+ while (shading->getNextSmallerExtendCircle(&xi, &yi, &iradius,
fExtend)) {
+ if (xi == xo && yi == yo && iradius == oradius) {
+ continue;
+ }
+ if (shading->testClip(xo, yo, oradius) ==
splashClipAllOutside)
+ break;
+ SplashPath *bresInnerPoints = drawCircle(xo, yo,
oradius, cur, bresOuterPoints,
+ xi, yi, iradius, cur, fExtend, &pipe);
+ if (bresInnerPoints == NULL)
+ break;
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ yo = yi; xo = xi; oradius = iradius;
+ }
+ delete bresOuterPoints;
+ }
+ if (fExtend && shading->getLargerExtendCircle(&xo, &yo, &oradius, cur))
{
+ tl = tr = tu = td = enclosure = 0;
+ ydl = xll = yul = xrl = -1;
+ SplashPath *bresOuterPoints = getBresenhamPoints(xo, yo,
oradius);
+ if (bresOuterPoints == NULL)
+ return splashErrEmptyPath;
+ // don't fill the circle here, just extend:
+ while (shading->getNextLargerExtendCircle(&xi, &yi, &iradius,
gTrue)) {
+ if (xi == xo && yi == yo && iradius == oradius) {
+ continue;
+ }
+ if (shading->testClip(xo, yo, oradius) ==
splashClipAllInside)
+ break;
+ SplashPath *bresInnerPoints = drawCircle(xo, yo,
oradius, cur, bresOuterPoints,
+ xi, yi, iradius, cur, gTrue, &pipe);
+ if (bresInnerPoints == NULL)
+ break;
+ // test for enclosure
+ if (shading->encloseCircle(xi, yi, iradius, xo, yo,
oradius))
+ enclosure++;
+ else
+ enclosure = 0;
+ // test for tangents
+ if (yo == yi && abs(xi - xo + oradius - iradius) < 2) {
+ if (xll == -1)
+ xll = xi - iradius;
+ if (abs(xll - xo + oradius) < 2)
+ tl++;
+ else {
+ tl = 0;
+ xll = xi - iradius;
+ }
+ }
+ if (yo == yi && abs(xi - xo + iradius - oradius) < 2) {
+ if (xrl == -1)
+ xrl = xi + iradius;
+ if (abs(xrl - xo - oradius) < 2)
+ tr++;
+ else {
+ tr = 0;
+ xrl = xi + iradius;
+ }
+ }
+ if (xo == xi && abs(yi - yo + oradius - iradius) < 2) {
+ if (ydl == -1)
+ ydl = yi - iradius;
+ if (abs(ydl - yo + oradius) < 2)
+ td++;
+ else {
+ td = 0;
+ ydl = yi - iradius;
+ }
+ }
+ if (xo == xi && abs(yi - yo + iradius - oradius) < 2) {
+ if (yul == -1)
+ yul = yi + iradius;
+ if (abs(yul - yo - oradius) < 2)
+ tu++;
+ else {
+ tu = 0;
+ yul = yi + iradius;
+ }
+ }
+ // do enclosure
+ if (enclosure == 6) {
+ SplashCoord curX, curY;
+ SplashCoord xMin, xMax;
+ Guchar dummy;
+ xll = (tl >= 6) ? xi - iradius : 0;
+ xrl = (tr >= 6) ? xi + iradius :
bitmap->getWidth() - 1;
+ ydl = (td >= 6) ? yi - iradius : 0;
+ yul = (tu >= 6) ? yi + iradius :
bitmap->getHeight() - 1;
+ bresOuterPoints->getPoint(0, &curX, &curY,
&dummy);
+ curY += yo;
+ for (int i = splashRound(curY) + 1; i <
bitmap->getHeight(); i++)
+ if (i >= ydl && i <= yul)
+ drawPartCircleLine(&pipe, i,
xll, xrl);
+ for (int i = 0; i <
bresOuterPoints->getLength(); i++) {
+ bresOuterPoints->getPoint(i, &curX,
&curY, &dummy);
+ curY += yo;
+ xMax = xo + curX;
+ xMin = xo - curX;
+ if (curY >= ydl && curY <= yul) {
+ if (xMin > 0)
+
drawPartCircleLine(&pipe, curY, xll, xMin);
+ if (xMax < bitmap->getWidth())
+
drawPartCircleLine(&pipe, curY, xMax, xrl);
+ }
+ curY = 2 * yo - curY;
+ if (curY >= ydl && curY <= yul) {
+ if (xMin > 0)
+
drawPartCircleLine(&pipe, curY, xll, xMin);
+ if (xMax < bitmap->getWidth())
+
drawPartCircleLine(&pipe, curY, xMax, xrl);
+ }
+ }
+ bresOuterPoints->getPoint(0, &curX, &curY,
&dummy);
+ curY = yo - curY;
+ for (int i = 0; i < curY; i++)
+ if (i >= ydl && i <= yul)
+ drawPartCircleLine(&pipe, i,
xll, xrl);
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ break;
+ }
+ // do tangents if other side is completely outside
+ if (tl >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, 0, 0)) {
+ for (int i = 0; i <
bitmap->getHeight(); i++)
+
drawPartCircleLine(&pipe, i, xi - iradius, xi - iradius);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ if (tr >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius, 0,
bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
0, 0, 0)) {
+ for (int i = 0; i <
bitmap->getHeight(); i++)
+
drawPartCircleLine(&pipe, i, xi + iradius, xi + iradius);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ if (tu >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, 0, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
0, 0, 0)) {
+ drawPartCircleLine(&pipe, yi +
iradius, 0, bitmap->getWidth() - 1);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ if (td >= 6) {
+ if (shading->encloseCircle(xi, yi, iradius,
bitmap->getWidth() - 1, bitmap->getHeight() - 1, 0) &&
+ shading->encloseCircle(xi, yi, iradius,
0, bitmap->getHeight() - 1, 0)) {
+ drawPartCircleLine(&pipe, yi -
iradius, 0, bitmap->getWidth() - 1);
+ delete bresOuterPoints;
+ bresOuterPoints =
bresInnerPoints;
+ break;
+ }
+ }
+ delete bresOuterPoints;
+ bresOuterPoints = bresInnerPoints;
+ yo = yi; xo = xi; oradius = iradius;
+ }
+ delete bresOuterPoints;
+ }
+ return splashOk;
+}
+
SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
int xDest, int yDest, int w, int h) {
SplashColor pixel;
@@ -3950,19 +4619,25 @@ SplashError Splash::shadedFill(SplashPath *path, GBool
hasBBox,
int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
SplashClipResult clipRes;
- if (aaBuf == NULL) { // should not happen, but to be secure
+ if (vectorAntialias && aaBuf == NULL) { // should not happen, but to be
secure
return splashErrGeneric;
}
if (path->length == 0) {
return splashErrEmptyPath;
}
xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
- xPath->aaScale();
+ if (vectorAntialias) {
+ xPath->aaScale();
+ }
xPath->sort();
scanner = new SplashXPathScanner(xPath, gFalse);
- // get the min and max x and y values
- scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ // get the min and max x and y values
+ if (vectorAntialias) {
+ scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ } else {
+ scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ }
// check clipping
if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) !=
splashClipAllOutside) {
@@ -3977,13 +4652,34 @@ SplashError Splash::shadedFill(SplashPath *path, GBool
hasBBox,
pipeInit(&pipe, 0, yMinI, pattern, NULL, state->fillAlpha, vectorAntialias
&& !hasBBox, gFalse);
// draw the spans
- for (y = yMinI; y <= yMaxI; ++y) {
- scanner->renderAALine(aaBuf, &x0, &x1, y);
- if (clipRes != splashClipAllInside) {
- state->clip->clipAALine(aaBuf, &x0, &x1, y);
- }
- drawAALine(&pipe, x0, x1, y);
- }
+ if (vectorAntialias) {
+ for (y = yMinI; y <= yMaxI; ++y) {
+ scanner->renderAALine(aaBuf, &x0, &x1, y);
+ if (clipRes != splashClipAllInside) {
+ state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ }
+ drawAALine(&pipe, x0, x1, y);
+ }
+ } else {
+ SplashClipResult clipRes2;
+ for (y = yMinI; y <= yMaxI; ++y) {
+ while (scanner->getNextSpan(y, &x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, gTrue);
+ } else {
+ // limit the x range
+ if (x0 < state->clip->getXMinI()) {
+ x0 = state->clip->getXMinI();
+ }
+ if (x1 > state->clip->getXMaxI()) {
+ x1 = state->clip->getXMaxI();
+ }
+ clipRes2 = state->clip->testSpan(x0,
x1, y);
+ drawSpan(&pipe, x0, x1, y, clipRes2 ==
splashClipAllInside);
+ }
+ }
+ }
+ }
}
opClipRes = clipRes;
diff --git a/splash/Splash.h b/splash/Splash.h
index a52dc13..a06f694 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -255,6 +255,17 @@ public:
SplashPattern *pattern);
// Draw a gouraud triangle shading.
GBool gouraudTriangleShadedFill(SplashGouraudColor *shading);
+ // Draw a radial shading.
+ void drawPartCircleLine(SplashPipe *pipe, SplashCoord y, SplashCoord xMin,
SplashCoord xMax);
+ void drawBCircleLine(SplashPipe *pipe, SplashPath *bresInnerPoints,
+ SplashCoord y, SplashCoord yiMin,
SplashCoord yiMax,
+ SplashCoord yi, SplashCoord xi,
SplashCoord iradius,
+ SplashCoord xMin, SplashCoord xMax,
int lineWidth);
+ SplashPath *getBresenhamPoints(SplashCoord x0, SplashCoord y0, SplashCoord
radius);
+ SplashPath *drawCircle(SplashCoord xo, SplashCoord yo, SplashCoord oradius,
SplashColorPtr cur,
+ SplashPath *bresOuterPoints,
SplashCoord xi, SplashCoord yi, SplashCoord iradius,
+ SplashColorPtr curNext, GBool
fExtend, SplashPipe *pipe);
+ SplashError radialShadedFill(SplashRadialColor *shading);
private:
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h
index 09e9b1a..f0b5f36 100644
--- a/splash/SplashPattern.h
+++ b/splash/SplashPattern.h
@@ -26,8 +26,11 @@
#endif
#include "SplashTypes.h"
+#include "SplashClip.h"
class SplashScreen;
+class Splash;
+class SplashBitmap;
//------------------------------------------------------------------------
// SplashPattern
@@ -92,4 +95,25 @@ public:
virtual void getParameterizedColor(double t, SplashColorMode mode,
SplashColorPtr c) = 0;
};
+//------------------------------------------------------------------------
+// SplashRadialColor (needed for radialShadedFill)
+//------------------------------------------------------------------------
+
+class SplashRadialColor: public SplashPattern {
+public:
+ virtual void getStartCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c) = 0;
+ virtual GBool getNextCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c) = 0;
+ virtual GBool getSmallerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c, GBool fExtend) = 0;
+ virtual GBool getNextSmallerExtendCircle(SplashCoord *x0, SplashCoord
*y0, SplashCoord *radius, GBool fExtend) = 0;
+ virtual GBool getLargerExtendCircle(SplashCoord *x0, SplashCoord *y0,
SplashCoord *radius, SplashColorPtr c) = 0;
+ virtual GBool getNextLargerExtendCircle(SplashCoord *x0, SplashCoord
*y0, SplashCoord *radius, GBool fExtend) = 0;
+ virtual SplashClipResult testClip(SplashCoord x, SplashCoord y,
SplashCoord r) = 0;
+ virtual GBool encloseCircle(SplashCoord x0, SplashCoord y0, SplashCoord
r0,
+ SplashCoord x1, SplashCoord y1, SplashCoord r1) = 0;
+ virtual GBool enlargeCircles() = 0;
+ virtual GBool isOk() = 0;
+ virtual Splash *getSplash() = 0;
+ virtual SplashBitmap *getBitmap() = 0;
+};
+
#endif
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler