Hi Albert!

I discussed this issue with Christian, and I have the following suggestion now: 1. You should commit the bugfix part of Christian's patch in 0.15.0, so that it will be part of 0.15.1. To clearify what I mean with the bugfix part, I attach the bugfix diff I made against 0.15.0 once again. This should already run over Your regtest, as far as I understand the several mails here. 2. I take over the improvement part of the patch, where Christian implements the gouraud shading in Splash. I made several suggestions to Christian, i.e. that in the Splash library should be nor references to the Gfx stuff from the poppler library. I will walk over the code and redesign it a little bit next weekend. The base should be the same. 3. After You create the 0.15.1, I will make a new diff including my improvements of bug 30436 and the improvements of Cjhristian and upload that patch to bug 30436.

Is this okay for You (and for Christian, too), or does anyone have other suggestions?

Best regards,
Thomas

Am 13.10.2010 20:56, schrieb Christian Feuersaenger:
Am 13.10.2010 20:34, schrieb Albert Astals Cid:
A Divendres, 8 d'octubre de 2010, Christian Feuersaenger va escriure:
Am 07.10.2010 23:17, schrieb Albert Astals Cid:
A Divendres, 1 d'octubre de 2010, Christian Feuersaenger va escriure:
Am 13.08.2010 23:43, schrieb Albert Astals Cid:
A Divendres, 30 de juliol de 2010, Albert Astals Cid va escriure:
A Dimarts, 27 de juliol de 2010, Christian Feuersaenger va escriure:
Dear Albert,

thank you for your time to perform the regression tests!

I have fixed the bug; it was a data type problem.

Attached you find the fixed version.

The file
bugfix_shadingtype4567_incremental.patch
is relative to the version you used for the regression tests.

The file
bugfix_shadingtype4567_poppler0.14.patch
is relative to poppler-0.14.0-3-gb2427d0 .

Thank you for considering my contributions.
I've ran the regression test with the Splash outputdev and all looks
ok, will have to run it over the cairo and ps outputdevs before
committing, though it'll take a while since next week i'm going to be
away on holidays.
Bad news, this patch produces a regression in pdftops when running over
the attached file, that is, the unpatched version creates a ps file
that is valid (gs will open it) and the patched version creates a ps
file that "crashes" gs.

Do you think you can have a look?

Albert
Dear Albert,

I am having difficulties to reproduce the problem. Here is what I did:

1. try to view bug157704.pdf with the standard gs
-->   crash (see below)
2. call pdftops (using system's version of libpoppler) and open gs on
the result
-->   works without errors (see below)
3. call pdftops using the patched libpoppler and open gs on the result
-->   works without errors
4. call pdftops of poppler git version of 0.14 without my patch (I have
not yet pulled the new version) and open gs on the result
-->   works without errors

Do you have more detailed information about the crash? I fear I am
unable to do anything here...
Wops, works for me now too, i must have done something weird, sorry :-/

I'll start the regression test again.

Albert
Ok, thanks for the notice!
Dear Albert,

thanks for the thorough testing.

The regression test was successful, though i have some questions i'd like to
get answered before commiting the patch.

In Gfx::gouraudFillTriangle you removed the check for contentIsHidden, why?
Hm. It seems as if the test should be there - I must have forgotten to include it. Thank you for pointing it out! Could you add it right before the fill statement?

Why do this if everything else in the line is intengers, what's the point of
having a 2. there?
-      color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
+      color01.c[i] = (color0->c[i] + color1->c[i]) / 2.;

You are right, that's certainly a waste of time. I should have investigated the compiler warnings; sorry about that. Please feel free to remove the double suffixes.

Best regards

Christian


Here are the detailed outputs for your reference:

for (1):
[ludewich] tmp>>gs bug157704.pdf
GPL Ghostscript 8.71 (2010-02-10)
Copyright (C) 2010 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 1.
Page 1
Error: /unknownerror in --run--

Operand stack:
      --dict:6/15(L)--

Execution stack:
      %interp_exit   .runexec2   --nostringval--   --nostringval--

--nostringval--   2   %stopped_push   --nostringval--
--nostringval--   --nostringval--   false   1   %stopped_push   1878
1   3   %oparray_pop   1877   1   3   %oparray_pop   1861   1   3
%oparray_pop   --nostringval--   --nostringval--   2   1   1
--nostringval--   %for_pos_int_continue   --nostringval--
--nostringval--   false   1   %stopped_push   --nostringval--
--nostringval--   --nostringval--   %array_continue   --nostringval--
false   1   %stopped_push   --nostringval--   %loop_continue
--nostringval--

Dictionary stack:
--dict:1153/1684(ro)(G)-- --dict:1/20(G)-- --dict:75/200(L)--

--dict:75/200(L)-- --dict:108/127(ro)(G)-- --dict:288/300(ro)(G)--
--dict:22/25(L)--   --dict:6/8(L)--   --dict:21/40(L)--
--dict:3/5(L)-- Current allocation mode is local
Last OS error: 11
GPL Ghostscript 8.71: Unrecoverable error, exit code 1

for (2):
[ludewich] tmp>>pdftops -?
pdftops version 0.12.4
[ludewich] tmp>>time pdftops bug157704.pdf

real    0m14.925s
user    0m13.900s
sys    0m0.140s
[ludewich] tmp>>gs bug157704.ps
GPL Ghostscript 8.71 (2010-02-10)
[ ALL OK ]

for (3):
[ludewich] poppler>>git describe # (with my patch)
poppler-0.14.0-18-g821bc2a
[ludewich] tmp>>time ~/code/xpdf/poppler/utils/pdftops bug157704.pdf

real    0m2.785s
user    0m2.540s
sys    0m0.130s
[ludewich] tmp>>gs bug157704.ps
GPL Ghostscript 8.71 (2010-02-10)
Copyright (C) 2010 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
[ ALL OK ]


for (4):
[ludewich] poppler>>git describe # (without my patch using poppler-0.14
) poppler-0.14.0-3-gb2427d0
[ludewich] tmp>>time ~/code/xpdf/poppler/utils/pdftops bug157704.pdf

