[poppler] 4 commits - CMakeLists.txt poppler/Gfx.cc poppler/Gfx.h poppler/GfxState.cc poppler/GfxState_helpers.h poppler/Makefile.am poppler/OutputDev.h poppler/PSOutputDev.cc poppler/PSOutputDev.h poppler/SplashOutputDev.cc poppler/SplashOutputDev.h splash/SplashState.cc splash/SplashTypes.h

Albert Astals Cid aacid at kemper.freedesktop.org
Tue Jun 2 14:02:48 PDT 2009


 CMakeLists.txt             |    1 
 poppler/Gfx.cc             |  135 ++++++++++++---
 poppler/Gfx.h              |    7 
 poppler/GfxState.cc        |   63 -------
 poppler/GfxState_helpers.h |   80 ++++++++
 poppler/Makefile.am        |    1 
 poppler/OutputDev.h        |   14 +
 poppler/PSOutputDev.cc     |  285 ++++++++++++++++++-------------
 poppler/PSOutputDev.h      |   18 ++
 poppler/SplashOutputDev.cc |  404 +++++++++++++++++++++++++++++++++++++--------
 poppler/SplashOutputDev.h  |   19 ++
 splash/SplashState.cc      |   17 +
 splash/SplashTypes.h       |   10 +
 13 files changed, 798 insertions(+), 256 deletions(-)

New commits:
commit 104f9286ceb5fcb5f4795bca7633029142d5f6a4
Author: Thomas Freitag <Thomas.Freitag at alfa.de>
Date:   Tue Jun 2 22:59:42 2009 +0200

    Support colorizing text in pattern colorspace
    
    This implements commits the final patches for bug 19670 and 19994
    Also fixes bugs 15819 and 2807
    Also implements blending for SPLASH_CMYK in Splash
    It's a quite big change but i've done regression testing over my whole
    pdf suite and did not fit anything that went worse, just improvements
    Missing the Cairo support

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 03085a5..9e81b39 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -287,6 +287,7 @@ if(ENABLE_XPDF_HEADERS)
     poppler/Gfx.h
     poppler/GfxFont.h
     poppler/GfxState.h
+    poppler/GfxState_helpers.h
     poppler/GlobalParams.h
     poppler/JArithmeticDecoder.h
     poppler/JBIG2Stream.h
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 72b1068..e907850 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -28,6 +28,7 @@
 // Copyright (C) 2008 Michael Vrable <mvrable at cs.ucsd.edu>
 // Copyright (C) 2008 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2009 M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -498,6 +499,9 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, Catalog *cata
   subPage = gFalse;
   printCommands = globalParams->getPrintCommands();
   profileCommands = globalParams->getProfileCommands();
+  textHaveCSPattern = gFalse;
+  drawText = gFalse;
+  maskHaveCSPattern = gFalse;
   mcStack = NULL;
 
   // start the resource stack
@@ -542,6 +546,9 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA,
   catalog = catalogA;
   subPage = gTrue;
   printCommands = globalParams->getPrintCommands();
+  textHaveCSPattern = gFalse;
+  drawText = gFalse;
+  maskHaveCSPattern = gFalse;
   mcStack = NULL;
 
   // start the resource stack
@@ -1230,12 +1237,32 @@ void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
 void Gfx::opSetFillGray(Object args[], int numArgs) {
   GfxColor color;
 
-  state->setFillPattern(NULL);
-  state->setFillColorSpace(new GfxDeviceGrayColorSpace());
-  out->updateFillColorSpace(state);
-  color.c[0] = dblToCol(args[0].getNum());
-  state->setFillColor(&color);
-  out->updateFillColor(state);
+  if (textHaveCSPattern) {
+    GBool needFill = out->deviceHasTextClip(state);
+    out->endTextObject(state);
+    if (needFill) {
+      doPatternFill(gTrue);
+    }
+    out->restoreState(state);
+    state->setFillPattern(NULL);
+    state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+    out->updateFillColorSpace(state);
+    color.c[0] = dblToCol(args[0].getNum());
+    state->setFillColor(&color);
+    out->updateFillColor(state);
+    out->beginTextObject(state);
+    out->updateRender(state);
+    out->updateTextMat(state);
+    out->updateTextPos(state);
+    textHaveCSPattern = gFalse;
+  } else {
+    state->setFillPattern(NULL);
+    state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+    out->updateFillColorSpace(state);
+    color.c[0] = dblToCol(args[0].getNum());
+    state->setFillColor(&color);
+    out->updateFillColor(state);
+  }
 }
 
 void Gfx::opSetStrokeGray(Object args[], int numArgs) {
@@ -1253,14 +1280,21 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
   GfxColor color;
   int i;
 
-  state->setFillPattern(NULL);
-  state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
-  out->updateFillColorSpace(state);
-  for (i = 0; i < 4; ++i) {
-    color.c[i] = dblToCol(args[i].getNum());
+  if (textHaveCSPattern) {
+    colorSpaceText = new GfxDeviceCMYKColorSpace();
+    for (i = 0; i < 4; ++i) {
+      colorText.c[i] = dblToCol(args[i].getNum());
+    }
+  } else {
+    state->setFillPattern(NULL);
+    state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
+    out->updateFillColorSpace(state);
+    for (i = 0; i < 4; ++i) {
+      color.c[i] = dblToCol(args[i].getNum());
+    }
+    state->setFillColor(&color);
+    out->updateFillColor(state);
   }
-  state->setFillColor(&color);
-  out->updateFillColor(state);
 }
 
 void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
@@ -1281,14 +1315,21 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
   GfxColor color;
   int i;
 
-  state->setFillPattern(NULL);
-  state->setFillColorSpace(new GfxDeviceRGBColorSpace());
-  out->updateFillColorSpace(state);
-  for (i = 0; i < 3; ++i) {
-    color.c[i] = dblToCol(args[i].getNum());
+  if (textHaveCSPattern) {
+    colorSpaceText = new GfxDeviceRGBColorSpace();
+    for (i = 0; i < 3; ++i) {
+      colorText.c[i] = dblToCol(args[i].getNum());
+    }
+  } else {
+    state->setFillPattern(NULL);
+    state->setFillColorSpace(new GfxDeviceRGBColorSpace());
+    out->updateFillColorSpace(state);
+    for (i = 0; i < 3; ++i) {
+      color.c[i] = dblToCol(args[i].getNum());
+    }
+    state->setFillColor(&color);
+    out->updateFillColor(state);
   }
-  state->setFillColor(&color);
-  out->updateFillColor(state);
 }
 
 void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
@@ -1324,6 +1365,24 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
     colorSpace->getDefaultColor(&color);
     state->setFillColor(&color);
     out->updateFillColor(state);
+    if (drawText) {
+      if (colorSpace->getMode() == csPattern) {
+        colorSpaceText = NULL;
+        textHaveCSPattern = gTrue;
+        out->beginTextObject(state);
+      } else if (textHaveCSPattern) {
+        GBool needFill = out->deviceHasTextClip(state);
+        out->endTextObject(state);
+        if (needFill) {
+          doPatternFill(gTrue);
+        }
+        out->beginTextObject(state);
+        out->updateRender(state);
+        out->updateTextMat(state);
+        out->updateTextPos(state);
+        textHaveCSPattern = gFalse;
+      }
+    }
   } else {
     error(getPos(), "Bad color space (fill)");
   }
