<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<span>>Unfortunately only implemented for shadings where the 3 vertices of the </span>triangle have the same color for now since i got lost trying to implement the coloring (and also have no pdf to check against)<br>
<span> </span><br>
</div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<span>Is the PDF with this fixed issue an example?</span></div>
<div style="font-family: Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
<a href="https://bugs.freedesktop.org/show_bug.cgi?id=90570" id="LPlnk997719">https://bugs.freedesktop.org/show_bug.cgi?id=90570</a><br>
</div>
<div>
<div id="appendonsend"></div>
<div style="font-family:Calibri,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>From:</b> poppler <poppler-bounces@lists.freedesktop.org> on behalf of GitLab Mirror <gitlab-mirror@kemper.freedesktop.org><br>
<b>Sent:</b> Thursday, February 27, 2020 8:17 AM<br>
<b>To:</b> poppler@lists.freedesktop.org <poppler@lists.freedesktop.org><br>
<b>Subject:</b> [poppler] poppler/SplashOutputDev.cc poppler/SplashOutputDev.h splash/Splash.cc splash/SplashPattern.h splash/SplashTypes.h</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt">
<div class="PlainText">poppler/SplashOutputDev.cc |   51 ++++----<br>
 poppler/SplashOutputDev.h  |   11 +<br>
 splash/Splash.cc           |  271 ++++++++++++++++++++++++++++++++-------------<br>
 splash/SplashPattern.h     |    7 -<br>
 splash/SplashTypes.h       |    7 +<br>
 5 files changed, 246 insertions(+), 101 deletions(-)<br>
<br>
New commits:<br>
commit 68af136fb2934a65f912d84a619c39c75d6d90b9<br>
Author: Albert Astals Cid <aacid@kde.org><br>
Date:   Sat Feb 22 10:05:25 2020 +0100<br>
<br>
    Implement Splash::gouraudTriangleShadedFill for non parametrized shadings<br>
    <br>
    Fixes #881<br>
    <br>
    Unfortunately only implemented for shadings where the 3 vertices of the<br>
    triangle have the same color for now since i got lost trying to<br>
    implement the coloring (and also have no pdf to check against)<br>
    <br>
    The reason this fixes #881 is because if Splash::gouraudTriangleShadedFill<br>
    returns false because it doesn't natively support this shading, the<br>
    default rendering algorithm of Gfx.cc kicks in, and that rendering what<br>
    does is render different triangles without them knowing they belong to<br>
    the same shading, meaning that if you have some opacity the edges of the<br>
    triangles will overlap and and up having different color than the one<br>
    you really wanted<br>