real    0m15.844s
user    0m13.820s
sys    0m0.140s
[ludewich] tmp>>gs bug157704.ps
GPL Ghostscript 8.71 (2010-02-10)
Copyright (C) 2010 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
[ ALL OK ]

Albert

Best regards

Christian

Am 25.07.2010 16:56, schrieb Albert Astals Cid:
A Dissabte, 3 de juliol de 2010, Christian Feuersaenger va escriure:
Hello Albert,
Hi

I've managed to fix a bug in the Shading Type 6/7 (Coons& cubic
tensor patches) implementation.

The bugfix is small and stable (in my eyes); the poppler-0.14
branch doesn't implement support for parameterized patch shadings. I modified the existing implementation accordingly with relatively
few changes.

Attached you find the patch file and the updated test.pdf to see
the improvement.

The file type4567patch.... also includes the patch of my previous
mail (they only share the same refinement threshold).

The patch should work relative to poppler-0.14.0-3-gb2427d0 .
This patch causes a regression in the attached pdf (the blue area
disappears)

Albert

Best regards

Christian


_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler



_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

.


diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 7552fed..079706e 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -32,6 +32,7 @@
 // Copyright (C) 2009 William Bader <[email protected]>
 // Copyright (C) 2009, 2010 David Benjamin <[email protected]>
 // Copyright (C) 2010 Nils Höglund <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -99,18 +100,26 @@
 #define radialColorDelta (dblToCol(1 / 256.0))
 
 // Max recursive depth for a Gouraud triangle shading fill.
+//
+// Triangles will be split at most gouraudMaxDepth times (each time into 4
+// smaller ones). That makes pow(4,gouraudMaxDepth) many triangles for
+// every triangle.
 #define gouraudMaxDepth 6
 
 // Max delta allowed in any color component for a Gouraud triangle
 // shading fill.
-#define gouraudColorDelta (dblToCol(1 / 256.0))
+#define gouraudColorDelta (dblToCol(3. / 256.0))
+
+// Gouraud triangle: if the three color parameters differ by at more than this 
percend of
+// the total color parameter range, the triangle will be refined
+#define gouraudParameterizedColorDelta 5e-3
 
 // Max recursive depth for a patch mesh shading fill.
 #define patchMaxDepth 6
 
 // Max delta allowed in any color component for a patch mesh shading
 // fill.
-#define patchColorDelta (dblToCol(1 / 256.0))
+#define patchColorDelta (dblToCol((3. / 256.0)))
 
 //------------------------------------------------------------------------
 // Operator table
@@ -487,7 +496,7 @@ GBool GfxResources::lookupGState(char *name, Object *obj) {
 
   if (!obj->isRef())
     return gTrue;
-  
+
   const Ref ref = obj->getRef();
   if (!gStateCache.lookup(ref, obj)->isNull())
     return gTrue;
@@ -716,7 +725,7 @@ void Gfx::go(GBool topLevel) {
            data_p = new ProfileData();
            hash->add (cmd_g, data_p);
          }
-         
+
          data_p->addElement(timer.getElapsed ());
        }
       }
@@ -2389,14 +2398,14 @@ void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
     colors2[2] = colorM0;
     colors2[3] = colorMM;
     doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
-    
+
     // lower-left sub-rectangle
     colors2[0] = color0M;
     colors2[1] = colors[1];
     colors2[2] = colorMM;
     colors2[3] = colorM1;
     doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
-    
+
     // upper-right sub-rectangle
     colors2[0] = colorM0;
     colors2[1] = colorMM;