@@ -1847,7 +1906,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
   if (stroke) {
     state->clipToStrokePath();
     out->clipToStrokePath(state);
-  } else {
+  } else if (!textHaveCSPattern && !maskHaveCSPattern) {
     state->clip();
     if (eoFill) {
       out->eoClip(state);
@@ -1975,7 +2034,7 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
   if (stroke) {
     state->clipToStrokePath();
     out->clipToStrokePath(state);
-  } else {
+  } else if (!textHaveCSPattern && !maskHaveCSPattern) {
     state->clip();
     if (eoFill) {
       out->eoClip(state);
@@ -3121,15 +3180,38 @@ void Gfx::opEOClip(Object args[], int numArgs) {
 //------------------------------------------------------------------------
 
 void Gfx::opBeginText(Object args[], int numArgs) {
+  out->beginTextObject(state);
+  drawText = gTrue;
   state->setTextMat(1, 0, 0, 1, 0, 0);
   state->textMoveTo(0, 0);
   out->updateTextMat(state);
   out->updateTextPos(state);
   fontChanged = gTrue;
+  if (out->supportTextCSPattern(state)) {
+    colorSpaceText = NULL;
+    textHaveCSPattern = gTrue;
+  }
 }
 
 void Gfx::opEndText(Object args[], int numArgs) {
+  GBool needFill = out->deviceHasTextClip(state);
   out->endTextObject(state);
+  drawText = gFalse;
+  if (out->supportTextCSPattern(state) && textHaveCSPattern) {
+    if (needFill) {
+      doPatternFill(gTrue);
+    }
+    out->restoreState(state);
+    if (colorSpaceText != NULL) {
+      state->setFillPattern(NULL);
+      state->setFillColorSpace(colorSpaceText);
+      out->updateFillColorSpace(state);
+      state->setFillColor(&colorText);
+      out->updateFillColor(state);
+      colorSpaceText = NULL;
+    }
+  }
+  textHaveCSPattern = gFalse;
 }
 
 //------------------------------------------------------------------------
@@ -3170,6 +3252,9 @@ void Gfx::opSetTextLeading(Object args[], int numArgs) {
 
 void Gfx::opSetTextRender(Object args[], int numArgs) {
   state->setRender(args[0].getInt());
+  if (args[0].getInt() == 7) {
+    textHaveCSPattern = gFalse;
+  }
   out->updateRender(state);
 }
 
@@ -3695,6 +3780,12 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
     // draw it
     if (!contentIsHidden())
       out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+      if (out->fillMaskCSPattern(state)) {
+        maskHaveCSPattern = gTrue;
+        doPatternFill(gTrue);
+        out->endMaskClip(state);
+        maskHaveCSPattern = gFalse;
+      }
 
   } else {
 
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index a75a92a..e03d025 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -18,6 +18,7 @@
 // Copyright (C) 2008 Brad Hards <bradh at kde.org>
 // Copyright (C) 2008 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2009 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -33,6 +34,7 @@
 
 #include "goo/gtypes.h"
 #include "goo/GooList.h"
+#include "GfxState.h"
 #include "Object.h"
 
 class GooString;
@@ -175,6 +177,11 @@ private:
   GBool subPage;		// is this a sub-page object?
   GBool printCommands;		// print the drawing commands (for debugging)
   GBool profileCommands;	// profile the drawing commands (for debugging)
+  GBool textHaveCSPattern;	// in text drawing and text has pattern colorspace
+  GBool drawText;		// in text drawing
+  GBool maskHaveCSPattern;	// in mask drawing and mask has pattern colorspace
+  GfxColorSpace *colorSpaceText;// colorspace after text has filled with pattern
+  GfxColor colorText;		// fill color after after text has filled with pattern
   GfxResources *res;		// resource stack
   int updateLevel;
 
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 14c0a3f..d75e015 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -40,19 +40,12 @@
 #include "Array.h"
 #include "Page.h"
 #include "GfxState.h"
+#include "GfxState_helpers.h"
 #include "GfxFont.h"
 #include "GlobalParams.h"
 
 //------------------------------------------------------------------------
 
-static inline GfxColorComp clip01(GfxColorComp x) {
-  return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
-}
-
-static inline double clip01(double x) {
-  return (x < 0) ? 0 : (x > 1) ? 1 : x;
-}
-
 GBool Matrix::invertTo(Matrix *other)
 {
   double det;
@@ -1077,7 +1070,7 @@ void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) {
 }
 
 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
-  double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
+  double c, m, y, k, c1, m1, y1, k1, r, g, b;
     
   c = colToDbl(color->c[0]);
   m = colToDbl(color->c[1]);
@@ -1087,52 +1080,7 @@ void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
   m1 = 1 - m;
   y1 = 1 - y;
   k1 = 1 - k;
-  // this is a matrix multiplication, unrolled for performance
-  //                        C M Y K
-  x = c1 * m1 * y1 * k1; // 0 0 0 0
-  r = g = b = x;
-  x = c1 * m1 * y1 * k;  // 0 0 0 1
-  r += 0.1373 * x;
-  g += 0.1216 * x;
-  b += 0.1255 * x;
-  x = c1 * m1 * y  * k1; // 0 0 1 0
-  r += x;
-  g += 0.9490 * x;
-  x = c1 * m1 * y  * k;  // 0 0 1 1
-  r += 0.1098 * x;
-  g += 0.1020 * x;
-  x = c1 * m  * y1 * k1; // 0 1 0 0
-  r += 0.9255 * x;
-  b += 0.5490 * x;
-  x = c1 * m  * y1 * k;  // 0 1 0 1
-  r += 0.1412 * x;
-  x = c1 * m  * y  * k1; // 0 1 1 0
-  r += 0.9294 * x;
-  g += 0.1098 * x;
-  b += 0.1412 * x;
-  x = c1 * m  * y  * k;  // 0 1 1 1
-  r += 0.1333 * x;
-  x = c  * m1 * y1 * k1; // 1 0 0 0
-  g += 0.6784 * x;
-  b += 0.9373 * x;
-  x = c  * m1 * y1 * k;  // 1 0 0 1
-  g += 0.0588 * x;
-  b += 0.1412 * x;
-  x = c  * m1 * y  * k1; // 1 0 1 0
-  g += 0.6510 * x;
-  b += 0.3137 * x;
-  x = c  * m1 * y  * k;  // 1 0 1 1
-  g += 0.0745 * x;
-  x = c  * m  * y1 * k1; // 1 1 0 0
-  r += 0.1804 * x;
-  g += 0.1922 * x;
-  b += 0.5725 * x;
-  x = c  * m  * y1 * k;  // 1 1 0 1
-  b += 0.0078 * x;
-  x = c  * m  * y  * k1; // 1 1 1 0
-  r += 0.2118 * x;
-  g += 0.2119 * x;
-  b += 0.2235 * x;
+  cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
   rgb->r = clip01(dblToCol(r));
   rgb->g = clip01(dblToCol(g));
   rgb->b = clip01(dblToCol(b));
diff --git a/poppler/GfxState_helpers.h b/poppler/GfxState_helpers.h
new file mode 100644
index 0000000..77ac710
--- /dev/null
+++ b/poppler/GfxState_helpers.h
@@ -0,0 +1,80 @@
+//========================================================================
+//
+// GfxState.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009 Albert Astals Cid <aacid at kde.org>
+//
+// 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
+//
+//========================================================================
+
+static inline GfxColorComp clip01(GfxColorComp x) {
+  return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
+}
+
+static inline double clip01(double x) {
+  return (x < 0) ? 0 : (x > 1) ? 1 : x;
+}
+
+static inline void cmykToRGBMatrixMultiplication(const double &c, const double &m, const double &y, const double &k, const double &c1, const double &m1, const double &y1, const double &k1, double &r, double &g, double &b)
+{
+  double x;
+  // this is a matrix multiplication, unrolled for performance
+  //                        C M Y K
+  x = c1 * m1 * y1 * k1; // 0 0 0 0
+  r = g = b = x;
+  x = c1 * m1 * y1 * k;  // 0 0 0 1
+  r += 0.1373 * x;
+  g += 0.1216 * x;
+  b += 0.1255 * x;
+  x = c1 * m1 * y  * k1; // 0 0 1 0
+  r += x;
+  g += 0.9490 * x;
+  x = c1 * m1 * y  * k;  // 0 0 1 1
+  r += 0.1098 * x;
+  g += 0.1020 * x;
+  x = c1 * m  * y1 * k1; // 0 1 0 0
+  r += 0.9255 * x;
+  b += 0.5490 * x;
+  x = c1 * m  * y1 * k;  // 0 1 0 1
+  r += 0.1412 * x;
+  x = c1 * m  * y  * k1; // 0 1 1 0
+  r += 0.9294 * x;
+  g += 0.1098 * x;
+  b += 0.1412 * x;
+  x = c1 * m  * y  * k;  // 0 1 1 1
+  r += 0.1333 * x;
+  x = c  * m1 * y1 * k1; // 1 0 0 0
+  g += 0.6784 * x;
+  b += 0.9373 * x;
+  x = c  * m1 * y1 * k;  // 1 0 0 1
+  g += 0.0588 * x;
+  b += 0.1412 * x;
+  x = c  * m1 * y  * k1; // 1 0 1 0
+  g += 0.6510 * x;
+  b += 0.3137 * x;
+  x = c  * m1 * y  * k;  // 1 0 1 1
+  g += 0.0745 * x;
+  x = c  * m  * y1 * k1; // 1 1 0 0
+  r += 0.1804 * x;
+  g += 0.1922 * x;
+  b += 0.5725 * x;
+  x = c  * m  * y1 * k;  // 1 1 0 1
+  b += 0.0078 * x;
+  x = c  * m  * y  * k1; // 1 1 1 0
+  r += 0.2118 * x;
+  g += 0.2119 * x;
+  b += 0.2235 * x;
+}
diff --git a/poppler/Makefile.am b/poppler/Makefile.am
index 1c63284..4f0f410 100644
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@ -169,6 +169,7 @@ poppler_include_HEADERS =	\
 	Gfx.h			\
 	GfxFont.h		\
 	GfxState.h		\
+	GfxState_helpers.h	\
 	GlobalParams.h		\
 	JArithmeticDecoder.h	\
 	JBIG2Stream.h		\
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index 66b5c38..4866631 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -17,6 +17,7 @@
 // Copyright (C) 2006 Thorkild Stray <thorkild at ifi.uio.no>
 // Copyright (C) 2007 Jeff Muizelaar <jeff at infidigm.net>
 // Copyright (C) 2007 Adrian Johnson <ajohnson at redneon.com>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -94,6 +95,17 @@ public:
   // Does this device need non-text content?
   virtual GBool needNonText() { return gTrue; }
 
+  // If current colorspace ist pattern,
+  // does this device support text in pattern colorspace?
+  // Default is false
+  virtual GBool supportTextCSPattern(GfxState * /*state*/) { return gFalse; }
+
+  // If current colorspace ist pattern,
+  // need this device special handling for masks in pattern colorspace?
+  // Default is false
+  virtual GBool fillMaskCSPattern(GfxState * /*state*/) { return gFalse; }
+  virtual void endMaskClip(GfxState * /*state*/) {}
+
   //----- initialization and control
 
   // Set default transform matrix.
@@ -204,6 +216,8 @@ public:
 			       double /*dx*/, double /*dy*/,
 			       CharCode /*code*/, Unicode * /*u*/, int /*uLen*/);
   virtual void endType3Char(GfxState * /*state*/) {}
+  virtual void beginTextObject(GfxState * /*state*/) {}
+  virtual GBool deviceHasTextClip(GfxState * /*state*/) { return gFalse; }
   virtual void endTextObject(GfxState * /*state*/) {}
 
   //----- image drawing
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index f02bd98..d24e77e 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -20,6 +20,7 @@
 // Copyright (C) 2007, 2008 Brad Hards <bradh at kde.org>
 // Copyright (C) 2008 Koji Otani <sho at bbr.jp>
 // Copyright (C) 2008 Hib Eris <hib at hiberis.nl>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -493,6 +494,8 @@ static char *prolog[] = {
   "        pdfTextMat dtransform rmoveto } def",
   "/Tclip { pdfTextClipPath cvx exec clip newpath",
   "         /pdfTextClipPath [] def } def",
+  "/Tclip* { pdfTextClipPath cvx exec eoclip newpath",
+  "         /pdfTextClipPath [] def } def",
   "~1ns",
   "% Level 1 image operators",
   "~1n",
@@ -990,6 +993,7 @@ PSOutputDev::PSOutputDev(const char *fileName, XRef *xrefA, Catalog *catalog,
   embFontList = NULL;
   customColors = NULL;
   haveTextClip = gFalse;
+  haveCSPattern = gFalse;
   t3String = NULL;
 
   forceRasterize = forceRasterizeA;
@@ -1053,6 +1057,7 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
   embFontList = NULL;
   customColors = NULL;
   haveTextClip = gFalse;
+  haveCSPattern = gFalse;
   t3String = NULL;
 
   forceRasterize = forceRasterizeA;
@@ -2755,6 +2760,9 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
 	  ++col;
 	}
       }
+      if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+	break;
+      }
       // each line is: "dup nnnnn <~...data...~> put<eol>"
       // so max data length = 255 - 20 = 235
       // chunks are 1 or 4 bytes each, so we have to stop at 232
@@ -3632,6 +3640,10 @@ void PSOutputDev::updateRender(GfxState *state) {
   int rm;
 
   rm = state->getRender();
+  if (rm == 7 && haveCSPattern) {
+    haveCSPattern = gFalse;
+    restoreState(state);
+  }
   writePSFmt("{0:d} Tr\n", rm);
   rm &= 3;
   if (rm != 0 && rm != 3) {
@@ -4283,34 +4295,71 @@ void PSOutputDev::drawString(GfxState *state, GooString *s) {
   }
 }
 
+void PSOutputDev::beginTextObject(GfxState *state) {
+  if (state->getFillColorSpace()->getMode() == csPattern) {
+    saveState(state);
+    haveCSPattern = gTrue;
+    savedRender = state->getRender();
+    state->setRender(7);
+    writePSFmt("{0:d} Tr\n", 7);
+  }
+}
+
 void PSOutputDev::endTextObject(GfxState *state) {
-  if (haveTextClip) {
+  if (haveCSPattern) {
+    if (haveTextClip) {
+      writePS("Tclip*\n");
+      haveTextClip = gFalse;
+      state->setRender(savedRender);
+      if (state->getFillColorSpace()->getMode() != csPattern) {
+        double cxMin, cyMin, cxMax, cyMax;
+        state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
+        writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re\n",
+                   cxMin, cyMin,
+                   cxMax, cyMax);
+        writePS("f*\n");
+        restoreState(state);
+        updateFillColor(state);
+      }
+    } else {
+      state->setRender(savedRender);
+    }
+    haveCSPattern = gFalse;
+  } else if (haveTextClip) {
     writePS("Tclip\n");
     haveTextClip = gFalse;
   }
 }
 
+void PSOutputDev::endMaskClip(GfxState * state) {
+  writePS("pdfImClipEnd\n");
+}
+
 void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
 				int width, int height, GBool invert,
 				GBool inlineImg) {
   int len;
 
   len = height * ((width + 7) / 8);
-  switch (level) {
-  case psLevel1:
-  case psLevel1Sep:
-    doImageL1(ref, NULL, invert, inlineImg, str, width, height, len);
-    break;
-  case psLevel2:
-  case psLevel2Sep:
-    doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
-	      NULL, NULL, 0, 0, gFalse);
-    break;
-  case psLevel3:
-  case psLevel3Sep:
-    doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
-	      NULL, NULL, 0, 0, gFalse);
-    break;
+  if (state->getFillColorSpace()->getMode() == csPattern && (level != psLevel1 && level != psLevel1Sep)) {
+    maskToClippingPath(str, width, height, invert);
+  } else {
+    switch (level) {
+      case psLevel1:
+      case psLevel1Sep:
+        doImageL1(ref, NULL, invert, inlineImg, str, width, height, len);
+      break;
+      case psLevel2:
+      case psLevel2Sep:
+        doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
+                  NULL, NULL, 0, 0, gFalse);
+      break;
+      case psLevel3:
+      case psLevel3Sep:
+        doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
+                  NULL, NULL, 0, 0, gFalse);
+      break;
+    }
   }
 }
 