<br>
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc<br>
index dbbd29a9..047b2d2d 100644<br>
--- a/poppler/SplashOutputDev.cc<br>
+++ b/poppler/SplashOutputDev.cc<br>
@@ -82,9 +82,9 @@<br>
 static const double s_minLineWidth = 0.0;<br>
 <br>
 static inline void convertGfxColor(SplashColorPtr dest,<br>
-                                   SplashColorMode colorMode,<br>
-                                   GfxColorSpace *colorSpace,<br>
-                                   GfxColor *src) {<br>
+                                   const SplashColorMode colorMode,<br>
+                                   const GfxColorSpace *colorSpace,<br>
+                                   const GfxColor *src) {<br>
   SplashColor color;<br>
   GfxGray gray;<br>
   GfxRGB rgb;<br>
@@ -134,9 +134,9 @@ static inline void convertGfxColor(SplashColorPtr dest,<br>
 // to ensure that everything is initialized.<br>
 <br>
 static inline void convertGfxShortColor(SplashColorPtr dest,<br>
-                                   SplashColorMode colorMode,<br>
-                                   GfxColorSpace *colorSpace,<br>
-                                   GfxColor *src) {<br>
+                                   const SplashColorMode colorMode,<br>
+                                   const GfxColorSpace *colorSpace,<br>
+                                   const GfxColor *src) {<br>
   switch (colorMode) {<br>
     case splashModeMono1:<br>
     case splashModeMono8:<br>
@@ -194,21 +194,29 @@ SplashGouraudPattern::SplashGouraudPattern(bool bDirectColorTranslationA,<br>
 SplashGouraudPattern::~SplashGouraudPattern() {<br>
 }<br>
 <br>
+void SplashGouraudPattern::getNonParametrizedTriangle(int i, SplashColorMode mode, double *x0, double *y0, SplashColorPtr color0,<br>
+                                        double *x1, double *y1, SplashColorPtr color1,<br>
+                                        double *x2, double *y2, SplashColorPtr color2) {<br>
+  GfxColor c0, c1, c2;<br>
+  shading->getTriangle(i, x0, y0, &c0, x1, y1, &c1, x2, y2, &c2);<br>
+<br>
+  const GfxColorSpace* srcColorSpace = shading->getColorSpace();<br>
+  convertGfxColor(color0, mode, srcColorSpace, &c0);<br>
+  convertGfxColor(color1, mode, srcColorSpace, &c1);<br>
+  convertGfxColor(color2, mode, srcColorSpace, &c2);<br>
+}<br>
+<br>
+<br>
 void SplashGouraudPattern::getParameterizedColor(double colorinterp, SplashColorMode mode, SplashColorPtr dest) {<br>
   GfxColor src;<br>
-  GfxColorSpace* srcColorSpace = shading->getColorSpace();<br>
-  int colorComps = 3;<br>
-  if (mode == splashModeCMYK8)<br>
-    colorComps=4;<br>
-  else if (mode == splashModeDeviceN8)<br>
-    colorComps=4 + SPOT_NCOMPS;<br>
-<br>
   shading->getParameterizedColor(colorinterp, &src);<br>
 <br>
   if (bDirectColorTranslation) {<br>
+    const int colorComps = splashColorModeNComps[mode];<br>
     for (int m = 0; m < colorComps; ++m)<br>
       dest[m] = colToByte(src.c[m]);<br>
   } else {<br>
+    GfxColorSpace* srcColorSpace = shading->getColorSpace();<br>
     convertGfxShortColor(dest, mode, srcColorSpace, &src);<br>
   }<br>
 }<br>
@@ -4540,17 +4548,12 @@ bool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTrian<br>
     break;<br>
   }<br>
   // restore vector antialias because we support it here<br>
-  if (shading->isParameterized()) {<br>
-    SplashGouraudColor *splashShading = new SplashGouraudPattern(bDirectColorTranslation, state, shading);<br>
-    bool vaa = getVectorAntialias();<br>
-    bool retVal = false;<br>
-    setVectorAntialias(true);<br>
-    retVal = splash->gouraudTriangleShadedFill(splashShading);<br>
-    setVectorAntialias(vaa);<br>
-    delete splashShading;<br>
-    return retVal;<br>
-  }<br>
-  return false;<br>
+  SplashGouraudPattern splashShading(bDirectColorTranslation, state, shading);<br>
+  const bool vaa = getVectorAntialias();<br>
+  setVectorAntialias(true);<br>
+  const bool retVal = splash->gouraudTriangleShadedFill(&splashShading);<br>
+  setVectorAntialias(vaa);<br>
+  return retVal;<br>
 }<br>
 <br>
 bool SplashOutputDev::univariateShadedFill(GfxState *state, SplashUnivariatePattern *pattern, double tMin, double tMax) {<br>
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h<br>
index 7a670d1b..a42e724c 100644<br>
--- a/poppler/SplashOutputDev.h<br>
+++ b/poppler/SplashOutputDev.h<br>
@@ -147,11 +147,16 @@ public:<br>
 <br>
   bool isParameterized() override { return shading->isParameterized(); }<br>
   int getNTriangles() override { return shading->getNTriangles(); }<br>
-   void getTriangle(int i, double *x0, double *y0, double *color0,<br>
-                            double *x1, double *y1, double *color1,<br>
-                            double *x2, double *y2, double *color2) override<br>
+  void getParametrizedTriangle(int i, double *x0, double *y0, double *color0,<br>
+                          double *x1, double *y1, double *color1,<br>
+                          double *x2, double *y2, double *color2) override<br>
   { shading->getTriangle(i, x0, y0, color0, x1, y1, color1, x2, y2, color2); }<br>
 <br>
+  void getNonParametrizedTriangle(int i, SplashColorMode mode,<br>
+                    double *x0, double *y0, SplashColorPtr color0,<br>
+                    double *x1, double *y1, SplashColorPtr color1,<br>
+                    double *x2, double *y2, SplashColorPtr color2) override;<br>
+<br>
   void getParameterizedColor(double colorinterp, SplashColorMode mode, SplashColorPtr dest) override;<br>
 <br>
 private:<br>
diff --git a/splash/Splash.cc b/splash/Splash.cc<br>
index 3d4e6177..70584ec4 100644<br>
--- a/splash/Splash.cc<br>
+++ b/splash/Splash.cc<br>
@@ -2385,7 +2385,7 @@ SplashError Splash::fillWithPattern(SplashPath *path, bool eo,<br>
   SplashPipe pipe = {};<br>
   int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;<br>
   SplashClipResult clipRes, clipRes2;<br>
-  bool adjustLine = false; <br>
+  bool adjustLine = false;<br>
   int linePosI = 0;<br>
 <br>
   if (path->length == 0) {<br>
@@ -5381,62 +5381,23 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
   int    x[3] = {0, 0, 0};<br>
   int    y[3] = {0, 0, 0};<br>
   double xt=0., xa=0., yt=0.;<br>
-  double ca=0., ct=0.;<br>
-<br>
-  // triangle interpolation:<br>
-  //<br>
-  double scanLimitMapL[2] = {0., 0.};<br>
-  double scanLimitMapR[2] = {0., 0.};<br>
-  double scanColorMapL[2] = {0., 0.};<br>
-  double scanColorMapR[2] = {0., 0.};<br>
-  double scanColorMap[2] = {0., 0.};<br>
-  int scanEdgeL[2] = { 0, 0 };<br>
-  int scanEdgeR[2] = { 0, 0 };<br>
-  bool hasFurtherSegment = false;<br>
-<br>
-  int scanLineOff = 0;<br>
-  int bitmapOff = 0;<br>
-  int scanLimitR = 0, scanLimitL = 0;<br>
-<br>
-  int bitmapWidth = bitmap->getWidth();<br>
+<br>
+  const int bitmapWidth = bitmap->getWidth();<br>
   SplashClip* clip = getClip();<br>
   SplashBitmap *blitTarget = bitmap;<br>
   SplashColorPtr bitmapData = bitmap->getDataPtr();<br>
-  int bitmapOffLimit = bitmap->getHeight() * bitmap->getRowSize();<br>
+  const int bitmapOffLimit = bitmap->getHeight() * bitmap->getRowSize();<br>
   SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();<br>
-  SplashColorPtr cur = nullptr;<br>
   SplashCoord* userToCanvasMatrix = getMatrix();<br>
-  SplashColorMode bitmapMode = bitmap->getMode();<br>
+  const SplashColorMode bitmapMode = bitmap->getMode();<br>
   bool hasAlpha = (bitmapAlpha != nullptr);<br>
-  int rowSize = bitmap->getRowSize();<br>
-  int colorComps = 0;<br>
-  switch (bitmapMode) {<br>
-    case splashModeMono1:<br>
-    break;<br>
-    case splashModeMono8:<br>
-      colorComps=1;<br>
-    break;<br>
-    case splashModeRGB8:<br>
-      colorComps=3;<br>
-    break;<br>
-    case splashModeBGR8:<br>
-      colorComps=3;<br>
-    break;<br>
-    case splashModeXBGR8:<br>
-      colorComps=4;<br>
-    break;<br>
-    case splashModeCMYK8:<br>
-      colorComps=4;<br>
-    break;<br>
-    case splashModeDeviceN8:<br>
-      colorComps=SPOT_NCOMPS+4;<br>
-    break;<br>
-  }<br>
+  const int rowSize = bitmap->getRowSize();<br>
+  const int colorComps = splashColorModeNComps[bitmapMode];<br>
 <br>
   SplashPipe pipe;<br>
   SplashColor cSrcVal;<br>
 <br>
-  pipeInit(&pipe, 0, 0, nullptr, cSrcVal, (unsigned char)splashRound(state->strokeAlpha * 255), false, false);<br>
+  pipeInit(&pipe, 0, 0, nullptr, cSrcVal, (unsigned char)splashRound(state->fillAlpha * 255), false, false);<br>
 <br>
   if (vectorAntialias) {<br>
     if (aaBuf == nullptr)<br>
@@ -5457,7 +5418,7 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
   // - the final step, is performed using a SplashPipe:<br>
   // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference<br>
   // - invoke drawPixel(&pipe,X,Y,bNoClip);<br>
-  bool bDirectBlit = vectorAntialias ? false : pipe.noTransparency && !state->blendFunc;<br>
+  const bool bDirectBlit = vectorAntialias ? false : pipe.noTransparency && !state->blendFunc && !shading->isParameterized();<br>
   if (!bDirectBlit) {<br>
     blitTarget = new SplashBitmap(bitmap->getWidth(),<br>
                                   bitmap->getHeight(),<br>
@@ -5469,7 +5430,7 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
     bitmapAlpha = blitTarget->getAlphaPtr();<br>
 <br>
     // initialisation seems to be necessary:<br>
-    int S = bitmap->getWidth() * bitmap->getHeight();<br>
+    const int S = bitmap->getWidth() * bitmap->getHeight();<br>
     for (int i = 0; i < S; ++i)<br>
       bitmapAlpha[i] = 0;<br>
     hasAlpha = true;<br>
@@ -5477,10 +5438,15 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
 <br>
   if (shading->isParameterized()) {<br>
     double color[3];<br>
-    double colorinterp;<br>
+    double scanLimitMapL[2] = {0., 0.};<br>
+    double scanLimitMapR[2] = {0., 0.};<br>
+    double scanColorMapL[2] = {0., 0.};<br>
+    double scanColorMapR[2] = {0., 0.};<br>
+    int scanEdgeL[2] = { 0, 0 };<br>
+    int scanEdgeR[2] = { 0, 0 };<br>
 <br>
     for (int i = 0; i < shading->getNTriangles(); ++i) {<br>
-      shading->getTriangle(i,<br>
+      shading->getParametrizedTriangle(i,<br>
                            xdbl + 0, ydbl + 0, color + 0,<br>
                            xdbl + 1, ydbl + 1, color + 1,<br>
                            xdbl + 2, ydbl + 2, color + 2);<br>
@@ -5504,9 +5470,9 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
       // first two are sorted.<br>
       assert(y[0] <= y[1]);<br>
       if (y[1] > y[2]) {<br>
-        int tmpX = x[2];<br>
-        int tmpY = y[2];<br>
-        double tmpC = color[2];<br>
+        const int tmpX = x[2];<br>
+        const int tmpY = y[2];<br>
+        const double tmpC = color[2];<br>
         x[2] = x[1]; y[2] = y[1]; color[2] = color[1];<br>
 <br>
         if (y[0] > tmpY) {<br>
@@ -5578,8 +5544,8 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
       scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);<br>
       scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];<br>
 <br>
-      hasFurtherSegment = (y[1] < y[2]);<br>
-      scanLineOff = y[0] * rowSize;<br>
+      bool hasFurtherSegment = (y[1] < y[2]);<br>
+      int scanLineOff = y[0] * rowSize;<br>
 <br>
       for (int Y = y[0]; Y <= y[2]; ++Y, scanLineOff += rowSize) {<br>
         if (hasFurtherSegment && Y == y[1]) {<br>
@@ -5614,34 +5580,34 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
         xa = yt * scanLimitMapL[0] + scanLimitMapL[1];<br>
         xt = yt * scanLimitMapR[0] + scanLimitMapR[1];<br>
 <br>
-        ca = yt * scanColorMapL[0] + scanColorMapL[1];<br>
-        ct = yt * scanColorMapR[0] + scanColorMapR[1];<br>
+        const double ca = yt * scanColorMapL[0] + scanColorMapL[1];<br>
+        const double ct = yt * scanColorMapR[0] + scanColorMapR[1];<br>
 <br>
-        scanLimitL = splashRound(xa);<br>
-        scanLimitR = splashRound(xt);<br>
+        const int scanLimitL = splashRound(xa);<br>
+        const int scanLimitR = splashRound(xt);<br>
 <br>
         // Ok. Now: init the color interpolation depending on the X<br>
         // coordinate inside of the current scanline:<br>
-        scanColorMap[0] = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));<br>
-        scanColorMap[1] = ca - scanLimitL * scanColorMap[0];<br>
+        const double scanColorMap0 = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));<br>
+        const double scanColorMap1 = ca - scanLimitL * scanColorMap0;<br>
 <br>
         // handled by clipping:<br>
         // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );<br>
         assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies<br>
         assert(scanLineOff == Y * rowSize);<br>
 <br>
-        colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1];<br>
+        double colorinterp = scanColorMap0 * scanLimitL + scanColorMap1;<br>
 <br>
-        bitmapOff = scanLineOff + scanLimitL * colorComps;<br>
+        int bitmapOff = scanLineOff + scanLimitL * colorComps;<br>
         if (likely(bitmapOff >= 0)) {<br>
-         for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, colorinterp += scanColorMap[0], bitmapOff += colorComps) {<br>
+         for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, colorinterp += scanColorMap0, bitmapOff += colorComps) {<br>
             // FIXME : standard rectangular clipping can be done for a<br>
             // complete scanline which is faster<br>
             // --> see SplashClip and its methods<br>
             if (!clip->test(X, Y))<br>
               continue;<br>
 <br>
-           assert(fabs(colorinterp - (scanColorMap[0] * X + scanColorMap[1])) < 1e-10);<br>
+           assert(fabs(colorinterp - (scanColorMap0 * X + scanColorMap1)) < 1e-10);<br>
             assert(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);<br>
 <br>
             shading->getParameterizedColor(colorinterp, bitmapMode, &bitmapData[bitmapOff]);<br>
@@ -5656,24 +5622,183 @@ bool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)<br>
       }<br>
     }<br>
   } else {<br>
-    if (!bDirectBlit) {<br>
-      delete blitTarget;<br>
+    SplashColor color, auxColor1, auxColor2;<br>
+    double scanLimitMapL[2] = {0., 0.};<br>
+    double scanLimitMapR[2] = {0., 0.};<br>
+    int scanEdgeL[2] = { 0, 0 };<br>
+    int scanEdgeR[2] = { 0, 0 };<br>
+<br>
+    for (int i = 0; i < shading->getNTriangles(); ++i) {<br>
+      // Sadly this current algorithm only supports shadings where the three triangle vertices have the same color<br>
+      shading->getNonParametrizedTriangle(i, bitmapMode,<br>
+                           xdbl + 0, ydbl + 0, (SplashColorPtr)&color,<br>
+                           xdbl + 1, ydbl + 1, (SplashColorPtr)&auxColor1,<br>
+                           xdbl + 2, ydbl + 2, (SplashColorPtr)&auxColor2);<br>
+      if (!splashColorEqual(color, auxColor1) ||<br>
+         !splashColorEqual(color, auxColor2))<br>
+      {<br>
+         delete blitTarget;<br>
+         return false;<br>
+      }<br>
+      for (int m = 0; m < 3; ++m) {<br>
+        xt = xdbl[m] * (double)userToCanvasMatrix[0] + ydbl[m] * (double)userToCanvasMatrix[2] + (double)userToCanvasMatrix[4];<br>
+        yt = xdbl[m] * (double)userToCanvasMatrix[1] + ydbl[m] * (double)userToCanvasMatrix[3] + (double)userToCanvasMatrix[5];<br>
+        xdbl[m] = xt;<br>
+        ydbl[m] = yt;<br>
+        // we operate on scanlines which are integer offsets into the<br>
+        // raster image. The double offsets are of no use here.<br>
+        x[m] = splashRound(xt);<br>
+        y[m] = splashRound(yt);<br>
+      }<br>
+      // sort according to y coordinate to simplify sweep through scanlines:<br>
+      // INSERTION SORT.<br>
+      if (y[0] > y[1]) {<br>
+        Guswap(x[0], x[1]);<br>
+        Guswap(y[0], y[1]);<br>
+      }<br>
+      // first two are sorted.<br>
+      assert(y[0] <= y[1]);<br>
+      if (y[1] > y[2]) {<br>
+       const int tmpX = x[2];<br>
+       const int tmpY = y[2];<br>
+       x[2] = x[1]; y[2] = y[1];<br>
+<br>
+       if (y[0] > tmpY) {<br>
+         x[1] = x[0]; y[1] = y[0];<br>
+         x[0] = tmpX; y[0] = tmpY;<br>
+       } else {<br>
+         x[1] = tmpX; y[1] = tmpY;<br>
+       }<br>
+      }<br>
+      // first three are sorted<br>
+      assert(y[0] <= y[1]);<br>
+      assert(y[1] <= y[2]);<br>
+      /////<br>
+<br>
+      // this here is det( T ) == 0<br>
+      // where T is the matrix to map to barycentric coordinates.<br>
+      if ((x[0] - x[2]) * (y[1] - y[2]) - (x[1] - x[2]) * (y[0] - y[2]) == 0)<br>
+        continue; // degenerate triangle.<br>
+<br>
+      // this here initialises the scanline generation.<br>
+      // We start with low Y coordinates and sweep up to the large Y<br>
+      // coordinates.<br>
+      //<br>
+      // scanEdgeL[m] in {0,1,2} m=0,1<br>
+      // scanEdgeR[m] in {0,1,2} m=0,1<br>
+      //<br>
+      // are the two edges between which scanlines are (currently)<br>
+      // sweeped. The values {0,1,2} are indices into 'x' and 'y'.<br>
+      // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.<br>
+      //<br>
+      scanEdgeL[0] = 0;<br>
+      scanEdgeR[0] = 0;<br>
+      if (y[0] == y[1]) {<br>
+        scanEdgeL[0] = 1;<br>
+        scanEdgeL[1] = scanEdgeR[1] = 2;<br>
+<br>
+      } else {<br>
+        scanEdgeL[1] = 1; scanEdgeR[1] = 2;<br>
+      }<br>
+      assert(y[scanEdgeL[0]] < y[scanEdgeL[1]]);<br>
+      assert(y[scanEdgeR[0]] < y[scanEdgeR[1]]);<br>
+<br>
+      // Ok. Now prepare the linear maps which map the y coordinate of<br>
+      // the current scanline to the corresponding LEFT and RIGHT x<br>
+      // coordinate (which define the scanline).<br>
+      scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);<br>
+      scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];<br>
+      scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);<br>
+      scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];<br>
+<br>
+      xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1];<br>
+      xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1];<br>
+      if (xa > xt) {<br>
+        // I have "left" is to the right of "right".<br>
+        // Exchange sides!<br>
+        Guswap(scanEdgeL[0], scanEdgeR[0]);<br>
+        Guswap(scanEdgeL[1], scanEdgeR[1]);<br>
+        Guswap(scanLimitMapL[0], scanLimitMapR[0]);<br>
+        Guswap(scanLimitMapL[1], scanLimitMapR[1]);<br>
+        // FIXME I'm sure there is a more efficient way to check this.<br>
+      }<br>
+<br>
+      bool hasFurtherSegment = (y[1] < y[2]);<br>
+      int scanLineOff = y[0] * rowSize;<br>
+<br>
+      for (int Y = y[0]; Y <= y[2]; ++Y, scanLineOff += rowSize) {<br>
+        if (hasFurtherSegment && Y == y[1]) {<br>
+          // SWEEP EVENT: we encountered the next segment.<br>
+          //<br>
+          // switch to next segment, either at left end or at right<br>
+          // end:<br>
+          if (scanEdgeL[1] == 1) {<br>
+            scanEdgeL[0] = 1;<br>
+            scanEdgeL[1] = 2;<br>
+            scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);<br>
+            scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];<br>
+          } else if (scanEdgeR[1] == 1) {<br>
+            scanEdgeR[0] = 1;<br>
+            scanEdgeR[1] = 2;<br>
+            scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);<br>
+            scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];<br>
+          }<br>
+          assert( y[scanEdgeL[0]]  <  y[scanEdgeL[1]] );<br>
+          assert( y[scanEdgeR[0]] <  y[scanEdgeR[1]] );<br>
+          hasFurtherSegment = false;<br>
+        }<br>
+<br>
+        yt = Y;<br>
+<br>
+        xa = yt * scanLimitMapL[0] + scanLimitMapL[1];<br>
+        xt = yt * scanLimitMapR[0] + scanLimitMapR[1];<br>
+<br>
+        const int scanLimitL = splashRound(xa);<br>
+        const int scanLimitR = splashRound(xt);<br>
+<br>
+        // handled by clipping:<br>
+        // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );<br>
+        assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies<br>
+        assert(scanLineOff == Y * rowSize);<br>
+<br>
+        int bitmapOff = scanLineOff + scanLimitL * colorComps;<br>
+        if (likely(bitmapOff >= 0)) {<br>
+         for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, bitmapOff += colorComps) {<br>
+           // FIXME : standard rectangular clipping can be done for a<br>
+           // complete scanline which is faster<br>
+           // --> see SplashClip and its methods<br>
+           if (!clip->test(X, Y))<br>
+             continue;<br>
+<br>
+           assert(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);<br>
+<br>
+           for (int k = 0; k < colorComps; ++k) {<br>
+             bitmapData[bitmapOff + k] = color[k];<br>
+           }<br>
+<br>
+           // make the shading visible.<br>
+           // Note that opacity is handled by the bDirectBlit stuff, see<br>
+           // above for comments and below for implementation.<br>
+           if (hasAlpha)<br>
+             bitmapAlpha[Y * bitmapWidth + X] = 255;<br>
+         }<br>
+       }<br>
+      }<br>
     }<br>