@@ -2594,10 +2603,10 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
       }
       shading->getColor(tt, &color1);
       if (isSameGfxColor(color1, color0, nComps, axialColorDelta)) {
-         // in these two if what we guarantee is that if we are skipping lots 
of 
+         // in these two if what we guarantee is that if we are skipping lots 
of
          // positions because the colors are the same, we still create a region
          // with vertexs passing by bboxIntersections[1] and 
bboxIntersections[2]
-         // otherwise we can have empty regions that should really be painted 
+         // otherwise we can have empty regions that should really be painted
          // like happened in bug 19896
          // What we do to ensure that we pass a line through this points
          // is making sure use the exact bboxIntersections[] value as one of 
the used ta[] values
@@ -3097,22 +3106,62 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
 
 void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
   double x0, y0, x1, y1, x2, y2;
-  GfxColor color0, color1, color2;
   int i;
 
-  for (i = 0; i < shading->getNTriangles(); ++i) {
-    shading->getTriangle(i, &x0, &y0, &color0,
-                        &x1, &y1, &color1,
-                        &x2, &y2, &color2);
-    gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
-                       shading->getColorSpace()->getNComps(), 0);
-  }
+  // preallocate a path.
+  // Overwriting the coordinates saves about 10% at runtime for larger
+  // shadings.
+  state->moveTo(0., 0.);
+  state->lineTo(1., 0.);
+  state->lineTo(0., 1.);
+  state->closePath();
+
+  GfxState::ReusablePathIterator *reusablePath = state->getReusablePath();
+
+// Idea:
+// - state->getReferenceToReusablePath()
+// the return value has the setX/setY methods, the standard GfxState doesn't
+// - state should not delete the current path until
+// - state->freeReusablePath()
+// but that's overhead and I am not highly motivated.
+//
+
+  if (shading->isParameterized()) {
+    // work with parameterized values:
+    double color0, color1, color2;
+    // a relative threshold:
+    const double refineColorThreshold = gouraudParameterizedColorDelta *
+                                        (shading->getParameterDomainMax() - 
shading->getParameterDomainMin());
+    for (i = 0; i < shading->getNTriangles(); ++i) {
+      shading->getTriangle(i, &x0, &y0, &color0,
+                              &x1, &y1, &color1,
+                              &x2, &y2, &color2);
+      gouraudFillTriangle(x0, y0, color0, x1, y1, color1, x2, y2, color2, 
refineColorThreshold, 0, shading, reusablePath);
+    }
+
+  } else {
+    // this always produces output -- even for parameterized ranges.
+       // But it ignores the parameterized color map (the function).
+       //
+       // Note that using this code in for parameterized shadings might be
+       // correct in circumstances (namely if the function is linear in the 
actual
+       // triangle), but in general, it will simply be wrong.
+    GfxColor color0, color1, color2;
+    for (i = 0; i < shading->getNTriangles(); ++i) {
+      shading->getTriangle(i, &x0, &y0, &color0,
+                              &x1, &y1, &color1,
+                              &x2, &y2, &color2);
+      gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2, 
shading->getColorSpace()->getNComps(), 0, reusablePath);
+    }
+  }
+
+  delete reusablePath;
 }
 
 void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
                              double x1, double y1, GfxColor *color1,
                              double x2, double y2, GfxColor *color2,
-                             int nComps, int depth) {
+                             int nComps, int depth, 
GfxState::ReusablePathIterator* path) {
   double x01, y01, x12, y12, x20, y20;
   GfxColor color01, color12, color20;
   int i;
@@ -3123,16 +3172,18 @@ void Gfx::gouraudFillTriangle(double x0, double y0, 
GfxColor *color0,
       break;
     }
   }
-  if (i == nComps || depth == gouraudMaxDepth) {
+   if (i == nComps || depth == gouraudMaxDepth) {
+
     state->setFillColor(color0);
     out->updateFillColor(state);
-    state->moveTo(x0, y0);
-    state->lineTo(x1, y1);
-    state->lineTo(x2, y2);
-    state->closePath();
-    if (!contentIsHidden())
-      out->fill(state);
-    state->clearPath();
+
+       path->reset();  assert(!path->isEnd());
+       path->setCoord(x0,y0);  path->next();   assert(!path->isEnd());
+       path->setCoord(x1,y1);  path->next();   assert(!path->isEnd());
+       path->setCoord(x2,y2);  path->next();   assert(!path->isEnd());
+       path->setCoord(x0,y0);  path->next();   assert( path->isEnd());
+
+    out->fill(state);
   } else {
     x01 = 0.5 * (x0 + x1);
     y01 = 0.5 * (y0 + y1);
@@ -3140,21 +3191,76 @@ void Gfx::gouraudFillTriangle(double x0, double y0, 
GfxColor *color0,
     y12 = 0.5 * (y1 + y2);
     x20 = 0.5 * (x2 + x0);
     y20 = 0.5 * (y2 + y0);
-    //~ if the shading has a Function, this should interpolate on the
-    //~ function parameter, not on the color components
     for (i = 0; i < nComps; ++i) {
-      color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
-      color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
-      color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
+      color01.c[i] = (color0->c[i] + color1->c[i]) / 2.;
+      color12.c[i] = (color1->c[i] + color2->c[i]) / 2.;
+      color20.c[i] = (color2->c[i] + color0->c[i]) / 2.;
     }
     gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
-                       x20, y20, &color20, nComps, depth + 1);
+                       x20, y20, &color20, nComps, depth + 1, path);
     gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
-                       x12, y12, &color12, nComps, depth + 1);
+                       x12, y12, &color12, nComps, depth + 1, path);
     gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