@@ -4547,6 +4596,110 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
   gfree(lineBuf);
 }
 
+void PSOutputDev::maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) {
+  ImageStream *imgStr;
+  Guchar *line;
+  PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
+  int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
+  GBool emitRect, addRect, extendRect;
+  int i, x0, x1, y, maskXor;
+
+  imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
+  imgStr->reset();
+  rects0Len = rects1Len = rectsOutLen = 0;
+  rectsSize = rectsOutSize = 64;
+  rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+  rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+  rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect));
+  maskXor = maskInvert ? 1 : 0;
+  for (y = 0; y < maskHeight; ++y) {
+    if (!(line = imgStr->getLine())) {
+      break;
+    }
+    i = 0;
+    rects1Len = 0;
+    for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+    for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+    while (x0 < maskWidth || i < rects0Len) {
+      emitRect = addRect = extendRect = gFalse;
+      if (x0 >= maskWidth) {
+        emitRect = gTrue;
+      } else if (i >= rects0Len) {
+        addRect = gTrue;
+      } else if (rects0[i].x0 < x0) {
+        emitRect = gTrue;
+      } else if (x0 < rects0[i].x0) {
+        addRect = gTrue;
+      } else if (rects0[i].x1 == x1) {
+        extendRect = gTrue;
+      } else {
+        emitRect = addRect = gTrue;
+      }
+      if (emitRect) {
+        if (rectsOutLen == rectsOutSize) {
+          rectsOutSize *= 2;
+          rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
+        }
+        rectsOut[rectsOutLen].x0 = rects0[i].x0;
+        rectsOut[rectsOutLen].x1 = rects0[i].x1;
+        rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+        rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+        ++rectsOutLen;
+        ++i;
+      }
+      if (addRect || extendRect) {
+        if (rects1Len == rectsSize) {
+          rectsSize *= 2;
+          rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect));
+          rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect));
+        }
+        rects1[rects1Len].x0 = x0;
+        rects1[rects1Len].x1 = x1;
+        if (addRect) {
+          rects1[rects1Len].y0 = y;
+        }
+        if (extendRect) {
+          rects1[rects1Len].y0 = rects0[i].y0;
+          ++i;
+        }
+        ++rects1Len;
+        for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+        for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+      }
+    }
+    rectsTmp = rects0;
+    rects0 = rects1;
+    rects1 = rectsTmp;
+    i = rects0Len;
+    rects0Len = rects1Len;
+    rects1Len = i;
+  }
+  for (i = 0; i < rects0Len; ++i) {
+    if (rectsOutLen == rectsOutSize) {
+      rectsOutSize *= 2;
+      rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
+    }
+    rectsOut[rectsOutLen].x0 = rects0[i].x0;
+    rectsOut[rectsOutLen].x1 = rects0[i].x1;
+    rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+    rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+    ++rectsOutLen;
+  }
+  writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
+  for (i = 0; i < rectsOutLen; ++i) {
+    writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
+               rectsOut[i].x0, rectsOut[i].y0,
+               rectsOut[i].x1 - rectsOut[i].x0,
+               rectsOut[i].y1 - rectsOut[i].y0);
+  }
+  writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight);
+  gfree(rectsOut);
+  gfree(rects0);
+  gfree(rects1);
+  delete imgStr;
+  maskStr->close();
+}
+
 void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 			    GBool invert, GBool inlineImg,
 			    Stream *str, int width, int height, int len,