-    return false;<br>
   }<br>
 <br>
   if (!bDirectBlit) {<br>
     // ok. Finalize the stuff by blitting the shading into the final<br>
     // geometry, this time respecting the rendering pipe.<br>
-    int W = blitTarget->getWidth();<br>
-    int H = blitTarget->getHeight();<br>
-    cur = cSrcVal;<br>
+    const int W = blitTarget->getWidth();<br>
+    const int H = blitTarget->getHeight();<br>
+    SplashColorPtr cur = cSrcVal;<br>
 <br>
     for (int X = 0; X < W; ++X) {<br>
       for (int Y = 0; Y < H; ++Y) {<br>
         if (!bitmapAlpha[Y * bitmapWidth + X])<br>
           continue; // draw only parts of the shading!<br>
-        bitmapOff = Y * rowSize + colorComps * X;<br>
+        const int bitmapOff = Y * rowSize + colorComps * X;<br>
 <br>
         for (int m = 0; m < colorComps; ++m)<br>
           cur[m] = bitmapData[bitmapOff + m];<br>
diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h<br>
index ce7eb446..1545c097 100644<br>
--- a/splash/SplashPattern.h<br>
+++ b/splash/SplashPattern.h<br>
@@ -94,10 +94,15 @@ public:<br>
 <br>
   virtual int getNTriangles() = 0;<br>
 <br>
-  virtual  void getTriangle(int i, double *x0, double *y0, double *color0,<br>
+  virtual void getParametrizedTriangle(int i, double *x0, double *y0, double *color0,<br>
                             double *x1, double *y1, double *color1,<br>
                             double *x2, double *y2, double *color2) = 0;<br>
 <br>
+  virtual void getNonParametrizedTriangle(int i, SplashColorMode mode,<br>
+                            double *x0, double *y0, SplashColorPtr color0,<br>
+                            double *x1, double *y1, SplashColorPtr color1,<br>
+                            double *x2, double *y2, SplashColorPtr color2) = 0;<br>
+<br>
   virtual void getParameterizedColor(double t, SplashColorMode mode, SplashColorPtr c) = 0;<br>
 };<br>
 <br>
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h<br>
index 7500f588..c036a56e 100644<br>
--- a/splash/SplashTypes.h<br>
+++ b/splash/SplashTypes.h<br>
@@ -128,6 +128,13 @@ static inline void splashColorCopy(SplashColorPtr dest, SplashColorConstPtr src)<br>
     dest[i] = src[i];<br>
 }<br>
 <br>
+static inline bool splashColorEqual(SplashColorConstPtr dest, SplashColorConstPtr src) {<br>
+  for (int i = 0; i < SPOT_NCOMPS + 4; i++)<br>
+    if (dest[i] != src[i])<br>
+        return false;<br>
+  return true;<br>
+}<br>
+<br>
 static inline void splashColorXor(SplashColorPtr dest, SplashColorConstPtr src) {<br>
   dest[0] ^= src[0];<br>
   dest[1] ^= src[1];<br>
_______________________________________________<br>
poppler mailing list<br>
poppler@lists.freedesktop.org<br>
<a href="https://lists.freedesktop.org/mailman/listinfo/poppler">https://lists.freedesktop.org/mailman/listinfo/poppler</a><br>
</div>
</span></font></div>
</div>
</body>
</html>