-                       x20, y20, &color20, nComps, depth + 1);
+                       x20, y20, &color20, nComps, depth + 1, path);
     gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
-                       x2, y2, color2, nComps, depth + 1);
+                       x2, y2, color2, nComps, depth + 1, path);
+  }
+}
+
+void Gfx::gouraudFillTriangle(double x0, double y0, double color0,
+                             double x1, double y1, double color1,
+                             double x2, double y2, double color2,
+                             double refineColorThreshold, int depth, 
GfxGouraudTriangleShading* shading, GfxState::ReusablePathIterator* path ) {
+  const double meanColor = (color0 + color1 + color2) / 3;
+
+  const bool isFineEnough =
+       fabs(color0 - meanColor) < refineColorThreshold &&
+       fabs(color1 - meanColor) < refineColorThreshold &&
+       fabs(color2 - meanColor) < refineColorThreshold;
+
+  if (isFineEnough || depth == gouraudMaxDepth) {
+    GfxColor color;
+
+    shading->getParameterizedColor(meanColor, &color);
+    state->setFillColor(&color);
+    out->updateFillColor(state);
+
+       path->reset();  assert(!path->isEnd());
+       path->setCoord(x0,y0);  path->next();   assert(!path->isEnd());
+       path->setCoord(x1,y1);  path->next();   assert(!path->isEnd());
+       path->setCoord(x2,y2);  path->next();   assert(!path->isEnd());
+       path->setCoord(x0,y0);  path->next();   assert( path->isEnd());
+
+    out->fill(state);
+  } else {
+    double x01, y01, x12, y12, x20, y20;
+    double color01, color12, color20;
+    x01 = 0.5 * (x0 + x1);
+    y01 = 0.5 * (y0 + y1);
+    x12 = 0.5 * (x1 + x2);
+    y12 = 0.5 * (y1 + y2);
+    x20 = 0.5 * (x2 + x0);
+    y20 = 0.5 * (y2 + y0);
+    color01 = (color0 + color1) / 2.;
+    color12 = (color1 + color2) / 2.;
+    color20 = (color2 + color0) / 2.;
+    ++depth;
+    gouraudFillTriangle(x0, y0, color0,
+                        x01, y01, color01,
+                        x20, y20, color20,
+                        refineColorThreshold, depth, shading, path);
+    gouraudFillTriangle(x01, y01, color01,
+                        x1, y1, color1,
+                        x12, y12, color12,
+                        refineColorThreshold, depth, shading, path);
+    gouraudFillTriangle(x01, y01, color01,
+                        x12, y12, color12,
+                        x20, y20, color20,
+                        refineColorThreshold, depth, shading, path);
+    gouraudFillTriangle(x20, y20, color20,
+                        x12, y12, color12,
+                        x2, y2, color2,
+                        refineColorThreshold, depth, shading, path);
   }
 }
 
@@ -3170,32 +3276,72 @@ void Gfx::doPatchMeshShFill(GfxPatchMeshShading 
*shading) {
   } else {
     start = 0;
   }
+  /*
+   * Parameterized shadings take one parameter [t_0,t_e]
+   * and map it into the color space.
+   *
+   * Consequently, all color values are stored as doubles.
+   *
+   * These color values are interpreted as parameters for parameterized
+   * shadings and as colorspace entities otherwise.
+   *
+   * The only difference is that color space entities are stored into
+   * DOUBLE arrays, not into arrays of type GfxColorComp.
+   */
+  int colorComps = shading->getColorSpace()->getNComps();
+  double refineColorThreshold;
+  if( shading->isParameterized() ) {
+         refineColorThreshold = gouraudParameterizedColorDelta *
+                 (shading->getParameterDomainMax() - 
shading->getParameterDomainMin());
+
+  } else {
+         refineColorThreshold = patchColorDelta;
+  }
+
   for (i = 0; i < shading->getNPatches(); ++i) {
-    fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
-             start);
+    fillPatch(shading->getPatch(i),
+                 colorComps,
+                 shading->isParameterized() ? 1 : colorComps,
+                 refineColorThreshold,
+             start,
+                 shading);
   }
 }
 