@@ -4713,105 +4866,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 
   // explicit masking
   } else if (maskStr) {
-    imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
-    imgStr->reset();
-    rects0Len = rects1Len = rectsOutLen = 0;
-    rectsSize = rectsOutSize = 64;
-    rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
-    rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
-    rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
-					    sizeof(PSOutImgClipRect));
-    maskXor = maskInvert ? 1 : 0;
-    for (y = 0; y < maskHeight; ++y) {
-      if (!(line = imgStr->getLine())) {
-	break;
-      }
-      i = 0;
-      rects1Len = 0;
-      for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
-      for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
-      while (x0 < maskWidth || i < rects0Len) {
-	emitRect = addRect = extendRect = gFalse;
-	if (x0 >= maskWidth) {
-	  emitRect = gTrue;
-	} else if (i >= rects0Len) {
-	  addRect = gTrue;
-	} else if (rects0[i].x0 < x0) {
-	  emitRect = gTrue;
-	} else if (x0 < rects0[i].x0) {
-	  addRect = gTrue;
-	} else if (rects0[i].x1 == x1) {
-	  extendRect = gTrue;
-	} else {
-	  emitRect = addRect = gTrue;
-	}
-	if (emitRect) {
-	  if (rectsOutLen == rectsOutSize) {
-	    rectsOutSize *= 2;
-	    rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
-						     sizeof(PSOutImgClipRect));
-	  }
-	  rectsOut[rectsOutLen].x0 = rects0[i].x0;
-	  rectsOut[rectsOutLen].x1 = rects0[i].x1;
-	  rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
-	  rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
-	  ++rectsOutLen;
-	  ++i;
-	}
-	if (addRect || extendRect) {
-	  if (rects1Len == rectsSize) {
-	    rectsSize *= 2;
-	    rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
-						   sizeof(PSOutImgClipRect));
-	    rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
-						   sizeof(PSOutImgClipRect));
-	  }
-	  rects1[rects1Len].x0 = x0;
-	  rects1[rects1Len].x1 = x1;
-	  if (addRect) {
-	    rects1[rects1Len].y0 = y;
-	  }
-	  if (extendRect) {
-	    rects1[rects1Len].y0 = rects0[i].y0;
-	    ++i;
-	  }
-	  ++rects1Len;
-	  for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
-	  for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
-	}
-      }
-      rectsTmp = rects0;
-      rects0 = rects1;
-      rects1 = rectsTmp;
-      i = rects0Len;
-      rects0Len = rects1Len;
-      rects1Len = i;
-    }
-    for (i = 0; i < rects0Len; ++i) {
-      if (rectsOutLen == rectsOutSize) {
-	rectsOutSize *= 2;
-	rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
-						 sizeof(PSOutImgClipRect));
-      }
-      rectsOut[rectsOutLen].x0 = rects0[i].x0;
-      rectsOut[rectsOutLen].x1 = rects0[i].x1;
-      rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
-      rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
-      ++rectsOutLen;
-    }
-    writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
-    for (i = 0; i < rectsOutLen; ++i) {
-      writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
-		 rectsOut[i].x0, rectsOut[i].y0,
-		 rectsOut[i].x1 - rectsOut[i].x0,
-		 rectsOut[i].y1 - rectsOut[i].y0);
-    }
-    writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight);
-    gfree(rectsOut);
-    gfree(rects0);
-    gfree(rects1);
-    delete imgStr;
-    maskStr->close();
+    maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
   }
 
   // color space
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index e490110..0aea502 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -17,6 +17,7 @@
 // Copyright (C) 2005 Kristian Høgsberg <krh at redhat.com>
 // Copyright (C) 2006-2008 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2007 Brad Hards <bradh at kde.org>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -33,6 +34,7 @@
 #include <poppler-config.h>
 #include <stddef.h>
 #include "Object.h"
+#include "GfxState.h"
 #include "GlobalParams.h"
 #include "OutputDev.h"
 
@@ -125,6 +127,10 @@ public:
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() { return gFalse; }
 
+  // This device now supports text in pattern colorspace!
+  virtual GBool supportTextCSPattern(GfxState *state)
+  	{ return state->getFillColorSpace()->getMode() == csPattern; }
+
   //----- header/trailer (used only if manualCtrl is true)
 
   // Write the document-level header.
@@ -216,6 +222,8 @@ public:
 
   //----- text drawing
   virtual void drawString(GfxState *state, GooString *s);
+  virtual void beginTextObject(GfxState *state);
+  virtual GBool deviceHasTextClip(GfxState *state) { return haveTextClip && haveCSPattern; }
   virtual void endTextObject(GfxState *state);
 
   //----- image drawing
@@ -230,6 +238,12 @@ public:
 			       GfxImageColorMap *colorMap,
 			       Stream *maskStr, int maskWidth, int maskHeight,
 			       GBool maskInvert);
+  // If current colorspace ist pattern,
+  // need this device special handling for masks in pattern colorspace?
+  // Default is false
+  virtual GBool fillMaskCSPattern(GfxState * state)
+  	{ return state->getFillColorSpace()->getMode() == csPattern && (level != psLevel1 && level != psLevel1Sep); }
+  virtual void endMaskClip(GfxState * /*state*/);
 
 #if OPI_SUPPORT
   //----- OPI functions
@@ -295,6 +309,7 @@ private:
   void addProcessColor(double c, double m, double y, double k);
   void addCustomColor(GfxSeparationColorSpace *sepCS);
   void doPath(GfxPath *path);
+  void maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert);
   void doImageL1(Object *ref, GfxImageColorMap *colorMap,
 		 GBool invert, GBool inlineImg,
 		 Stream *str, int width, int height, int len);
@@ -400,6 +415,9 @@ private:
 
   GBool haveTextClip;		// set if text has been drawn with a
 				//   clipping render mode
+  GBool haveCSPattern;		// set if text has been drawn with a
+				//   clipping render mode because of pattern colorspace
+  int savedRender;		// use if pattern colorspace
 
   GBool inType3Char;		// inside a Type 3 CharProc
   GooString *t3String;		// Type 3 content string
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index ca44682..9341c86 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -20,6 +20,7 @@
 // Copyright (C) 2006 Scott Turner <scotty1024 at mac.com>
 // Copyright (C) 2007 Koji Otani <sho at bbr.jp>
 // Copyright (C) 2009 Petr Gajdos <pgajdos at novell.com>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -70,6 +71,54 @@ static inline Guchar div255(int x) {
   return (Guchar)((x + (x >> 8) + 0x80) >> 8);
 }
 