-void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
-  GfxPatch patch00, patch01, patch10, patch11;
-  double xx[4][8], yy[4][8];
-  double xxm, yym;
-  int i;
-
-  for (i = 0; i < nComps; ++i) {
-    if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
-         > patchColorDelta ||
-       abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
-         > patchColorDelta ||
-       abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
-         > patchColorDelta ||
-       abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
-         > patchColorDelta) {
+void Gfx::fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, 
double refineColorThreshold, int depth, GfxPatchMeshShading *shading ) {
+   GfxPatch patch00, patch01, patch10, patch11;
+   double xx[4][8], yy[4][8];
+   double xxm, yym;
+   int i;
+
+  for (i = 0; i < patchColorComps; ++i) {
+       // these comparisons are done in double arithmetics.
+       //
+       // For non-parameterized shadings, they are done in color space
+       // components.
+    if (fabs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
+         > refineColorThreshold ||
+       fabs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
+         > refineColorThreshold ||
+       fabs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
+         > refineColorThreshold ||
+       fabs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
+         > refineColorThreshold) {
       break;
     }
   }
-  if (i == nComps || depth == patchMaxDepth) {
-    state->setFillColor(&patch->color[0][0]);
+  if (i == patchColorComps || depth == patchMaxDepth) {
+       GfxColor flatColor;
+       if( shading->isParameterized() ) {
+               shading->getParameterizedColor( patch->color[0][0].c[0], 
&flatColor );
+
+       } else {
+               for( i = 0; i<colorComps; ++i ) {
+                       // simply cast to the desired type; that's all what is 
needed.
+                       flatColor.c[i] = GfxColorComp(patch->color[0][0].c[i]);
+               }
+       }
+    state->setFillColor(&flatColor);
     out->updateFillColor(state);
     state->moveTo(patch->x[0][0], patch->y[0][0]);
     state->curveTo(patch->x[0][1], patch->y[0][1],
@@ -3273,9 +3419,7 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int 
depth) {
       patch11.x[3][i-4] = xx[3][i];
       patch11.y[3][i-4] = yy[3][i];
     }
-    //~ if the shading has a Function, this should interpolate on the
-    //~ function parameter, not on the color components
-    for (i = 0; i < nComps; ++i) {
+    for (i = 0; i < patchColorComps; ++i) {
       patch00.color[0][0].c[i] = patch->color[0][0].c[i];
       patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
                                  patch->color[0][1].c[i]) / 2;
@@ -3298,10 +3442,10 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int 
depth) {
       patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
       patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
     }
-    fillPatch(&patch00, nComps, depth + 1);
-    fillPatch(&patch10, nComps, depth + 1);
-    fillPatch(&patch01, nComps, depth + 1);
-    fillPatch(&patch11, nComps, depth + 1);
+    fillPatch(&patch00, colorComps, patchColorComps, refineColorThreshold, 
depth + 1, shading);
+    fillPatch(&patch10, colorComps, patchColorComps, refineColorThreshold, 
depth + 1, shading);
+    fillPatch(&patch01, colorComps, patchColorComps, refineColorThreshold, 
depth + 1, shading);
+    fillPatch(&patch11, colorComps, patchColorComps, refineColorThreshold, 
depth + 1, shading);
   }
 }
 
@@ -3399,21 +3543,21 @@ void Gfx::opSetTextLeading(Object args[], int numArgs) {
 void Gfx::opSetTextRender(Object args[], int numArgs) {
   int rm = state->getRender();
   state->setRender(args[0].getInt());
-  if ((args[0].getInt() & 4) && textHaveCSPattern && drawText) {
-    GBool needFill = out->deviceHasTextClip(state);
-    out->endTextObject(state);
-    if (needFill) {
-      doPatternFill(gTrue);
-    }
-    out->restoreState(state);
-    out->beginTextObject(state);
-    out->updateTextMat(state);
-    out->updateTextPos(state);
-    textHaveCSPattern = gFalse;
-  } else if ((rm & 4) && !(args[0].getInt() & 4) && 
out->supportTextCSPattern(state) && drawText) {
-       out->beginTextObject(state);
-    textHaveCSPattern = gTrue;
-  }
+  if ((args[0].getInt() & 4) && textHaveCSPattern && drawText) {
+    GBool needFill = out->deviceHasTextClip(state);
+    out->endTextObject(state);
+    if (needFill) {
+      doPatternFill(gTrue);
+    }
+    out->restoreState(state);
+    out->beginTextObject(state);
+    out->updateTextMat(state);
+    out->updateTextPos(state);
+    textHaveCSPattern = gFalse;
+  } else if ((rm & 4) && !(args[0].getInt() & 4) && 
out->supportTextCSPattern(state) && drawText) {
+       out->beginTextObject(state);
+    textHaveCSPattern = gTrue;
+  }
   out->updateRender(state);
 }
 
@@ -4379,7 +4523,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double 
*matrix, double *bbox,
 
   // draw the form
   display(str, gFalse);
-  
+
   if (stateBefore != state) {
     if (state->isParentState(stateBefore)) {
       error(-1, "There's a form with more q than Q, trying to fix");
@@ -4432,7 +4576,7 @@ void Gfx::opBeginImage(Object args[], int numArgs) {
   // display the image
   if (str) {
     doImage(NULL, str, gTrue);
-  
+
     // skip 'EI' tag
     c1 = str->getUndecodedStream()->getChar();
     c2 = str->getUndecodedStream()->getChar();
@@ -4559,7 +4703,7 @@ GBool Gfx::contentIsHidden() {
 void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
   // push a new stack entry
   pushMarkedContent();
-  
+
   OCGs *contentConfig = catalog->getOptContentConfig();
   char* name0 = args[0].getName();
   if ( strncmp( name0, "OC", 2) == 0 && contentConfig) {
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index cb42b5c..86dc03c 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -20,6 +20,7 @@
 // Copyright (C) 2009 Albert Astals Cid <[email protected]>
 // Copyright (C) 2009, 2010 Thomas Freitag <[email protected]>
 // Copyright (C) 2010 David Benjamin <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -299,9 +300,13 @@ private:
   void gouraudFillTriangle(double x0, double y0, GfxColor *color0,
                           double x1, double y1, GfxColor *color1,
                           double x2, double y2, GfxColor *color2,
-                          int nComps, int depth);
-  void doPatchMeshShFill(GfxPatchMeshShading *shading);
-  void fillPatch(GfxPatch *patch, int nComps, int depth);
+                          int nComps, int depth, 
GfxState::ReusablePathIterator* path);
+  void gouraudFillTriangle(double x0, double y0, double color0,
+                          double x1, double y1, double color1,
+                          double x2, double y2, double color2,
+                          double refineColorThreshold, int depth, 
GfxGouraudTriangleShading* shading, GfxState::ReusablePathIterator* path);
+  void doPatchMeshShFill(GfxPatchMeshShading *shading);
+  void fillPatch(GfxPatch *patch, int colorComps, int patchColorComps, double 
refineColorThreshold, int depth, GfxPatchMeshShading *shading );
   void doEndPath();
 
   // path clipping operators
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 59a8863..381a09e 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -21,6 +21,7 @@
 // Copyright (C) 2009 Thomas Freitag <[email protected]>
 // Copyright (C) 2009 Christian Persch <[email protected]>
 // Copyright (C) 2010 Paweł Wiejacha <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -672,9 +673,9 @@ void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB 
*rgb) {
   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
-  rgb->r = dblToCol(sqrt(clip01(r * kr)));
-  rgb->g = dblToCol(sqrt(clip01(g * kg)));
-  rgb->b = dblToCol(sqrt(clip01(b * kb)));
+  rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+  rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+  rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
 }
 
 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
@@ -908,12 +909,12 @@ void GfxCalRGBColorSpace::getXYZ(GfxColor *color,
   double *pX, double *pY, double *pZ) {
   double A, B, C;
 
-  A = pow(colToDbl(color->c[0]), gammaR);
-  B = pow(colToDbl(color->c[1]), gammaG);
-  C = pow(colToDbl(color->c[2]), gammaB);
-  *pX = mat[0] * A + mat[3] * B + mat[6] * C;
-  *pY = mat[1] * A + mat[4] * B + mat[7] * C;
-  *pZ = mat[2] * A + mat[5] * B + mat[8] * C;
+  A = colToDbl(color->c[0]);
+  B = colToDbl(color->c[1]);
+  C = colToDbl(color->c[2]);
+  *pX = mat[0]*pow(A,gammaR)+mat[3]*pow(B,gammaG)+mat[6]*pow(C,gammaB);
+  *pY = mat[1]*pow(A,gammaR)+mat[4]*pow(B,gammaG)+mat[7]*pow(C,gammaB);
+  *pZ = mat[2]*pow(A,gammaR)+mat[5]*pow(B,gammaG)+mat[8]*pow(C,gammaB);
 }
 
 void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
@@ -964,9 +965,9 @@ void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB 
*rgb) {
   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
-  rgb->r = dblToCol(sqrt(clip01(r)));
-  rgb->g = dblToCol(sqrt(clip01(g)));
-  rgb->b = dblToCol(sqrt(clip01(b)));
+  rgb->r = dblToCol(pow(clip01(r), 0.5));
+  rgb->g = dblToCol(pow(clip01(g), 0.5));
+  rgb->b = dblToCol(pow(clip01(b), 0.5));
 }
 
 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
@@ -1245,9 +1246,9 @@ void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB 
*rgb) {
   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
-  rgb->r = dblToCol(sqrt(clip01(r * kr)));
-  rgb->g = dblToCol(sqrt(clip01(g * kg)));
-  rgb->b = dblToCol(sqrt(clip01(b * kb)));
+  rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+  rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+  rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
 }
 
 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
@@ -3350,6 +3351,8 @@ void GfxGouraudTriangleShading::getTriangle(
   double out[gfxColorMaxComps];
   int v, j;
 
+  assert(!isParameterized()); 
+
   v = triangles[i][0];
   *x0 = vertices[v].x;
   *y0 = vertices[v].y;
@@ -3394,6 +3397,40 @@ void GfxGouraudTriangleShading::getTriangle(
   }
 }
 
+void GfxGouraudTriangleShading::getParameterizedColor(double t, GfxColor 
*color) {
+  double out[gfxColorMaxComps];
+
+  for (int j = 0; j < nFuncs; ++j) {
+    funcs[j]->transform(&t, &out[j]);
+  }
+  for (int j = 0; j < gfxColorMaxComps; ++j) {
+    color->c[j] = dblToCol(out[j]);
+  }
+}
+
+void GfxGouraudTriangleShading::getTriangle(
+                                   int i,
+                                   double *x0, double *y0, double *color0,
+                                   double *x1, double *y1, double *color1,
+                                   double *x2, double *y2, double *color2) {
+  int v;
+
+  assert(isParameterized()); 
+
+  v = triangles[i][0];
+  *x0 = vertices[v].x;
+  *y0 = vertices[v].y;
+  *color0 = colToDbl(vertices[v].color.c[0]);
+  v = triangles[i][1];
+  *x1 = vertices[v].x;
+  *y1 = vertices[v].y;
+  *color1 = colToDbl(vertices[v].color.c[0]);
+  v = triangles[i][2];
+  *x2 = vertices[v].x;
+  *y2 = vertices[v].y;
+  *color2 = colToDbl(vertices[v].color.c[0]);
+}
+
 //------------------------------------------------------------------------
 // GfxPatchMeshShading
 //------------------------------------------------------------------------
@@ -3451,7 +3488,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int 
typeA, Dict *dict,
   Guint flag;
   double x[16], y[16];
   Guint xi, yi;
-  GfxColorComp c[4][gfxColorMaxComps];
+  double c[4][gfxColorMaxComps];
   Guint ci[4];
   GfxShadingBitBuf *bitBuf;
   Object obj1, obj2;
@@ -3573,7 +3610,14 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int 
typeA, Dict *dict,
        if (!bitBuf->getBits(compBits, &ci[j])) {
          break;
        }
-       c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
+       // store it into a double array.
+       // That's necessary for parameterized shadings....
+       c[i][j] = cMin[j] + cMul[j] * (double)ci[j];
+       if( nFuncsA == 0 ) {
+         // ... and colorspace values can also be stored into doubles.
+         // They will be casted later.
+         c[i][j] = dblToCol(c[i][j]);
+       }
       }
       if (j < nComps) {
        break;
@@ -3950,6 +3994,17 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int 
typeA, Dict *dict,
   return NULL;
 }
 
+void GfxPatchMeshShading::getParameterizedColor(double t, GfxColor *color) {
+  double out[gfxColorMaxComps];
+
+  for (int j = 0; j < nFuncs; ++j) {
+    funcs[j]->transform(&t, &out[j]);
+  }
+  for (int j = 0; j < gfxColorMaxComps; ++j) {
+    color->c[j] = dblToCol(out[j]);
+  }
+}
+
 GfxShading *GfxPatchMeshShading::copy() {
   return new GfxPatchMeshShading(this);
 }
@@ -4507,6 +4562,52 @@ void GfxPath::offset(double dx, double dy) {
 // GfxState
 //------------------------------------------------------------------------
 
+GfxState::ReusablePathIterator::ReusablePathIterator( GfxPath *path )
+       : 
+       path(path),
+       subPathOff(0),
+       coordOff(0),
+       numCoords(0),
+       curSubPath(NULL)
+{
+       if( path->getNumSubpaths() ) {
+               curSubPath = path->getSubpath(subPathOff);
+               numCoords = curSubPath->getNumPoints();
+       }
+}
+
+bool
+GfxState::ReusablePathIterator::isEnd() {
+       return coordOff >= numCoords;
+}
+
+void
+GfxState::ReusablePathIterator::next() {
+       ++coordOff;
+       if( coordOff == numCoords ) {
+               ++subPathOff;
+               if( subPathOff < path->getNumSubpaths() ) {
+                       coordOff=0;
+                       curSubPath = path->getSubpath(subPathOff);
+                       numCoords = curSubPath->getNumPoints();
+               }
+       }
+}
+
+void 
+GfxState::ReusablePathIterator::setCoord( double x, double y ) {
+       curSubPath->setX( coordOff, x );
+       curSubPath->setY( coordOff, y );
+}
+
+void 
+GfxState::ReusablePathIterator::reset() {
+       coordOff = 0;
+       subPathOff = 0;
+       curSubPath = path->getSubpath(0);
+       numCoords = curSubPath->getNumPoints();
+}
+
 GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
                   int rotateA, GBool upsideDown) {
   double kx, ky;
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 900214d..0d259da 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -18,6 +18,7 @@
 // Copyright (C) 2006 Carlos Garcia Campos <[email protected]>
 // Copyright (C) 2009 Koji Otani <[email protected]>
 // Copyright (C) 2009, 2010 Albert Astals Cid <[email protected]>
+// Copyright (C) 2010 Christian Feuersänger <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -35,6 +36,8 @@
 #include "Object.h"
 #include "Function.h"
 
+#include <assert.h>
+
 class Array;
 class Gfx;
 class GfxFont;
@@ -876,10 +879,37 @@ public:
   virtual GfxShading *copy();
 
   int getNTriangles() { return nTriangles; }
-  void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
-                  double *x1, double *y1, GfxColor *color1,
-                  double *x2, double *y2, GfxColor *color2);
-
+
+  bool isParameterized() const { return nFuncs > 0; }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMin() const { assert(isParameterized()); return 
funcs[0]->getDomainMin(0); }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMax() const { assert(isParameterized()); return 
funcs[0]->getDomainMax(0); }
+
+  /**
+   * @precondition isParameterized() == false
+   */
+  void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
+                  double *x1, double *y1, GfxColor *color1,
+                  double *x2, double *y2, GfxColor *color2);
+
+  /**
+   * Variant for functions.
+   *
+   * @precondition isParameterized() == true
+   */
+  void getTriangle(int i, double *x0, double *y0, double *color0,
+                  double *x1, double *y1, double *color1,
+                  double *x2, double *y2, double *color2);
+
+  void getParameterizedColor(double t, GfxColor *color);
+
 private:
 
   GfxGouraudVertex *vertices;
@@ -894,10 +924,32 @@ private:
 // GfxPatchMeshShading
 //------------------------------------------------------------------------
 
-struct GfxPatch {
-  double x[4][4];
-  double y[4][4];
-  GfxColor color[2][2];
+/**
+ * A tensor product cubic bezier patch consisting of 4x4 points and 4 color
+ * values.
+ *
+ * See the Shading Type 7 specifications. Note that Shading Type 6 is also
+ * represented using GfxPatch.
+ */
+ struct GfxPatch {
+  /**
+   * Represents a single color value for the patch.
+   */
+  struct ColorValue {
+         /**
+          * For parameterized patches, only element 0 is valid; it contains
+          * the single parameter.
+          *
+          * For non-parameterized patches, c contains all color components
+          * as decoded from the input stream. In this case, you will need to
+          * use dblToCol() before assigning them to GfxColor.
+          */
+         double c[gfxColorMaxComps];
+  };
+
+   double x[4][4];
+   double y[4][4];
+  ColorValue color[2][2];
 };
 
 class GfxPatchMeshShading: public GfxShading {
@@ -915,6 +967,20 @@ public:
   int getNPatches() { return nPatches; }
   GfxPatch *getPatch(int i) { return &patches[i]; }
 
+  bool isParameterized() const { return nFuncs > 0; }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMin() const { assert(isParameterized()); return 
funcs[0]->getDomainMin(0); }
+
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMax() const { assert(isParameterized()); return 
funcs[0]->getDomainMax(0); }
+
+  void getParameterizedColor(double t, GfxColor *color);
+
 private:
 
   GfxPatch *patches;
@@ -1004,6 +1070,9 @@ public:
   double getY(int i) { return y[i]; }
   GBool getCurve(int i) { return curve[i]; }
 
+  void setX(int i, double a) { x[i] = a; }
+  void setY(int i, double a) { y[i] = a; }
+
   // Get last point.
   double getLastX() { return x[n-1]; }
   double getLastY() { return y[n-1]; }
@@ -1098,6 +1167,60 @@ private:
 
 class GfxState {
 public:
+  /**
+   * When GfxState::getReusablePath() is invoked, the currently active
+   * path is taken per reference and its coordinates can be re-edited.
+   *
+   * A ReusablePathIterator is intented to reduce overhead when the same
+   * path type is used a lot of times, only with different coordinates. It
+   * allows just to update the coordinates (occuring in the same order as
+   * in the original path).
+   */
+  class ReusablePathIterator {
+         GfxPath *path;
+         int subPathOff;
+
+         int coordOff;
+         int numCoords;
+
+         GfxSubpath *curSubPath;
+  public:
+         /**
+          * Creates the ReusablePathIterator. This should only be done from
+          * GfxState::getReusablePath().
+          *
+          * @param path the path as it is used so far. Changing this path,
+          * deleting it or starting a new path from scratch will most likely
+          * invalidate the iterator (and may cause serious problems). Make
+          * sure the path's memory structure is not changed during the
+          * lifetime of the ReusablePathIterator.
+          */
+         ReusablePathIterator( GfxPath* path );
+
+         /**
+          * Returns true if and only if the current iterator position is
+          * beyond the last valid point.
+          *
+          * A call to setCoord() will be undefined.
+          */
+         bool isEnd();
+
+         /**
+          * Advances the iterator.
+          */
+         void next();
+
+         /**
+          * Updates the coordinates associated to the current iterator
+          * position.
+          */
+         void setCoord( double x, double y );
+
+         /**
+          * Resets the iterator.
+          */
+         void reset();
+  };
 
   // Construct a default GfxState, for a device with resolution <hDPI>
   // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and
@@ -1276,6 +1399,7 @@ public:
   // Misc
   GBool parseBlendMode(Object *obj, GfxBlendMode *mode);
 
+  ReusablePathIterator *getReusablePath() { return new 
ReusablePathIterator(path); }
 private:
 
   double hDPI, vDPI;           // resolution
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to