+#if SPLASH_CMYK
+
+#include "GfxState_helpers.h"
+
+//-------------------------------------------------------------------------
+// helper for Blend functions (convert CMYK to RGB, do blend, convert back)
+//-------------------------------------------------------------------------
+
+// based in GfxState.cc
+
+static void cmykToRGB(SplashColorPtr cmyk, SplashColor rgb) {
+  double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+  c = colToDbl(byteToCol(cmyk[0]));
+  m = colToDbl(byteToCol(cmyk[1]));
+  y = colToDbl(byteToCol(cmyk[2]));
+  k = colToDbl(byteToCol(cmyk[3]));
+  c1 = 1 - c;
+  m1 = 1 - m;
+  y1 = 1 - y;
+  k1 = 1 - k;
+  cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+  rgb[0] = colToByte(clip01(dblToCol(r)));
+  rgb[1] = colToByte(clip01(dblToCol(g)));
+  rgb[2] = colToByte(clip01(dblToCol(b)));
+}
+
+static void rgbToCMYK(SplashColor rgb, SplashColorPtr cmyk) {
+  GfxColorComp c, m, y, k;
+
+  c = clip01(gfxColorComp1 - byteToCol(rgb[0]));
+  m = clip01(gfxColorComp1 - byteToCol(rgb[1]));
+  y = clip01(gfxColorComp1 - byteToCol(rgb[2]));
+  k = c;
+  if (m < k) {
+    k = m;
+  }
+  if (y < k) {
+    k = y;
+  }
+  cmyk[0] = colToByte(c - k);
+  cmyk[1] = colToByte(m - k);
+  cmyk[2] = colToByte(y - k);
+  cmyk[3] = colToByte(k);
+}
+
+#endif
+
 //------------------------------------------------------------------------
 // Blend functions
 //------------------------------------------------------------------------
@@ -78,8 +127,23 @@ static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest,
 				   SplashColorPtr blend, SplashColorMode cm) {
   int i;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = (dest[i] * src[i]) / 255;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      rgbBlend[i] = (rgbDest[i] * rgbSrc[i]) / 255;
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      blend[i] = (dest[i] * src[i]) / 255;
+    }
   }
 }
 
@@ -87,8 +151,23 @@ static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest,
 				 SplashColorPtr blend, SplashColorMode cm) {
   int i;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      rgbBlend[i] = rgbDest[i] + rgbSrc[i] - (rgbDest[i] * rgbSrc[i]) / 255;
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255;
+    }
   }
 }
 
@@ -96,10 +175,27 @@ static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest,
 				  SplashColorPtr blend, SplashColorMode cm) {
   int i;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = dest[i] < 0x80
-                 ? (src[i] * 2 * dest[i]) / 255
-                 : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      rgbBlend[i] = rgbDest[i] < 0x80
+                      ? (rgbSrc[i] * 2 * rgbDest[i]) / 255
+                      : 255 - 2 * ((255 - rgbSrc[i]) * (255 - rgbDest[i])) / 255;
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      blend[i] = dest[i] < 0x80
+                   ? (src[i] * 2 * dest[i]) / 255
+                   : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255;
+    }
   }
 }
 
@@ -107,8 +203,23 @@ static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest,
 				 SplashColorPtr blend, SplashColorMode cm) {
   int i;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = dest[i] < src[i] ? dest[i] : src[i];
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      rgbBlend[i] = rgbDest[i] < rgbSrc[i] ? rgbDest[i] : rgbSrc[i];
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      blend[i] = dest[i] < src[i] ? dest[i] : src[i];
+    }
   }
 }
 
@@ -116,8 +227,23 @@ static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest,
 				  SplashColorPtr blend, SplashColorMode cm) {
   int i;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = dest[i] > src[i] ? dest[i] : src[i];
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      rgbBlend[i] = rgbDest[i] > rgbSrc[i] ? rgbDest[i] : rgbSrc[i];
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      blend[i] = dest[i] > src[i] ? dest[i] : src[i];
+    }
   }
 }
 
@@ -126,12 +252,32 @@ static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest,
 				     SplashColorMode cm) {
   int i, x;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    if (src[i] == 255) {
-      blend[i] = 255;
-    } else {
-      x = (dest[i] * 255) / (255 - src[i]);
-      blend[i] = x <= 255 ? x : 255;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      if (rgbSrc[i] == 255) {
+        rgbBlend[i] = 255;
+      } else {
+        x = (rgbDest[i] * 255) / (255 - rgbSrc[i]);
+        rgbBlend[i] = x <= 255 ? x : 255;
+      }
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      if (src[i] == 255) {
+        blend[i] = 255;
+      } else {
+        x = (dest[i] * 255) / (255 - src[i]);
+        blend[i] = x <= 255 ? x : 255;
+      }
     }
   }
 }
@@ -140,12 +286,32 @@ static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest,
 				    SplashColorPtr blend, SplashColorMode cm) {
   int i, x;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    if (src[i] == 0) {
-      blend[i] = 0;
-    } else {
-      x = ((255 - dest[i]) * 255) / src[i];
-      blend[i] = x <= 255 ? 255 - x : 0;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      if (rgbSrc[i] == 0) {
+        rgbBlend[i] = 0;
+      } else {
+        x = ((255 - rgbDest[i]) * 255) / rgbSrc[i];
+        rgbBlend[i] = x <= 255 ? 255 - x : 0;
+      }
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      if (src[i] == 0) {
+        blend[i] = 0;
+      } else {
+        x = ((255 - dest[i]) * 255) / src[i];
+        blend[i] = x <= 255 ? 255 - x : 0;
+      }
     }
   }
 }
@@ -154,10 +320,27 @@ static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest,
 				    SplashColorPtr blend, SplashColorMode cm) {
   int i;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = src[i] < 0x80
-                 ? (dest[i] * 2 * src[i]) / 255
-                 : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      rgbBlend[i] = rgbSrc[i] < 0x80
+                      ? (rgbDest[i] * 2 * rgbSrc[i]) / 255
+                      : 255 - 2 * ((255 - rgbDest[i]) * (255 - rgbSrc[i])) / 255;
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      blend[i] = src[i] < 0x80
+                   ? (dest[i] * 2 * src[i]) / 255
+                   : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255;
+    }
   }
 }
 
@@ -165,18 +348,40 @@ static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest,
 				    SplashColorPtr blend, SplashColorMode cm) {
   int i, x;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    if (src[i] < 0x80) {
-      blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) /
-	         (255 * 255);
-    } else {
-      if (dest[i] < 0x40) {
-	x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255)
-	      + 4 * 255) * dest[i]) / 255;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      if (rgbSrc[i] < 0x80) {
+        rgbBlend[i] = rgbDest[i] - (255 - 2 * rgbSrc[i]) * rgbDest[i] * (255 - rgbDest[i]) / (255 * 255);
       } else {
-	x = (int)sqrt(255.0 * dest[i]);
+        if (rgbDest[i] < 0x40) {
+          x = (((((16 * rgbDest[i] - 12 * 255) * rgbDest[i]) / 255) + 4 * 255) * rgbDest[i]) / 255;
+        } else {
+          x = (int)sqrt(255.0 * rgbDest[i]);
+        }
+        rgbBlend[i] = rgbDest[i] + (2 * rgbSrc[i] - 255) * (x - rgbDest[i]) / 255;
+      }
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      if (src[i] < 0x80) {
+        blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) / (255 * 255);
+      } else {
+        if (dest[i] < 0x40) {
+          x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255) + 4 * 255) * dest[i]) / 255;
+        } else {
+          x = (int)sqrt(255.0 * dest[i]);
+        }
+        blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255;
       }
-      blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255;
     }
   }
 }
@@ -187,7 +392,12 @@ static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest,
   int i;
 
   for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i];
+#ifdef SPLASH_CMYK
+    if (cm == splashModeCMYK8) {
+      blend[i] = dest[i] < src[i] ? 255 - (src[i] - dest[i]) : 255 - (dest[i] - src[i]);
+    } else {
+#endif
+      blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i];
   }
 }
 
@@ -195,8 +405,23 @@ static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest,
 				    SplashColorPtr blend, SplashColorMode cm) {
   int i;
 
-  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
-    blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255;
+#ifdef SPLASH_CMYK
+  if (cm == splashModeCMYK8) {
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    for (i = 0; i < 3; ++i) {
+      rgbBlend[i] = rgbDest[i] + rgbSrc[i] - (2 * rgbDest[i] * rgbSrc[i]) / 255;
+    }
+    rgbToCMYK(rgbBlend, blend);
+  } else
+#endif
+  {
+    for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+      blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255;
+    }
   }
 }
 
@@ -355,19 +580,15 @@ static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
     break;
 #if SPLASH_CMYK
   case splashModeCMYK8:
-    //~ (0xff - ...) should be clipped
-    cvtRGBToHSV(0xff - (src[0] + src[3]),
-		0xff - (src[1] + src[3]),
-		0xff - (src[2] + src[3]), &hs, &ss, &vs);
-    cvtRGBToHSV(0xff - (dest[0] + dest[3]),
-		0xff - (dest[1] + dest[3]),
-		0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
-    cvtHSVToRGB(hs, ss, vd, &r, &g, &b);
-    //~ should do black generation
-    blend[0] = 0xff - r;
-    blend[1] = 0xff - g;
-    blend[2] = 0xff - b;
-    blend[3] = 0;
+    SplashColor rgbSrc;
+    SplashColor rgbDest;
+    SplashColor rgbBlend;
+    cmykToRGB(src, rgbSrc);
+    cmykToRGB(dest, rgbDest);
+    cvtRGBToHSV(rgbSrc[0], rgbSrc[1], rgbSrc[2], &hs, &ss, &vs);
+    cvtRGBToHSV(rgbDest[0], rgbDest[1], rgbDest[2], &hd, &sd, &vd);
+    cvtHSVToRGB(hs, ss, vd, &rgbBlend[0], &rgbBlend[1], &rgbBlend[2]);
+	rgbToCMYK(rgbBlend, blend);
     break;
 #endif
   }
@@ -607,7 +828,12 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
 		      colorMode != splashModeMono1;
   setupScreenParams(72.0, 72.0);
   reverseVideo = reverseVideoA;
-  splashColorCopy(paperColor, paperColorA);
+  if (paperColorA != NULL) {
+    splashColorCopy(paperColor, paperColorA);
+  } else {
+    splashClearColor(paperColor);
+  }
+  keepAlphaChannel = paperColorA == NULL;
 
   xref = NULL;
 
@@ -624,7 +850,7 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
   font = NULL;
   needFontUpdate = gFalse;
   textClipPath = NULL;
-
+  haveCSPattern = gFalse;
   transpGroupStack = NULL;
 }
 
@@ -791,7 +1017,7 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) {
 }
 
 void SplashOutputDev::endPage() {
-  if (colorMode != splashModeMono1) {
+  if (colorMode != splashModeMono1 && !keepAlphaChannel) {
     splash->compositeBackground(paperColor);
   }
 }
@@ -982,6 +1208,15 @@ void SplashOutputDev::updateFont(GfxState * /*state*/) {
   needFontUpdate = gTrue;
 }
 
+void SplashOutputDev::updateRender(GfxState *state) {
+  int rm;
+  rm = state->getRender();
+  if (rm == 7 && haveCSPattern) {
+    haveCSPattern = gFalse;
+    restoreState(state);
+  }
+}
+
 void SplashOutputDev::doUpdateFont(GfxState *state) {
   GfxFont *gfxFont;
   GfxFontType fontType;
@@ -1674,7 +1909,29 @@ void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
   splash->fillGlyph(0, 0, &glyph);
 }
 
+void SplashOutputDev::beginTextObject(GfxState *state) {
+  if (state->getFillColorSpace()->getMode() == csPattern) {
+    haveCSPattern = gTrue;
+    saveState(state);
+    savedRender = state->getRender();
+    state->setRender(7);
+  }
+}
+
 void SplashOutputDev::endTextObject(GfxState *state) {
+  if (haveCSPattern) {
+    state->setRender(savedRender);
+    haveCSPattern = gFalse;
+    if (state->getFillColorSpace()->getMode() != csPattern) {
+      if (textClipPath) {
+        splash->fill(textClipPath, gTrue);
+        delete textClipPath;
+        textClipPath = NULL;
+      }
+      restoreState(state);
+      updateFillColor(state);
+    }
+  }
   if (textClipPath) {
     splash->clipToPath(textClipPath, gFalse);
     delete textClipPath;
@@ -1706,6 +1963,10 @@ GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) {
   return gTrue;
 }
 
+void SplashOutputDev::endMaskClip(GfxState * state) {
+	splash->setSoftMask(NULL);
+}
+
 void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
 				    int width, int height, GBool invert,
 				    GBool inlineImg) {
@@ -1732,12 +1993,27 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
   imgMaskData.height = height;
   imgMaskData.y = 0;
 
-  splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat,
-			t3GlyphStack != NULL);
-  if (inlineImg) {
-    while (imgMaskData.y < height) {
-      imgMaskData.imgStr->getLine();
-      ++imgMaskData.y;
+  if (state->getFillColorSpace()->getMode() == csPattern) {
+    SplashBitmap *maskBitmap;
+    Splash *maskSplash;
+    SplashColor maskColor;
+    
+    maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), 1, splashModeMono8, gFalse);
+    maskSplash = new Splash(maskBitmap, vectorAntialias);
+    maskColor[0] = 0;
+    maskSplash->clear(maskColor);
+    maskColor[0] = 0xff;
+    maskSplash->setFillPattern(new SplashSolidColor(maskColor));
+    maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,  width, height, mat, t3GlyphStack != NULL);
+    delete maskSplash;
+    splash->setSoftMask(maskBitmap);
+  } else {
+    splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, t3GlyphStack != NULL);
+    if (inlineImg) {
+      while (imgMaskData.y < height) {
+        imgMaskData.imgStr->getLine();
+        ++imgMaskData.y;
+      }
     }
   }
 
@@ -2724,7 +3000,7 @@ void SplashOutputDev::setSoftMask(GfxState * /*state*/, double * /*bbox*/,
 	  break;
 #if SPLASH_CMYK
 	case splashModeCMYK8:
-	  lum = (1 - color[4] / 255.0)
+	  lum = (1 - color[3] / 255.0)
 	        - (0.3 / 255.0) * color[0]
 	        - (0.59 / 255.0) * color[1]
 	        - (0.11 / 255.0) * color[2];
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index 02c7f9a..b9a7aad 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -14,6 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005 Takashi Iwai <tiwai at suse.de>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -79,6 +80,10 @@ public:
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() { return gTrue; }
 
+  // This device now supports text in pattern colorspace!
+  virtual GBool supportTextCSPattern(GfxState *state)
+  	{ return state->getFillColorSpace()->getMode() == csPattern; }
+
   //----- initialization and control
 
   // Start a page.
@@ -110,6 +115,7 @@ public:
 
   //----- update text state
   virtual void updateFont(GfxState *state);
+  virtual void updateRender(GfxState *state);
 
   //----- path painting
   virtual void stroke(GfxState *state);
@@ -130,6 +136,8 @@ public:
 			       double dx, double dy,
 			       CharCode code, Unicode *u, int uLen);
   virtual void endType3Char(GfxState *state);
+  virtual void beginTextObject(GfxState *state);
+  virtual GBool deviceHasTextClip(GfxState *state) { return textClipPath && haveCSPattern; }
   virtual void endTextObject(GfxState *state);
 
   //----- image drawing
@@ -150,6 +158,12 @@ public:
 				   Stream *maskStr,
 				   int maskWidth, int maskHeight,
 				   GfxImageColorMap *maskColorMap);
+  // If current colorspace ist pattern,
+  // need this device special handling for masks in pattern colorspace?
+  // Default is false
+  virtual GBool fillMaskCSPattern(GfxState * state)
+  	{ return state->getFillColorSpace()->getMode() == csPattern; }
+  virtual void endMaskClip(GfxState * /*state*/);
 
   //----- Type 3 font operators
   virtual void type3D0(GfxState *state, double wx, double wy);
@@ -225,6 +239,11 @@ private:
   static GBool maskedImageSrc(void *data, SplashColorPtr line,
 			      Guchar *alphaLine);
 
+  GBool haveCSPattern;		// set if text has been drawn with a
+				//   clipping render mode because of pattern colorspace
+  int savedRender;		// use if pattern colorspace
+  GBool keepAlphaChannel;	// don't fill with paper color, keep alpha channel
+
   SplashColorMode colorMode;
   int bitmapRowPad;
   GBool bitmapTopDown;
commit d3e4563146cbff4cb507522783e60462461c7524
Author: Thomas Freitag <Thomas.Freitag at alfa.de>
Date:   Sun May 31 23:23:07 2009 +0200

    Set memory to 0 after allocation, fixes problems on Sun machines, should not hurt for others

diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 361060c..14c0a3f 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -18,6 +18,7 @@
 // Copyright (C) 2006 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright (C) 2006-2009 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2009 Koji Otani <sho at bbr.jp>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -3356,9 +3357,11 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA,
       break;
     }
     if (nVerticesA == vertSize) {
+      int oldVertSize = vertSize;
       vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
       verticesA = (GfxGouraudVertex *)
 	              greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
+      memset(verticesA + oldVertSize, 0, (vertSize - oldVertSize) * sizeof(GfxGouraudVertex));
     }
     verticesA[nVerticesA].x = xMin + xMul * (double)x;
     verticesA[nVerticesA].y = yMin + yMul * (double)y;
@@ -3678,9 +3681,11 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
       break;
     }
     if (nPatchesA == patchesSize) {
+      int oldPatchesSize = patchesSize;
       patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
       patchesA = (GfxPatch *)greallocn(patchesA,
 				       patchesSize, sizeof(GfxPatch));
+      memset(patchesA + oldPatchesSize, 0, (patchesSize - oldPatchesSize) * sizeof(GfxPatch));
     }
     p = &patchesA[nPatchesA];
     if (typeA == 6) {
commit 78a58931b4347ecb505bad5a51104382ef5f91c7
Author: Thomas Freitag <Thomas.Freitag at alfa.de>
Date:   Sun May 31 22:52:23 2009 +0200

    Add splashClearColor that assigns white to the given colorptr

diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index ba12a82..a868652 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -13,6 +13,7 @@
 //
 // Copyright (C) 2006 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2008 Tomas Are Haavet <tomasare at gmail.com>
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
 //
 // 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
@@ -90,6 +91,15 @@ static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; }
 static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; }
 #endif
 
+static inline void splashClearColor(SplashColorPtr dest) {
+  dest[0] = 0;
+  dest[1] = 0;
+  dest[2] = 0;
+#if SPLASH_CMYK
+  dest[3] = 0;
+#endif
+}
+
 static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) {
   dest[0] = src[0];
   dest[1] = src[1];
commit 47c26747b32c242ec8ac60e7b93150a67eb22e31
Author: Thomas Freitag <Thomas.Freitag at alfa.de>
Date:   Sun May 31 22:51:22 2009 +0200

    Fix splashColorModeNComps to correctly include all values for each SplashColorMode

diff --git a/splash/SplashState.cc b/splash/SplashState.cc
index 70a79ac..b1fa2f5 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -4,6 +4,20 @@
 //
 //========================================================================
 
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009 Thomas Freitag <Thomas.Freitag at alfa.de>
+//
+// 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
+//
+//========================================================================
+
 #include <config.h>
 
 #ifdef USE_GCC_PRAGMAS
@@ -25,6 +39,9 @@
 // number of components in each color mode
 int splashColorModeNComps[] = {
   1, 1, 3, 3, 4
+#if SPLASH_CMYK
+  ,4
+#endif
 };
 
 SplashState::SplashState(int width, int height, GBool vectorAntialias,


More information about the poppler mailing list