[poppler] poppler/poppler: Annot.cc, 1.9, 1.9.2.1 Annot.h, 1.5, 1.5.2.1 ArthurOutputDev.cc, 1.12, 1.12.2.1 Catalog.cc, 1.19, 1.19.2.1 Catalog.h, 1.11, 1.11.2.1 CharCodeToUnicode.cc, 1.5, 1.5.2.1 DCTStream.cc, 1.5, 1.5.4.1 DCTStream.h, 1.6, 1.6.4.1 Decrypt.cc, 1.3, 1.3.4.1 Decrypt.h, 1.2, 1.2.4.1 Dict.cc, 1.6, 1.6.2.1 Dict.h, 1.5, 1.5.2.1 FontInfo.cc, 1.11, 1.11.4.1 Form.cc, 1.3, 1.3.2.1 Function.cc, 1.6, 1.6.2.1 Function.h, 1.2, 1.2.4.1 Gfx.cc, 1.14, 1.14.2.1 Gfx.h, 1.3, 1.3.4.1 GfxFont.cc, 1.10, 1.10.2.1 GfxFont.h, 1.5, 1.5.2.1 GfxState.cc, 1.14, 1.14.4.1 GfxState.h, 1.6, 1.6.4.1 GlobalParams.cc, 1.19, 1.19.2.1 GlobalParams.h, 1.8, 1.8.2.1 JBIG2Stream.cc, 1.9, 1.9.4.1 JBIG2Stream.h, 1.2, 1.2.4.1 JPXStream.cc, 1.6, 1.6.4.1 JPXStream.h, 1.2, 1.2.4.1 Lexer.cc, 1.5, 1.5.2.1 Link.cc, 1.5, 1.5.2.1 Link.h, 1.3, 1.3.2.1 Makefile.am, 1.29, 1.29.2.1 Object.cc, 1.3, 1.3.4.1 Object.h, 1.4, 1.4.2.1 Outline.cc, 1.5, 1.5.4.1 OutputDev.cc, 1.4, 1.4.4.1 OutputDev.h, 1.5, 1.5.4.1 PDFDoc.cc, 1.10, 1.10.4.1 PDFDoc.h, 1.7, 1.7.4.1 PSOutputDev.cc, 1.13, 1.13.2.1 PSOutputDev.h, 1.7, 1.7.4.1 PSTokenizer.cc, 1.2, 1.2.2.1 Page.cc, 1.17, 1.17.2.1 Page.h, 1.8, 1.8.2.1 PageLabelInfo.cc, 1.7, 1.7.2.1 Parser.cc, 1.7, 1.7.2.1 Parser.h, 1.3, 1.3.4.1 SecurityHandler.cc, 1.2, 1.2.4.1 SecurityHandler.h, 1.1, 1.1.4.1 SplashOutputDev.cc, 1.12, 1.12.2.1 SplashOutputDev.h, 1.4, 1.4.4.1 Stream.cc, 1.15, 1.15.2.1 Stream.h, 1.11, 1.11.2.1 TextOutputDev.cc, 1.22, 1.22.4.1 TextOutputDev.h, 1.12, 1.12.4.1 UGooString.cc, 1.5, NONE UGooString.h, 1.2, NONE XRef.cc, 1.14, 1.14.2.1 XRef.h, 1.7, 1.7.2.1

Albert Astals Cid aacid at kemper.freedesktop.org
Fri Apr 6 07:22:34 PDT 2007


Update of /cvs/poppler/poppler/poppler
In directory kemper:/tmp/cvs-serv11025/poppler

Modified Files:
      Tag: xpdf302merge
	Annot.cc Annot.h ArthurOutputDev.cc Catalog.cc Catalog.h 
	CharCodeToUnicode.cc DCTStream.cc DCTStream.h Decrypt.cc 
	Decrypt.h Dict.cc Dict.h FontInfo.cc Form.cc Function.cc 
	Function.h Gfx.cc Gfx.h GfxFont.cc GfxFont.h GfxState.cc 
	GfxState.h GlobalParams.cc GlobalParams.h JBIG2Stream.cc 
	JBIG2Stream.h JPXStream.cc JPXStream.h Lexer.cc Link.cc Link.h 
	Makefile.am Object.cc Object.h Outline.cc OutputDev.cc 
	OutputDev.h PDFDoc.cc PDFDoc.h PSOutputDev.cc PSOutputDev.h 
	PSTokenizer.cc Page.cc Page.h PageLabelInfo.cc Parser.cc 
	Parser.h SecurityHandler.cc SecurityHandler.h 
	SplashOutputDev.cc SplashOutputDev.h Stream.cc Stream.h 
	TextOutputDev.cc TextOutputDev.h XRef.cc XRef.h 
Removed Files:
      Tag: xpdf302merge
	UGooString.cc UGooString.h 
Log Message:
The big xpdf 3.02 merge, it's mostly working except
Annot has still to be merged, i'll leave that to jrebetez
DCTStream and FlateStream classes have not been tested
ArthurOutputDev had some code commented, but as it was nto working it's not crucial
UGooString got removed as i got clear it was not needed, yay!
HtmlOutputDev won't detect links as the base outputdev changed signature
Did not test CairoOutputDev but i have 0 knowledge of Cairo so i need someone here anyway
glib frontend has some nasty warnings probably due to changed signatures, have a look
And in all i'm quite happy of the merge as it renders "something" and my kpdf port all it had was crashes :D


Index: Annot.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Annot.cc,v
retrieving revision 1.9
retrieving revision 1.9.2.1
diff -u -d -r1.9 -r1.9.2.1
--- Annot.cc	6 Mar 2007 22:27:18 -0000	1.9
+++ Annot.cc	6 Apr 2007 14:22:23 -0000	1.9.2.1
@@ -18,7 +18,6 @@
 #include "Catalog.h"
 #include "Gfx.h"
 #include "Lexer.h"
-#include "UGooString.h"
 #include "Annot.h"
 #include "GfxFont.h"
 #include "CharCodeToUnicode.h"
@@ -334,7 +333,7 @@
         Object obj3, obj4;
         //--
         bool found = false;
-        if (obj1.dictLookup(*fontName, &obj3)->isDict() && obj3.dictLookup("Type", &obj4)->isName("Font")) {
+        if (obj1.dictLookup(fontName->getCString(), &obj3)->isDict() && obj3.dictLookup("Type", &obj4)->isName("Font")) {
           found = true;
         }
         if (!found) { //font not found in DR, try to lookup in each entry BaseFont/Name
@@ -364,7 +363,7 @@
         }
         if (found) {
           obj4.free();
-          obj1.dictLookupNF(*fontName, &obj4);
+          obj1.dictLookupNF(fontName->getCString(), &obj4);
           Ref r;
           if (obj4.isRef()) r = obj4.getRef();
           else r.gen = r.num = 0;
@@ -476,7 +475,8 @@
 void Annot::draw(Gfx *gfx) {
   Object obj;
   if (appearance.fetch(xref, &obj)->isStream()) {
-    gfx->doAnnot(&obj, xMin, yMin, xMax, yMax);
+#warning TODO!!!
+    // gfx->doAnnot(&obj, xMin, yMin, xMax, yMax);
   }
   obj.free();
 }

Index: Annot.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Annot.h,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -d -r1.5 -r1.5.2.1
--- Annot.h	25 Feb 2007 00:34:21 -0000	1.5
+++ Annot.h	6 Apr 2007 14:22:23 -0000	1.5.2.1
@@ -21,6 +21,42 @@
 class FormWidget;
 
 //------------------------------------------------------------------------
+// AnnotBorderStyle
+//------------------------------------------------------------------------
+
+enum AnnotBorderType {
+  annotBorderSolid,
+  annotBorderDashed,
+  annotBorderBeveled,
+  annotBorderInset,
+  annotBorderUnderlined
+};
+
+class AnnotBorderStyle {
+public:
+
+  AnnotBorderStyle(AnnotBorderType typeA, double widthA,
+		   double *dashA, int dashLengthA,
+		   double rA, double gA, double bA);
+  ~AnnotBorderStyle();
+
+  AnnotBorderType getType() { return type; }
+  double getWidth() { return width; }
+  void getDash(double **dashA, int *dashLengthA)
+    { *dashA = dash; *dashLengthA = dashLength; }
+  void getColor(double *rA, double *gA, double *bA)
+    { *rA = r; *gA = g; *bA = b; }
+
+private:
+
+  AnnotBorderType type;
+  double width;
+  double *dash;
+  int dashLength;
+  double r, g, b;
+};
+
+//------------------------------------------------------------------------
 // Annot
 //------------------------------------------------------------------------
 

Index: ArthurOutputDev.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/ArthurOutputDev.cc,v
retrieving revision 1.12
retrieving revision 1.12.2.1
diff -u -d -r1.12 -r1.12.2.1
--- ArthurOutputDev.cc	13 Nov 2006 19:16:44 -0000	1.12
+++ ArthurOutputDev.cc	6 Apr 2007 14:22:23 -0000	1.12.2.1
@@ -241,6 +241,8 @@
 
 void ArthurOutputDev::updateFont(GfxState *state)
 {
+#warning fix this, probably update with updated code from SplashOutputdev
+/*
   GfxFont *gfxFont;
   GfxFontType fontType;
   SplashOutFontFileID *id;
@@ -403,7 +405,7 @@
 
  err2:
   delete id;
- err1:
+ err1:*/
   return;
 }
 
@@ -513,9 +515,12 @@
 	  qPath.quadTo(x0+fontPath->pts[i].x, y0+fontPath->pts[i].y,
 		       x0+fontPath->pts[i+1].x, y0+fontPath->pts[i+1].y);
 	  ++i;
-	} else if (fontPath->flags[i] & splashPathArcCW) {
-	  qDebug() << "Need to implement arc";
-	} else {
+	}
+#warning FIX THIS
+// 	else if (fontPath->flags[i] & splashPathArcCW) {
+// 	  qDebug() << "Need to implement arc";
+// 	}
+	else {
 	  qPath.lineTo(x0+fontPath->pts[i].x, y0+fontPath->pts[i].y);
 	}
 	if (fontPath->flags[i] & splashPathLast) {

Index: Catalog.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Catalog.cc,v
retrieving revision 1.19
retrieving revision 1.19.2.1
diff -u -d -r1.19 -r1.19.2.1
--- Catalog.cc	24 Feb 2007 23:32:23 -0000	1.19
+++ Catalog.cc	6 Apr 2007 14:22:23 -0000	1.19.2.1
@@ -2,7 +2,7 @@
 //
 // Catalog.cc
 //
-// Copyright 1996-2003 Glyph & Cog, LLC
+// Copyright 1996-2007 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -23,23 +23,17 @@
 #include "Error.h"
 #include "Link.h"
 #include "PageLabelInfo.h"
-#include "UGooString.h"
 #include "Catalog.h"
 #include "Form.h"
 
-// This define is used to limit the depth of recursive readPageTree calls
-// This is needed because the page tree nodes can reference their parents
-// leaving us in an infinite loop
-// Most sane pdf documents don't have a call depth higher than 10
-#define MAX_CALL_DEPTH 1000
-
 //------------------------------------------------------------------------
 // Catalog
 //------------------------------------------------------------------------
 
 Catalog::Catalog(XRef *xrefA) {
-  Object catDict, pagesDict;
+  Object catDict, pagesDict, pagesDictRef;
   Object obj, obj2;
+  char *alreadyRead;
   int numPages0;
   int i;
 
@@ -91,7 +85,16 @@
     pageRefs[i].num = -1;
     pageRefs[i].gen = -1;
   }
-  numPages = readPageTree(pagesDict.getDict(), NULL, 0, 0);
+  alreadyRead = (char *)gmalloc(xref->getNumObjects());
+  memset(alreadyRead, 0, xref->getNumObjects());
+  if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() &&
+      pagesDictRef.getRefNum() >= 0 &&
+      pagesDictRef.getRefNum() < xref->getNumObjects()) {
+    alreadyRead[pagesDictRef.getRefNum()] = 1;
+  }
+  pagesDictRef.free();
+  numPages = readPageTree(pagesDict.getDict(), NULL, 0, alreadyRead);
+  gfree(alreadyRead);
   if (numPages != numPages0) {
     error(-1, "Page count in top-level pages object is incorrect");
   }
@@ -234,7 +237,8 @@
   return s;
 }
 
-int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, int callDepth) {
+int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
+			  char *alreadyRead) {
   Object kids;
   Object kid;
   Object kidRef;
@@ -250,6 +254,17 @@
     goto err1;
   }
   for (i = 0; i < kids.arrayGetLength(); ++i) {
+    kids.arrayGetNF(i, &kidRef);
+    if (kidRef.isRef() &&
+	kidRef.getRefNum() >= 0 &&
+	kidRef.getRefNum() < xref->getNumObjects()) {
+      if (alreadyRead[kidRef.getRefNum()]) {
+	error(-1, "Loop in Pages tree");
+	kidRef.free();
+	continue;
+      }
+      alreadyRead[kidRef.getRefNum()] = 1;
+    }
     kids.arrayGet(i, &kid);
     if (kid.isDict("Page")) {
       attrs2 = new PageAttrs(attrs1, kid.getDict());
@@ -269,28 +284,23 @@
 	}
       }
       pages[start] = page;
-      kids.arrayGetNF(i, &kidRef);
       if (kidRef.isRef()) {
 	pageRefs[start].num = kidRef.getRefNum();
 	pageRefs[start].gen = kidRef.getRefGen();
       }
-      kidRef.free();
       ++start;
     // This should really be isDict("Pages"), but I've seen at least one
     // PDF file where the /Type entry is missing.
     } else if (kid.isDict()) {
-      if (callDepth > MAX_CALL_DEPTH) {
-        error(-1, "Limit of %d recursive calls reached while reading the page tree. If your document is correct and not a test to try to force a crash, please report a bug.", MAX_CALL_DEPTH);
-      } else {
-        if ((start = readPageTree(kid.getDict(), attrs1, start, callDepth + 1))
-	    < 0)
-	  goto err2;
-      }
+      if ((start = readPageTree(kid.getDict(), attrs1, start, alreadyRead))
+	  < 0)
+	goto err2;
     } else {
       error(-1, "Kid object (page %d) is wrong type (%s)",
 	    start+1, kid.getTypeName());
     }
     kid.free();
+    kidRef.free();
   }
   delete attrs1;
   kids.free();
@@ -317,7 +327,7 @@
   return 0;
 }
 
-LinkDest *Catalog::findDest(UGooString *name) {
+LinkDest *Catalog::findDest(GooString *name) {
   LinkDest *dest;
   Object obj1, obj2;
   GBool found;
@@ -325,7 +335,7 @@
   // try named destination dictionary then name tree
   found = gFalse;
   if (dests.isDict()) {
-    if (!dests.dictLookup(*name, &obj1)->isNull())
+    if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
       found = gTrue;
     else
       obj1.free();
@@ -377,7 +387,7 @@
     delete[] descString;
     GooString *createDate = new GooString();
     GooString *modDate = new GooString();
-    Stream *efStream;
+    Stream *efStream = NULL;
     if (obj.isRef()) {
 	if (obj.fetch(xref, &efDict)->isDict()) {
 	    // efDict matches Table 3.40 in the PDF1.6 spec
@@ -452,7 +462,7 @@
     return embeddedFile;
 }
 
-NameTree::NameTree(void)
+NameTree::NameTree()
 {
   size = 0;
   length = 0;
@@ -460,23 +470,20 @@
 }
 
 NameTree::Entry::Entry(Array *array, int index) {
-    GooString n;
-    if (!array->getString(index, &n) || !array->getNF(index + 1, &value)) {
+    if (!array->getString(index, &name) || !array->getNF(index + 1, &value)) {
       Object aux;
       array->get(index, &aux);
       if (aux.isString() && array->getNF(index + 1, &value) )
       {
-        n.append(aux.getString());
+        name.append(aux.getString());
       }
       else
         error(-1, "Invalid page tree");
     }
-    name = new UGooString(n);
 }
 
 NameTree::Entry::~Entry() {
   value.free();
-  delete name;
 }
 
 void NameTree::addEntry(Entry *entry)
@@ -531,13 +538,13 @@
 
 int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry)
 {
-  UGooString *key = (UGooString *) voidKey;
+  GooString *key = (GooString *) voidKey;
   Entry *entry = *(NameTree::Entry **) voidEntry;
 
-  return key->cmp(entry->name);
+  return key->cmp(&entry->name);
 }
 
-GBool NameTree::lookup(UGooString *name, Object *obj)
+GBool NameTree::lookup(GooString *name, Object *obj)
 {
   Entry **entry;
   char *cname;
@@ -565,10 +572,10 @@
   }
 }
 
-UGooString *NameTree::getName(int index)
+GooString *NameTree::getName(int index)
 {
     if (index < length) {
-	return entries[index]->name;
+	return &entries[index]->name;
     } else {
 	return NULL;
     }

Index: Catalog.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Catalog.h,v
retrieving revision 1.11
retrieving revision 1.11.2.1
diff -u -d -r1.11 -r1.11.2.1
--- Catalog.h	24 Feb 2007 23:32:23 -0000	1.11
+++ Catalog.h	6 Apr 2007 14:22:23 -0000	1.11.2.1
@@ -2,7 +2,7 @@
 //
 // Catalog.h
 //
-// Copyright 1996-2003 Glyph & Cog, LLC
+// Copyright 1996-2007 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -19,7 +19,6 @@
 class PageAttrs;
 struct Ref;
 class LinkDest;
-class UGooString;
 class PageLabelInfo;
 class Form;
 
@@ -32,18 +31,18 @@
   NameTree();
   void init(XRef *xref, Object *tree);
   void parse(Object *tree);
-  GBool lookup(UGooString *name, Object *obj);
+  GBool lookup(GooString *name, Object *obj);
   void free();
   int numEntries() { return length; };
   // iterator accessor
   Object getValue(int i);
-  UGooString *getName(int i);
+  GooString *getName(int i);
 
 private:
   struct Entry {
     Entry(Array *array, int index);
     ~Entry();
-    UGooString *name;
+    GooString name;
     Object value;
     void free();
     static int cmp(const void *key, const void *entry);
@@ -136,7 +135,9 @@
 
   // Find a named destination.  Returns the link destination, or
   // NULL if <name> is not a destination.
-  LinkDest *findDest(UGooString *name);
+  LinkDest *findDest(GooString *name);
+
+  Object *getDests() { return &dests; }
 
   // Get the number of embedded files
   int numEmbeddedFiles() { return embeddedFileNameTree.numEntries(); }
@@ -197,7 +198,8 @@
   PageMode pageMode;		// page mode
   PageLayout pageLayout;	// page layout
 
-  int readPageTree(Dict *pages, PageAttrs *attrs, int start, int callDepth);
+  int readPageTree(Dict *pages, PageAttrs *attrs, int start,
+		   char *alreadyRead);
   Object *findDestInTree(Object *tree, GooString *name, Object *obj);
 };
 

Index: CharCodeToUnicode.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/CharCodeToUnicode.cc,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -d -r1.5 -r1.5.2.1
--- CharCodeToUnicode.cc	24 Feb 2007 23:32:23 -0000	1.5
+++ CharCodeToUnicode.cc	6 Apr 2007 14:22:23 -0000	1.5.2.1
@@ -243,18 +243,8 @@
 	}
 	if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
 	      tok2[0] == '<' && tok2[n2 - 1] == '>')) {
-	  
-	  // check there was no line jump inside the token and so the length is 
-	  // longer than it should be
-	  int countAux = 0;
-	  for (int k = 0; k < n1; k++)
-	    if (tok1[k] != '\n' && tok1[k] != '\r') countAux++;
-	
-	  if (!(countAux == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
-	      tok2[0] == '<' && tok2[n2 - 1] == '>')) {
-	    error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
-	    continue;
-	  }
+	  error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
+	  continue;
 	}
 	tok1[n1 - 1] = tok2[n2 - 1] = '\0';
 	if (sscanf(tok1 + 1, "%x", &code1) != 1) {
@@ -278,21 +268,8 @@
 	}
 	if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
 	      n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) {
-	  // check there was no line jump inside the token and so the length is 
-	  // longer than it should be
-	  int countAux = 0;
-	  for (int k = 0; k < n1; k++)
-	    if (tok1[k] != '\n' && tok1[k] != '\r') countAux++;
-	  
-	  int countAux2 = 0;
-	  for (int k = 0; k < n1; k++)
-	    if (tok2[k] != '\n' && tok2[k] != '\r') countAux++;
-	  
-	  if (!(countAux == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
-	      countAux2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) {
-	    error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
-	    continue;
-	  }
+	  error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
+	  continue;
 	}
 	tok1[n1 - 1] = tok2[n2 - 1] = '\0';
 	if (sscanf(tok1 + 1, "%x", &code1) != 1 ||

Index: DCTStream.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/DCTStream.cc,v
retrieving revision 1.5
retrieving revision 1.5.4.1
diff -u -d -r1.5 -r1.5.4.1
--- DCTStream.cc	28 Jun 2006 19:23:52 -0000	1.5
+++ DCTStream.cc	6 Apr 2007 14:22:23 -0000	1.5.4.1
@@ -6,6 +6,9 @@
 //
 //========================================================================
 
+#warning LIBJPEG DCTSTream is broken, fix it
+#if 0
+
 #include "DCTStream.h"
 
 static void str_init_source(j_decompress_ptr cinfo)
@@ -168,3 +171,5 @@
 GBool DCTStream::isBinary(GBool last) {
   return str->isBinary(gTrue);
 }
+
+#endif // this is the #if 0 endif
\ No newline at end of file

Index: DCTStream.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/DCTStream.h,v
retrieving revision 1.6
retrieving revision 1.6.4.1
diff -u -d -r1.6 -r1.6.4.1
--- DCTStream.h	28 Jun 2006 19:23:52 -0000	1.6
+++ DCTStream.h	6 Apr 2007 14:22:23 -0000	1.6.4.1
@@ -10,6 +10,9 @@
 #define DCTSTREAM_H
 #include <config.h>
 
+#warning LIBJPEG DCTSTream is broken, fix it
+#if 0
+
 #ifdef USE_GCC_PRAGMAS
 #pragma interface
 #endif
@@ -70,4 +73,6 @@
   JSAMPARRAY row_buffer;
 };
 
-#endif
+#endif // this is the #if 0 endif
+
+#endif 

Index: Decrypt.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Decrypt.cc,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -u -d -r1.3 -r1.3.4.1
--- Decrypt.cc	16 Sep 2005 18:29:18 -0000	1.3
+++ Decrypt.cc	6 Apr 2007 14:22:23 -0000	1.3.4.1
@@ -18,6 +18,9 @@
 
 static void rc4InitKey(Guchar *key, int keyLen, Guchar *state);
 static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c);
+static void aesKeyExpansion(DecryptAESState *s,
+			    Guchar *objKey, int objKeyLen);
+static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last);
 static void md5(Guchar *msg, int msgLen, Guchar *digest);
 
 static Guchar passwordPad[32] = {
@@ -31,37 +34,6 @@
 // Decrypt
 //------------------------------------------------------------------------
 
-Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) {
-  int i;
-
-  // construct object key
-  for (i = 0; i < keyLength; ++i) {
-    objKey[i] = fileKey[i];
-  }
-  objKey[keyLength] = objNum & 0xff;
-  objKey[keyLength + 1] = (objNum >> 8) & 0xff;
-  objKey[keyLength + 2] = (objNum >> 16) & 0xff;
-  objKey[keyLength + 3] = objGen & 0xff;
-  objKey[keyLength + 4] = (objGen >> 8) & 0xff;
-  md5(objKey, keyLength + 5, objKey);
-
-  // set up for decryption
-  x = y = 0;
-  if ((objKeyLength = keyLength + 5) > 16) {
-    objKeyLength = 16;
-  }
-  rc4InitKey(objKey, objKeyLength, state);
-}
-
-void Decrypt::reset() {
-  x = y = 0;
-  rc4InitKey(objKey, objKeyLength, state);
-}
-
-Guchar Decrypt::decryptByte(Guchar c) {
-  return rc4DecryptByte(state, &x, &y, c);
-}
-
 GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
 			   GooString *ownerKey, GooString *userKey,
 			   int permissions, GooString *fileID,
@@ -206,6 +178,144 @@
 }
 
 //------------------------------------------------------------------------
+// DecryptStream
+//------------------------------------------------------------------------
+
+DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey,
+			     CryptAlgorithm algoA, int keyLength,
+			     int objNum, int objGen):
+  FilterStream(strA)
+{
+  int n, i;
+
+  algo = algoA;
+
+  // construct object key
+  for (i = 0; i < keyLength; ++i) {
+    objKey[i] = fileKey[i];
+  }
+  objKey[keyLength] = objNum & 0xff;
+  objKey[keyLength + 1] = (objNum >> 8) & 0xff;
+  objKey[keyLength + 2] = (objNum >> 16) & 0xff;
+  objKey[keyLength + 3] = objGen & 0xff;
+  objKey[keyLength + 4] = (objGen >> 8) & 0xff;
+  if (algo == cryptAES) {
+    objKey[keyLength + 5] = 0x73; // 's'
+    objKey[keyLength + 6] = 0x41; // 'A'
+    objKey[keyLength + 7] = 0x6c; // 'l'
+    objKey[keyLength + 8] = 0x54; // 'T'
+    n = keyLength + 9;
+  } else {
+    n = keyLength + 5;
+  }
+  md5(objKey, n, objKey);
+  if ((objKeyLength = keyLength + 5) > 16) {
+    objKeyLength = 16;
+  }
+}
+
+DecryptStream::~DecryptStream() {
+  delete str;
+}
+
+void DecryptStream::reset() {
+  int i;
+
+  str->reset();
+  switch (algo) {
+  case cryptRC4:
+    state.rc4.x = state.rc4.y = 0;
+    rc4InitKey(objKey, objKeyLength, state.rc4.state);
+    state.rc4.buf = EOF;
+    break;
+  case cryptAES:
+    aesKeyExpansion(&state.aes, objKey, objKeyLength);
+    for (i = 0; i < 16; ++i) {
+      state.aes.cbc[i] = str->getChar();
+    }
+    state.aes.bufIdx = 16;
+    break;
+  }
+}
+
+int DecryptStream::getChar() {
+  Guchar in[16];
+  int c, i;
+
+  c = EOF; // make gcc happy
+  switch (algo) {
+  case cryptRC4:
+    if (state.rc4.buf == EOF) {
+      c = str->getChar();
+      if (c != EOF) {
+	state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x,
+				       &state.rc4.y, (Guchar)c);
+      }
+    }
+    c = state.rc4.buf;
+    state.rc4.buf = EOF;
+    break;
+  case cryptAES:
+    if (state.aes.bufIdx == 16) {
+      for (i = 0; i < 16; ++i) {
+	if ((c = str->getChar()) == EOF) {
+	  return EOF;
+	}
+	in[i] = (Guchar)c;
+      }
+      aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
+    }
+    if (state.aes.bufIdx == 16) {
+      c = EOF;
+    } else {
+      c = state.aes.buf[state.aes.bufIdx++];
+    }
+    break;
+  }
+  return c;
+}
+
+int DecryptStream::lookChar() {
+  Guchar in[16];
+  int c, i;
+
+  c = EOF; // make gcc happy
+  switch (algo) {
+  case cryptRC4:
+    if (state.rc4.buf == EOF) {
+      c = str->getChar();
+      if (c != EOF) {
+	state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x,
+				       &state.rc4.y, (Guchar)c);
+      }
+    }
+    c = state.rc4.buf;
+    break;
+  case cryptAES:
+    if (state.aes.bufIdx == 16) {
+      for (i = 0; i < 16; ++i) {
+	if ((c = str->getChar()) == EOF) {
+	  return EOF;
+	}
+	in[i] = c;
+      }
+      aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
+    }
+    if (state.aes.bufIdx == 16) {
+      c = EOF;
+    } else {
+      c = state.aes.buf[state.aes.bufIdx];
+    }
+    break;
+  }
+  return c;
+}
+
+GBool DecryptStream::isBinary(GBool last) {
+  return str->isBinary(last);
+}
+
+//------------------------------------------------------------------------
 // RC4-compatible decryption
 //------------------------------------------------------------------------
 
@@ -239,6 +349,261 @@
 }
 
 //------------------------------------------------------------------------
+// AES decryption
+//------------------------------------------------------------------------
+
+static Guchar sbox[256] = {
+  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+static Guchar invSbox[256] = {
+  0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+};
+
+static Guint rcon[11] = {
+  0x00000000, // unused
+  0x01000000,
+  0x02000000,
+  0x04000000,
+  0x08000000,
+  0x10000000,
+  0x20000000,
+  0x40000000,
+  0x80000000,
+  0x1b000000,
+  0x36000000
+};
+
+static inline Guint subWord(Guint x) {
+  return (sbox[x >> 24] << 24)
+         | (sbox[(x >> 16) & 0xff] << 16)
+         | (sbox[(x >> 8) & 0xff] << 8)
+         | sbox[x & 0xff];
+}
+
+static inline Guint rotWord(Guint x) {
+  return ((x << 8) & 0xffffffff) | (x >> 24);
+}
+
+static inline void invSubBytes(Guchar *state) {
+  int i;
+
+  for (i = 0; i < 16; ++i) {
+    state[i] = invSbox[state[i]];
+  }
+}
+
+static inline void invShiftRows(Guchar *state) {
+  Guchar t;
+
+  t = state[7];
+  state[7] = state[6];
+  state[6] = state[5];
+  state[5] = state[4];
+  state[4] = t;
+
+  t = state[8];
+  state[8] = state[10];
+  state[10] = t;
+  t = state[9];
+  state[9] = state[11];
+  state[11] = t;
+
+  t = state[12];
+  state[12] = state[13];
+  state[13] = state[14];
+  state[14] = state[15];
+  state[15] = t;
+}
+
+// {09} \cdot s
+static inline Guchar mul09(Guchar s) {
+  Guchar s2, s4, s8;
+
+  s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+  s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+  s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+  return s ^ s8;
+}
+
+// {0b} \cdot s
+static inline Guchar mul0b(Guchar s) {
+  Guchar s2, s4, s8;
+
+  s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+  s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+  s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+  return s ^ s2 ^ s8;
+}
+
+// {0d} \cdot s
+static inline Guchar mul0d(Guchar s) {
+  Guchar s2, s4, s8;
+
+  s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+  s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+  s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+  return s ^ s4 ^ s8;
+}
+
+// {0e} \cdot s
+static inline Guchar mul0e(Guchar s) {
+  Guchar s2, s4, s8;
+
+  s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+  s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+  s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+  return s2 ^ s4 ^ s8;
+}
+
+static inline void invMixColumns(Guchar *state) {
+  int c;
+  Guchar s0, s1, s2, s3;
+
+  for (c = 0; c < 4; ++c) {
+    s0 = state[c];
+    s1 = state[4+c];
+    s2 = state[8+c];
+    s3 = state[12+c];
+    state[c] =    mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3);
+    state[4+c] =  mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3);
+    state[8+c] =  mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3);
+    state[12+c] = mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3);
+  }
+}
+
+static inline void invMixColumnsW(Guint *w) {
+  int c;
+  Guchar s0, s1, s2, s3;
+
+  for (c = 0; c < 4; ++c) {
+    s0 = w[c] >> 24;
+    s1 = w[c] >> 16;
+    s2 = w[c] >> 8;
+    s3 = w[c];
+    w[c] = ((mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3)) << 24)
+           | ((mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3)) << 16)
+           | ((mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3)) << 8)
+           | (mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3));
+  }
+}
+
+static inline void addRoundKey(Guchar *state, Guint *w) {
+  int c;
+
+  for (c = 0; c < 4; ++c) {
+    state[c] ^= w[c] >> 24;
+    state[4+c] ^= w[c] >> 16;
+    state[8+c] ^= w[c] >> 8;
+    state[12+c] ^= w[c];
+  }
+}
+
+static void aesKeyExpansion(DecryptAESState *s,
+			    Guchar *objKey, int /*objKeyLen*/) {
+  Guint temp;
+  int i, round;
+
+  //~ this assumes objKeyLen == 16
+
+  for (i = 0; i < 4; ++i) {
+    s->w[i] = (objKey[4*i] << 24) + (objKey[4*i+1] << 16) +
+              (objKey[4*i+2] << 8) + objKey[4*i+3];
+  }
+  for (i = 4; i < 44; ++i) {
+    temp = s->w[i-1];
+    if (!(i & 3)) {
+      temp = subWord(rotWord(temp)) ^ rcon[i/4];
+    }
+    s->w[i] = s->w[i-4] ^ temp;
+  }
+  for (round = 1; round <= 9; ++round) {
+    invMixColumnsW(&s->w[round * 4]);
+  }
+}
+
+static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) {
+  int c, round, n, i;
+
+  // initial state
+  for (c = 0; c < 4; ++c) {
+    s->state[c] = in[4*c];
+    s->state[4+c] = in[4*c+1];
+    s->state[8+c] = in[4*c+2];
+    s->state[12+c] = in[4*c+3];
+  }
+
+  // round 0
+  addRoundKey(s->state, &s->w[10 * 4]);
+
+  // rounds 1-9
+  for (round = 9; round >= 1; --round) {
+    invSubBytes(s->state);
+    invShiftRows(s->state);
+    invMixColumns(s->state);
+    addRoundKey(s->state, &s->w[round * 4]);
+  }
+
+  // round 10
+  invSubBytes(s->state);
+  invShiftRows(s->state);
+  addRoundKey(s->state, &s->w[0]);
+
+  // CBC
+  for (c = 0; c < 4; ++c) {
+    s->buf[4*c] = s->state[c] ^ s->cbc[4*c];
+    s->buf[4*c+1] = s->state[4+c] ^ s->cbc[4*c+1];
+    s->buf[4*c+2] = s->state[8+c] ^ s->cbc[4*c+2];
+    s->buf[4*c+3] = s->state[12+c] ^ s->cbc[4*c+3];
+  }
+
+  // save the input block for the next CBC
+  for (i = 0; i < 16; ++i) {
+    s->cbc[i] = in[i];
+  }
+
+  // remove padding
+  s->bufIdx = 0;
+  if (last) {
+    n = s->buf[15];
+    for (i = 15; i >= n; --i) {
+      s->buf[i] = s->buf[i-n];
+    }
+    s->bufIdx = n;
+  }
+}
+
+//------------------------------------------------------------------------
 // MD5 message digest
 //------------------------------------------------------------------------
 

Index: Decrypt.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Decrypt.h,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -d -r1.2 -r1.2.4.1
--- Decrypt.h	16 Sep 2005 18:29:18 -0000	1.2
+++ Decrypt.h	6 Apr 2007 14:22:23 -0000	1.2.4.1
@@ -15,6 +15,8 @@
 
 #include "goo/gtypes.h"
 #include "goo/GooString.h"
+#include "Object.h"
+#include "Stream.h"
 
 //------------------------------------------------------------------------
 // Decrypt
@@ -23,15 +25,6 @@
 class Decrypt {
 public:
 
-  // Initialize the decryptor object.
-  Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen);
-
-  // Reset decryption.
-  void reset();
-
-  // Decrypt one byte.
-  Guchar decryptByte(Guchar c);
-
   // Generate a file key.  The <fileKey> buffer must have space for at
   // least 16 bytes.  Checks <ownerPassword> and then <userPassword>
   // and returns true if either is correct.  Sets <ownerPasswordOk> if
@@ -51,11 +44,50 @@
 			    int permissions, GooString *fileID,
 			    GooString *userPassword, Guchar *fileKey,
 			    GBool encryptMetadata);
+};
 
-  int objKeyLength;
-  Guchar objKey[21];
+//------------------------------------------------------------------------
+// DecryptStream
+//------------------------------------------------------------------------
+
+struct DecryptRC4State {
   Guchar state[256];
   Guchar x, y;
+  int buf;
+};
+
+struct DecryptAESState {
+  Guint w[44];
+  Guchar state[16];
+  Guchar cbc[16];
+  Guchar buf[16];
+  int bufIdx;
+};
+
+class DecryptStream: public FilterStream {
+public:
+
+  DecryptStream(Stream *strA, Guchar *fileKey,
+		CryptAlgorithm algoA, int keyLength,
+		int objNum, int objGen);
+  virtual ~DecryptStream();
+  virtual StreamKind getKind() { return strWeird; }
+  virtual void reset();
+  virtual int getChar();
+  virtual int lookChar();
+  virtual GBool isBinary(GBool last);
+  virtual Stream *getUndecodedStream() { return this; }
+
+private:
+
+  CryptAlgorithm algo;
+  int objKeyLength;
+  Guchar objKey[16 + 9];
+
+  union {
+    DecryptRC4State rc4;
+    DecryptAESState aes;
+  } state;
 };
 
 #endif

Index: Dict.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Dict.cc,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -d -r1.6 -r1.6.2.1
--- Dict.cc	24 Feb 2007 23:32:23 -0000	1.6
+++ Dict.cc	6 Apr 2007 14:22:23 -0000	1.6.2.1
@@ -16,7 +16,6 @@
 #include <string.h>
 #include "goo/gmem.h"
 #include "Object.h"
-#include "UGooString.h"
 #include "XRef.h"
 #include "Dict.h"
 
@@ -35,13 +34,13 @@
   int i;
 
   for (i = 0; i < length; ++i) {
-    delete entries[i].key;
+    gfree(entries[i].key);
     entries[i].val.free();
   }
   gfree(entries);
 }
 
-void Dict::addOwnKeyVal(UGooString *key, Object *val) {
+void Dict::add(char *key, Object *val) {
   if (length == size) {
     if (length == 0) {
       size = 8;
@@ -55,24 +54,24 @@
   ++length;
 }
 
-inline DictEntry *Dict::find(const UGooString &key) {
+inline DictEntry *Dict::find(char *key) {
   int i;
 
   for (i = 0; i < length; ++i) {
-    if (!key.cmp(entries[i].key))
+    if (!strcmp(key, entries[i].key))
       return &entries[i];
   }
   return NULL;
 }
 
-void Dict::remove(const UGooString &key) {
+void Dict::remove(char *key) {
   int i; 
   bool found = false;
   DictEntry tmp;
   if(length == 0) return;
 
   for(i=0; i<length; i++) {
-    if (!key.cmp(entries[i].key)) {
+    if (!strcmp(key, entries[i].key)) {
       found = true;
       break;
     }
@@ -85,7 +84,7 @@
     entries[i] = tmp;
 }
 
-void Dict::set(const UGooString &key, Object *val) {
+void Dict::set(char *key, Object *val) {
   DictEntry *e;
   e = find (key);
   if (e) {
@@ -103,13 +102,13 @@
   return (e = find("Type")) && e->val.isName(type);
 }
 
-Object *Dict::lookup(const UGooString &key, Object *obj) {
+Object *Dict::lookup(char *key, Object *obj) {
   DictEntry *e;
 
   return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull();
 }
 
-Object *Dict::lookupNF(const UGooString &key, Object *obj) {
+Object *Dict::lookupNF(char *key, Object *obj) {
   DictEntry *e;
 
   return (e = find(key)) ? e->val.copy(obj) : obj->initNull();
@@ -135,7 +134,7 @@
   return success;
 }
 
-UGooString *Dict::getKey(int i) {
+char *Dict::getKey(int i) {
   return entries[i].key;
 }
 

Index: Dict.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Dict.h,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -d -r1.5 -r1.5.2.1
--- Dict.h	24 Feb 2007 23:32:23 -0000	1.5
+++ Dict.h	6 Apr 2007 14:22:23 -0000	1.5.2.1
@@ -14,14 +14,13 @@
 #endif
 
 #include "Object.h"
-#include "UGooString.h"
 
 //------------------------------------------------------------------------
 // Dict
 //------------------------------------------------------------------------
 
 struct DictEntry {
-  UGooString *key;
+  char *key;
   Object val;
 };
 
@@ -41,31 +40,25 @@
   // Get number of entries.
   int getLength() { return length; }
 
-  // Add an entry
-  void addOwnKeyVal(UGooString *key, Object *val);
-  // FIXME: should also be renamed to addOwnVal()
-  void add(const UGooString &key, Object *val) {
-    addOwnKeyVal(new UGooString(key), val);
-  }
-  void addOwnVal(const char *key, Object *val) {
-    addOwnKeyVal(new UGooString(key), val);
-  }
+  // Add an entry.  NB: does not copy key.
+  void add(char *key, Object *val);
+
   // Update the value of an existing entry, otherwise create it
-  void set(const UGooString &key, Object *val);
+  void set(char *key, Object *val);
   // Remove an entry. This invalidate indexes
-  void remove(const UGooString &key);
+  void remove(char *key);
 
   // Check if dictionary is of specified type.
   GBool is(char *type);
 
   // Look up an entry and return the value.  Returns a null object
   // if <key> is not in the dictionary.
-  Object *lookup(const UGooString &key, Object *obj);
-  Object *lookupNF(const UGooString &key, Object *obj);
+  Object *lookup(char *key, Object *obj);
+  Object *lookupNF(char *key, Object *obj);
   GBool lookupInt(const char *key, const char *alt_key, int *value);
 
   // Iterative accessors.
-  UGooString *getKey(int i);
+  char *getKey(int i);
   Object *getVal(int i, Object *obj);
   Object *getValNF(int i, Object *obj);
 
@@ -82,7 +75,7 @@
   int length;			// number of entries in dictionary
   int ref;			// reference count
 
-  DictEntry *find(const UGooString &key);
+  DictEntry *find(char *key);
 };
 
 #endif

Index: FontInfo.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/FontInfo.cc,v
retrieving revision 1.11
retrieving revision 1.11.4.1
diff -u -d -r1.11 -r1.11.4.1
--- FontInfo.cc	14 May 2006 16:11:54 -0000	1.11
+++ FontInfo.cc	6 Apr 2007 14:22:23 -0000	1.11.4.1
@@ -12,7 +12,6 @@
 #include "Annot.h"
 #include "PDFDoc.h"
 #include "FontInfo.h"
-#include "UGooString.h"
 
 FontInfoScanner::FontInfoScanner(PDFDoc *docA) {
   doc = docA;

Index: Form.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Form.cc,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -u -d -r1.3 -r1.3.2.1
--- Form.cc	6 Mar 2007 22:27:18 -0000	1.3
+++ Form.cc	6 Apr 2007 14:22:23 -0000	1.3.2.1
@@ -21,7 +21,6 @@
 #include "Array.h"
 #include "Dict.h"
 #include "Form.h"
-#include "UGooString.h"
 #include "XRef.h"
 #include "PDFDocEncoding.h"
 #include "Annot.h"
@@ -202,9 +201,9 @@
           for(int j=0; j<length2; j++) {
             Object obj3;
             tmpDict2->getVal(j, &obj3);
-            UGooString *key = tmpDict2->getKey(j);
-            if(strcmp(key->getCString(), "Off")) { //if we don't have Off, we have the name of the "on" state
-              onStr = strdup(key->getCString());
+            char *key = tmpDict2->getKey(j);
+            if(strcmp(key, "Off")) { //if we don't have Off, we have the name of the "on" state
+              onStr = strdup(key);
             }
             obj3.free();
           }

Index: Function.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Function.cc,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -d -r1.6 -r1.6.2.1
--- Function.cc	10 Dec 2006 05:24:56 -0000	1.6
+++ Function.cc	6 Apr 2007 14:22:23 -0000	1.6.2.1
@@ -22,7 +22,6 @@
 #include "Stream.h"
 #include "Error.h"
 #include "Function.h"
-#include "UGooString.h"
 
 //------------------------------------------------------------------------
 // Function
@@ -191,10 +190,11 @@
   Object obj1, obj2;
   Guint buf, bitMask;
   int bits;
-  int s;
+  Guint s;
   int i;
 
   samples = NULL;
+  sBuf = NULL;
   ok = gFalse;
 
   //----- initialize the generic stuff
@@ -205,6 +205,14 @@
     error(-1, "Type 0 function is missing range");
     goto err1;
   }
+  if (m > sampledFuncMaxInputs) {
+    error(-1, "Sampled functions with more than %d inputs are unsupported",
+	  sampledFuncMaxInputs);
+    goto err1;
+  }
+
+  //----- buffer
+  sBuf = (double *)gmallocn(1 << m, sizeof(double));
 
   //----- get the stream
   if (!funcObj->isStream()) {
@@ -240,7 +248,7 @@
     goto err2;
   }
   sampleBits = obj1.getInt();
-  sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
+  sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
   obj1.free();
 
   //----- Encode
@@ -348,12 +356,16 @@
   if (samples) {
     gfree(samples);
   }
+  if (sBuf) {
+    gfree(sBuf);
+  }
 }
 
 SampledFunction::SampledFunction(SampledFunction *func) {
   memcpy(this, func, sizeof(SampledFunction));
   samples = (double *)gmallocn(nSamples, sizeof(double));
   memcpy(samples, func->samples, nSamples * sizeof(double));
+  sBuf = (double *)gmallocn(1 << m, sizeof(double));
 }
 
 void SampledFunction::transform(double *in, double *out) {
@@ -361,7 +373,6 @@
   int e[funcMaxInputs][2];
   double efrac0[funcMaxInputs];
   double efrac1[funcMaxInputs];
-  double s[1 << funcMaxInputs];
   int i, j, k, idx, t;
 
   // map input values into sample array
@@ -390,18 +401,18 @@
       for (k = 0, t = j; k < m; ++k, t >>= 1) {
 	idx += idxMul[k] * (e[k][t & 1]);
       }
-      if (idx >= 0 && idx < nSamples) s[j] = samples[idx];
+      sBuf[j] = samples[idx];
     }
 
     // do m sets of interpolations
     for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
       for (k = 0; k < t; k += 2) {
-	s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1];
+	sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1];
       }
     }
 
     // map output value to range
-    out[i] = s[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
+    out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
     if (out[i] < range[i][0]) {
       out[i] = range[i][0];
     } else if (out[i] > range[i][1]) {
@@ -541,6 +552,7 @@
   funcs = NULL;
   bounds = NULL;
   encode = NULL;
+  scale = NULL;
 
   //----- initialize the generic stuff
   if (!init(dict)) {
@@ -560,6 +572,7 @@
   funcs = (Function **)gmallocn(k, sizeof(Function *));
   bounds = (double *)gmallocn(k + 1, sizeof(double));
   encode = (double *)gmallocn(2 * k, sizeof(double));
+  scale = (double *)gmallocn(k, sizeof(double));
   for (i = 0; i < k; ++i) {
     funcs[i] = NULL;
   }
@@ -610,6 +623,17 @@
   }
   obj1.free();
 
+  //----- pre-compute the scale factors
+  for (i = 0; i < k; ++i) {
+    if (bounds[i] == bounds[i+1]) {
+      // avoid a divide-by-zero -- in this situation, function i will
+      // never be used anyway
+      scale[i] = 0;
+    } else {
+      scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]);
+    }
+  }
+
   ok = gTrue;
   return;
 
@@ -631,6 +655,8 @@
   memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
   encode = (double *)gmallocn(2 * k, sizeof(double));
   memcpy(encode, func->encode, 2 * k * sizeof(double));
+  scale = (double *)gmallocn(k, sizeof(double));
+  memcpy(scale, func->scale, k * sizeof(double));
   ok = gTrue;
 }
 
@@ -647,6 +673,7 @@
   gfree(funcs);
   gfree(bounds);
   gfree(encode);
+  gfree(scale);
 }
 
 void StitchingFunction::transform(double *in, double *out) {
@@ -665,8 +692,7 @@
       break;
     }
   }
-  x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) *
-                    (encode[2*i+1] - encode[2*i]);
+  x = encode[2*i] + (x - bounds[i]) * scale[i];
   funcs[i]->transform(&x, out);
 }
 
@@ -1182,14 +1208,25 @@
 GooString *PostScriptFunction::getToken(Stream *str) {
   GooString *s;
   int c;
+  GBool comment;
 
   s = new GooString();
-  do {
-    c = str->getChar();
-    if (c != EOF) {
-      codeString->append(c);
+  comment = gFalse;
+  while (1) {
+    if ((c = str->getChar()) == EOF) {
+      break;
     }
-  } while (c != EOF && isspace(c));
+    codeString->append(c);
+    if (comment) {
+      if (c == '\x0a' || c == '\x0d') {
+	comment = gFalse;
+      }
+    } else if (c == '%') {
+      comment = gTrue;
+    } else if (!isspace(c)) {
+      break;
+    }
+  }
   if (c == '{' || c == '}') {
     s->append((char)c);
   } else if (isdigit(c) || c == '.' || c == '-') {

Index: Function.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Function.h,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -d -r1.2 -r1.2.4.1
--- Function.h	16 Oct 2005 14:58:14 -0000	1.2
+++ Function.h	6 Apr 2007 14:22:23 -0000	1.2.4.1
@@ -25,8 +25,9 @@
 // Function
 //------------------------------------------------------------------------
 
-#define funcMaxInputs   8
-#define funcMaxOutputs 32
+#define funcMaxInputs        32
+#define funcMaxOutputs       32
+#define sampledFuncMaxInputs 16
 
 class Function {
 public:
@@ -129,6 +130,7 @@
   int idxMul[funcMaxInputs];	// sample array index multipliers
   double *samples;		// the samples
   int nSamples;			// size of the samples array
+  double *sBuf;			// buffer for the transform function
   GBool ok;
 };
 
@@ -178,6 +180,7 @@
   Function *getFunc(int i) { return funcs[i]; }
   double *getBounds() { return bounds; }
   double *getEncode() { return encode; }
+  double *getScale() { return scale; }
 
 private:
 
@@ -187,6 +190,7 @@
   Function **funcs;
   double *bounds;
   double *encode;
+  double *scale;
   GBool ok;
 };
 

Index: Gfx.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Gfx.cc,v
retrieving revision 1.14
retrieving revision 1.14.2.1
diff -u -d -r1.14 -r1.14.2.1
--- Gfx.cc	22 Mar 2007 20:56:25 -0000	1.14
+++ Gfx.cc	6 Apr 2007 14:22:23 -0000	1.14.2.1
@@ -32,10 +32,10 @@
 #include "GfxState.h"
 #include "OutputDev.h"
 #include "Page.h"
+#include "Annot.h"
 #include "Error.h"
 #include "Gfx.h"
 #include "ProfileData.h"
-#include "UGooString.h"
 
 // the MSVC math.h doesn't define this
 #ifndef M_PI
[...1753 lines suppressed...]
+      }
+      state->setLineDash(dash2, dashLength, 0);
+      out->updateLineDash(state);
+    }
+    //~ this doesn't currently handle the beveled and engraved styles
+    state->clearPath();
+    state->moveTo(annotX0, out->upsideDown() ? annotY1 : annotY0);
+    state->lineTo(annotX1, out->upsideDown() ? annotY1 : annotY0);
+    if (borderStyle->getType() != annotBorderUnderlined) {
+      state->lineTo(annotX1, out->upsideDown() ? annotY0 : annotY1);
+      state->lineTo(annotX0, out->upsideDown() ? annotY0 : annotY1);
+      state->closePath();
+    }
+    out->stroke(state);
+  }
+}
+
 void Gfx::saveState() {
   out->saveState(state);
   state = state->save();

Index: Gfx.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Gfx.h,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -u -d -r1.3 -r1.3.4.1
--- Gfx.h	30 Oct 2005 20:29:05 -0000	1.3
+++ Gfx.h	6 Apr 2007 14:22:23 -0000	1.3.4.1
@@ -22,6 +22,7 @@
 class Stream;
 class Parser;
 class Dict;
+class Function;
 class OutputDev;
 class GfxFontDict;
 class GfxFont;
@@ -37,12 +38,12 @@
 struct GfxPatch;
 class GfxState;
 struct GfxColor;
+class GfxColorSpace;
 class Gfx;
 class PDFRectangle;
+class AnnotBorderStyle;
 
 //------------------------------------------------------------------------
-// Gfx
-//------------------------------------------------------------------------
 
 enum GfxClipType {
   clipNone,
@@ -62,7 +63,7 @@
   tchkNone			// used to avoid empty initializer lists
 };
 
-#define maxArgs 8
+#define maxArgs 33
 
 struct Operator {
   char name[4];
@@ -71,6 +72,8 @@
   void (Gfx::*func)(Object args[], int numArgs);
 };
 
+//------------------------------------------------------------------------
+
 class GfxResources {
 public:
 
@@ -98,6 +101,10 @@
   GfxResources *next;
 };
 
+//------------------------------------------------------------------------
+// Gfx
+//------------------------------------------------------------------------
+
 class Gfx {
 public:
 
@@ -119,10 +126,10 @@
   // Interpret a stream or array of streams.
   void display(Object *obj, GBool topLevel = gTrue);
 
-  // Display an annotation, given its appearance (a Form XObject) and
-  // bounding box (in default user space).
-  void doAnnot(Object *str, double xMin, double yMin,
-	       double xMax, double yMax);
+  // Display an annotation, given its appearance (a Form XObject),
+  // border style, and bounding box (in default user space).
+  void drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
+		 double xMin, double yMin, double xMax, double yMax);
 
   // Save graphics state.
   void saveState();
@@ -176,6 +183,10 @@
   void opSetMiterLimit(Object args[], int numArgs);
   void opSetLineWidth(Object args[], int numArgs);
   void opSetExtGState(Object args[], int numArgs);
+  void doSoftMask(Object *str, GBool alpha,
+		  GfxColorSpace *blendingColorSpace,
+		  GBool isolated, GBool knockout,
+		  Function *transferFunc, GfxColor *backdropColor);
   void opSetRenderingIntent(Object args[], int numArgs);
 
   // color operators
@@ -212,8 +223,11 @@
   void opEOFillStroke(Object args[], int numArgs);
   void opCloseEOFillStroke(Object args[], int numArgs);
   void doPatternFill(GBool eoFill);
-  void doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill);
-  void doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill);
+  void doPatternStroke();
+  void doTilingPatternFill(GfxTilingPattern *tPat,
+			   GBool stroke, GBool eoFill);
+  void doShadingPatternFill(GfxShadingPattern *sPat,
+			    GBool stroke, GBool eoFill);
   void opShFill(Object args[], int numArgs);
   void doFunctionShFill(GfxFunctionShading *shading);
   void doFunctionShFill1(GfxFunctionShading *shading,
@@ -265,7 +279,12 @@
   void opXObject(Object args[], int numArgs);
   void doImage(Object *ref, Stream *str, GBool inlineImg);
   void doForm(Object *str);
-  void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox);
+  void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
+	       GBool transpGroup = gFalse, GBool softMask = gFalse,
+	       GfxColorSpace *blendingColorSpace = NULL,
+	       GBool isolated = gFalse, GBool knockout = gFalse,
+	       GBool alpha = gFalse, Function *transferFunc = NULL,
+	       GfxColor *backdropColor = NULL);
 
   // in-line image operators
   void opBeginImage(Object args[], int numArgs);

Index: GfxFont.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GfxFont.cc,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -u -d -r1.10 -r1.10.2.1
--- GfxFont.cc	24 Feb 2007 23:32:23 -0000	1.10
+++ GfxFont.cc	6 Apr 2007 14:22:23 -0000	1.10.2.1
@@ -28,7 +28,6 @@
 #include <fofi/FoFiType1.h>
 #include <fofi/FoFiType1C.h>
 #include <fofi/FoFiTrueType.h>
-#include "UGooString.h"
 #include "GfxFont.h"
 
 //------------------------------------------------------------------------
@@ -264,29 +263,42 @@
       if (obj2.fetch(xref, &obj3)->isStream()) {
 	obj3.streamGetDict()->lookup("Subtype", &obj4);
 	if (obj4.isName("Type1")) {
-	    embFontID = obj2.getRef();
+	  embFontID = obj2.getRef();
 	  if (type != fontType1) {
 	    error(-1, "Mismatch between font type and embedded font file");
 	    type = fontType1;
 	  }
 	} else if (obj4.isName("Type1C")) {
-	    embFontID = obj2.getRef();
+	  embFontID = obj2.getRef();
 	  if (type != fontType1 && type != fontType1C) {
 	    error(-1, "Mismatch between font type and embedded font file");
 	  }
 	  type = fontType1C;
 	} else if (obj4.isName("TrueType")) {
-	    embFontID = obj2.getRef();
+	  embFontID = obj2.getRef();
 	  if (type != fontTrueType) {
 	    error(-1, "Mismatch between font type and embedded font file");
 	    type = fontTrueType;
 	  }
 	} else if (obj4.isName("CIDFontType0C")) {
-	    embFontID = obj2.getRef();
+	  embFontID = obj2.getRef();
 	  if (type != fontCIDType0) {
 	    error(-1, "Mismatch between font type and embedded font file");
 	  }
 	  type = fontCIDType0C;
+	} else if (obj4.isName("OpenType")) {
+	  embFontID = obj2.getRef();
+	  if (type == fontTrueType) {
+	    type = fontTrueTypeOT;
+	  } else if (type == fontType1) {
+	    type = fontType1COT;
+	  } else if (type == fontCIDType0) {
+	    type = fontCIDType0COT;
+	  } else if (type == fontCIDType2) {
+	    type = fontCIDType2OT;
+	  } else {
+	    error(-1, "Mismatch between font type and embedded font file");
+	  }
 	} else {
 	  error(-1, "Unknown embedded font type '%s'",
 		obj4.isName() ? obj4.getName() : "???");
@@ -804,6 +816,15 @@
 	}
       }
     }
+
+  // if the 'mapUnknownCharNames' flag is set, do a simple pass-through
+  // mapping for unknown character names
+  } else if (missing && globalParams->getMapUnknownCharNames()) {
+    for (code = 0; code < 256; ++code) {
+      if (!toUnicode[code]) {
+	toUnicode[code] = code;
+      }
+    }
   }
 
   // construct the char code -> Unicode mapping object
@@ -1026,10 +1047,10 @@
       useMacRoman = gTrue;
     }
   } else {
-    if (macRomanCmap >= 0) {
-      cmap = macRomanCmap;
-    } else if (msSymbolCmap >= 0) {
+    if (msSymbolCmap >= 0) {
       cmap = msSymbolCmap;
+    } else if (macRomanCmap >= 0) {
+      cmap = macRomanCmap;
     }
   }
 
@@ -1215,9 +1236,9 @@
 	  n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
 	  if (n >= 1) {
 	    ctu->setMapping(c, uBuf, n);
+	  }
+	}
       }
-    }
-  }
       utu->decRefCnt();
     } else {
       ctu = utu;
@@ -1637,10 +1658,8 @@
 	  r.gen = 999999;
 	}
       }
-      char *aux = fontDict->getKey(i)->getCString();
-      fonts[i] = GfxFont::makeFont(xref, aux,
+      fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i),
 				   r, obj2.getDict());
-      delete[] aux;
       if (fonts[i] && !fonts[i]->isOk()) {
 	delete fonts[i];
 	fonts[i] = NULL;

Index: GfxFont.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GfxFont.h,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -d -r1.5 -r1.5.2.1
--- GfxFont.h	24 Feb 2007 23:32:23 -0000	1.5
+++ GfxFont.h	6 Apr 2007 14:22:23 -0000	1.5.2.1
@@ -33,12 +33,16 @@
   fontUnknownType,
   fontType1,
   fontType1C,
+  fontType1COT,
   fontType3,
   fontTrueType,
+  fontTrueTypeOT,
   //----- GfxCIDFont
   fontCIDType0,
   fontCIDType0C,
-  fontCIDType2
+  fontCIDType0COT,
+  fontCIDType2,
+  fontCIDType2OT
 };
 
 //------------------------------------------------------------------------
@@ -161,6 +165,7 @@
   GooString *getExtFontFile() { return extFontFile; }
 
   // Get font descriptor flags.
+  int getFlags() { return flags; }
   GBool isFixedWidth() { return flags & fontFixedWidth; }
   GBool isSerif() { return flags & fontSerif; }
   GBool isSymbolic() { return flags & fontSymbolic; }

Index: GfxState.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GfxState.cc,v
retrieving revision 1.14
retrieving revision 1.14.4.1
diff -u -d -r1.14 -r1.14.4.1
--- GfxState.cc	30 Jul 2006 20:31:31 -0000	1.14
+++ GfxState.cc	6 Apr 2007 14:22:23 -0000	1.14.4.1
@@ -22,7 +22,6 @@
 #include "Page.h"
 #include "GfxState.h"
 #include "GfxFont.h"
-#include "UGooString.h"
 
 //------------------------------------------------------------------------
 
@@ -62,12 +61,12 @@
 
 //------------------------------------------------------------------------
 
-struct gfxBlendModeName {
+struct GfxBlendModeInfo {
   char *name;
   GfxBlendMode mode;
 };
 
-static gfxBlendModeName gfxBlendModeNames[] = {
+static GfxBlendModeInfo gfxBlendModeNames[] = {
   { "Normal",     gfxBlendNormal },
   { "Compatible", gfxBlendNormal },
   { "Multiply",   gfxBlendMultiply },
@@ -88,7 +87,7 @@
 };
 
 #define nGfxBlendModeNames \
-          ((int)((sizeof(gfxBlendModeNames) / sizeof(gfxBlendModeName))))
+          ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo))))
 	 
 //------------------------------------------------------------------------
 // 
@@ -264,6 +263,10 @@
   cmyk->k = clip01(gfxColorComp1 - color->c[0]);
 }
 
+void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = 0;
+}
+
 //------------------------------------------------------------------------
 // GfxCalGrayColorSpace
 //------------------------------------------------------------------------
@@ -361,6 +364,10 @@
   cmyk->k = clip01(gfxColorComp1 - color->c[0]);
 }
 
+void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = 0;
+}
+
 //------------------------------------------------------------------------
 // GfxDeviceRGBColorSpace
 //------------------------------------------------------------------------
@@ -426,6 +433,12 @@
   cmyk->k = k;
 }
 
+void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = 0;
+  color->c[1] = 0;
+  color->c[2] = 0;
+}
+
 //------------------------------------------------------------------------
 // GfxCalRGBColorSpace
 //------------------------------------------------------------------------
@@ -577,6 +590,12 @@
   cmyk->k = k;
 }
 
+void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = 0;
+  color->c[1] = 0;
+  color->c[2] = 0;
+}
+
 //------------------------------------------------------------------------
 // GfxDeviceCMYKColorSpace
 //------------------------------------------------------------------------
@@ -667,6 +686,13 @@
   cmyk->k = clip01(color->c[3]);
 }
 
+void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = 0;
+  color->c[1] = 0;
+  color->c[2] = 0;
+  color->c[3] = gfxColorComp1;
+}
+
 //------------------------------------------------------------------------
 // GfxLabColorSpace
 //------------------------------------------------------------------------
@@ -782,7 +808,7 @@
 
   getRGB(color, &rgb);
   *gray = clip01((GfxColorComp)(0.299 * rgb.r +
-		 0.587 * rgb.g +
+				0.587 * rgb.g +
 				0.114 * rgb.b + 0.5));
 }
 
@@ -844,6 +870,24 @@
   cmyk->k = k;
 }
 
+void GfxLabColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = 0;
+  if (aMin > 0) {
+    color->c[1] = dblToCol(aMin);
+  } else if (aMax < 0) {
+    color->c[1] = dblToCol(aMax);
+  } else {
+    color->c[1] = 0;
+  }
+  if (bMin > 0) {
+    color->c[2] = dblToCol(bMin);
+  } else if (bMax < 0) {
+    color->c[2] = dblToCol(bMax);
+  } else {
+    color->c[2] = 0;
+  }
+}
+
 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
 					int maxImgPixel) {
   decodeLow[0] = 0;
@@ -974,6 +1018,20 @@
   alt->getCMYK(color, cmyk);
 }
 
+void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
+  int i;
+
+  for (i = 0; i < nComps; ++i) {
+    if (rangeMin[i] > 0) {
+      color->c[i] = dblToCol(rangeMin[i]);
+    } else if (rangeMax[i] < 0) {
+      color->c[i] = dblToCol(rangeMax[i]);
+    } else {
+      color->c[i] = 0;
+    }
+  }
+}
+
 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
 					     double *decodeRange,
 					     int maxImgPixel) {
@@ -1142,6 +1200,10 @@
   base->getCMYK(mapColorToBase(color, &color2), cmyk);
 }
 
+void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = 0;
+}
+
 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
 					    double *decodeRange,
 					    int maxImgPixel) {
@@ -1159,6 +1221,7 @@
   name = nameA;
   alt = altA;
   func = funcA;
+  nonMarking = !name->cmp("None");
 }
 
 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
@@ -1255,6 +1318,10 @@
   alt->getCMYK(&color2, cmyk);
 }
 
+void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
+  color->c[0] = gfxColorComp1;
+}
+
 //------------------------------------------------------------------------
 // GfxDeviceNColorSpace
 //------------------------------------------------------------------------
@@ -1265,6 +1332,7 @@
   nComps = nCompsA;
   alt = altA;
   func = funcA;
+  nonMarking = gFalse;
 }
 
 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
@@ -1285,6 +1353,7 @@
   for (i = 0; i < nComps; ++i) {
     cs->names[i] = names[i]->copy();
   }
+  cs->nonMarking = nonMarking;
   return cs;
 }
 
@@ -1334,8 +1403,12 @@
   }
   obj1.free();
   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+  cs->nonMarking = gTrue;
   for (i = 0; i < nCompsA; ++i) {
     cs->names[i] = namesA[i];
+    if (namesA[i]->cmp("None")) {
+      cs->nonMarking = gFalse;
+    }
   }
   return cs;
 
@@ -1396,6 +1469,14 @@
   alt->getCMYK(&color2, cmyk);
 }
 
+void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
+  int i;
+
+  for (i = 0; i < nComps; ++i) {
+    color->c[i] = gfxColorComp1;
+  }
+}
+
 //------------------------------------------------------------------------
 // GfxPatternColorSpace
 //------------------------------------------------------------------------
@@ -1451,6 +1532,10 @@
   cmyk->k = 1;
 }
 
+void GfxPatternColorSpace::getDefaultColor(GfxColor * /*color*/) {
+  // not used
+}
+
 //------------------------------------------------------------------------
 // Pattern
 //------------------------------------------------------------------------
@@ -3265,6 +3350,11 @@
   maxPixel = (1 << bits) - 1;
   colorSpace = colorSpaceA;
 
+  // initialize
+  for (k = 0; k < gfxColorMaxComps; ++k) {
+    lookup[k] = NULL;
+  }
+
   // get decode map
   if (decode->isNull()) {
     nComps = colorSpace->getNComps();
@@ -3299,9 +3389,6 @@
   // Optimization: for Indexed and Separation color spaces (which have
   // only one component), we store color values in the lookup table
   // rather than component values.
-  for (k = 0; k < gfxColorMaxComps; ++k) {
-    lookup[k] = NULL;
-  }
   colorSpace2 = NULL;
   nComps2 = 0;
   if (colorSpace->getMode() == csIndexed) {
@@ -3371,9 +3458,6 @@
   obj.free();
  err1:
   ok = gFalse;
-  for (k = 0; k < gfxColorMaxComps; ++k) {
-    lookup[k] = NULL;
-  }
   byte_lookup = NULL;
 }
 
@@ -3741,10 +3825,12 @@
 // GfxState
 //------------------------------------------------------------------------
 
-GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
+GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
 		   int rotateA, GBool upsideDown) {
   double kx, ky;
 
+  hDPI = hDPIA;
+  vDPI = vDPIA;
   rotate = rotateA;
   px1 = pageBox->x1;
   py1 = pageBox->y1;
@@ -3801,6 +3887,7 @@
   strokeOpacity = 1;
   fillOverprint = gFalse;
   strokeOverprint = gFalse;
+  transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
 
   lineWidth = 1;
   lineDash = NULL;
@@ -3810,6 +3897,7 @@
   lineJoin = 0;
   lineCap = 0;
   miterLimit = 10;
+  strokeAdjust = gFalse;
 
   font = NULL;
   fontSize = 0;
@@ -3836,6 +3924,8 @@
 }
 
 GfxState::~GfxState() {
+  int i;
+
   if (fillColorSpace) {
     delete fillColorSpace;
   }
@@ -3848,6 +3938,11 @@
   if (strokePattern) {
     delete strokePattern;
   }
+  for (i = 0; i < 4; ++i) {
+    if (transfer[i]) {
+      delete transfer[i];
+    }
+  }
   gfree(lineDash);
   if (path) {
     // this gets set to NULL by restore()
@@ -3863,6 +3958,8 @@
 
 // Used for copy();
 GfxState::GfxState(GfxState *state) {
+  int i;
+
   memcpy(this, state, sizeof(GfxState));
   if (fillColorSpace) {
     fillColorSpace = state->fillColorSpace->copy();
@@ -3876,6 +3973,11 @@
   if (strokePattern) {
     strokePattern = state->strokePattern->copy();
   }
+  for (i = 0; i < 4; ++i) {
+    if (transfer[i]) {
+      transfer[i] = state->transfer[i]->copy();
+    }
+  }
   if (lineDashLength > 0) {
     lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
@@ -4024,6 +4126,15 @@
   }
 }
 
+void GfxState::shiftCTM(double tx, double ty) {
+  ctm[4] += tx;
+  ctm[5] += ty;
+  clipXMin += tx;
+  clipYMin += ty;
+  clipXMax += tx;
+  clipYMax += ty;
+}
+
 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
   if (fillColorSpace) {
     delete fillColorSpace;
@@ -4060,6 +4171,17 @@
   fontSize = fontSizeA;
 }
 
+void GfxState::setTransfer(Function **funcs) {
+  int i;
+
+  for (i = 0; i < 4; ++i) {
+    if (transfer[i]) {
+      delete transfer[i];
+    }
+    transfer[i] = funcs[i];
+  }
+}
+
 void GfxState::setLineDash(double *dash, int length, double start) {
   if (lineDash)
     gfree(lineDash);
@@ -4114,6 +4236,69 @@
   }
 }
 
+void GfxState::clipToStrokePath() {
+  double xMin, yMin, xMax, yMax, x, y, t0, t1;
+  GfxSubpath *subpath;
+  int i, j;
+
+  xMin = xMax = yMin = yMax = 0; // make gcc happy
+  for (i = 0; i < path->getNumSubpaths(); ++i) {
+    subpath = path->getSubpath(i);
+    for (j = 0; j < subpath->getNumPoints(); ++j) {
+      transform(subpath->getX(j), subpath->getY(j), &x, &y);
+      if (i == 0 && j == 0) {
+	xMin = xMax = x;
+	yMin = yMax = y;
+      } else {
+	if (x < xMin) {
+	  xMin = x;
+	} else if (x > xMax) {
+	  xMax = x;
+	}
+	if (y < yMin) {
+	  yMin = y;
+	} else if (y > yMax) {
+	  yMax = y;
+	}
+      }
+    }
+  }
+
+  // allow for the line width
+  //~ miter joins can extend farther than this
+  t0 = fabs(ctm[0]);
+  t1 = fabs(ctm[2]);
+  if (t0 > t1) {
+    xMin -= 0.5 * lineWidth * t0;
+    xMax += 0.5 * lineWidth * t0;
+  } else {
+    xMin -= 0.5 * lineWidth * t1;
+    xMax += 0.5 * lineWidth * t1;
+  }
+  t0 = fabs(ctm[0]);
+  t1 = fabs(ctm[3]);
+  if (t0 > t1) {
+    yMin -= 0.5 * lineWidth * t0;
+    yMax += 0.5 * lineWidth * t0;
+  } else {
+    yMin -= 0.5 * lineWidth * t1;
+    yMax += 0.5 * lineWidth * t1;
+  }
+
+  if (xMin > clipXMin) {
+    clipXMin = xMin;
+  }
+  if (yMin > clipYMin) {
+    clipYMin = yMin;
+  }
+  if (xMax < clipXMax) {
+    clipXMax = xMax;
+  }
+  if (yMax < clipYMax) {
+    clipYMax = yMax;
+  }
+}
+
 void GfxState::textShift(double tx, double ty) {
   double dx, dy;
 

Index: GfxState.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GfxState.h,v
retrieving revision 1.6
retrieving revision 1.6.4.1
diff -u -d -r1.6 -r1.6.4.1
--- GfxState.h	13 May 2006 16:01:57 -0000	1.6
+++ GfxState.h	6 Apr 2007 14:22:23 -0000	1.6.4.1
@@ -156,11 +156,18 @@
   // Return the number of color components.
   virtual int getNComps() = 0;
 
+  // Get this color space's default color.
+  virtual void getDefaultColor(GfxColor *color) = 0;
+
   // Return the default ranges for each component, assuming an image
   // with a max pixel value of <maxImgPixel>.
   virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
 				int maxImgPixel);
 
+  // Returns true if painting operations in this color space never
+  // mark the page (e.g., the "None" colorant).
+  virtual GBool isNonMarking() { return gFalse; }
+
   // Return the number of color space modes
   static int getNumColorSpaceModes();
 
@@ -189,6 +196,7 @@
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
 
   virtual int getNComps() { return 1; }
+  virtual void getDefaultColor(GfxColor *color);
 
 private:
 };
@@ -215,6 +223,7 @@
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
 
   virtual int getNComps() { return 1; }
+  virtual void getDefaultColor(GfxColor *color);
 
   // CalGray-specific access.
   double getWhiteX() { return whiteX; }
@@ -251,6 +260,7 @@
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
 
   virtual int getNComps() { return 3; }
+  virtual void getDefaultColor(GfxColor *color);
 
 private:
 };
@@ -277,6 +287,7 @@
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
 
   virtual int getNComps() { return 3; }
+  virtual void getDefaultColor(GfxColor *color);
 
   // CalRGB-specific access.
   double getWhiteX() { return whiteX; }
@@ -295,7 +306,7 @@
   double whiteX, whiteY, whiteZ;    // white point
   double blackX, blackY, blackZ;    // black point
   double gammaR, gammaG, gammaB;    // gamma values
-  double mat[9];		// ABC -> XYZ transform matrix
+  double mat[9];		    // ABC -> XYZ transform matrix
 };
 
 //------------------------------------------------------------------------
@@ -315,6 +326,7 @@
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
   virtual int getNComps() { return 4; }
+  virtual void getDefaultColor(GfxColor *color);
 
 private:
 };
@@ -339,6 +351,7 @@
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
   virtual int getNComps() { return 3; }
+  virtual void getDefaultColor(GfxColor *color);
 
   virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
 				int maxImgPixel);
@@ -385,6 +398,7 @@
 
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
   virtual int getNComps() { return nComps; }
+  virtual void getDefaultColor(GfxColor *color);
 
   virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
 				int maxImgPixel);
@@ -422,6 +436,7 @@
   virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
 
   virtual int getNComps() { return 1; }
+  virtual void getDefaultColor(GfxColor *color);
 
   virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
 				int maxImgPixel);
@@ -460,6 +475,9 @@
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
   virtual int getNComps() { return 1; }
+  virtual void getDefaultColor(GfxColor *color);
+
+  virtual GBool isNonMarking() { return nonMarking; }
 
   // Separation-specific access.
   GooString *getName() { return name; }
@@ -471,6 +489,7 @@
   GooString *name;		// colorant name
   GfxColorSpace *alt;		// alternate color space
   Function *func;		// tint transform (into alternate color space)
+  GBool nonMarking;
 };
 
 //------------------------------------------------------------------------
@@ -493,6 +512,9 @@
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
   virtual int getNComps() { return nComps; }
+  virtual void getDefaultColor(GfxColor *color);
+
+  virtual GBool isNonMarking() { return nonMarking; }
 
   // DeviceN-specific access.
   GooString *getColorantName(int i) { return names[i]; }
@@ -506,6 +528,7 @@
     *names[gfxColorMaxComps];
   GfxColorSpace *alt;		// alternate color space
   Function *func;		// tint transform (into alternate color space)
+  GBool nonMarking;
 };
 
 //------------------------------------------------------------------------
@@ -528,6 +551,7 @@
   virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
 
   virtual int getNComps() { return 0; }
+  virtual void getDefaultColor(GfxColor *color);
 
   // Pattern-specific access.
   GfxColorSpace *getUnder() { return under; }
@@ -1014,7 +1038,7 @@
   // Construct a default GfxState, for a device with resolution <hDPI>
   // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and
   // coordinate system specified by <upsideDown>.
-  GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
+  GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
 	   int rotateA, GBool upsideDown);
 
   // Destructor.
@@ -1024,6 +1048,8 @@
   GfxState *copy() { return new GfxState(this); }
 
   // Accessors.
+  double getHDPI() { return hDPI; }
+  double getVDPI() { return vDPI; }
   double *getCTM() { return ctm; }
   void getCTM(Matrix *m) { memcpy (m->m, ctm, sizeof m->m); }
   double getX1() { return px1; }
@@ -1056,6 +1082,7 @@
   double getStrokeOpacity() { return strokeOpacity; }
   GBool getFillOverprint() { return fillOverprint; }
   GBool getStrokeOverprint() { return strokeOverprint; }
+  Function **getTransfer() { return transfer; }
   double getLineWidth() { return lineWidth; }
   void getLineDash(double **dash, int *length, double *start)
     { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; }
@@ -1063,6 +1090,7 @@
   int getLineJoin() { return lineJoin; }
   int getLineCap() { return lineCap; }
   double getMiterLimit() { return miterLimit; }
+  GBool getStrokeAdjust() { return strokeAdjust; }
   GfxFont *getFont() { return font; }
   double getFontSize() { return fontSize; }
   double *getTextMat() { return textMat; }
@@ -1110,6 +1138,7 @@
 	      double d, double e, double f);
   void concatCTM(double a, double b, double c,
 		 double d, double e, double f);
+  void shiftCTM(double tx, double ty);
   void setFillColorSpace(GfxColorSpace *colorSpace);
   void setStrokeColorSpace(GfxColorSpace *colorSpace);
   void setFillColor(GfxColor *color) { fillColor = *color; }
@@ -1121,12 +1150,14 @@
   void setStrokeOpacity(double opac) { strokeOpacity = opac; }
   void setFillOverprint(GBool op) { fillOverprint = op; }
   void setStrokeOverprint(GBool op) { strokeOverprint = op; }
+  void setTransfer(Function **funcs);
   void setLineWidth(double width) { lineWidth = width; }
   void setLineDash(double *dash, int length, double start);
   void setFlatness(int flatness1) { flatness = flatness1; }
   void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; }
   void setLineCap(int lineCap1) { lineCap = lineCap1; }
   void setMiterLimit(double limit) { miterLimit = limit; }
+  void setStrokeAdjust(GBool sa) { strokeAdjust = sa; }
   void setFont(GfxFont *fontA, double fontSizeA);
   void setTextMat(double a, double b, double c,
 		  double d, double e, double f)
@@ -1159,6 +1190,7 @@
 
   // Update clip region.
   void clip();
+  void clipToStrokePath();
 
   // Text position.
   void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; }
@@ -1177,6 +1209,7 @@
 
 private:
 
+  double hDPI, vDPI;		// resolution
   double ctm[6];		// coord transform matrix
   double px1, py1, px2, py2;	// page corners (user coords)
   double pageWidth, pageHeight;	// page size (pixels)
@@ -1193,6 +1226,10 @@
   double strokeOpacity;		// stroke opacity
   GBool fillOverprint;		// fill overprint
   GBool strokeOverprint;	// stroke overprint
+  Function *transfer[4];	// transfer function (entries may be: all
+				//   NULL = identity; last three NULL =
+				//   single function; all four non-NULL =
+				//   R,G,B,gray functions)
 
   double lineWidth;		// line width
   double *lineDash;		// line dash
@@ -1202,6 +1239,7 @@
   int lineJoin;			// line join style
   int lineCap;			// line cap style
   double miterLimit;		// line miter limit
+  GBool strokeAdjust;		// stroke adjustment
 
   GfxFont *font;		// font
   double fontSize;		// font size

Index: GlobalParams.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GlobalParams.cc,v
retrieving revision 1.19
retrieving revision 1.19.2.1
diff -u -d -r1.19 -r1.19.2.1
--- GlobalParams.cc	24 Feb 2007 23:43:35 -0000	1.19
+++ GlobalParams.cc	6 Apr 2007 14:22:23 -0000	1.19.2.1
@@ -42,6 +42,10 @@
 #include "GlobalParams.h"
 #include "GfxFont.h"
 
+#ifdef WIN32
+#  define strcasecmp stricmp
+#endif
+
 #if MULTITHREADED
 #  define lockGlobalParams            gLockMutex(&mutex)
 #  define lockUnicodeMapCache         gLockMutex(&unicodeMapCacheMutex)
@@ -115,6 +119,251 @@
   }
 }
 
+#ifdef WIN32
+
+//------------------------------------------------------------------------
+// WinFontInfo
+//------------------------------------------------------------------------
+
+class WinFontInfo: public DisplayFontParam {
+public:
+
+  GBool bold, italic;
+
+  static WinFontInfo *make(GString *nameA, GBool boldA, GBool italicA,
+			   HKEY regKey, char *winFontDir);
+  WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
+	      GString *fileNameA);
+  virtual ~WinFontInfo();
+  GBool equals(WinFontInfo *fi);
+};
+
+WinFontInfo *WinFontInfo::make(GString *nameA, GBool boldA, GBool italicA,
+			       HKEY regKey, char *winFontDir) {
+  GString *regName;
+  GString *fileNameA;
+  char buf[MAX_PATH];
+  DWORD n;
+  char c;
+  int i;
+
+  //----- find the font file
+  fileNameA = NULL;
+  regName = nameA->copy();
+  if (boldA) {
+    regName->append(" Bold");
+  }
+  if (italicA) {
+    regName->append(" Italic");
+  }
+  regName->append(" (TrueType)");
+  n = sizeof(buf);
+  if (RegQueryValueEx(regKey, regName->getCString(), NULL, NULL,
+		      (LPBYTE)buf, &n) == ERROR_SUCCESS) {
+    fileNameA = new GString(winFontDir);
+    fileNameA->append('\\')->append(buf);
+  }
+  delete regName;
+  if (!fileNameA) {
+    delete nameA;
+    return NULL;
+  }
+
+  //----- normalize the font name
+  i = 0;
+  while (i < nameA->getLength()) {
+    c = nameA->getChar(i);
+    if (c == ' ' || c == ',' || c == '-') {
+      nameA->del(i);
+    } else {
+      ++i;
+    }
+  }
+
+  return new WinFontInfo(nameA, boldA, italicA, fileNameA);
+}
+
+WinFontInfo::WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
+			 GString *fileNameA):
+  DisplayFontParam(nameA, displayFontTT)
+{
+  bold = boldA;
+  italic = italicA;
+  tt.fileName = fileNameA;
+}
+
+WinFontInfo::~WinFontInfo() {
+}
+
+GBool WinFontInfo::equals(WinFontInfo *fi) {
+  return !name->cmp(fi->name) && bold == fi->bold && italic == fi->italic;
+}
+
+//------------------------------------------------------------------------
+// WinFontList
+//------------------------------------------------------------------------
+
+class WinFontList {
+public:
+
+  WinFontList(char *winFontDirA);
+  ~WinFontList();
+  WinFontInfo *find(GString *font);
+
+private:
+
+  void add(WinFontInfo *fi);
+  static int CALLBACK enumFunc1(CONST LOGFONT *font,
+				CONST TEXTMETRIC *metrics,
+				DWORD type, LPARAM data);
+  static int CALLBACK enumFunc2(CONST LOGFONT *font,
+				CONST TEXTMETRIC *metrics,
+				DWORD type, LPARAM data);
+
+  GList *fonts;			// [WinFontInfo]
+  HDC dc;			// (only used during enumeration)
+  HKEY regKey;			// (only used during enumeration)
+  char *winFontDir;		// (only used during enumeration)
+};
+
+WinFontList::WinFontList(char *winFontDirA) {
+  OSVERSIONINFO version;
+  char *path;
+
+  fonts = new GList();
+  dc = GetDC(NULL);
+  winFontDir = winFontDirA;
+  version.dwOSVersionInfoSize = sizeof(version);
+  GetVersionEx(&version);
+  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+    path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
+  } else {
+    path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
+  }
+  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
+		   KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+		   &regKey) == ERROR_SUCCESS) {
+    EnumFonts(dc, NULL, &WinFontList::enumFunc1, (LPARAM)this);
+    RegCloseKey(regKey);
+  }
+  ReleaseDC(NULL, dc);
+}
+
+WinFontList::~WinFontList() {
+  deleteGList(fonts, WinFontInfo);
+}
+
+void WinFontList::add(WinFontInfo *fi) {
+  int i;
+
+  for (i = 0; i < fonts->getLength(); ++i) {
+    if (((WinFontInfo *)fonts->get(i))->equals(fi)) {
+      delete fi;
+      return;
+    }
+  }
+  fonts->append(fi);
+}
+
+WinFontInfo *WinFontList::find(GString *font) {
+  GString *name;
+  GBool bold, italic;
+  WinFontInfo *fi;
+  char c;
+  int n, i;
+
+  name = font->copy();
+
+  // remove space, comma, dash chars
+  i = 0;
+  while (i < name->getLength()) {
+    c = name->getChar(i);
+    if (c == ' ' || c == ',' || c == '-') {
+      name->del(i);
+    } else {
+      ++i;
+    }
+  }
+  n = name->getLength();
+
+  // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
+  if (!strcmp(name->getCString() + n - 2, "MT")) {
+    name->del(n - 2, 2);
+    n -= 2;
+  }
+
+  // look for "Italic"
+  if (!strcmp(name->getCString() + n - 6, "Italic")) {
+    name->del(n - 6, 6);
+    italic = gTrue;
+    n -= 6;
+  } else {
+    italic = gFalse;
+  }
+
+  // look for "Bold"
+  if (!strcmp(name->getCString() + n - 4, "Bold")) {
+    name->del(n - 4, 4);
+    bold = gTrue;
+    n -= 4;
+  } else {
+    bold = gFalse;
+  }
+
+  // remove trailing "MT" (FooMT-Bold, etc.)
+  if (!strcmp(name->getCString() + n - 2, "MT")) {
+    name->del(n - 2, 2);
+    n -= 2;
+  }
+
+  // remove trailing "PS"
+  if (!strcmp(name->getCString() + n - 2, "PS")) {
+    name->del(n - 2, 2);
+    n -= 2;
+  }
+
+  // search for the font
+  fi = NULL;
+  for (i = 0; i < fonts->getLength(); ++i) {
+    fi = (WinFontInfo *)fonts->get(i);
+    if (!fi->name->cmp(name) && fi->bold == bold && fi->italic == italic) {
+      break;
+    }
+    fi = NULL;
+  }
+
+  delete name;
+  return fi;
+}
+
+int CALLBACK WinFontList::enumFunc1(CONST LOGFONT *font,
+				    CONST TEXTMETRIC *metrics,
+				    DWORD type, LPARAM data) {
+  WinFontList *fl = (WinFontList *)data;
+
+  EnumFonts(fl->dc, font->lfFaceName, &WinFontList::enumFunc2, (LPARAM)fl);
+  return 1;
+}
+
+int CALLBACK WinFontList::enumFunc2(CONST LOGFONT *font,
+				    CONST TEXTMETRIC *metrics,
+				    DWORD type, LPARAM data) {
+  WinFontList *fl = (WinFontList *)data;
+  WinFontInfo *fi;
+
+  if (type & TRUETYPE_FONTTYPE) {
+    if ((fi = WinFontInfo::make(new GString(font->lfFaceName),
+				font->lfWeight >= 600,
+				font->lfItalic ? gTrue : gFalse,
+				fl->regKey, fl->winFontDir))) {
+      fl->add(fi);
+    }
+  }
+  return 1;
+}
+
+#endif // WIN32
+
 //------------------------------------------------------------------------
 // PSFontParam
 //------------------------------------------------------------------------
@@ -330,6 +579,7 @@
   psEmbedTrueType = gTrue;
   psEmbedCIDPostScript = gTrue;
   psEmbedCIDTrueType = gTrue;
+  psPreload = gFalse;
   psOPI = gFalse;
   psASCIIHex = gFalse;
   textEncoding = new GooString("UTF-8");
@@ -345,7 +595,16 @@
   fontDirs = new GooList();
   enableFreeType = gTrue;
   antialias = gTrue;
+  vectorAntialias = gTrue;
+  strokeAdjust = gTrue;
+  screenType = screenUnset;
+  screenSize = -1;
+  screenDotRadius = -1;
+  screenGamma = 1.0;
+  screenBlackThreshold = 0.0;
+  screenWhiteThreshold = 1.0;
   mapNumericCharNames = gTrue;
+  mapUnknownCharNames = gFalse;
   printCommands = gFalse;
   profileCommands = gFalse;
   errQuiet = gFalse;
@@ -356,6 +615,10 @@
   unicodeMapCache = new UnicodeMapCache();
   cMapCache = new CMapCache();
 
+#ifdef WIN32
+  winFontList = NULL;
+#endif
+
 #ifdef ENABLE_PLUGINS
   plugins = new GooList();
   securityHandlers = new GooList();
@@ -508,6 +771,11 @@
   deleteGooHash(unicodeMaps, GooString);
   deleteGooList(toUnicodeDirs, GooString);
   deleteGooHash(displayFonts, DisplayFontParam);
+#ifdef WIN32
+  if (winFontList) {
+    delete winFontList;
+  }
+#endif
   deleteGooHash(psFonts, PSFontParam);
   deleteGooList(psNamedFonts16, PSFontParam);
   deleteGooList(psFonts16, PSFontParam);
@@ -542,6 +810,12 @@
 void GlobalParams::setBaseDir(char *dir) {
   delete baseDir;
   baseDir = new GooString(dir);
+
+#ifdef WIN32
+  if (winFontDir[0]) {
+    winFontList = new WinFontList(winFontDir);
+  }
+#endif
 }
 
 //------------------------------------------------------------------------
@@ -970,6 +1244,15 @@
   return e;
 }
 
+GBool GlobalParams::getPSPreload() {
+  GBool preload;
+
+  lockGlobalParams;
+  preload = psPreload;
+  unlockGlobalParams;
+  return preload;
+}
+
 GBool GlobalParams::getPSOPI() {
   GBool opi;
 
@@ -1067,6 +1350,78 @@
   return f;
 }
 
+GBool GlobalParams::getVectorAntialias() {
+  GBool f;
+
+  lockGlobalParams;
+  f = vectorAntialias;
+  unlockGlobalParams;
+  return f;
+}
+
+GBool GlobalParams::getStrokeAdjust() {
+  GBool f;
+
+  lockGlobalParams;
+  f = strokeAdjust;
+  unlockGlobalParams;
+  return f;
+}
+
+ScreenType GlobalParams::getScreenType() {
+  ScreenType t;
+
+  lockGlobalParams;
+  t = screenType;
+  unlockGlobalParams;
+  return t;
+}
+
+int GlobalParams::getScreenSize() {
+  int size;
+
+  lockGlobalParams;
+  size = screenSize;
+  unlockGlobalParams;
+  return size;
+}
+
+int GlobalParams::getScreenDotRadius() {
+  int r;
+
+  lockGlobalParams;
+  r = screenDotRadius;
+  unlockGlobalParams;
+  return r;
+}
+
+double GlobalParams::getScreenGamma() {
+  double gamma;
+
+  lockGlobalParams;
+  gamma = screenGamma;
+  unlockGlobalParams;
+  return gamma;
+}
+
+double GlobalParams::getScreenBlackThreshold() {
+  double thresh;
+
+  lockGlobalParams;
+  thresh = screenBlackThreshold;
+  unlockGlobalParams;
+  return thresh;
+}
+
+double GlobalParams::getScreenWhiteThreshold() {
+  double thresh;
+
+  lockGlobalParams;
+  thresh = screenWhiteThreshold;
+  unlockGlobalParams;
+  return thresh;
+}
+
 GBool GlobalParams::getMapNumericCharNames() {
   GBool map;
 
@@ -1076,6 +1431,15 @@
   return map;
 }
 
+GBool GlobalParams::getMapUnknownCharNames() {
+  GBool map;
+
+  lockGlobalParams;
+  map = mapUnknownCharNames;
+  unlockGlobalParams;
+  return map;
+}
+
 GBool GlobalParams::getPrintCommands() {
   GBool p;
 
@@ -1095,12 +1459,9 @@
 }
 
 GBool GlobalParams::getErrQuiet() {
-  GBool q;
-
-  lockGlobalParams;
-  q = errQuiet;
-  unlockGlobalParams;
-  return q;
+  // no locking -- this function may get called from inside a locked
+  // section
+  return errQuiet;
 }
 
 CharCodeToUnicode *GlobalParams::getCIDToUnicode(GooString *collection) {
@@ -1226,6 +1587,12 @@
   unlockGlobalParams;
 }
 
+void GlobalParams::setPSPreload(GBool preload) {
+  lockGlobalParams;
+  psPreload = preload;
+  unlockGlobalParams;
+}
+
 void GlobalParams::setPSOPI(GBool opi) {
   lockGlobalParams;
   psOPI = opi;
@@ -1292,12 +1659,27 @@
   return ok;
 }
 
+GBool GlobalParams::setVectorAntialias(char *s) {
+  GBool ok;
+
+  lockGlobalParams;
+  ok = parseYesNo2(s, &vectorAntialias);
+  unlockGlobalParams;
+  return ok;
+}
+
 void GlobalParams::setMapNumericCharNames(GBool map) {
   lockGlobalParams;
   mapNumericCharNames = map;
   unlockGlobalParams;
 }
 
+void GlobalParams::setMapUnknownCharNames(GBool map) {
+  lockGlobalParams;
+  mapUnknownCharNames = map;
+  unlockGlobalParams;
+}
+
 void GlobalParams::setPrintCommands(GBool printCommandsA) {
   lockGlobalParams;
   printCommands = printCommandsA;
@@ -1332,7 +1714,7 @@
   lockGlobalParams;
   for (i = 0; i < securityHandlers->getLength(); ++i) {
     hdlr = (XpdfSecurityHandler *)securityHandlers->get(i);
-    if (!stricmp(hdlr->name, name)) {
+    if (!strcasecmp(hdlr->name, name)) {
       unlockGlobalParams;
       return hdlr;
     }
@@ -1342,6 +1724,7 @@
   if (!loadPlugin("security", name)) {
     return NULL;
   }
+  deleteGList(keyBindings, KeyBinding);
 
   lockGlobalParams;
   for (i = 0; i < securityHandlers->getLength(); ++i) {
@@ -1352,6 +1735,8 @@
     }
   }
   unlockGlobalParams;
+#else
+  (void)name;
 #endif
 
   return NULL;

Index: GlobalParams.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/GlobalParams.h,v
retrieving revision 1.8
retrieving revision 1.8.2.1
diff -u -d -r1.8 -r1.8.2.1
--- GlobalParams.h	24 Feb 2007 23:43:35 -0000	1.8
+++ GlobalParams.h	6 Apr 2007 14:22:23 -0000	1.8.2.1
@@ -36,6 +36,9 @@
 struct XpdfSecurityHandler;
 class GlobalParams;
 class GfxFont;
+#ifdef WIN32
+class WinFontList;
+#endif
 
 //------------------------------------------------------------------------
 
@@ -71,7 +74,7 @@
   };
 
   DisplayFontParam(GooString *nameA, DisplayFontParamKind kindA);
-  ~DisplayFontParam();
+  virtual ~DisplayFontParam();
 };
 
 //------------------------------------------------------------------------
@@ -113,6 +116,15 @@
 
 //------------------------------------------------------------------------
 
+enum ScreenType {
+  screenUnset,
+  screenDispersed,
+  screenClustered,
+  screenStochasticClustered
+};
+
+//------------------------------------------------------------------------
+
 class GlobalParams {
 public:
 
@@ -145,6 +157,7 @@
   GBool getPSEmbedTrueType();
   GBool getPSEmbedCIDPostScript();
   GBool getPSEmbedCIDTrueType();
+  GBool getPSPreload();
   GBool getPSOPI();
   GBool getPSASCIIHex();
   GooString *getTextEncodingName();
@@ -154,7 +167,16 @@
   GooString *findFontFile(GooString *fontName, char **exts);
   GBool getEnableFreeType();
   GBool getAntialias();
+  GBool getVectorAntialias();
+  GBool getStrokeAdjust();
+  ScreenType getScreenType();
+  int getScreenSize();
+  int getScreenDotRadius();
+  double getScreenGamma();
+  double getScreenBlackThreshold();
+  double getScreenWhiteThreshold();
   GBool getMapNumericCharNames();
+  GBool getMapUnknownCharNames();
   GBool getPrintCommands();
   GBool getProfileCommands();
   GBool getErrQuiet();
@@ -177,6 +199,7 @@
   void setPSEmbedTrueType(GBool embed);
   void setPSEmbedCIDPostScript(GBool embed);
   void setPSEmbedCIDTrueType(GBool embed);
+  void setPSPreload(GBool preload);
   void setPSOPI(GBool opi);
   void setPSASCIIHex(GBool hex);
   void setTextEncoding(char *encodingName);
@@ -185,7 +208,9 @@
   void setTextKeepTinyChars(GBool keep);
   GBool setEnableFreeType(char *s);
   GBool setAntialias(char *s);
+  GBool setVectorAntialias(char *s);
   void setMapNumericCharNames(GBool map);
+  void setMapUnknownCharNames(GBool map);
   void setPrintCommands(GBool printCommandsA);
   void setProfileCommands(GBool profileCommandsA);
   void setErrQuiet(GBool errQuietA);
@@ -230,6 +255,9 @@
   GooList *toUnicodeDirs;		// list of ToUnicode CMap dirs [GooString]
   GooHash *displayFonts;		// display font info, indexed by font name
 				//   [DisplayFontParam]
+#ifdef WIN32
+  WinFontList *winFontList;	// system TrueType fonts
+#endif
   GBool psExpandSmaller;	// expand smaller pages to fill paper
   GBool psShrinkLarger;		// shrink larger pages to fit paper
   GBool psCenter;		// center pages on the paper
@@ -242,6 +270,8 @@
   GBool psEmbedTrueType;	// embed TrueType fonts?
   GBool psEmbedCIDPostScript;	// embed CID PostScript fonts?
   GBool psEmbedCIDTrueType;	// embed CID TrueType fonts?
+  GBool psPreload;		// preload PostScript images and forms into
+				//   memory
   GBool psOPI;			// generate PostScript OPI comments?
   GBool psASCIIHex;		// use ASCIIHex instead of ASCII85?
   GooString *textEncoding;	// encoding (unicodeMap) to use for text
@@ -253,7 +283,16 @@
   GooList *fontDirs;		// list of font dirs [GooString]
   GBool enableFreeType;		// FreeType enable flag
   GBool antialias;		// anti-aliasing enable flag
+  GBool vectorAntialias;	// vector anti-aliasing enable flag
+  GBool strokeAdjust;		// stroke adjustment enable flag
+  ScreenType screenType;	// halftone screen type
+  int screenSize;		// screen matrix size
+  int screenDotRadius;		// screen dot radius
+  double screenGamma;		// screen gamma correction
+  double screenBlackThreshold;	// screen black clamping threshold
+  double screenWhiteThreshold;	// screen white clamping threshold
   GBool mapNumericCharNames;	// map numeric char names (from font subsets)?
+  GBool mapUnknownCharNames;	// map unknown char names?
   GBool printCommands;		// print the drawing commands
   GBool profileCommands;	// profile the drawing commands
   GBool errQuiet;		// suppress error messages?

Index: JBIG2Stream.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/JBIG2Stream.cc,v
retrieving revision 1.9
retrieving revision 1.9.4.1
diff -u -d -r1.9 -r1.9.4.1
--- JBIG2Stream.cc	29 Apr 2006 15:23:41 -0000	1.9
+++ JBIG2Stream.cc	6 Apr 2007 14:22:23 -0000	1.9.4.1
@@ -1106,7 +1106,7 @@
 // JBIG2Stream
 //------------------------------------------------------------------------
 
-JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream):
+JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA):
   FilterStream(strA)
 {
   pageBitmap = NULL;
@@ -1131,22 +1131,15 @@
   huffDecoder = new JBIG2HuffmanDecoder();
   mmrDecoder = new JBIG2MMRDecoder();
 
-  segments = globalSegments = new GooList();
-  if (globalsStream->isStream()) {
-    curStr = globalsStream->getStream();
-    curStr->reset();
-    arithDecoder->setStream(curStr);
-    huffDecoder->setStream(curStr);
-    mmrDecoder->setStream(curStr);
-    readSegments();
-  }
-
-  segments = NULL;
+  globalsStreamA->copy(&globalsStream);
+  segments = globalSegments = NULL;
   curStr = NULL;
   dataPtr = dataEnd = NULL;
 }
 
 JBIG2Stream::~JBIG2Stream() {
+  close();
+  globalsStream.free();
   delete arithDecoder;
   delete genericRegionStats;
   delete refinementRegionStats;
@@ -1166,28 +1159,25 @@
   delete iaidStats;
   delete huffDecoder;
   delete mmrDecoder;
-  if (pageBitmap) {
-    delete pageBitmap;
-  }
-  if (segments) {
-    deleteGooList(segments, JBIG2Segment);
-  }
-  if (globalSegments) {
-    deleteGooList(globalSegments, JBIG2Segment);
-  }
   delete str;
 }
 
 void JBIG2Stream::reset() {
-  if (pageBitmap) {
-    delete pageBitmap;
-    pageBitmap = NULL;
-  }
-  if (segments) {
-    deleteGooList(segments, JBIG2Segment);
+  // read the globals stream
+  globalSegments = new GooList();
+  if (globalsStream.isStream()) {
+    segments = globalSegments;
+    curStr = globalsStream.getStream();
+    curStr->reset();
+    arithDecoder->setStream(curStr);
+    huffDecoder->setStream(curStr);
+    mmrDecoder->setStream(curStr);
+    readSegments();
+    curStr->close();
   }
-  segments = new GooList();
 
+  // read the main stream
+  segments = new GooList();
   curStr = str;
   curStr->reset();
   arithDecoder->setStream(curStr);
@@ -1199,10 +1189,27 @@
     dataPtr = pageBitmap->getDataPtr();
     dataEnd = dataPtr + pageBitmap->getDataSize();
   } else {
-    dataPtr = NULL;
+    dataPtr = dataEnd = NULL;
   }
 }
 
+void JBIG2Stream::close() {
+  if (pageBitmap) {
+    delete pageBitmap;
+    pageBitmap = NULL;
+  }
+  if (segments) {
+    deleteGooList(segments, JBIG2Segment);
+    segments = NULL;
+  }
+  if (globalSegments) {
+    deleteGooList(globalSegments, JBIG2Segment);
+    globalSegments = NULL;
+  }
+  dataPtr = dataEnd = NULL;
+  FilterStream::close();
+}
+
 int JBIG2Stream::getChar() {
   if (dataPtr && dataPtr < dataEnd) {
     return (*dataPtr++ ^ 0xff) & 0xff;
@@ -2361,6 +2368,14 @@
     error(getPos(), "Bad grid size in JBIG2 halftone segment");
     return;
   }
+  if (w == 0 || h == 0 || w >= INT_MAX / h) {
+    error(getPos(), "Bad bitmap size in JBIG2 halftone segment");
+    return;
+  }
+  if (gridH == 0 || gridW >= INT_MAX / gridH) {
+    error(getPos(), "Bad grid size in JBIG2 halftone segment");
+    return;
+  }
 
   // get pattern dictionary
   if (nRefSegs != 1) {
@@ -2372,14 +2387,6 @@
     error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
     return;
   }
-  if (gridH == 0 || gridW >= INT_MAX / gridH) {
-    error(getPos(), "Bad size in JBIG2 halftone segment");
-    return;
-  }
-  if (w == 0 || h >= INT_MAX / w) {
-     error(getPos(), "Bad size in JBIG2 bitmap segment");
-    return;
-  }
 
   patternDict = (JBIG2PatternDict *)seg;
   bpp = 0;
@@ -2411,9 +2418,9 @@
     skipBitmap = new JBIG2Bitmap(0, gridW, gridH);
     skipBitmap->clearToZero();
     for (m = 0; m < gridH; ++m) {
-      xx = gridX + m * stepY;
-      yy = gridY + m * stepX;
       for (n = 0; n < gridW; ++n) {
+	xx = gridX + m * stepY + n * stepX;
+	yy = gridY + m * stepX - n * stepY;
 	if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w ||
 	    ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) {
 	  skipBitmap->setPixel(n, m);
@@ -2459,8 +2466,10 @@
     }
   }
 
-  delete skipBitmap;
   gfree(grayImg);
+  if (skipBitmap) {
+    delete skipBitmap;
+  }
 
   // combine the region bitmap into the page bitmap
   if (imm) {
@@ -3013,11 +3022,6 @@
   JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2;
   int x, y, pix;
 
-  if (w < 0 || h <= 0 || w >= INT_MAX / h) {
-    error(-1, "invalid width/height");
-    return NULL;
-  }
-
   bitmap = new JBIG2Bitmap(0, w, h);
   bitmap->clearToZero();
 
@@ -3396,7 +3400,7 @@
   iardwStats->reset();
   iardhStats->reset();
   iariStats->reset();
-  if (iaidStats->getContextSize() == symCodeLen + 1) {
+  if (iaidStats->getContextSize() == 1 << (symCodeLen + 1)) {
     iaidStats->reset();
   } else {
     delete iaidStats;

Index: JBIG2Stream.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/JBIG2Stream.h,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -d -r1.2 -r1.2.4.1
--- JBIG2Stream.h	31 Aug 2005 09:51:41 -0000	1.2
+++ JBIG2Stream.h	6 Apr 2007 14:22:23 -0000	1.2.4.1
@@ -31,10 +31,11 @@
 class JBIG2Stream: public FilterStream {
 public:
 
-  JBIG2Stream(Stream *strA, Object *globalsStream);
+  JBIG2Stream(Stream *strA, Object *globalsStreamA);
   virtual ~JBIG2Stream();
   virtual StreamKind getKind() { return strJBIG2; }
   virtual void reset();
+  virtual void close();
   virtual int getChar();
   virtual int lookChar();
   virtual GooString *getPSFilter(int psLevel, char *indent);
@@ -107,6 +108,7 @@
   GBool readULong(Guint *x);
   GBool readLong(int *x);
 
+  Object globalsStream;
   Guint pageW, pageH, curPageH;
   Guint pageDefPixel;
   JBIG2Bitmap *pageBitmap;

Index: JPXStream.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/JPXStream.cc,v
retrieving revision 1.6
retrieving revision 1.6.4.1
diff -u -d -r1.6 -r1.6.4.1
--- JPXStream.cc	21 Dec 2005 22:09:47 -0000	1.6
+++ JPXStream.cc	6 Apr 2007 14:22:23 -0000	1.6.4.1
@@ -177,6 +177,59 @@
 
 //------------------------------------------------------------------------
 
+#if 1 //----- disable coverage tracking
+
+#define cover(idx)
+
+#else //----- enable coverage tracking
+
+class JPXCover {
+public:
+
+  JPXCover(int sizeA);
+  ~JPXCover();
+  void incr(int idx);
+
+private:
+
+  int size, used;
+  int *data;
+};
+
+JPXCover::JPXCover(int sizeA) {
+  size = sizeA;
+  used = -1;
+  data = (int *)gmallocn(size, sizeof(int));
+  memset(data, 0, size * sizeof(int));
+}
+
+JPXCover::~JPXCover() {
+  int i;
+
+  printf("JPX coverage:\n");
+  for (i = 0; i <= used; ++i) {
+    printf("  %4d: %8d\n", i, data[i]);
+  }
+  gfree(data);
+}
+
+void JPXCover::incr(int idx) {
+  if (idx < size) {
+    ++data[idx];
+    if (idx > used) {
+      used = idx;
+    }
+  }
+}
+
+JPXCover jpxCover(150);
+
+#define cover(idx) jpxCover.incr(idx)
+
+#endif //----- coverage tracking
+
+//------------------------------------------------------------------------
+
 JPXStream::JPXStream(Stream *strA):
   FilterStream(strA)
 {
@@ -196,6 +249,24 @@
 }
 
 JPXStream::~JPXStream() {
+  close();
+  delete str;
+}
+
+void JPXStream::reset() {
+  str->reset();
+  if (readBoxes()) {
+    curY = img.yOffset;
+  } else {
+    // readBoxes reported an error, so we go immediately to EOF
+    curY = img.ySize;
+  }
+  curX = img.xOffset;
+  curComp = 0;
+  readBufLen = 0;
+}
+
+void JPXStream::close() {
   JPXTile *tile;
   JPXTileComp *tileComp;
   JPXResLevel *resLevel;
@@ -205,19 +276,23 @@
   Guint comp, i, k, r, pre, sb;
 
   gfree(bpc);
+  bpc = NULL;
   if (havePalette) {
     gfree(palette.bpc);
     gfree(palette.c);
+    havePalette = gFalse;
   }
   if (haveCompMap) {
     gfree(compMap.comp);
     gfree(compMap.type);
     gfree(compMap.pComp);
+    haveCompMap = gFalse;
   }
   if (haveChannelDefn) {
     gfree(channelDefn.idx);
     gfree(channelDefn.type);
     gfree(channelDefn.assoc);
+    haveChannelDefn = gFalse;
   }
 
   if (img.tiles) {
@@ -236,7 +311,7 @@
 		for (pre = 0; pre < 1; ++pre) {
 		  precinct = &resLevel->precincts[pre];
 		  if (precinct->subbands) {
-		    for (sb = 0; sb < (r == 0 ? 1 : 3); ++sb) {
+		    for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) {
 		      subband = &precinct->subbands[sb];
 		      gfree(subband->inclusion);
 		      gfree(subband->zeroBitPlane);
@@ -267,21 +342,9 @@
       }
     }
     gfree(img.tiles);
+    img.tiles = NULL;
   }
-  delete str;
-}
-
-void JPXStream::reset() {
-  str->reset();
-  if (readBoxes()) {
-    curY = img.yOffset;
-  } else {
-    // readBoxes reported an error, so we go immediately to EOF
-    curY = img.ySize;
-  }
-  curX = img.xOffset;
-  curComp = 0;
-  readBufLen = 0;
+  FilterStream::close();
 }
 
 int JPXStream::getChar() {
@@ -394,8 +457,10 @@
   } else {
     while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
       if (boxType == 0x6a703268) { // JP2 header
+	cover(0);
 	// skip the superbox
       } else if (boxType == 0x69686472) { // image header
+	cover(1);
 	if (readULong(&dummy) &&
 	    readULong(&dummy) &&
 	    readUWord(&dummy) &&
@@ -407,6 +472,7 @@
 	  haveBPC = gTrue;
 	}
       } else if (boxType == 0x636F6C72) { // color specification
+	cover(2);
 	if (readByte(&csMeth) &&
 	    readByte(&csPrec1) &&
 	    readByte(&dummy2)) {
@@ -440,11 +506,13 @@
 	  }
 	}
       } else if (boxType == 0x6A703263) { // codestream
+	cover(3);
 	if (!(haveBPC && haveCSMode)) {
 	  getImageParams2(bitsPerComponent, csMode);
 	}
 	break;
       } else {
+	cover(4);
 	for (i = 0; i < dataLen; ++i) {
 	  str->getChar();
 	}
@@ -462,6 +530,7 @@
 
   while (readMarkerHdr(&segType, &segLen)) {
     if (segType == 0x51) { // SIZ - image and tile size
+      cover(5);
       if (readUWord(&dummy) &&
 	  readULong(&dummy) &&
 	  readULong(&dummy) &&
@@ -485,6 +554,7 @@
       }
       break;
     } else {
+      cover(6);
       if (segLen > 2) {
 	for (i = 0; i < segLen - 2; ++i) {
 	  str->getChar();
@@ -505,6 +575,7 @@
   // wrapper) -- this appears to be a violation of the PDF spec, but
   // Acrobat allows it
   if (str->lookChar() == 0xff) {
+    cover(7);
     error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
     readCodestream(0);
     nComps = img.nComps;
@@ -525,8 +596,10 @@
       // some things which should be subboxes of the JP2 header box
       // show up outside of it - so we simply ignore the JP2 header
       // box
+      cover(8);
       break;
     case 0x69686472:		// image header
+      cover(9);
       if (!readULong(&height) ||
 	  !readULong(&width) ||
 	  !readUWord(&nComps) ||
@@ -548,6 +621,7 @@
       haveImgHdr = gTrue;
       break;
     case 0x62706363:		// bits per component
+      cover(10);
       if (!haveImgHdr) {
 	error(getPos(), "Found bits per component box before image header box in JPX stream");
 	return gFalse;
@@ -564,11 +638,13 @@
       }
       break;
     case 0x636F6C72:		// color specification
+      cover(11);
       if (!readColorSpecBox(dataLen)) {
 	return gFalse;
       }
       break;
     case 0x70636c72:		// palette
+      cover(12);
       if (!readUWord(&palette.nEntries) ||
 	  !readUByte(&palette.nComps)) {
 	error(getPos(), "Unexpected EOF in JPX stream");
@@ -597,6 +673,7 @@
       havePalette = gTrue;
       break;
     case 0x636d6170:		// component mapping
+      cover(13);
       compMap.nChannels = dataLen / 4;
       compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
       compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
@@ -612,6 +689,7 @@
       haveCompMap = gTrue;
       break;
     case 0x63646566:		// channel definition
+      cover(14);
       if (!readUWord(&channelDefn.nChannels)) {
 	error(getPos(), "Unexpected EOF in JPX stream");
 	return gFalse;
@@ -633,6 +711,7 @@
       haveChannelDefn = gTrue;
       break;
     case 0x6A703263:		// contiguous codestream
+      cover(15);
       if (!bpc) {
 	error(getPos(), "JPX stream is missing the image header box");
       }
@@ -644,6 +723,7 @@
       }
       break;
     default:
+      cover(16);
       for (i = 0; i < dataLen; ++i) {
 	if (str->getChar() == EOF) {
 	  error(getPos(), "Unexpected EOF in JPX stream");
@@ -670,6 +750,7 @@
   }
   switch (newCS.meth) {
   case 1:			// enumerated colorspace
+    cover(17);
     if (!readULong(&csEnum)) {
       goto err;
     }
@@ -712,6 +793,7 @@
 	}
       } else if (dataLen == 7) {
 	//~ this assumes the 8-bit case
+	cover(92);
 	newCS.enumerated.cieLab.rl = 100;
 	newCS.enumerated.cieLab.ol = 0;
 	newCS.enumerated.cieLab.ra = 255;
@@ -758,6 +840,7 @@
   case 2:			// restricted ICC profile
   case 3: 			// any ICC profile (JPX)
   case 4:			// vendor color (JPX)
+    cover(18);
     for (i = 0; i < dataLen - 3; ++i) {
       if (str->getChar() == EOF) {
 	goto err;
@@ -784,7 +867,7 @@
   int segType;
   GBool haveSIZ, haveCOD, haveQCD, haveSOT;
   Guint precinctSize, style;
-  Guint segLen, capabilities, nTiles, comp, i, j, r;
+  Guint segLen, capabilities, comp, i, j, r;
 
   //----- main header
   haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
@@ -796,8 +879,10 @@
     switch (segType) {
     case 0x4f:			// SOC - start of codestream
       // marker only
+      cover(19);
       break;
     case 0x51:			// SIZ - image and tile size
+      cover(20);
       if (!readUWord(&capabilities) ||
 	  !readULong(&img.xSize) ||
 	  !readULong(&img.ySize) ||
@@ -819,13 +904,14 @@
 	            / img.xTileSize;
       img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
 	            / img.yTileSize;
-      nTiles = img.nXTiles * img.nYTiles;
       // check for overflow before allocating memory
-      if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) {
+      if (img.nXTiles <= 0 || img.nYTiles <= 0 ||
+	  img.nXTiles >= INT_MAX / img.nYTiles) {
 	error(getPos(), "Bad tile count in JPX SIZ marker segment");
 	return gFalse;
       }
-      img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile));
+      img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles,
+				      sizeof(JPXTile));
       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
 	img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
 							 sizeof(JPXTileComp));
@@ -854,6 +940,7 @@
       haveSIZ = gTrue;
       break;
     case 0x52:			// COD - coding style default
+      cover(21);
       if (!readUByte(&img.tiles[0].tileComps[0].style) ||
 	  !readUByte(&img.tiles[0].progOrder) ||
 	  !readUWord(&img.tiles[0].nLayers) ||
@@ -900,6 +987,7 @@
       }
       for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) {
 	if (img.tiles[0].tileComps[0].style & 0x01) {
+	  cover(91);
 	  if (!readUByte(&precinctSize)) {
 	    error(getPos(), "Error in JPX COD marker segment");
 	    return gFalse;
@@ -928,6 +1016,7 @@
       haveCOD = gTrue;
       break;
     case 0x53:			// COC - coding style component
+      cover(22);
       if (!haveCOD) {
 	error(getPos(), "JPX COC marker segment before COD segment");
 	return gFalse;
@@ -997,6 +1086,7 @@
       }
       break;
     case 0x5c:			// QCD - quantization default
+      cover(23);
       if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) {
 	error(getPos(), "Error in JPX QCD marker segment");
 	return gFalse;
@@ -1060,6 +1150,7 @@
       haveQCD = gTrue;
       break;
     case 0x5d:			// QCC - quantization component
+      cover(24);
       if (!haveQCD) {
 	error(getPos(), "JPX QCC marker segment before QCD segment");
 	return gFalse;
@@ -1127,6 +1218,7 @@
       }
       break;
     case 0x5e:			// RGN - region of interest
+      cover(25);
 #if 1 //~ ROI is unimplemented
       fprintf(stderr, "RGN\n");
       for (i = 0; i < segLen - 2; ++i) {
@@ -1147,6 +1239,7 @@
 #endif
       break;
     case 0x5f:			// POC - progression order change
+      cover(26);
 #if 1 //~ progression order changes are unimplemented
       fprintf(stderr, "POC\n");
       for (i = 0; i < segLen - 2; ++i) {
@@ -1174,6 +1267,7 @@
 #endif
       break;
     case 0x60:			// PPM - packed packet headers, main header
+      cover(27);
 #if 1 //~ packed packet headers are unimplemented
       fprintf(stderr, "PPM\n");
       for (i = 0; i < segLen - 2; ++i) {
@@ -1186,6 +1280,7 @@
       break;
     case 0x55:			// TLM - tile-part lengths
       // skipped
+      cover(28);
       for (i = 0; i < segLen - 2; ++i) {
 	if (str->getChar() == EOF) {
 	  error(getPos(), "Error in JPX TLM marker segment");
@@ -1195,6 +1290,7 @@
       break;
     case 0x57:			// PLM - packet length, main header
       // skipped
+      cover(29);
       for (i = 0; i < segLen - 2; ++i) {
 	if (str->getChar() == EOF) {
 	  error(getPos(), "Error in JPX PLM marker segment");
@@ -1204,6 +1300,7 @@
       break;
     case 0x63:			// CRG - component registration
       // skipped
+      cover(30);
       for (i = 0; i < segLen - 2; ++i) {
 	if (str->getChar() == EOF) {
 	  error(getPos(), "Error in JPX CRG marker segment");
@@ -1213,6 +1310,7 @@
       break;
     case 0x64:			// COM - comment
       // skipped
+      cover(31);
       for (i = 0; i < segLen - 2; ++i) {
 	if (str->getChar() == EOF) {
 	  error(getPos(), "Error in JPX COM marker segment");
@@ -1221,9 +1319,11 @@
       }
       break;
     case 0x90:			// SOT - start of tile
+      cover(32);
       haveSOT = gTrue;
       break;
     default:
+      cover(33);
       error(getPos(), "Unknown marker segment %02x in JPX stream", segType);
       for (i = 0; i < segLen - 2; ++i) {
 	if (str->getChar() == EOF) {
@@ -1324,6 +1424,7 @@
     tilePartLen -= 2 + segLen;
     switch (segType) {
     case 0x52:			// COD - coding style default
+      cover(34);
       if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) ||
 	  !readUByte(&img.tiles[tileIdx].progOrder) ||
 	  !readUWord(&img.tiles[tileIdx].nLayers) ||
@@ -1391,6 +1492,7 @@
       }
       break;
     case 0x53:			// COC - coding style component
+      cover(35);
       if ((img.nComps > 256 && !readUWord(&comp)) ||
 	  (img.nComps <= 256 && !readUByte(&comp)) ||
 	  comp >= img.nComps ||
@@ -1432,6 +1534,7 @@
       }
       break;
     case 0x5c:			// QCD - quantization default
+      cover(36);
       if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
 	error(getPos(), "Error in JPX QCD marker segment");
 	return gFalse;
@@ -1491,6 +1594,7 @@
       }
       break;
     case 0x5d:			// QCC - quantization component
+      cover(37);
       if ((img.nComps > 256 && !readUWord(&comp)) ||
 	  (img.nComps <= 256 && !readUByte(&comp)) ||
 	  comp >= img.nComps ||
@@ -1542,6 +1646,7 @@
       }
       break;
     case 0x5e:			// RGN - region of interest
+      cover(38);
 #if 1 //~ ROI is unimplemented
       fprintf(stderr, "RGN\n");
       for (i = 0; i < segLen - 2; ++i) {
@@ -1562,6 +1667,7 @@
 #endif
       break;
     case 0x5f:			// POC - progression order change
+      cover(39);
 #if 1 //~ progression order changes are unimplemented
       fprintf(stderr, "POC\n");
       for (i = 0; i < segLen - 2; ++i) {
@@ -1589,6 +1695,7 @@
 #endif
       break;
     case 0x61:			// PPT - packed packet headers, tile-part hdr
+      cover(40);
 #if 1 //~ packed packet headers are unimplemented
       fprintf(stderr, "PPT\n");
       for (i = 0; i < segLen - 2; ++i) {
@@ -1600,6 +1707,7 @@
 #endif
     case 0x58:			// PLT - packet length, tile-part header
       // skipped
+      cover(41);
       for (i = 0; i < segLen - 2; ++i) {
 	if (str->getChar() == EOF) {
 	  error(getPos(), "Error in JPX PLT marker segment");
@@ -1609,6 +1717,7 @@
       break;
     case 0x64:			// COM - comment
       // skipped
+      cover(42);
       for (i = 0; i < segLen - 2; ++i) {
 	if (str->getChar() == EOF) {
 	  error(getPos(), "Error in JPX COM marker segment");
@@ -1617,9 +1726,11 @@
       }
       break;
     case 0x93:			// SOD - start of data
+      cover(43);
       haveSOD = gTrue;
       break;
     default:
+      cover(44);
       error(getPos(), "Unknown marker segment %02x in JPX tile-part stream",
 	    segType);
       for (i = 0; i < segLen - 2; ++i) {
@@ -1817,6 +1928,7 @@
   while (1) {
     if (tilePartToEOC) {
       //~ peek for an EOC marker
+      cover(93);
     } else if (tilePartLen == 0) {
       break;
     }
@@ -1827,13 +1939,17 @@
 
     //----- packet header
 
+    // setup
+    startBitBuf(tilePartLen);
+
     // zero-length flag
     if (!readBits(1, &bits)) {
       goto err;
     }
     if (!bits) {
       // packet is empty -- clear all code-block inclusion flags
-      for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
+      cover(45);
+      for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
 	subband = &precinct->subbands[sb];
 	for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
 	  for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
@@ -1844,7 +1960,7 @@
       }
     } else {
 
-      for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
+      for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
 	subband = &precinct->subbands[sb];
 	for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
 	  for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
@@ -1852,16 +1968,19 @@
 
 	    // skip code-blocks with no coefficients
 	    if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) {
+	      cover(46);
 	      cb->included = gFalse;
 	      continue;
 	    }
 
 	    // code-block inclusion
 	    if (cb->seen) {
+	      cover(47);
 	      if (!readBits(1, &cb->included)) {
 		goto err;
 	      }
 	    } else {
+	      cover(48);
 	      ttVal = 0;
 	      i = 0;
 	      for (level = subband->maxTTLevel; level >= 0; --level) {
@@ -1895,9 +2014,11 @@
 	    }
 
 	    if (cb->included) {
+	      cover(49);
 
 	      // zero bit-plane count
 	      if (!cb->seen) {
+		cover(50);
 		ttVal = 0;
 		i = 0;
 		for (level = subband->maxTTLevel; level >= 0; --level) {
@@ -1931,26 +2052,33 @@
 		goto err;
 	      }
 	      if (bits == 0) {
+		cover(51);
 		cb->nCodingPasses = 1;
 	      } else {
 		if (!readBits(1, &bits)) {
 		  goto err;
 		}
 		if (bits == 0) {
+		  cover(52);
 		  cb->nCodingPasses = 2;
 		} else {
+		  cover(53);
 		  if (!readBits(2, &bits)) {
 		    goto err;
 		  }
 		  if (bits < 3) {
+		    cover(54);
 		    cb->nCodingPasses = 3 + bits;
 		  } else {
+		    cover(55);
 		    if (!readBits(5, &bits)) {
 		      goto err;
 		    }
 		    if (bits < 31) {
+		      cover(56);
 		      cb->nCodingPasses = 6 + bits;
 		    } else {
+		      cover(57);
 		      if (!readBits(7, &bits)) {
 			goto err;
 		      }
@@ -1984,12 +2112,11 @@
 	}
       }
     }
-    tilePartLen -= byteCount;
-    clearBitBuf();
+    tilePartLen = finishBitBuf();
 
     //----- packet data
 
-    for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
+    for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
       subband = &precinct->subbands[sb];
       for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
 	for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
@@ -2010,6 +2137,7 @@
 
     switch (tile->progOrder) {
     case 0: // layer, resolution level, component, precinct
+      cover(58);
       if (++tile->comp == img.nComps) {
 	tile->comp = 0;
 	if (++tile->res == tile->maxNDecompLevels + 1) {
@@ -2021,6 +2149,7 @@
       }
       break;
     case 1: // resolution level, layer, component, precinct
+      cover(59);
       if (++tile->comp == img.nComps) {
 	tile->comp = 0;
 	if (++tile->layer == tile->nLayers) {
@@ -2033,6 +2162,7 @@
       break;
     case 2: // resolution level, precinct, component, layer
       //~ this isn't correct -- see B.12.1.3
+      cover(60);
       if (++tile->layer == tile->nLayers) {
 	tile->layer = 0;
 	if (++tile->comp == img.nComps) {
@@ -2045,6 +2175,7 @@
       break;
     case 3: // precinct, component, resolution level, layer
       //~ this isn't correct -- see B.12.1.4
+      cover(61);
       if (++tile->layer == tile->nLayers) {
 	tile->layer = 0;
 	if (++tile->res == tile->maxNDecompLevels + 1) {
@@ -2057,6 +2188,7 @@
       break;
     case 4: // component, precinct, resolution level, layer
       //~ this isn't correct -- see B.12.1.5
+      cover(62);
       if (++tile->layer == tile->nLayers) {
 	tile->layer = 0;
 	if (++tile->res == tile->maxNDecompLevels + 1) {
@@ -2089,8 +2221,10 @@
   Guint i, x, y0, y1, y2;
 
   if (cb->arithDecoder) {
+    cover(63);
     cb->arithDecoder->restart(cb->dataLen);
   } else {
+    cover(64);
     cb->arithDecoder = new JArithmeticDecoder();
     cb->arithDecoder->setStream(str, cb->dataLen);
     cb->arithDecoder->start();
@@ -2105,6 +2239,7 @@
 
     //----- significance propagation pass
     case jpxPassSigProp:
+      cover(65);
       for (y0 = cb->y0, coeff0 = cb->coeffs;
 	   y0 < cb->y1;
 	   y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
@@ -2182,6 +2317,7 @@
 
     //----- magnitude refinement pass
     case jpxPassMagRef:
+      cover(66);
       for (y0 = cb->y0, coeff0 = cb->coeffs;
 	   y0 < cb->y1;
 	   y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
@@ -2243,6 +2379,7 @@
 
     //----- cleanup pass
     case jpxPassCleanup:
+      cover(67);
       for (y0 = cb->y0, coeff0 = cb->coeffs;
 	   y0 < cb->y1;
 	   y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
@@ -2404,6 +2541,8 @@
   Guint nx0, ny0, nx1, ny1;
   Guint r, cbX, cbY, x, y;
 
+  cover(68);
+
   //----- (NL)LL subband (resolution level 0)
 
   resLevel = &tileComp->resLevels[0];
@@ -2414,14 +2553,17 @@
   qStyle = tileComp->quantStyle & 0x1f;
   guard = (tileComp->quantStyle >> 5) & 7;
   if (qStyle == 0) {
+    cover(69);
     eps = (tileComp->quantSteps[0] >> 3) & 0x1f;
     shift = guard + eps - 1;
     mu = 0; // make gcc happy
   } else {
+    cover(70);
     shift = guard - 1 + tileComp->prec;
     mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0;
   }
   if (tileComp->transform == 0) {
+    cover(71);
     shift += fracBits;
   }
 
@@ -2441,18 +2583,24 @@
 	  if (val != 0) {
 	    shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
 	    if (shift2 > 0) {
+	      cover(94);
 	      val = (val << shift2) + (1 << (shift2 - 1));
 	    } else {
+	      cover(95);
 	      val >>= -shift2;
 	    }
 	    if (qStyle == 0) {
+	      cover(96);
 	      if (tileComp->transform == 0) {
+		cover(97);
 		val &= -1 << fracBits;
 	      }
 	    } else {
+	      cover(98);
 	      val = (int)((double)val * mu);
 	    }
 	    if (coeff->flags & jpxCoeffSign) {
+	      cover(99);
 	      val = -val;
 	    }
 	  }
@@ -2473,11 +2621,13 @@
     // and inverse transform to get (n-1)LL, which will be stored
     // in the upper-left corner of the tile-component data array
     if (r == tileComp->nDecompLevels) {
+      cover(72);
       nx0 = tileComp->x0;
       ny0 = tileComp->y0;
       nx1 = tileComp->x1;
       ny1 = tileComp->y1;
     } else {
+      cover(73);
       nx0 = tileComp->resLevels[r+1].x0;
       ny0 = tileComp->resLevels[r+1].y0;
       nx1 = tileComp->resLevels[r+1].x1;
@@ -2530,18 +2680,22 @@
 
     // i-quant parameters
     if (qStyle == 0) {
+      cover(100);
       eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f;
       shift = guard + eps - 1;
       mu = 0; // make gcc happy
     } else {
+      cover(101);
       shift = guard + tileComp->prec;
       if (sb == 2) {
+	cover(102);
 	++shift;
       }
       t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)];
       mu = (double)(0x800 + (t & 0x7ff)) / 2048.0;
     }
     if (tileComp->transform == 0) {
+      cover(103);
       shift += fracBits;
     }
 
@@ -2564,18 +2718,23 @@
 	    if (val != 0) {
 	      shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
 	      if (shift2 > 0) {
+		cover(74);
 		val = (val << shift2) + (1 << (shift2 - 1));
 	      } else {
+		cover(75);
 		val >>= -shift2;
 	      }
 	      if (qStyle == 0) {
+		cover(76);
 		if (tileComp->transform == 0) {
 		  val &= -1 << fracBits;
 		}
 	      } else {
+		cover(77);
 		val = (int)((double)val * mu);
 	      }
 	      if (coeff->flags & jpxCoeffSign) {
+		cover(78);
 		val = -val;
 	      }
 	    }
@@ -2612,11 +2771,14 @@
 
   //----- special case for length = 1
   if (i1 - i0 == 1) {
+    cover(79);
     if (i0 & 1) {
+      cover(104);
       *data >>= 1;
     }
 
   } else {
+    cover(80);
 
     // choose an offset: this makes even buf[] indexes correspond to
     // odd values of i, and vice versa
@@ -2632,19 +2794,25 @@
     //----- extend right
     buf[end] = buf[end - 2];
     if (i1 - i0 == 2) {
+      cover(81);
       buf[end+1] = buf[offset + 1];
       buf[end+2] = buf[offset];
       buf[end+3] = buf[offset + 1];
     } else {
+      cover(82);
       buf[end+1] = buf[end - 3];
       if (i1 - i0 == 3) {
+	cover(105);
 	buf[end+2] = buf[offset + 1];
 	buf[end+3] = buf[offset + 2];
       } else {
+	cover(106);
 	buf[end+2] = buf[end - 4];
 	if (i1 - i0 == 4) {
+	  cover(107);
 	  buf[end+3] = buf[offset + 1];
 	} else {
+	  cover(108);
 	  buf[end+3] = buf[end - 5];
 	}
       }
@@ -2655,12 +2823,14 @@
     buf[offset - 2] = buf[offset + 2];
     buf[offset - 3] = buf[offset + 3];
     if (offset == 4) {
+      cover(83);
       buf[0] = buf[offset + 4];
     }
 
     //----- 9-7 irreversible filter
 
     if (tileComp->transform == 0) {
+      cover(84);
       // step 1 (even)
       for (i = 1; i <= end + 2; i += 2) {
 	buf[i] = (int)(idwtKappa * buf[i]);
@@ -2689,6 +2859,7 @@
     //----- 5-3 reversible filter
 
     } else {
+      cover(85);
       // step 1 (even)
       for (i = 3; i <= end; i += 2) {
 	buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2;
@@ -2717,6 +2888,7 @@
   //----- inverse multi-component transform
 
   if (tile->multiComp == 1) {
+    cover(86);
     if (img.nComps < 3 ||
 	tile->tileComps[0].hSep != tile->tileComps[1].hSep ||
 	tile->tileComps[0].vSep != tile->tileComps[1].vSep ||
@@ -2727,6 +2899,7 @@
 
     // inverse irreversible multiple component transform
     if (tile->tileComps[0].transform == 0) {
+      cover(87);
       j = 0;
       for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
 	for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
@@ -2743,6 +2916,7 @@
 
     // inverse reversible multiple component transform
     } else {
+      cover(88);
       j = 0;
       for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
 	for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
@@ -2764,6 +2938,7 @@
 
     // signed: clip
     if (tileComp->sgned) {
+      cover(89);
       minVal = -(1 << (tileComp->prec - 1));
       maxVal = (1 << (tileComp->prec - 1)) - 1;
       dataPtr = tileComp->data;
@@ -2771,11 +2946,14 @@
 	for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
 	  coeff = *dataPtr;
 	  if (tileComp->transform == 0) {
+	    cover(109);
 	    coeff >>= fracBits;
 	  }
 	  if (coeff < minVal) {
+	    cover(110);
 	    coeff = minVal;
 	  } else if (coeff > maxVal) {
+	    cover(111);
 	    coeff = maxVal;
 	  }
 	  *dataPtr++ = coeff;
@@ -2784,6 +2962,7 @@
 
     // unsigned: inverse DC level shift and clip
     } else {
+      cover(90);
       maxVal = (1 << tileComp->prec) - 1;
       zeroVal = 1 << (tileComp->prec - 1);
       dataPtr = tileComp->data;
@@ -2791,12 +2970,15 @@
 	for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
 	  coeff = *dataPtr;
 	  if (tileComp->transform == 0) {
+	    cover(112);
 	    coeff >>= fracBits;
 	  }
 	  coeff += zeroVal;
 	  if (coeff < 0) {
+	    cover(113);
 	    coeff = 0;
 	  } else if (coeff > maxVal) {
+	    cover(114);
 	    coeff = maxVal;
 	  }
 	  *dataPtr++ = coeff;
@@ -2929,10 +3111,10 @@
   int c;
 
   while (bitBufLen < nBits) {
-    if ((c = str->getChar()) == EOF) {
+    if (byteCount == 0 || (c = str->getChar()) == EOF) {
       return gFalse;
     }
-    ++byteCount;
+    --byteCount;
     if (bitBufSkip) {
       bitBuf = (bitBuf << 7) | (c & 0x7f);
       bitBufLen += 7;
@@ -2947,8 +3129,16 @@
   return gTrue;
 }
 
-void JPXStream::clearBitBuf() {
+void JPXStream::startBitBuf(Guint byteCountA) {
   bitBufLen = 0;
   bitBufSkip = gFalse;
-  byteCount = 0;
+  byteCount = byteCountA;
+}
+
+Guint JPXStream::finishBitBuf() {
+  if (bitBufSkip) {
+    str->getChar();
+    --byteCount;
+  }
+  return byteCount;
 }

Index: JPXStream.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/JPXStream.h,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -d -r1.2 -r1.2.4.1
--- JPXStream.h	31 Aug 2005 15:28:46 -0000	1.2
+++ JPXStream.h	6 Apr 2007 14:22:23 -0000	1.2.4.1
@@ -17,6 +17,7 @@
 #include "Object.h"
 #include "Stream.h"
 
+class JArithmeticDecoder;
 class JArithmeticDecoderStats;
 
 //------------------------------------------------------------------------
@@ -275,6 +276,7 @@
   virtual ~JPXStream();
   virtual StreamKind getKind() { return strJPX; }
   virtual void reset();
+  virtual void close();
   virtual int getChar();
   virtual int lookChar();
   virtual GooString *getPSFilter(int psLevel, char *indent);
@@ -315,7 +317,8 @@
   GBool readULong(Guint *x);
   GBool readNBytes(int nBytes, GBool signd, int *x);
   GBool readBits(int nBits, Guint *x);
-  void clearBitBuf();
+  void startBitBuf(Guint byteCountA);
+  Guint finishBitBuf();
 
   Guint nComps;			// number of components
   Guint *bpc;			// bits per component, for each component
@@ -336,8 +339,7 @@
   int bitBufLen;		// number of bits in bitBuf
   GBool bitBufSkip;		// true if next bit should be skipped
 				//   (for bit stuffing)
-  Guint byteCount;		// number of bytes read since last call
-				//   to clearBitBuf
+  Guint byteCount;		// number of available bytes left
 
   Guint curX, curY, curComp;	// current position for lookChar/getChar
   Guint readBuf;		// read buffer

Index: Lexer.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Lexer.cc,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -d -r1.5 -r1.5.2.1
--- Lexer.cc	4 Feb 2007 00:16:43 -0000	1.5
+++ Lexer.cc	6 Apr 2007 14:22:23 -0000	1.5.2.1
@@ -319,11 +319,13 @@
 	  // we are growing see if the document is not malformed and we are growing too much
 	  if (objNum != -1)
 	  {
-	    int newObjNum = xref->getNumEntry(getPos());
+	    int newObjNum = xref->getNumEntry(curStr.streamGetPos());
 	    if (newObjNum != objNum)
 	    {
 	      error(getPos(), "Unterminated string");
 	      done = gTrue;
+	      delete s;
+	      n = -2;
 	    }
 	  }
 	}
@@ -331,11 +333,15 @@
 	++n;
       }
     } while (!done);
-    if (!s)
-      s = new GooString(tokBuf, n);
-    else
-      s->append(tokBuf, n);
-    obj->initString(s);
+    if (n >= 0) {
+      if (!s)
+        s = new GooString(tokBuf, n);
+      else
+        s->append(tokBuf, n);
+      obj->initString(s);
+    } else {
+      obj->initEOF();
+    }
     break;
 
   // name

Index: Link.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Link.cc,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -d -r1.5 -r1.5.2.1
--- Link.cc	8 Oct 2006 20:38:47 -0000	1.5
+++ Link.cc	6 Apr 2007 14:22:23 -0000	1.5.2.1
@@ -22,7 +22,6 @@
 #include "Dict.h"
 #include "Link.h"
 #include "Sound.h"
-#include "UGooString.h"
 
 //------------------------------------------------------------------------
 // LinkAction
@@ -296,7 +295,7 @@
     kind = destFitH;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     top = obj2.getNum();
     obj2.free();
@@ -310,7 +309,7 @@
     kind = destFitV;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     left = obj2.getNum();
     obj2.free();
@@ -324,25 +323,25 @@
     kind = destFitR;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     left = obj2.getNum();
     obj2.free();
     if (!a->get(3, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     bottom = obj2.getNum();
     obj2.free();
     if (!a->get(4, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     right = obj2.getNum();
     obj2.free();
     if (!a->get(5, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     top = obj2.getNum();
     obj2.free();
@@ -364,7 +363,7 @@
     kind = destFitBH;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     top = obj2.getNum();
     obj2.free();
@@ -378,7 +377,7 @@
     kind = destFitBV;
     if (!a->get(2, &obj2)->isNum()) {
       error(-1, "Bad annotation destination position");
-      goto err1;
+      kind = destFit;
     }
     left = obj2.getNum();
     obj2.free();
@@ -427,9 +426,9 @@
 
   // named destination
   if (destObj->isName()) {
-    namedDest = new UGooString(destObj->getName());
+    namedDest = new GooString(destObj->getName());
   } else if (destObj->isString()) {
-    namedDest = new UGooString(*destObj->getString());
+    namedDest = destObj->getString()->copy();
 
   // destination dictionary
   } else if (destObj->isArray()) {
@@ -465,9 +464,9 @@
 
   // named destination
   if (destObj->isName()) {
-    namedDest = new UGooString(destObj->getName());
+    namedDest = new GooString(destObj->getName());
   } else if (destObj->isString()) {
-    namedDest = new UGooString(*destObj->getString());
+    namedDest = destObj->getString()->copy();
 
   // destination dictionary
   } else if (destObj->isArray()) {
@@ -691,42 +690,13 @@
 }
 
 //------------------------------------------------------------------------
-// LinkBorderStyle
-//------------------------------------------------------------------------
-
-LinkBorderStyle::LinkBorderStyle(LinkBorderType typeA, double widthA,
-				 double *dashA, int dashLengthA,
-				 double rA, double gA, double bA) {
-  type = typeA;
-  width = widthA;
-  dash = dashA;
-  dashLength = dashLengthA;
-  r = rA;
-  g = gA;
-  b = bA;
-}
-
-LinkBorderStyle::~LinkBorderStyle() {
-  if (dash) {
-    gfree(dash);
-  }
-}
-
-//------------------------------------------------------------------------
 // Link
 //------------------------------------------------------------------------
 
 Link::Link(Dict *dict, GooString *baseURI) {
-  Object obj1, obj2, obj3;
-  LinkBorderType borderType;
-  double borderWidth;
-  double *borderDash;
-  int borderDashLength;
-  double borderR, borderG, borderB;
+  Object obj1, obj2;
   double t;
-  int i;
 
-  borderStyle = NULL;
   action = NULL;
   ok = gFalse;
 
@@ -771,97 +741,6 @@
     y2 = t;
   }
 
-  // get the border style info
-  borderType = linkBorderSolid;
-  borderWidth = 1;
-  borderDash = NULL;
-  borderDashLength = 0;
-  borderR = 0;
-  borderG = 0;
-  borderB = 1;
-  if (dict->lookup("BS", &obj1)->isDict()) {
-    if (obj1.dictLookup("S", &obj2)->isName()) {
-      if (obj2.isName("S")) {
-	borderType = linkBorderSolid;
-      } else if (obj2.isName("D")) {
-	borderType = linkBorderDashed;
-      } else if (obj2.isName("B")) {
-	borderType = linkBorderEmbossed;
-      } else if (obj2.isName("I")) {
-	borderType = linkBorderEngraved;
-      } else if (obj2.isName("U")) {
-	borderType = linkBorderUnderlined;
-      }
-    }
-    obj2.free();
-    if (obj1.dictLookup("W", &obj2)->isNum()) {
-      borderWidth = obj2.getNum();
-    }
-    obj2.free();
-    if (obj1.dictLookup("D", &obj2)->isArray()) {
-      borderDashLength = obj2.arrayGetLength();
-      borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
-      for (i = 0; i < borderDashLength; ++i) {
-	if (obj2.arrayGet(i, &obj3)->isNum()) {
-	  borderDash[i] = obj3.getNum();
-	} else {
-	  borderDash[i] = 1;
-	}
-	obj3.free();
-      }
-    }
-    obj2.free();
-  } else {
-    obj1.free();
-    if (dict->lookup("Border", &obj1)->isArray()) {
-      if (obj1.arrayGetLength() >= 3) {
-	if (obj1.arrayGet(2, &obj2)->isNum()) {
-	  borderWidth = obj2.getNum();
-	}
-	obj2.free();
-	if (obj1.arrayGetLength() >= 4) {
-	  if (obj1.arrayGet(3, &obj2)->isArray()) {
-	    borderType = linkBorderDashed;
-	    borderDashLength = obj2.arrayGetLength();
-	    borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
-	    for (i = 0; i < borderDashLength; ++i) {
-	      if (obj2.arrayGet(i, &obj3)->isNum()) {
-		borderDash[i] = obj3.getNum();
-	      } else {
-		borderDash[i] = 1;
-	      }
-	      obj3.free();
-	    }
-	  } else {
-	    // Adobe draws no border at all if the last element is of
-	    // the wrong type.
-	    borderWidth = 0;
-	  }
-	  obj2.free();
-	}
-      }
-    }
-  }
-  obj1.free();
-  if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) {
-    if (obj1.arrayGet(0, &obj2)->isNum()) {
-      borderR = obj2.getNum();
-    }
-    obj1.free();
-    if (obj1.arrayGet(1, &obj2)->isNum()) {
-      borderG = obj2.getNum();
-    }
-    obj1.free();
-    if (obj1.arrayGet(2, &obj2)->isNum()) {
-      borderB = obj2.getNum();
-    }
-    obj1.free();
-  }
-  obj1.free();
-  borderStyle = new LinkBorderStyle(borderType, borderWidth,
-				    borderDash, borderDashLength,
-				    borderR, borderG, borderB);
-
   // look for destination
   if (!dict->lookup("Dest", &obj1)->isNull()) {
     action = LinkAction::parseDest(&obj1);
@@ -889,9 +768,6 @@
 }
 
 Link::~Link() {
-  if (borderStyle) {
-    delete borderStyle;
-  }
   if (action) {
     delete action;
   }

Index: Link.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Link.h,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -u -d -r1.3 -r1.3.2.1
--- Link.h	8 Oct 2006 20:38:47 -0000	1.3
+++ Link.h	6 Apr 2007 14:22:23 -0000	1.3.2.1
@@ -16,7 +16,6 @@
 #include "Object.h"
 
 class GooString;
-class UGooString;
 class Array;
 class Dict;
 class Sound;
@@ -137,13 +136,13 @@
   // Accessors.
   virtual LinkActionKind getKind() { return actionGoTo; }
   LinkDest *getDest() { return dest; }
-  UGooString *getNamedDest() { return namedDest; }
+  GooString *getNamedDest() { return namedDest; }
 
 private:
 
   LinkDest *dest;		// regular destination (NULL for remote
 				//   link with bad destination)
-  UGooString *namedDest;	// named destination (only one of dest and
+  GooString *namedDest;	// named destination (only one of dest and
 				//   and namedDest may be non-NULL)
 };
 
@@ -168,14 +167,14 @@
   virtual LinkActionKind getKind() { return actionGoToR; }
   GooString *getFileName() { return fileName; }
   LinkDest *getDest() { return dest; }
-  UGooString *getNamedDest() { return namedDest; }
+  GooString *getNamedDest() { return namedDest; }
 
 private:
 
   GooString *fileName;		// file name
   LinkDest *dest;		// regular destination (NULL for remote
 				//   link with bad destination)
-  UGooString *namedDest;	// named destination (only one of dest and
+  GooString *namedDest;	// named destination (only one of dest and
 				//   and namedDest may be non-NULL)
 };
 
@@ -333,42 +332,6 @@
 };
 
 //------------------------------------------------------------------------
-// LinkBorderStyle
-//------------------------------------------------------------------------
-
-enum LinkBorderType {
-  linkBorderSolid,
-  linkBorderDashed,
-  linkBorderEmbossed,
-  linkBorderEngraved,
-  linkBorderUnderlined
-};
-
-class LinkBorderStyle {
-public:
-
-  LinkBorderStyle(LinkBorderType typeA, double widthA,
-		  double *dashA, int dashLengthA,
-		  double rA, double gA, double bA);
-  ~LinkBorderStyle();
-
-  LinkBorderType getType() { return type; }
-  double getWidth() { return width; }
-  void getDash(double **dashA, int *dashLengthA)
-    { *dashA = dash; *dashLengthA = dashLength; }
-  void getColor(double *rA, double *gA, double *bA)
-    { *rA = r; *gA = g; *bA = b; }
-
-private:
-
-  LinkBorderType type;
-  double width;
-  double *dash;
-  int dashLength;
-  double r, g, b;
-};
-
-//------------------------------------------------------------------------
 // Link
 //------------------------------------------------------------------------
 
@@ -395,14 +358,10 @@
   void getRect(double *xa1, double *ya1, double *xa2, double *ya2)
     { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; }
 
-  // Get the border style info.
-  LinkBorderStyle *getBorderStyle() { return borderStyle; }
-
 private:
 
   double x1, y1;		// lower left corner
   double x2, y2;		// upper right corner
-  LinkBorderStyle *borderStyle;	// border style
   LinkAction *action;		// action
   GBool ok;			// is link valid?
 };

Index: Makefile.am
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Makefile.am,v
retrieving revision 1.29
retrieving revision 1.29.2.1
diff -u -d -r1.29 -r1.29.2.1
--- Makefile.am	4 Mar 2007 07:30:31 -0000	1.29
+++ Makefile.am	6 Apr 2007 14:22:23 -0000	1.29.2.1
@@ -138,6 +138,7 @@
 	PDFDoc.h		\
 	PDFDocEncoding.h	\
 	ProfileData.h		\
+	PreScanOutputDev.h	\
 	PSTokenizer.h		\
 	Stream-CCITT.h		\
 	Stream.h		\
@@ -155,7 +156,6 @@
 	PSOutputDev.h		\
 	TextOutputDev.h		\
 	SecurityHandler.h	\
-	UGooString.h		\
 	UTF8.h			\
 	XpdfPluginAPI.h		\
 	Sound.h			\
@@ -201,6 +201,7 @@
 	PDFDoc.cc 		\
 	PDFDocEncoding.cc	\
 	ProfileData.cc		\
+	PreScanOutputDev.cc \
 	PSTokenizer.cc		\
 	Stream.cc 		\
 	UnicodeMap.cc		\
@@ -211,7 +212,6 @@
 	PageLabelInfo.h		\
 	PageLabelInfo.cc	\
 	SecurityHandler.cc	\
-	UGooString.cc	 	\
 	Sound.cc		\
 	XpdfPluginAPI.cc
 

Index: Object.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Object.cc,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -u -d -r1.3 -r1.3.4.1
--- Object.cc	25 Feb 2006 12:30:30 -0000	1.3
+++ Object.cc	6 Apr 2007 14:22:23 -0000	1.3.4.1
@@ -18,7 +18,6 @@
 #include "Dict.h"
 #include "Error.h"
 #include "Stream.h"
-#include "UGooString.h"
 #include "XRef.h"
 
 //------------------------------------------------------------------------
@@ -185,7 +184,7 @@
   case objDict:
     fprintf(f, "<<");
     for (i = 0; i < dictGetLength(); ++i) {
-      fprintf(f, " /%s ", dictGetKey(i)->getCString());
+      fprintf(f, " /%s ", dictGetKey(i));
       dictGetValNF(i, &obj);
       obj.print(f);
       obj.free();
@@ -228,5 +227,7 @@
 	fprintf(f, "  %-20s: %6d\n", objTypeNames[i], numAlloc[i]);
     }
   }
+#else
+  (void)f;
 #endif
 }

Index: Object.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Object.h,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -d -r1.4 -r1.4.2.1
--- Object.h	24 Feb 2007 23:32:23 -0000	1.4
+++ Object.h	6 Apr 2007 14:22:23 -0000	1.4.2.1
@@ -23,7 +23,6 @@
 class Array;
 class Dict;
 class Stream;
-class UGooString;
 
 //------------------------------------------------------------------------
 // Ref
@@ -168,14 +167,12 @@
 
   // Dict accessors.
   int dictGetLength();
-  void dictAddOwnKeyVal(UGooString *key, Object *val);
-  void dictAdd(const UGooString &key, Object *val);
-  void dictAddOwnVal(const char *key, Object *val);
-  void dictSet(const UGooString &key, Object *val);
+  void dictAdd(char *key, Object *val);
+  void dictSet(char *key, Object *val);
   GBool dictIs(char *dictType);
-  Object *dictLookup(const UGooString &key, Object *obj);
-  Object *dictLookupNF(const UGooString &key, Object *obj);
-  UGooString *dictGetKey(int i);
+  Object *dictLookup(char *key, Object *obj);
+  Object *dictLookupNF(char *key, Object *obj);
+  char *dictGetKey(int i);
   Object *dictGetVal(int i, Object *obj);
   Object *dictGetValNF(int i, Object *obj);
 
@@ -246,16 +243,10 @@
 inline int Object::dictGetLength()
   { return dict->getLength(); }
 
-inline void Object::dictAdd(const UGooString &key, Object *val)
+inline void Object::dictAdd(char *key, Object *val)
   { dict->add(key, val); }
 
-inline void Object::dictAddOwnVal(const char *key, Object *val)
-  { dict->addOwnVal(key, val); }
-
-inline void Object::dictAddOwnKeyVal(UGooString *key, Object *val)
-  { dict->addOwnKeyVal(key, val); }
-
-inline void Object::dictSet(const UGooString &key, Object *val)
+inline void Object::dictSet(char *key, Object *val)
  	{ dict->set(key, val); }
 
 inline GBool Object::dictIs(char *dictType)
@@ -264,13 +255,13 @@
 inline GBool Object::isDict(char *dictType)
   { return type == objDict && dictIs(dictType); }
 
-inline Object *Object::dictLookup(const UGooString &key, Object *obj)
+inline Object *Object::dictLookup(char *key, Object *obj)
   { return dict->lookup(key, obj); }
 
-inline Object *Object::dictLookupNF(const UGooString &key, Object *obj)
+inline Object *Object::dictLookupNF(char *key, Object *obj)
   { return dict->lookupNF(key, obj); }
 
-inline UGooString *Object::dictGetKey(int i)
+inline char *Object::dictGetKey(int i)
   { return dict->getKey(i); }
 
 inline Object *Object::dictGetVal(int i, Object *obj)

Index: Outline.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Outline.cc,v
retrieving revision 1.5
retrieving revision 1.5.4.1
diff -u -d -r1.5 -r1.5.4.1
--- Outline.cc	18 Jan 2006 22:32:13 -0000	1.5
+++ Outline.cc	6 Apr 2007 14:22:23 -0000	1.5.4.1
@@ -18,7 +18,6 @@
 #include "Link.h"
 #include "PDFDocEncoding.h"
 #include "Outline.h"
-#include "UGooString.h"
 
 //------------------------------------------------------------------------
 

Index: OutputDev.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/OutputDev.cc,v
retrieving revision 1.4
retrieving revision 1.4.4.1
diff -u -d -r1.4 -r1.4.4.1
--- OutputDev.cc	4 Feb 2006 21:10:41 -0000	1.4
+++ OutputDev.cc	6 Apr 2007 14:22:23 -0000	1.4.4.1
@@ -56,6 +56,7 @@
   updateLineCap(state);
   updateMiterLimit(state);
   updateLineWidth(state);
+  updateStrokeAdjust(state);
   updateFillColorSpace(state);
   updateFillColor(state);
   updateStrokeColorSpace(state);
@@ -65,6 +66,7 @@
   updateStrokeOpacity(state);
   updateFillOverprint(state);
   updateStrokeOverprint(state);
+  updateTransfer(state);
   updateFont(state);
 }
 

Index: OutputDev.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/OutputDev.h,v
retrieving revision 1.5
retrieving revision 1.5.4.1
diff -u -d -r1.5 -r1.5.4.1
--- OutputDev.h	4 Feb 2006 21:10:41 -0000	1.5
+++ OutputDev.h	6 Apr 2007 14:22:23 -0000	1.5.4.1
@@ -21,14 +21,18 @@
 class GooHash;
 class GooString;
 class GfxState;
+struct GfxColor;
 class GfxColorSpace;
 class GfxImageColorMap;
 class GfxFunctionShading;
 class GfxAxialShading;
 class GfxRadialShading;
 class Stream;
+class Links;
 class Link;
 class Catalog;
+class Page;
+class Function;
 
 //------------------------------------------------------------------------
 // OutputDev
@@ -62,6 +66,10 @@
   // will be reduced to a series of other drawing operations.
   virtual GBool useShadedFills() { return gFalse; }
 
+  // Does this device use drawForm()?  If this returns false,
+  // form-type XObjects will be interpreted (i.e., unrolled).
+  virtual GBool useDrawForm() { return gFalse; }
+
   // Does this device use beginType3Char/endType3Char?  Otherwise,
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() = 0;
@@ -74,8 +82,20 @@
   // Set default transform matrix.
   virtual void setDefaultCTM(double *ctm);
 
+  // Check to see if a page slice should be displayed.  If this
+  // returns false, the page display is aborted.  Typically, an
+  // OutputDev will use some alternate means to display the page
+  // before returning false.
+  virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI,
+			       int rotate, GBool useMediaBox, GBool crop,
+			       int sliceX, int sliceY, int sliceW, int sliceH,
+			       GBool printing, Catalog * catalog,
+			       GBool (* abortCheckCbk)(void *data) = NULL,
+			       void * abortCheckCbkData = NULL)
+    { return gTrue; }
+
   // Start a page.
-  virtual void startPage(int /*pageNum*/, GfxState * /*state*/) {}
+  virtual void startPage(int pageNum, GfxState *state) {}
 
   // End a page.
   virtual void endPage() {}
@@ -92,9 +112,6 @@
   double *getDefCTM() { return defCTM; }
   double *getDefICTM() { return defICTM; }
 
-  //----- link borders
-  virtual void drawLink(Link * /*link*/, Catalog * /*catalog*/) {}
-
   //----- save/restore graphics state
   virtual void saveState(GfxState * /*state*/) {}
   virtual void restoreState(GfxState * /*state*/) {}
@@ -109,6 +126,7 @@
   virtual void updateLineCap(GfxState * /*state*/) {}
   virtual void updateMiterLimit(GfxState * /*state*/) {}
   virtual void updateLineWidth(GfxState * /*state*/) {}
+  virtual void updateStrokeAdjust(GfxState * /*state*/) {}
   virtual void updateFillColorSpace(GfxState * /*state*/) {}
   virtual void updateStrokeColorSpace(GfxState * /*state*/) {}
   virtual void updateFillColor(GfxState * /*state*/) {}
@@ -118,6 +136,7 @@
   virtual void updateStrokeOpacity(GfxState * /*state*/) {}
   virtual void updateFillOverprint(GfxState * /*state*/) {}
   virtual void updateStrokeOverprint(GfxState * /*state*/) {}
+  virtual void updateTransfer(GfxState * /*state*/) {}
 
   //----- update text state
   virtual void updateFont(GfxState * /*state*/) {}
@@ -139,14 +158,18 @@
 				 double * /*mat*/, double * /*bbox*/,
 				 int /*x0*/, int /*y0*/, int /*x1*/, int /*y1*/,
 				 double /*xStep*/, double /*yStep*/) {}
-  virtual void functionShadedFill(GfxState * /*state*/,
-				  GfxFunctionShading * /*shading*/) {}
-  virtual void axialShadedFill(GfxState * /*state*/, GfxAxialShading * /*shading*/) {}
-  virtual void radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/) {}
+  virtual GBool functionShadedFill(GfxState * /*state*/,
+				   GfxFunctionShading * /*shading*/)
+    { return gFalse; }
+  virtual GBool axialShadedFill(GfxState * /*state*/, GfxAxialShading * /*shading*/)
+    { return gFalse; }
+  virtual GBool radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/)
+    { return gFalse; }
 
   //----- path clipping
   virtual void clip(GfxState * /*state*/) {}
   virtual void eoClip(GfxState * /*state*/) {}
+  virtual void clipToStrokePath(GfxState * /*state*/) {}
 
   //----- text drawing
   virtual void beginStringOp(GfxState * /*state*/) {}
@@ -204,6 +227,9 @@
   virtual void type3D1(GfxState * /*state*/, double /*wx*/, double /*wy*/,
 		       double /*llx*/, double /*lly*/, double /*urx*/, double /*ury*/) {}
 
+  //----- form XObjects
+  virtual void drawForm(Ref /*id*/) {}
+
   //----- PostScript XObjects
   virtual void psXObject(Stream * /*psStream*/, Stream * /*level1Stream*/) {}
 
@@ -212,7 +238,25 @@
   virtual GooHash *getProfileHash() {return profileHash; }
   virtual GooHash *endProfile();
 
-  
+  //----- transparency groups and soft masks
+  virtual void beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/,
+				      GfxColorSpace * /*blendingColorSpace*/,
+				      GBool /*isolated*/, GBool /*knockout*/,
+				      GBool /*forSoftMask*/) {}
+  virtual void endTransparencyGroup(GfxState * /*state*/) {}
+  virtual void paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) {}
+  virtual void setSoftMask(GfxState * /*state*/, double * /*bbox*/, GBool /*alpha*/,
+			   Function * /*transferFunc*/, GfxColor * /*backdropColor*/) {}
+  virtual void clearSoftMask(GfxState * /*state*/) {}
+
+  //----- links
+  virtual void processLink(Link * /*link*/, Catalog * /*catalog*/) {}
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+  virtual GBool getVectorAntialias() { return gFalse; }
+  virtual void setVectorAntialias(GBool /*vaa*/) {}
+#endif
+
 private:
 
   double defCTM[6];		// default coordinate transform matrix

Index: PDFDoc.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/PDFDoc.cc,v
retrieving revision 1.10
retrieving revision 1.10.4.1
diff -u -d -r1.10 -r1.10.4.1
--- PDFDoc.cc	18 Jan 2006 22:32:13 -0000	1.10
+++ PDFDoc.cc	6 Apr 2007 14:22:23 -0000	1.10.4.1
@@ -38,7 +38,6 @@
 #include "Outline.h"
 #endif
 #include "PDFDoc.h"
-#include "UGooString.h"
 
 //------------------------------------------------------------------------
 
@@ -63,7 +62,6 @@
   str = NULL;
   xref = NULL;
   catalog = NULL;
-  links = NULL;
 #ifndef DISABLE_OUTLINE
   outline = NULL;
 #endif
@@ -121,7 +119,6 @@
   str = NULL;
   xref = NULL;
   catalog = NULL;
-  links = NULL;
 #ifndef DISABLE_OUTLINE
   outline = NULL;
 #endif
@@ -166,12 +163,15 @@
   ok = gFalse;
   errCode = errNone;
   guiData = guiDataA;
-  fileName = NULL;
+  if (strA->getFileName()) {
+    fileName = strA->getFileName()->copy();
+  } else {
+    fileName = NULL;
+  }
   file = NULL;
   str = strA;
   xref = NULL;
   catalog = NULL;
-  links = NULL;
 #ifndef DISABLE_OUTLINE
   outline = NULL;
 #endif
@@ -239,9 +239,6 @@
   if (fileName) {
     delete fileName;
   }
-  if (links) {
-    delete links;
-  }
 }
 
 
@@ -330,7 +327,8 @@
 			    secHdlr->getFileKey(),
 			    secHdlr->getFileKeyLength(),
 			    secHdlr->getEncVersion(),
-			    secHdlr->getEncRevision());
+			    secHdlr->getEncRevision(),
+			    secHdlr->getEncAlgorithm());
 	ret = gTrue;
       } else {
 	// authorization failed
@@ -349,36 +347,25 @@
   return ret;
 }
 
-void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI,
-			 int rotate, GBool useMediaBox, GBool crop, GBool doLinks,
+void PDFDoc::displayPage(OutputDev *out, int page,
+			 double hDPI, double vDPI, int rotate,
+			 GBool useMediaBox, GBool crop, GBool printing,
 			 GBool (*abortCheckCbk)(void *data),
 			 void *abortCheckCbkData,
                          GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
                          void *annotDisplayDecideCbkData) {
-  Page *p;
-
   if (globalParams->getPrintCommands()) {
     printf("***** page %d *****\n", page);
   }
-  p = catalog->getPage(page);
-  if (doLinks) {
-    if (links) {
-      delete links;
-    }
-    getLinks(p);
-    p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog,
-	       abortCheckCbk, abortCheckCbkData,
-               annotDisplayDecideCbk, annotDisplayDecideCbkData);
-  } else {
-    p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog,
-	       abortCheckCbk, abortCheckCbkData,
-               annotDisplayDecideCbk, annotDisplayDecideCbkData);
-  }
+  catalog->getPage(page)->display(out, hDPI, vDPI,
+				  rotate, useMediaBox, crop, printing, catalog,
+				  abortCheckCbk, abortCheckCbkData,
+				  annotDisplayDecideCbk, annotDisplayDecideCbkData);
 }
 
 void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
-			  double hDPI, double vDPI, int rotate, GBool useMediaBox,
-			  GBool crop, GBool doLinks,
+			  double hDPI, double vDPI, int rotate,
+			  GBool useMediaBox, GBool crop, GBool printing,
 			  GBool (*abortCheckCbk)(void *data),
 			  void *abortCheckCbkData,
                           GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
@@ -386,49 +373,34 @@
   int page;
 
   for (page = firstPage; page <= lastPage; ++page) {
-    displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks,
+    displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing,
 		abortCheckCbk, abortCheckCbkData,
                 annotDisplayDecideCbk, annotDisplayDecideCbkData);
   }
 }
 
 void PDFDoc::displayPageSlice(OutputDev *out, int page,
-			      double hDPI, double vDPI,
-			      int rotate, GBool useMediaBox, GBool crop, GBool doLinks,
+			      double hDPI, double vDPI, int rotate,
+			      GBool useMediaBox, GBool crop, GBool printing,
 			      int sliceX, int sliceY, int sliceW, int sliceH,
 			      GBool (*abortCheckCbk)(void *data),
 			      void *abortCheckCbkData,
                               GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
                               void *annotDisplayDecideCbkData) {
-  Page *p;
-
-  p = catalog->getPage(page);
-  if (doLinks)
-  {
-    if (links) {
-      delete links;
-    }
-    getLinks(p);
-    p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
-		  sliceX, sliceY, sliceW, sliceH,
-		  links, catalog,
-                  abortCheckCbk, abortCheckCbkData,
-                  annotDisplayDecideCbk, annotDisplayDecideCbkData);
-  } else {
-    p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
-                  sliceX, sliceY, sliceW, sliceH,
-	          NULL, catalog,
-	          abortCheckCbk, abortCheckCbkData,
-	          annotDisplayDecideCbk, annotDisplayDecideCbkData);
-  } 
+  catalog->getPage(page)->displaySlice(out, hDPI, vDPI,
+				       rotate, useMediaBox, crop,
+				       sliceX, sliceY, sliceW, sliceH,
+				       printing, catalog,
+				       abortCheckCbk, abortCheckCbkData,
+				       annotDisplayDecideCbk, annotDisplayDecideCbkData);
 }
 
-Links *PDFDoc::takeLinks() {
-  Links *ret;
-
-  ret = links;
-  links = NULL;
-  return ret;
+Links *PDFDoc::getLinks(int page) {
+  return catalog->getPage(page)->getLinks(catalog);
+}
+  
+void PDFDoc::processLinks(OutputDev *out, int page) {
+  catalog->getPage(page)->processLinks(out, catalog);
 }
 
 GBool PDFDoc::isLinearized() {
@@ -440,7 +412,8 @@
   obj1.initNull();
   parser = new Parser(xref,
 	     new Lexer(xref,
-	       str->makeSubStream(str->getStart(), gFalse, 0, &obj1)));
+	       str->makeSubStream(str->getStart(), gFalse, 0, &obj1)),
+	     gTrue);
   parser->getObj(&obj1);
   parser->getObj(&obj2);
   parser->getObj(&obj3);
@@ -477,10 +450,3 @@
   fclose(f);
   return gTrue;
 }
-
-void PDFDoc::getLinks(Page *page) {
-  Object obj;
-
-  links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
-  obj.free();
-}

Index: PDFDoc.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/PDFDoc.h,v
retrieving revision 1.7
retrieving revision 1.7.4.1
diff -u -d -r1.7 -r1.7.4.1
--- PDFDoc.h	18 Jan 2006 22:32:13 -0000	1.7
+++ PDFDoc.h	6 Apr 2007 14:22:23 -0000	1.7.4.1
@@ -87,8 +87,9 @@
   Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); }
 
   // Display a page.
-  void displayPage(OutputDev *out, int page, double hDPI, double vDPI,
-		   int rotate, GBool useMediaBox, GBool crop, GBool doLinks,
+  void displayPage(OutputDev *out, int page,
+		   double hDPI, double vDPI, int rotate,
+		   GBool useMediaBox, GBool crop, GBool printing,
 		   GBool (*abortCheckCbk)(void *data) = NULL,
 		   void *abortCheckCbkData = NULL,
                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
@@ -97,7 +98,7 @@
   // Display a range of pages.
   void displayPages(OutputDev *out, int firstPage, int lastPage,
 		    double hDPI, double vDPI, int rotate,
-		    GBool useMediaBox, GBool crop, GBool doLinks,
+		    GBool useMediaBox, GBool crop, GBool printing,
 		    GBool (*abortCheckCbk)(void *data) = NULL,
 		    void *abortCheckCbkData = NULL,
                     GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
@@ -105,8 +106,8 @@
 
   // Display part of a page.
   void displayPageSlice(OutputDev *out, int page,
-			double hDPI, double vDPI,
-			int rotate, GBool useMediaBox, GBool crop, GBool doLinks,
+			double hDPI, double vDPI, int rotate, 
+			GBool useMediaBox, GBool crop, GBool printing,
 			int sliceX, int sliceY, int sliceW, int sliceH,
 			GBool (*abortCheckCbk)(void *data) = NULL,
 			void *abortCheckCbkData = NULL,
@@ -119,13 +120,17 @@
 
   // Returns the links for the current page, transferring ownership to
   // the caller.
-  Links *takeLinks();
+  Links *getLinks(int page);
 
   // Find a named destination.  Returns the link destination, or
   // NULL if <name> is not a destination.
-  LinkDest *findDest(UGooString *name)
+  LinkDest *findDest(GooString *name)
     { return catalog->findDest(name); }
 
+  // Process the links for a page.
+  void processLinks(OutputDev *out, int page);
+
+
 #ifndef DISABLE_OUTLINE
   // Return the outline object.
   Outline *getOutline() { return outline; }
@@ -175,7 +180,6 @@
   GBool checkFooter();
   void checkHeader();
   GBool checkEncryption(GooString *ownerPassword, GooString *userPassword);
-  void getLinks(Page *page);
 
   GooString *fileName;
   FILE *file;
@@ -184,7 +188,6 @@
   double pdfVersion;
   XRef *xref;
   Catalog *catalog;
-  Links *links;
 #ifndef DISABLE_OUTLINE
   Outline *outline;
 #endif

Index: PSOutputDev.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/PSOutputDev.cc,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -u -d -r1.13 -r1.13.2.1
--- PSOutputDev.cc	24 Feb 2007 23:43:35 -0000	1.13
+++ PSOutputDev.cc	6 Apr 2007 14:22:23 -0000	1.13.2.1
@@ -34,14 +34,30 @@
 #include "Page.h"
 #include "Stream.h"
 #include "Annot.h"
+#include "XRef.h"
+#include "PreScanOutputDev.h"
+#if HAVE_SPLASH
+#  include "splash/Splash.h"
+#  include "splash/SplashBitmap.h"
+#  include "SplashOutputDev.h"
+#endif
 #include "PSOutputDev.h"
[...3947 lines suppressed...]
+    step = 2;
+  } else {
+    i = 0;
+    step = 1;
+  }
+  for (j = 0; i < s->getLength() && j < 200; i += step) {
+    c = s->getChar(i) & 0xff;
+    if (c == '\\') {
+      writePS("\\\\");
+      j += 2;
+    } else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) {
+      writePSFmt("\\{0:03o}", c);
+      j += 4;
+    } else {
+      writePSChar(c);
+      ++j;
+    }
+  }
+  writePS("\n");
+}

Index: PSOutputDev.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/PSOutputDev.h,v
retrieving revision 1.7
retrieving revision 1.7.4.1
diff -u -d -r1.7 -r1.7.4.1
--- PSOutputDev.h	1 Jun 2006 06:42:25 -0000	1.7
+++ PSOutputDev.h	6 Apr 2007 14:22:23 -0000	1.7.4.1
@@ -24,6 +24,7 @@
 class GfxColorSpace;
 class GfxSeparationColorSpace;
 class PDFRectangle;
+struct PSFont8Info;
 struct PSFont16Enc;
 class PSOutCustomColor;
 class Function;
@@ -93,7 +94,11 @@
   // radialShadedFill()?  If this returns false, these shaded fills
   // will be reduced to a series of other drawing operations.
   virtual GBool useShadedFills()
-    { return level == psLevel2 || level == psLevel3; }
+    { return level >= psLevel2; }
+
+  // Does this device use drawForm()?  If this returns false,
+  // form-type XObjects will be interpreted (i.e., unrolled).
+  virtual GBool useDrawForm() { return preload; }
 
   // Does this device use beginType3Char/endType3Char?  Otherwise,
   // text in Type 3 fonts will be drawn with drawChar/drawString.
@@ -120,6 +125,17 @@
 
   //----- initialization and control
 
+  // Check to see if a page slice should be displayed.  If this
+  // returns false, the page display is aborted.  Typically, an
+  // OutputDev will use some alternate means to display the page
+  // before returning false.
+  virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI,
+			       int rotate, GBool useMediaBox, GBool crop,
+			       int sliceX, int sliceY, int sliceW, int sliceH,
+			       GBool printing, Catalog *catalog,
+			       GBool (*abortCheckCbk)(void *data) = NULL,
+			       void *abortCheckCbkData = NULL);
+
   // Start a page.
   virtual void startPage(int pageNum, GfxState *state);
 
@@ -145,6 +161,7 @@
   virtual void updateStrokeColor(GfxState *state);
   virtual void updateFillOverprint(GfxState *state);
   virtual void updateStrokeOverprint(GfxState *state);
+  virtual void updateTransfer(GfxState *state);
 
   //----- update text state
   virtual void updateFont(GfxState *state);
@@ -166,14 +183,15 @@
 				 double *mat, double *bbox,
 				 int x0, int y0, int x1, int y1,
 				 double xStep, double yStep);
-  virtual void functionShadedFill(GfxState *state,
-				  GfxFunctionShading *shading);
-  virtual void axialShadedFill(GfxState *state, GfxAxialShading *shading);
-  virtual void radialShadedFill(GfxState *state, GfxRadialShading *shading);
+  virtual GBool functionShadedFill(GfxState *state,
+				   GfxFunctionShading *shading);
+  virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
+  virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
 
   //----- path clipping
   virtual void clip(GfxState *state);
   virtual void eoClip(GfxState *state);
+  virtual void clipToStrokePath(GfxState *state);
 
   //----- text drawing
   virtual void drawString(GfxState *state, GooString *s);
@@ -203,6 +221,9 @@
   virtual void type3D1(GfxState *state, double wx, double wy,
 		       double llx, double lly, double urx, double ury);
 
+  //----- form XObjects
+  virtual void drawForm(Ref ref);
+
   //----- PostScript XObjects
   virtual void psXObject(Stream *psStream, Stream *level1Stream);
 
@@ -236,15 +257,19 @@
   void setupEmbeddedType1Font(Ref *id, GooString *psName);
   void setupExternalType1Font(GooString *fileName, GooString *psName);
   void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GooString *psName);
+  void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GooString *psName);
   void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GooString *psName);
   GooString *setupExternalTrueTypeFont(GfxFont *font);
   void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GooString *psName);
   void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GooString *psName,
 				    GBool needVerticalMetrics);
+  void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GooString *psName);
   GooString *setupExternalCIDTrueTypeFont(GfxFont *font, GooString *fileName, int faceIndex = 0);
   void setupType3Font(GfxFont *font, GooString *psName, Dict *parentResDict);
   void setupImages(Dict *resDict);
   void setupImage(Ref id, Stream *str);
+  void setupForms(Dict *resDict);
+  void setupForm(Ref id, Object *strObj);
   void addProcessColor(double c, double m, double y, double k);
   void addCustomColor(GfxSeparationColorSpace *sepCS);
   void doPath(GfxPath *path);
@@ -259,8 +284,14 @@
 		 Stream *str, int width, int height, int len,
 		 int *maskColors, Stream *maskStr,
 		 int maskWidth, int maskHeight, GBool maskInvert);
+  void doImageL3(Object *ref, GfxImageColorMap *colorMap,
+		 GBool invert, GBool inlineImg,
+		 Stream *str, int width, int height, int len,
+		 int *maskColors, Stream *maskStr,
+		 int maskWidth, int maskHeight, GBool maskInvert);
   void dumpColorSpaceL2(GfxColorSpace *colorSpace,
-			GBool genXform, GBool updateColors);
+			GBool genXform, GBool updateColors,
+			GBool map01);
 #if OPI_SUPPORT
   void opiBegin20(GfxState *state, Dict *dict);
   void opiBegin13(GfxState *state, Dict *dict);
@@ -271,10 +302,11 @@
   void cvtFunction(Function *func);
   void writePSChar(char c);
   void writePS(char *s);
-  void writePSFmt(const char *fmt, ...) GCC_PRINTF_FORMAT(2, 3);
+  void writePSFmt(const char *fmt, ...);
   void writePSString(GooString *s);
   void writePSName(char *s);
   GooString *filterPSName(GooString *name);
+  void writePSTextLine(GooString *s);
 
   PSLevel level;		// PostScript level (1, 2, separation)
   PSOutMode mode;		// PostScript mode (PS, EPS, form)
@@ -282,6 +314,8 @@
   int paperHeight;		// height of paper, in pts
   int imgLLX, imgLLY,		// imageable area, in pts
       imgURX, imgURY;
+  GBool preload;		// load all images into memory, and
+				//   predefine forms
 
   PSOutputFunc outputFunc;
   void *outputStream;
@@ -307,9 +341,18 @@
   int fontFileNameSize;		// size of fontFileNames array
   int nextTrueTypeNum;		// next unique number to append to a TrueType
 				//   font name
+  PSFont8Info *font8Info;	// info for 8-bit fonts
+  int font8InfoLen;		// number of entries in font8Info array
+  int font8InfoSize;		// size of font8Info array
   PSFont16Enc *font16Enc;	// encodings for substitute 16-bit fonts
   int font16EncLen;		// number of entries in font16Enc array
   int font16EncSize;		// size of font16Enc array
+  Ref *imgIDs;			// list of image IDs for in-memory images
+  int imgIDLen;			// number of entries in imgIDs array
+  int imgIDSize;		// size of imgIDs array
+  Ref *formIDs;			// list of IDs for predefined forms
+  int formIDLen;		// number of entries in formIDs array
+  int formIDSize;		// size of formIDs array
   GooList *xobjStack;		// stack of XObject dicts currently being
 				//   processed
   int numSaves;			// current number of gsaves
@@ -341,6 +384,7 @@
   double t3WX, t3WY,		// Type 3 character parameters
          t3LLX, t3LLY, t3URX, t3URY;
   GBool t3Cacheable;		// cleared if char is not cacheable
+  GBool t3NeedsRestore;		// set if a 'q' operator was issued
 
 #if OPI_SUPPORT
   int opi13Nest;		// nesting level of OPI 1.3 objects

Index: PSTokenizer.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/PSTokenizer.cc,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -d -r1.2 -r1.2.2.1
--- PSTokenizer.cc	23 Dec 2006 13:12:14 -0000	1.2
+++ PSTokenizer.cc	6 Apr 2007 14:22:23 -0000	1.2.2.1
@@ -98,7 +98,7 @@
   } else if (c == '<') {
     while ((c = lookChar()) != EOF) {
       consumeChar();
-      if (i < size) {
+      if (i < size && specialChars[c] != 1) {
 	buf[i++] = c;
       }
       if (c == '>') {

Index: Page.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Page.cc,v
retrieving revision 1.17
retrieving revision 1.17.2.1
diff -u -d -r1.17 -r1.17.2.1
--- Page.cc	7 Mar 2007 19:15:32 -0000	1.17
+++ Page.cc	6 Apr 2007 14:22:23 -0000	1.17.2.1
@@ -2,7 +2,7 @@
 //
 // Page.cc
 //
-// Copyright 1996-2003 Glyph & Cog, LLC
+// Copyright 1996-2007 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -30,10 +30,37 @@
 #endif
 #include "Error.h"
 #include "Page.h"
-#include "UGooString.h"
+#include "Catalog.h"
 #include "Form.h"
 
 //------------------------------------------------------------------------
+// PDFRectangle
+//------------------------------------------------------------------------
+
+void PDFRectangle::clipTo(PDFRectangle *rect) {
+  if (x1 < rect->x1) {
+    x1 = rect->x1;
+  } else if (x1 > rect->x2) {
+    x1 = rect->x2;
+  }
+  if (x2 < rect->x1) {
+    x2 = rect->x1;
+  } else if (x2 > rect->x2) {
+    x2 = rect->x2;
+  }
+  if (y1 < rect->y1) {
+    y1 = rect->y1;
+  } else if (y1 > rect->y2) {
+    y1 = rect->y2;
+  }
+  if (y2 < rect->y1) {
+    y2 = rect->y1;
+  } else if (y2 > rect->y2) {
+    y2 = rect->y2;
+  }
+}
+
+//------------------------------------------------------------------------
 // PageAttrs
 //------------------------------------------------------------------------
 
@@ -96,6 +123,12 @@
   artBox = cropBox;
   readBox(dict, "ArtBox", &artBox);
 
+  // clip all other boxes to the media box
+  cropBox.clipTo(&mediaBox);
+  bleedBox.clipTo(&mediaBox);
+  trimBox.clipTo(&mediaBox);
+  artBox.clipTo(&mediaBox);
+
   // rotate
   dict->lookup("Rotate", &obj1);
   if (obj1.isInt()) {
@@ -280,14 +313,23 @@
   contents.free();
 }
 
+Links *Page::getLinks(Catalog *catalog) {
+  Links *links;
+  Object obj;
+
+  links = new Links(getAnnots(&obj), catalog->getBaseURI());
+  obj.free();
+  return links;
+}
+
 void Page::display(OutputDev *out, double hDPI, double vDPI,
 		   int rotate, GBool useMediaBox, GBool crop,
-		   Links *links, Catalog *catalog,
+		   GBool printing, Catalog *catalog,
 		   GBool (*abortCheckCbk)(void *data),
 		   void *abortCheckCbkData,
                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
                    void *annotDisplayDecideCbkData) {
-  displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, links, catalog,
+  displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing, catalog,
 	       abortCheckCbk, abortCheckCbkData,
                annotDisplayDecideCbk, annotDisplayDecideCbkData);
 }
@@ -295,15 +337,14 @@
 Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
 		     int rotate, GBool useMediaBox, GBool crop,
 		     int sliceX, int sliceY, int sliceW, int sliceH,
-		     Links *links, Catalog *catalog,
+		     GBool printing, Catalog *catalog,
 		     GBool (*abortCheckCbk)(void *data),
 		     void *abortCheckCbkData,
 		     GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
 		     void *annotDisplayDecideCbkData) {
-  PDFRectangle *mediaBox, *cropBox, *baseBox;
+  PDFRectangle *mediaBox, *cropBox;
   PDFRectangle box;
   Gfx *gfx;
-  double kx, ky;
 
   rotate += getRotate();
   if (rotate >= 360) {
@@ -312,59 +353,9 @@
     rotate += 360;
   }
 
-  mediaBox = getMediaBox();
+  makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
+	  sliceX, sliceY, sliceW, sliceH, &box, &crop);
   cropBox = getCropBox();
-  if (sliceW >= 0 && sliceH >= 0) {
-    baseBox =  useMediaBox ? mediaBox : cropBox;
-    kx = 72.0 / hDPI;
-    ky = 72.0 / vDPI;
-    if (rotate == 90) {
-      if (out->upsideDown()) {
-	box.x1 = baseBox->x1 + ky * sliceY;
-	box.x2 = baseBox->x1 + ky * (sliceY + sliceH);
-      } else {
-	box.x1 = baseBox->x2 - ky * (sliceY + sliceH);
-	box.x2 = baseBox->x2 - ky * sliceY;
-      }
-      box.y1 = baseBox->y1 + kx * sliceX;
-      box.y2 = baseBox->y1 + kx * (sliceX + sliceW);
-    } else if (rotate == 180) {
-      box.x1 = baseBox->x2 - kx * (sliceX + sliceW);
-      box.x2 = baseBox->x2 - kx * sliceX;
-      if (out->upsideDown()) {
-	box.y1 = baseBox->y1 + ky * sliceY;
-	box.y2 = baseBox->y1 + ky * (sliceY + sliceH);
-      } else {
-	box.y1 = baseBox->y2 - ky * (sliceY + sliceH);
-	box.y2 = baseBox->y2 - ky * sliceY;
-      }
-    } else if (rotate == 270) {
-      if (out->upsideDown()) {
-	box.x1 = baseBox->x2 - ky * (sliceY + sliceH);
-	box.x2 = baseBox->x2 - ky * sliceY;
-      } else {
-	box.x1 = baseBox->x1 + ky * sliceY;
-	box.x2 = baseBox->x1 + ky * (sliceY + sliceH);
-      }
-      box.y1 = baseBox->y2 - kx * (sliceX + sliceW);
-      box.y2 = baseBox->y2 - kx * sliceX;
-    } else {
-      box.x1 = baseBox->x1 + kx * sliceX;
-      box.x2 = baseBox->x1 + kx * (sliceX + sliceW);
-      if (out->upsideDown()) {
-	box.y1 = baseBox->y2 - ky * (sliceY + sliceH);
-	box.y2 = baseBox->y2 - ky * sliceY;
-      } else {
-	box.y1 = baseBox->y1 + ky * sliceY;
-	box.y2 = baseBox->y1 + ky * (sliceY + sliceH);
-      }
-    }
-  } else if (useMediaBox) {
-    box = *mediaBox;
-  } else {
-    box = *cropBox;
-    crop = gFalse;
-  }
 
   if (globalParams->getPrintCommands()) {
     printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
@@ -384,20 +375,27 @@
 void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
 			int rotate, GBool useMediaBox, GBool crop,
 			int sliceX, int sliceY, int sliceW, int sliceH,
-			Links *links, Catalog *catalog,
+			GBool printing, Catalog *catalog,
 			GBool (*abortCheckCbk)(void *data),
 			void *abortCheckCbkData,
                         GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
                         void *annotDisplayDecideCbkData) {
   Gfx *gfx;
   Object obj;
-  Link *link;
   Annots *annotList;
+  Dict *acroForm;
   int i;
+  
+  if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
+			   sliceX, sliceY, sliceW, sliceH,
+			   printing, catalog,
+			   abortCheckCbk, abortCheckCbkData)) {
+    return;
+  }
 
   gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
 		  sliceX, sliceY, sliceW, sliceH,
-		  links, catalog,
+		  printing, catalog,
 		  abortCheckCbk, abortCheckCbkData,
 		  annotDisplayDecideCbk, annotDisplayDecideCbkData);
 
@@ -409,20 +407,21 @@
   }
   obj.free();
 
-  // draw links
-  if (links) {
-    gfx->saveState();
-    for (i = 0; i < links->getNumLinks(); ++i) {
-      link = links->getLink(i);
-      out->drawLink(link, catalog);
-    }
-    gfx->restoreState();
-    out->dump();
-  }
 
-  // draw non-link annotations
-  annotList = new Annots(xref, catalog, annots.fetch(xref, &obj));
+  // draw annotations
+  annotList = new Annots(xref, catalog, getAnnots(&obj));
   obj.free();
+  acroForm = catalog->getAcroForm()->isDict() ?
+               catalog->getAcroForm()->getDict() : NULL;
+  if (acroForm) {
+    if (acroForm->lookup("NeedAppearances", &obj)) {
+      if (obj.isBool() && obj.getBool()) {
+#warning Annot is broken FIXME!
+//	annotList->generateAppearances(acroForm);
+      }
+    }
+    obj.free();
+  }
   if (annotList->getNumAnnots() > 0) {
     if (globalParams->getPrintCommands()) {
       printf("***** Annotations\n");
@@ -432,7 +431,8 @@
         if ((annotDisplayDecideCbk &&
              (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) || 
             !annotDisplayDecideCbk) {
-          annot->draw(gfx); 
+#warning Annot is broken FIXME!
+//           annotList->getAnnot(i)->draw(gfx, printing);
     }
     }
     out->dump();
@@ -560,8 +560,81 @@
   return success;
 }
 
+void Page::makeBox(double hDPI, double vDPI, int rotate,
+		   GBool useMediaBox, GBool upsideDown,
+		   double sliceX, double sliceY, double sliceW, double sliceH,
+		   PDFRectangle *box, GBool *crop) {
+  PDFRectangle *mediaBox, *cropBox, *baseBox;
+  double kx, ky;
+
+  mediaBox = getMediaBox();
+  cropBox = getCropBox();
+  if (sliceW >= 0 && sliceH >= 0) {
+    baseBox = useMediaBox ? mediaBox : cropBox;
+    kx = 72.0 / hDPI;
+    ky = 72.0 / vDPI;
+    if (rotate == 90) {
+      if (upsideDown) {
+	box->x1 = baseBox->x1 + ky * sliceY;
+	box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
+      } else {
+	box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
+	box->x2 = baseBox->x2 - ky * sliceY;
+      }
+      box->y1 = baseBox->y1 + kx * sliceX;
+      box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
+    } else if (rotate == 180) {
+      box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
+      box->x2 = baseBox->x2 - kx * sliceX;
+      if (upsideDown) {
+	box->y1 = baseBox->y1 + ky * sliceY;
+	box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
+      } else {
+	box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
+	box->y2 = baseBox->y2 - ky * sliceY;
+      }
+    } else if (rotate == 270) {
+      if (upsideDown) {
+	box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
+	box->x2 = baseBox->x2 - ky * sliceY;
+      } else {
+	box->x1 = baseBox->x1 + ky * sliceY;
+	box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
+      }
+      box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
+      box->y2 = baseBox->y2 - kx * sliceX;
+    } else {
+      box->x1 = baseBox->x1 + kx * sliceX;
+      box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
+      if (upsideDown) {
+	box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
+	box->y2 = baseBox->y2 - ky * sliceY;
+      } else {
+	box->y1 = baseBox->y1 + ky * sliceY;
+	box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
+      }
+    }
+  } else if (useMediaBox) {
+    *box = *mediaBox;
+  } else {
+    *box = *cropBox;
+    *crop = gFalse;
+  }
+}
+
+void Page::processLinks(OutputDev *out, Catalog *catalog) {
+  Links *links;
+  int i;
+
+  links = getLinks(catalog);
+  for (i = 0; i < links->getNumLinks(); ++i) {
+    out->processLink(links->getLink(i), catalog);
+  }
+  delete links;
+}
+
 void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
-			 int rotate, GBool upsideDown) {
+			 int rotate, GBool useMediaBox, GBool upsideDown) {
   GfxState *state;
   int i;
   rotate += getRotate();
@@ -570,7 +643,9 @@
   } else if (rotate < 0) {
     rotate += 360;
   }
-  state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown);
+  state = new GfxState(hDPI, vDPI,
+		       useMediaBox ? getMediaBox() : getCropBox(),
+		       rotate, upsideDown);
   for (i = 0; i < 6; ++i) {
     ctm[i] = state->getCTM()[i];
   }

Index: Page.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Page.h,v
retrieving revision 1.8
retrieving revision 1.8.2.1
diff -u -d -r1.8 -r1.8.2.1
--- Page.h	24 Feb 2007 23:32:23 -0000	1.8
+++ Page.h	6 Apr 2007 14:22:23 -0000	1.8.2.1
@@ -36,6 +36,7 @@
   PDFRectangle(double x1A, double y1A, double x2A, double y2A)
     { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; }
   GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; }
+  void clipTo(PDFRectangle *rect);
 };
 
 //------------------------------------------------------------------------
@@ -115,6 +116,7 @@
   GBool isOk() { return ok; }
 
   // Get page parameters.
+  int getNum() { return num; }
   PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
   PDFRectangle *getCropBox() { return attrs->getCropBox(); }
   GBool isCropped() { return attrs->isCropped(); }
@@ -143,6 +145,9 @@
   // Get annotations array.
   Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); }
 
+  // Return a list of links.
+  Links *getLinks(Catalog *catalog);
+
   // Get contents.
   Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
 
@@ -167,7 +172,7 @@
   Gfx *createGfx(OutputDev *out, double hDPI, double vDPI,
 		 int rotate, GBool useMediaBox, GBool crop,
 		 int sliceX, int sliceY, int sliceW, int sliceH,
-		 Links *links, Catalog *catalog,
+		 GBool printing, Catalog *catalog,
 		 GBool (*abortCheckCbk)(void *data),
 		 void *abortCheckCbkData,
 		 GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
@@ -176,7 +181,7 @@
   // Display a page.
   void display(OutputDev *out, double hDPI, double vDPI,
 	       int rotate, GBool useMediaBox, GBool crop,
-	       Links *links, Catalog *catalog,
+	       GBool printing, Catalog *catalog,
 	       GBool (*abortCheckCbk)(void *data) = NULL,
 	       void *abortCheckCbkData = NULL,
                GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
@@ -186,17 +191,24 @@
   void displaySlice(OutputDev *out, double hDPI, double vDPI,
 		    int rotate, GBool useMediaBox, GBool crop,
 		    int sliceX, int sliceY, int sliceW, int sliceH,
-		    Links *links, Catalog *catalog,
+		    GBool printing, Catalog *catalog,
 		    GBool (*abortCheckCbk)(void *data) = NULL,
 		    void *abortCheckCbkData = NULL,
                     GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
                     void *annotDisplayDecideCbkData = NULL);
 
   void display(Gfx *gfx);
-  
+
+  void makeBox(double hDPI, double vDPI, int rotate,
+	       GBool useMediaBox, GBool upsideDown,
+	       double sliceX, double sliceY, double sliceW, double sliceH,
+	       PDFRectangle *box, GBool *crop);
+
+  void processLinks(OutputDev *out, Catalog *catalog);
+
   // Get the page's default CTM.
   void getDefaultCTM(double *ctm, double hDPI, double vDPI,
-		     int rotate, GBool upsideDown);
+		     int rotate, GBool useMediaBox, GBool upsideDown);
 
 private:
 

Index: PageLabelInfo.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/PageLabelInfo.cc,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -d -r1.7 -r1.7.2.1
--- PageLabelInfo.cc	28 Dec 2006 15:51:44 -0000	1.7
+++ PageLabelInfo.cc	6 Apr 2007 14:22:23 -0000	1.7.2.1
@@ -3,7 +3,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <assert.h>
-#include "UGooString.h"
 
 #include "PageLabelInfo.h"
 

Index: Parser.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Parser.cc,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -d -r1.7 -r1.7.2.1
--- Parser.cc	28 Dec 2006 15:51:44 -0000	1.7
+++ Parser.cc	6 Apr 2007 14:22:23 -0000	1.7.2.1
@@ -16,16 +16,16 @@
 #include "Object.h"
 #include "Array.h"
 #include "Dict.h"
+#include "Decrypt.h"
 #include "Parser.h"
 #include "XRef.h"
 #include "Error.h"
-#include "Decrypt.h"
-#include "UGooString.h"
 
-Parser::Parser(XRef *xrefA, Lexer *lexerA) {
+Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) {
   xref = xrefA;
   lexer = lexerA;
   inlineImg = 0;
+  allowStreams = allowStreamsA;
   lexer->getObj(&buf1);
   lexer->getObj(&buf2);
 }
@@ -36,17 +36,16 @@
   delete lexer;
 }
 
-Object *Parser::getObj(Object *obj,
-		       Guchar *fileKey, int keyLength,
+Object *Parser::getObj(Object *obj, Guchar *fileKey,
+		       CryptAlgorithm encAlgorithm, int keyLength,
 		       int objNum, int objGen) {
-  UGooString key;
+  char *key;
   Stream *str;
   Object obj2;
   int num;
-  Decrypt *decrypt;
-  GooString *s;
-  char *p;
-  int i;
+  DecryptStream *decrypt;
+  GooString *s, *s2;
+  int c;
 
   // refill buffer after inline image data
   if (inlineImg == 2) {
@@ -62,7 +61,8 @@
     shift();
     obj->initArray(xref);
     while (!buf1.isCmd("]") && !buf1.isEOF())
-      obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen));
+      obj->arrayAdd(getObj(&obj2, fileKey, encAlgorithm, keyLength,
+			   objNum, objGen));
     if (buf1.isEOF())
       error(getPos(), "End of file inside array");
     shift();
@@ -77,23 +77,23 @@
 	shift();
       } else {
 	// buf1 might go away in shift(), so construct the key
-	key.Set(buf1.getName());
+	key = copyString(buf1.getName());
 	shift();
 	if (buf1.isEOF() || buf1.isError()) {
+	  gfree(key);
 	  break;
 	}
-	obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
+	obj->dictAdd(key, getObj(&obj2, fileKey, encAlgorithm, keyLength, objNum, objGen));
       }
     }
     if (buf1.isEOF())
       error(getPos(), "End of file inside dictionary");
-    if (buf2.isCmd("stream")) {
-      if ((str = makeStream(obj))) {
+    // stream objects are not allowed inside content streams or
+    // object streams
+    if (allowStreams && buf2.isCmd("stream")) {
+      if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength,
+			    objNum, objGen))) {
 	obj->initStream(str);
-	if (fileKey) {
-	  str->getBaseStream()->doDecryption(fileKey, keyLength,
-					     objNum, objGen);
-	}
       } else {
 	obj->free();
 	obj->initError();
@@ -116,15 +116,19 @@
 
   // string
   } else if (buf1.isString() && fileKey) {
-    buf1.copy(obj);
-    s = obj->getString();
-    decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
-    for (i = 0, p = obj->getString()->getCString();
-      i < s->getLength();
-      ++i, ++p) {
-      *p = decrypt->decryptByte(*p);
+    s = buf1.getString();
+    s2 = new GooString();
+    obj2.initNull();
+    decrypt = new DecryptStream(new MemStream(s->getCString(), 0,
+					      s->getLength(), &obj2),
+				fileKey, encAlgorithm, keyLength,
+				objNum, objGen);
+    decrypt->reset();
+    while ((c = decrypt->getChar()) != EOF) {
+      s2->append((char)c);
     }
     delete decrypt;
+    obj->initString(s2);
     shift();
 
   // simple object
@@ -140,7 +144,9 @@
   return obj;
 }
 
-Stream *Parser::makeStream(Object *dict) {
+Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
+			   CryptAlgorithm encAlgorithm, int keyLength,
+			   int objNum, int objGen) {
   Object obj;
   BaseStream *baseStr;
   Stream *str;
@@ -196,6 +202,12 @@
   // make base stream
   str = baseStr->makeSubStream(pos, gTrue, length, dict);
 
+  // handle decryption
+  if (fileKey) {
+    str = new DecryptStream(str, fileKey, encAlgorithm, keyLength,
+			    objNum, objGen);
+  }
+
   // get filters
   str = str->addFilters(dict);
 

Index: Parser.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Parser.h,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -u -d -r1.3 -r1.3.4.1
--- Parser.h	17 Jan 2006 21:35:31 -0000	1.3
+++ Parser.h	6 Apr 2007 14:22:23 -0000	1.3.4.1
@@ -23,14 +23,14 @@
 public:
 
   // Constructor.
-  Parser(XRef *xrefA, Lexer *lexerA);
+  Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA);
 
   // Destructor.
   ~Parser();
 
   // Get the next object from the input stream.
-  Object *getObj(Object *obj,
-		 Guchar *fileKey = NULL, int keyLength = 0,
+  Object *getObj(Object *obj, Guchar *fileKey = NULL,
+		 CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0,
 		 int objNum = 0, int objGen = 0);
 
   // Get stream.
@@ -43,10 +43,13 @@
 
   XRef *xref;			// the xref table for this PDF file
   Lexer *lexer;			// input stream
+  GBool allowStreams;		// parse stream objects?
   Object buf1, buf2;		// next two tokens
   int inlineImg;		// set when inline image data is encountered
 
-  Stream *makeStream(Object *dict);
+  Stream *makeStream(Object *dict, Guchar *fileKey,
+		     CryptAlgorithm encAlgorithm, int keyLength,
+		     int objNum, int objGen);
   void shift(int objNum = -1);
 };
 

Index: SecurityHandler.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/SecurityHandler.cc,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -d -r1.2 -r1.2.4.1
--- SecurityHandler.cc	18 Jan 2006 22:32:13 -0000	1.2
+++ SecurityHandler.cc	6 Apr 2007 14:22:23 -0000	1.2.4.1
@@ -26,7 +26,6 @@
 #  include "XpdfPluginAPI.h"
 #endif
 #include "SecurityHandler.h"
-#include "UGooString.h"
 
 //------------------------------------------------------------------------
 // SecurityHandler
@@ -35,7 +34,9 @@
 SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
   Object filterObj;
   SecurityHandler *secHdlr;
+#ifdef ENABLE_PLUGINS
   XpdfSecurityHandler *xsh;
+#endif
 
   encryptDictA->dictLookup("Filter", &filterObj);
   if (filterObj.isName("Standard")) {
@@ -152,6 +153,7 @@
       permObj.isInt()) {
     encVersion = versionObj.getInt();
     encRevision = revisionObj.getInt();
+    encAlgorithm = cryptRC4;
     // revision 2 forces a 40-bit key - some buggy PDF generators
     // set the Length value incorrectly
     if (encRevision == 2 || !lengthObj.isInt()) {
@@ -171,7 +173,8 @@
 	  !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
 	if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
 				       &cryptFilterObj)->isDict()) {
-	  if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) {
+	  cryptFilterObj.dictLookup("CFM", &cfmObj);
+	  if (cfmObj.isName("V2")) {
 	    encVersion = 2;
 	    encRevision = 3;
 	    if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) {
@@ -179,6 +182,15 @@
 	      fileKeyLength = cfLengthObj.getInt();
 	    }
 	    cfLengthObj.free();
+	  } else if (cfmObj.isName("AESV2")) {
+	    encVersion = 2;
+	    encRevision = 3;
+	    encAlgorithm = cryptAES;
+	    if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) {
+	      //~ according to the spec, this should be cfLengthObj / 8
+	      fileKeyLength = cfLengthObj.getInt();
+	    }
+	    cfLengthObj.free();
 	  }
 	  cfmObj.free();
 	}
@@ -311,6 +323,7 @@
 {
   encryptDictA->copy(&encryptDict);
   xsh = xshA;
+  encAlgorithm = cryptRC4; //~ this should be obtained via getKey
   ok = gFalse;
 
   if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA,

Index: SecurityHandler.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/SecurityHandler.h,v
retrieving revision 1.1
retrieving revision 1.1.4.1
diff -u -d -r1.1 -r1.1.4.1
--- SecurityHandler.h	16 Sep 2005 18:29:18 -0000	1.1
+++ SecurityHandler.h	6 Apr 2007 14:22:23 -0000	1.1.4.1
@@ -75,6 +75,7 @@
   virtual int getFileKeyLength() = 0;
   virtual int getEncVersion() = 0;
   virtual int getEncRevision() = 0;
+  virtual CryptAlgorithm getEncAlgorithm() = 0;
 
 protected:
 
@@ -102,6 +103,7 @@
   virtual int getFileKeyLength() { return fileKeyLength; }
   virtual int getEncVersion() { return encVersion; }
   virtual int getEncRevision() { return encRevision; }
+  virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; }
 
 private:
 
@@ -112,6 +114,7 @@
   int encVersion;
   int encRevision;
   GBool encryptMetadata;
+  CryptAlgorithm encAlgorithm;
 
   GooString *ownerKey, *userKey;
   GooString *fileID;
@@ -140,6 +143,7 @@
   virtual Guchar *getFileKey() { return fileKey; }
   virtual int getFileKeyLength() { return fileKeyLength; }
   virtual int getEncVersion() { return encVersion; }
+  virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; }
 
 private:
 
@@ -150,6 +154,7 @@
   Guchar fileKey[16];
   int fileKeyLength;
   int encVersion;
+  CryptAlgorithm encAlgorithm;
   GBool ok;
 };
 #endif // ENABLE_PLUGINS

Index: SplashOutputDev.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/SplashOutputDev.cc,v
retrieving revision 1.12
retrieving revision 1.12.2.1
diff -u -d -r1.12 -r1.12.2.1
--- SplashOutputDev.cc	19 Dec 2006 20:27:55 -0000	1.12
+++ SplashOutputDev.cc	6 Apr 2007 14:22:23 -0000	1.12.2.1
@@ -37,6 +37,19 @@
 #include "splash/Splash.h"
 #include "SplashOutputDev.h"
 
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+
[...2325 lines suppressed...]
   ret = bitmap;
-  bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, bitmapTopDown);
+  bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
+			    colorMode != splashModeMono1, bitmapTopDown);
   return ret;
 }
 
@@ -2508,3 +2699,12 @@
 #endif
 }
 
+#if 1 //~tmp: turn off anti-aliasing temporarily
+GBool SplashOutputDev::getVectorAntialias() {
+  return splash->getVectorAntialias();
+}
+
+void SplashOutputDev::setVectorAntialias(GBool vaa) {
+  splash->setVectorAntialias(vaa);
+}
+#endif

Index: SplashOutputDev.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/SplashOutputDev.h,v
retrieving revision 1.4
retrieving revision 1.4.4.1
diff -u -d -r1.4 -r1.4.4.1
--- SplashOutputDev.h	30 Oct 2005 20:29:05 -0000	1.4
+++ SplashOutputDev.h	6 Apr 2007 14:22:23 -0000	1.4.4.1
@@ -29,6 +29,7 @@
 class T3FontCache;
 struct T3FontCacheTag;
 struct T3GlyphStack;
+struct SplashTransparencyGroup;
 
 //------------------------------------------------------------------------
 
@@ -72,9 +73,6 @@
   // End a page.
   virtual void endPage();
 
-  //----- link borders
-  virtual void drawLink(Link *link, Catalog *catalog);
-
   //----- save/restore graphics state
   virtual void saveState(GfxState *state);
   virtual void restoreState(GfxState *state);
@@ -89,6 +87,7 @@
   virtual void updateLineCap(GfxState *state);
   virtual void updateMiterLimit(GfxState *state);
   virtual void updateLineWidth(GfxState *state);
+  virtual void updateStrokeAdjust(GfxState *state);
   virtual void updateFillColor(GfxState *state);
   virtual void updateStrokeColor(GfxState *state);
   virtual void updateBlendMode(GfxState *state);
@@ -106,6 +105,7 @@
   //----- path clipping
   virtual void clip(GfxState *state);
   virtual void eoClip(GfxState *state);
+  virtual void clipToStrokePath(GfxState *state);
 
   //----- text drawing
   virtual void drawChar(GfxState *state, double x, double y,
@@ -142,6 +142,17 @@
   virtual void type3D1(GfxState *state, double wx, double wy,
 		       double llx, double lly, double urx, double ury);
 
+  //----- transparency groups and soft masks
+  virtual void beginTransparencyGroup(GfxState *state, double *bbox,
+				      GfxColorSpace *blendingColorSpace,
+				      GBool isolated, GBool knockout,
+				      GBool forSoftMask);
+  virtual void endTransparencyGroup(GfxState *state);
+  virtual void paintTransparencyGroup(GfxState *state, double *bbox);
+  virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha,
+			   Function *transferFunc, GfxColor *backdropColor);
+  virtual void clearSoftMask(GfxState *state);
+
   //----- special access
 
   // Called to indicate that a new PDF document has been loaded.
@@ -175,28 +186,39 @@
 
   SplashFont *getCurrentFont() { return font; }
 
+#if 1 //~tmp: turn off anti-aliasing temporarily
+  virtual GBool getVectorAntialias();
+  virtual void setVectorAntialias(GBool vaa);
+#endif
+
 private:
 
+  void setupScreenParams(double hDPI, double vDPI);
 #if SPLASH_CMYK
   SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk);
 #else
   SplashPattern *getColor(GfxGray gray, GfxRGB *rgb);
 #endif
   SplashPath *convertPath(GfxState *state, GfxPath *path);
+  void doUpdateFont(GfxState *state);
   void drawType3Glyph(T3FontCache *t3Font,
-		      T3FontCacheTag *tag, Guchar *data,
-		      double x, double y);
+		      T3FontCacheTag *tag, Guchar *data);
   static GBool imageMaskSrc(void *data, SplashColorPtr line);
-  static GBool imageSrc(void *data, SplashColorPtr line);
-  static GBool alphaImageSrc(void *data, SplashColorPtr line);
-  static GBool maskedImageSrc(void *data, SplashColorPtr line);
+  static GBool imageSrc(void *data, SplashColorPtr colorLine,
+			Guchar *alphaLine);
+  static GBool alphaImageSrc(void *data, SplashColorPtr line,
+			     Guchar *alphaLine);
+  static GBool maskedImageSrc(void *data, SplashColorPtr line,
+			      Guchar *alphaLine);
 
   SplashColorMode colorMode;
   int bitmapRowPad;
   GBool bitmapTopDown;
   GBool allowAntialias;
+  GBool vectorAntialias;
   GBool reverseVideo;		// reverse video mode
   SplashColor paperColor;	// paper color
+  SplashScreenParams screenParams;
 
   XRef *xref;			// xref table for current document
 
@@ -212,6 +234,9 @@
   SplashFont *font;		// current font
   GBool needFontUpdate;		// set when the font needs to be updated
   SplashPath *textClipPath;	// clipping path built with text object
+
+  SplashTransparencyGroup *	// transparency group stack
+    transpGroupStack;
 };
 
 #endif

Index: Stream.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Stream.cc,v
retrieving revision 1.15
retrieving revision 1.15.2.1
diff -u -d -r1.15 -r1.15.2.1
--- Stream.cc	13 Jan 2007 23:19:21 -0000	1.15
+++ Stream.cc	6 Apr 2007 14:22:23 -0000	1.15.2.1
@@ -27,17 +27,16 @@
 #include "Error.h"
 #include "Object.h"
 #include "Lexer.h"
-#include "Decrypt.h"
 #include "GfxState.h"
 #include "Stream.h"
 #include "JBIG2Stream.h"
 #include "JPXStream.h"
 #include "Stream-CCITT.h"
-#include "UGooString.h"
 
-#ifdef ENABLE_LIBJPEG
-#include "DCTStream.h"
-#endif
+#warning LIBJPEG DCTSTream is broken, fix it
+// #ifdef ENABLE_LIBJPEG
+// #include "DCTStream.h"
+// #endif
 
 #ifdef ENABLE_ZLIB
 #include "FlateStream.h"
@@ -151,6 +150,7 @@
   int encoding;
   GBool endOfLine, byteAlign, endOfBlock, black;
   int columns, rows;
+  int colorXform;
   Object globals, obj;
 
   if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) {
@@ -236,7 +236,14 @@
     str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign,
 			     columns, rows, endOfBlock, black);
   } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) {
-    str = new DCTStream(str);
+    colorXform = -1;
+    if (params->isDict()) {
+      if (params->dictLookup("ColorTransform", &obj)->isInt()) {
+	colorXform = obj.getInt();
+      }
+      obj.free();
+    }
+    str = new DCTStream(str, colorXform);
   } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) {
     pred = 1;
     columns = 1;
@@ -282,18 +289,10 @@
 
 BaseStream::BaseStream(Object *dictA) {
   dict = *dictA;
-  decrypt = NULL;
 }
 
 BaseStream::~BaseStream() {
   dict.free();
-  if (decrypt)
-    delete decrypt;
-}
-
-void BaseStream::doDecryption(Guchar *fileKey, int keyLength,
-			      int objNum, int objGen) {
-  decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
 }
 
 //------------------------------------------------------------------------
@@ -411,8 +410,6 @@
 
 StreamPredictor::StreamPredictor(Stream *strA, int predictorA,
 				 int widthA, int nCompsA, int nBitsA) {
-  int totalBits;
-
   str = strA;
   predictor = predictorA;
   width = widthA;
@@ -428,15 +425,9 @@
       nVals * nBits + 7 < 0) {
     return;
   }
-  totalBits = nVals * nBits;
-  if (totalBits == 0 ||
-      (totalBits / nBits) / nComps != width ||
-      totalBits + 7 < 0) {
-    return;
-  }
   pixBytes = (nComps * nBits + 7) >> 3;
-  rowBytes = ((totalBits + 7) >> 3) + pixBytes;
-  if (rowBytes < 0) {
+  rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes;
+  if (rowBytes <= 0) {
     return;
   }
   predLine = (Guchar *)gmalloc(rowBytes);
@@ -560,17 +551,17 @@
       j = k = pixBytes;
       for (i = 0; i < width; ++i) {
 	for (kk = 0; kk < nComps; ++kk) {
-	if (inBits < nBits) {
-	  inBuf = (inBuf << 8) | (predLine[j++] & 0xff);
-	  inBits += 8;
-	}
-	  upLeftBuf[kk] = (upLeftBuf[kk] +
-			(inBuf >> (inBits - nBits))) & bitMask;
-	inBits -= nBits;
+	  if (inBits < nBits) {
+	    inBuf = (inBuf << 8) | (predLine[j++] & 0xff);
+	    inBits += 8;
+	  }
+	  upLeftBuf[kk] = (Guchar)((upLeftBuf[kk] +
+				    (inBuf >> (inBits - nBits))) & bitMask);
+	  inBits -= nBits;
 	  outBuf = (outBuf << nBits) | upLeftBuf[kk];
-	outBits += nBits;
+	  outBits += nBits;
 	  if (outBits >= 8) {
-	  predLine[k++] = (Guchar)(outBuf >> (outBits - 8));
+	    predLine[k++] = (Guchar)(outBuf >> (outBits - 8));
 	    outBits -= 8;
 	  }
 	}
@@ -628,8 +619,6 @@
   saved = gTrue;
   bufPtr = bufEnd = buf;
   bufPos = start;
-  if (decrypt)
-    decrypt->reset();
 }
 
 void FileStream::close() {
@@ -647,7 +636,6 @@
 
 GBool FileStream::fillBuf() {
   int n;
-  char *p;
 
   bufPos += bufEnd - buf;
   bufPtr = bufEnd = buf;
@@ -664,11 +652,6 @@
   if (bufPtr >= bufEnd) {
     return gFalse;
   }
-  if (decrypt) {
-    for (p = buf; p < bufEnd; ++p) {
-      *p = (char)decrypt->decryptByte((Guchar)*p);
-    }
-  }
   return gTrue;
 }
 
@@ -757,9 +740,6 @@
 
 void MemStream::reset() {
   bufPtr = buf + start;
-  if (decrypt) {
-    decrypt->reset();
-  }
 }
 
 void MemStream::close() {
@@ -787,25 +767,6 @@
   bufPtr = buf + start;
 }
 
-void MemStream::doDecryption(Guchar *fileKey, int keyLength,
-			     int objNum, int objGen) {
-  char *newBuf;
-  char *p, *q;
-
-  this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen);
-  if (decrypt) {
-    newBuf = (char *)gmalloc(length);
-    for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) {
-      *q = (char)decrypt->decryptByte((Guchar)*p);
-    }
-    bufEnd = newBuf + length;
-    bufPtr = newBuf + (bufPtr - (buf + start));
-    start = 0;
-    buf = newBuf;
-    needFree = gTrue;
-  }
-}
-
 //------------------------------------------------------------------------
 // EmbedStream
 //------------------------------------------------------------------------
@@ -1291,14 +1252,17 @@
   endOfLine = endOfLineA;
   byteAlign = byteAlignA;
   columns = columnsA;
-  if (columns + 3 < 1 || columns + 4 < 1 || columns < 1) {
+  if (columns < 1) {
     columns = 1;
   }
+  if (columns + 4 <= 0) {
+    columns = INT_MAX - 4;
+  }
   rows = rowsA;
   endOfBlock = endOfBlockA;
   black = blackA;
-  refLine = (short *)gmallocn(columns + 4, sizeof(short));
-  codingLine = (short *)gmallocn(columns + 3, sizeof(short));
+  refLine = (short *)gmallocn(columns + 3, sizeof(short));
+  codingLine = (short *)gmallocn(columns + 2, sizeof(short));
 
   eof = gFalse;
   row = 0;
@@ -1326,7 +1290,7 @@
   nextLine2D = encoding < 0;
   inputBits = 0;
   codingLine[0] = 0;
-  codingLine[1] = refLine[2] = columns;
+  codingLine[1] = columns;
   a0 = 1;
   buf = EOF;
 
@@ -1362,8 +1326,27 @@
 
     // 2-D encoding
     if (nextLine2D) {
-      for (i = 0; codingLine[i] < columns; ++i)
+      // state:
+      //   a0New = current position in coding line (0 <= a0New <= columns)
+      //   codingLine[a0] = last change in coding line
+      //                    (black-to-white if a0 is even,
+      //                     white-to-black if a0 is odd)
+      //   refLine[b1] = next change in reference line of opposite color
+      //                 to a0
+      // invariants:
+      //   0 <= codingLine[a0] <= a0New
+      //           <= refLine[b1] <= refLine[b1+1] <= columns
+      //   0 <= a0 <= columns+1
+      //   refLine[0] = 0
+      //   refLine[n] = refLine[n+1] = columns
+      //     -- for some 1 <= n <= columns+1
+      // end condition:
+      //   0 = codingLine[0] <= codingLine[1] < codingLine[2] < ...
+      //     < codingLine[n-1] < codingLine[n] = columns
+      //     -- where 1 <= n <= columns+1
+      for (i = 0; codingLine[i] < columns; ++i) {
 	refLine[i] = codingLine[i];
+      }
       refLine[i] = refLine[i + 1] = columns;
       b1 = 1;
       a0New = codingLine[a0 = 0] = 0;
@@ -1395,68 +1378,93 @@
 	    } while (code3 >= 64);
 	  }
 	  if (code1 > 0 || code2 > 0) {
-	    codingLine[a0 + 1] = a0New + code1;
+	    if (a0New + code1 <= columns) {
+	      codingLine[a0 + 1] = a0New + code1;
+	    } else {
+	      codingLine[a0 + 1] = columns;
+	    }
 	    ++a0;
-	    a0New = codingLine[a0 + 1] = codingLine[a0] + code2;
+	    if (codingLine[a0] + code2 <= columns) {
+	      codingLine[a0 + 1] = codingLine[a0] + code2;
+	    } else {
+	      codingLine[a0 + 1] = columns;
+	    }
 	    ++a0;
-	    while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+	    a0New = codingLine[a0];
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
 	      b1 += 2;
+	    }
 	  }
 	  break;
 	case twoDimVert0:
-	  a0New = codingLine[++a0] = refLine[b1];
 	  if (refLine[b1] < columns) {
+	    a0New = codingLine[++a0] = refLine[b1];
 	    ++b1;
-	    while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
 	      b1 += 2;
+	    }
+	  } else {
+	    a0New = codingLine[++a0] = columns;
 	  }
 	  break;
 	case twoDimVertR1:
-	  a0New = codingLine[++a0] = refLine[b1] + 1;
-	  if (refLine[b1] < columns) {
+	  if (refLine[b1] + 1 < columns) {
+	    a0New = codingLine[++a0] = refLine[b1] + 1;
 	    ++b1;
-	    while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
 	      b1 += 2;
+	    }
+	  } else {
+	    a0New = codingLine[++a0] = columns;
 	  }
 	  break;
 	case twoDimVertL1:
-	  if (a0 == 0 || refLine[b1] - 1 > a0New) {
-	  a0New = codingLine[++a0] = refLine[b1] - 1;
-	  --b1;
-	  while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
-	    b1 += 2;
+	  if (refLine[b1] - 1 > a0New || (a0 == 0 && refLine[b1] == 1)) {
+	    a0New = codingLine[++a0] = refLine[b1] - 1;
+	    --b1;
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
+	      b1 += 2;
+	    }
 	  }
 	  break;
 	case twoDimVertR2:
-	  a0New = codingLine[++a0] = refLine[b1] + 2;
-	  if (refLine[b1] < columns) {
+	  if (refLine[b1] + 2 < columns) {
+	    a0New = codingLine[++a0] = refLine[b1] + 2;
 	    ++b1;
-	    while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
 	      b1 += 2;
+	    }
+	  } else {
+	    a0New = codingLine[++a0] = columns;
 	  }
 	  break;
 	case twoDimVertL2:
-	  if (a0 == 0 || refLine[b1] - 2 > a0New) {
-	  a0New = codingLine[++a0] = refLine[b1] - 2;
-	  --b1;
-	  while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
-	    b1 += 2;
+	  if (refLine[b1] - 2 > a0New || (a0 == 0 && refLine[b1] == 2)) {
+	    a0New = codingLine[++a0] = refLine[b1] - 2;
+	    --b1;
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
+	      b1 += 2;
+	    }
 	  }
 	  break;
 	case twoDimVertR3:
-	  a0New = codingLine[++a0] = refLine[b1] + 3;
-	  if (refLine[b1] < columns) {
+	  if (refLine[b1] + 3 < columns) {
+	    a0New = codingLine[++a0] = refLine[b1] + 3;
 	    ++b1;
-	    while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
 	      b1 += 2;
+	    }
+	  } else {
+	    a0New = codingLine[++a0] = columns;
 	  }
 	  break;
 	case twoDimVertL3:
-	  if (a0 == 0 || refLine[b1] - 3 > a0New) {
-	  a0New = codingLine[++a0] = refLine[b1] - 3;
-	  --b1;
-	  while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
-	    b1 += 2;
+	  if (refLine[b1] - 3 > a0New || (a0 == 0 && refLine[b1] == 3)) {
+	    a0New = codingLine[++a0] = refLine[b1] - 3;
+	    --b1;
+	    while (refLine[b1] <= a0New && refLine[b1] < columns) {
+	      b1 += 2;
+	    }
 	  }
 	  break;
 	case EOF:
@@ -1480,16 +1488,18 @@
 	} while (code3 >= 64);
 	codingLine[a0+1] = codingLine[a0] + code1;
 	++a0;
-	if (codingLine[a0] >= columns)
+	if (codingLine[a0] >= columns) {
 	  break;
+	}
 	code2 = 0;
 	do {
 	  code2 += code3 = getBlackCode();
 	} while (code3 >= 64);
 	codingLine[a0+1] = codingLine[a0] + code2;
 	++a0;
-	if (codingLine[a0] >= columns)
+	if (codingLine[a0] >= columns) {
 	  break;
+	}
       }
     }
 
@@ -1826,7 +1836,8 @@
   return str->isBinary(gTrue);
 }
 
-#ifndef ENABLE_LIBJPEG
+#warning LIBJPEG DCTSTream is broken, fix it
+// #ifndef ENABLE_LIBJPEG
 
 //------------------------------------------------------------------------
 // DCTStream
@@ -1872,10 +1883,11 @@
   63
 };
 
-DCTStream::DCTStream(Stream *strA):
+DCTStream::DCTStream(Stream *strA, GBool colorXformA):
     FilterStream(strA) {
   int i, j;
 
+  colorXform = colorXformA;
   progressive = interleaved = gFalse;
   width = height = 0;
   mcuWidth = mcuHeight = 0;
@@ -1901,20 +1913,8 @@
 }
 
 DCTStream::~DCTStream() {
-  int i, j;
-
+  close();
   delete str;
-  if (progressive || !interleaved) {
-    for (i = 0; i < numComps; ++i) {
-      gfree(frameBuf[i]);
-    }
-  } else {
-    for (i = 0; i < numComps; ++i) {
-      for (j = 0; j < mcuHeight; ++j) {
-	gfree(rowBuf[i][j]);
-      }
-    }
-  }
 }
 
 void DCTStream::reset() {
@@ -1928,7 +1928,6 @@
   numQuantTables = 0;
   numDCHuffTables = 0;
   numACHuffTables = 0;
-  colorXform = 0;
   gotJFIFMarker = gFalse;
   gotAdobeMarker = gFalse;
   restartInterval = 0;
@@ -1950,20 +1949,24 @@
     }
     if (compInfo[i].vSample > mcuHeight) {
       mcuHeight = compInfo[i].vSample;
-  }
+    }
   }
   mcuWidth *= 8;
   mcuHeight *= 8;
 
   // figure out color transform
-  if (!gotAdobeMarker && numComps == 3) {
-    if (gotJFIFMarker) {
-      colorXform = 1;
-    } else if (compInfo[0].id == 82 && compInfo[1].id == 71 &&
-	       compInfo[2].id == 66) { // ASCII "RGB"
-      colorXform = 0;
+  if (colorXform == -1) {
+    if (numComps == 3) {
+      if (gotJFIFMarker) {
+	colorXform = 1;
+      } else if (compInfo[0].id == 82 && compInfo[1].id == 71 &&
+		 compInfo[2].id == 66) { // ASCII "RGB"
+	colorXform = 0;
+      } else {
+	colorXform = 1;
+      }
     } else {
-      colorXform = 1;
+      colorXform = 0;
     }
   }
 
@@ -2013,6 +2016,20 @@
   }
 }
 
+void DCTStream::close() {
+  int i, j;
+
+  for (i = 0; i < 4; ++i) {
+    for (j = 0; j < 32; ++j) {
+      gfree(rowBuf[i][j]);
+      rowBuf[i][j] = NULL;
+    }
+    gfree(frameBuf[i]);
+    frameBuf[i] = NULL;
+  }
+  FilterStream::close();
+}
+
 int DCTStream::getChar() {
   int c;
 
@@ -2937,8 +2954,8 @@
   width = read16();
   numComps = str->getChar();
   if (numComps <= 0 || numComps > 4) {
-    numComps = 0;
     error(getPos(), "Bad number of components in DCT stream");
+    numComps = 0;
     return gFalse;
   }
   if (prec != 8) {
@@ -2990,8 +3007,8 @@
   length = read16() - 2;
   scanInfo.numComps = str->getChar();
   if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) {
-    scanInfo.numComps = 0;
     error(getPos(), "Bad number of components in DCT stream");
+    scanInfo.numComps = 0;
     return gFalse;
   }
   --length;
@@ -3053,14 +3070,14 @@
       if (prec) {
 	quantTables[index][dctZigZag[i]] = read16();
       } else {
-      quantTables[index][dctZigZag[i]] = str->getChar();
+	quantTables[index][dctZigZag[i]] = str->getChar();
       }
     }
     if (prec) {
       length -= 129;
     } else {
-    length -= 65;
-  }
+      length -= 65;
+    }
   }
   return gTrue;
 }
@@ -3078,12 +3095,12 @@
   while (length > 0) {
     index = str->getChar();
     --length;
-    if ((index & ~0x10) >= 4 || (index & ~0x10) < 0) {
+    if ((index & 0x0f) >= 4) {
       error(getPos(), "Bad DCT Huffman table");
       return gFalse;
     }
     if (index & 0x10) {
-      index &= 0x03;
+      index &= 0x0f;
       if (index >= numACHuffTables)
 	numACHuffTables = index+1;
       tbl = &acHuffTables[index];
@@ -3237,7 +3254,7 @@
   return str->isBinary(gTrue);
 }
 
-#endif
+// #endif
 
 #ifndef ENABLE_ZLIB
 //------------------------------------------------------------------------
@@ -3887,14 +3904,15 @@
   }
   litCodeTab.codes = NULL;
   distCodeTab.codes = NULL;
+  memset(buf, 0, flateWindow);
 }
 
 FlateStream::~FlateStream() {
   if (litCodeTab.codes != fixedLitCodeTab.codes) {
-  gfree(litCodeTab.codes);
+    gfree(litCodeTab.codes);
   }
   if (distCodeTab.codes != fixedDistCodeTab.codes) {
-  gfree(distCodeTab.codes);
+    gfree(distCodeTab.codes);
   }
   if (pred) {
     delete pred;
@@ -4073,11 +4091,11 @@
 
   // free the code tables from the previous block
   if (litCodeTab.codes != fixedLitCodeTab.codes) {
-  gfree(litCodeTab.codes);
+    gfree(litCodeTab.codes);
   }
   litCodeTab.codes = NULL;
   if (distCodeTab.codes != fixedDistCodeTab.codes) {
-  gfree(distCodeTab.codes);
+    gfree(distCodeTab.codes);
   }
   distCodeTab.codes = NULL;
 
@@ -4446,35 +4464,63 @@
 }
 
 GBool ASCII85Encoder::fillBuf() {
-  Gulong t;
+  Guint t;
   char buf1[5];
-  int c;
+  int c0, c1, c2, c3;
   int n, i;
 
-  if (eof)
+  if (eof) {
     return gFalse;
-  t = 0;
-  for (n = 0; n < 4; ++n) {
-    if ((c = str->getChar()) == EOF)
-      break;
-    t = (t << 8) + c;
   }
+  c0 = str->getChar();
+  c1 = str->getChar();
+  c2 = str->getChar();
+  c3 = str->getChar();
   bufPtr = bufEnd = buf;
-  if (n > 0) {
-    if (n == 4 && t == 0) {
+  if (c3 == EOF) {
+    if (c0 == EOF) {
+      n = 0;
+      t = 0;
+    } else {
+      if (c1 == EOF) {
+	n = 1;
+	t = c0 << 24;
+      } else if (c2 == EOF) {
+	n = 2;
+	t = (c0 << 24) | (c1 << 16);
+      } else {
+	n = 3;
+	t = (c0 << 24) | (c1 << 16) | (c2 << 8);
+      }
+      for (i = 4; i >= 0; --i) {
+	buf1[i] = (char)(t % 85 + 0x21);
+	t /= 85;
+      }
+      for (i = 0; i <= n; ++i) {
+	*bufEnd++ = buf1[i];
+	if (++lineLen == 65) {
+	  *bufEnd++ = '\n';
+	  lineLen = 0;
+	}
+      }
+    }
+    *bufEnd++ = '~';
+    *bufEnd++ = '>';
+    eof = gTrue;
+  } else {
+    t = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
+    if (t == 0) {
       *bufEnd++ = 'z';
       if (++lineLen == 65) {
 	*bufEnd++ = '\n';
 	lineLen = 0;
       }
     } else {
-      if (n < 4)
-	t <<= 8 * (4 - n);
       for (i = 4; i >= 0; --i) {
 	buf1[i] = (char)(t % 85 + 0x21);
 	t /= 85;
       }
-      for (i = 0; i <= n; ++i) {
+      for (i = 0; i <= 4; ++i) {
 	*bufEnd++ = buf1[i];
 	if (++lineLen == 65) {
 	  *bufEnd++ = '\n';
@@ -4483,12 +4529,7 @@
       }
     }
   }
-  if (n < 4) {
-    *bufEnd++ = '~';
-    *bufEnd++ = '>';
-    eof = gTrue;
-  }
-  return bufPtr < bufEnd;
+  return gTrue;
 }
 
 //------------------------------------------------------------------------

Index: Stream.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/Stream.h,v
retrieving revision 1.11
retrieving revision 1.11.2.1
diff -u -d -r1.11 -r1.11.2.1
--- Stream.h	13 Jan 2007 23:19:21 -0000	1.11
+++ Stream.h	6 Apr 2007 14:22:23 -0000	1.11.2.1
@@ -17,7 +17,6 @@
 #include "goo/gtypes.h"
 #include "Object.h"
 
-class Decrypt;
 class BaseStream;
 
 //------------------------------------------------------------------------
@@ -44,6 +43,15 @@
 };
 
 //------------------------------------------------------------------------
+
+// This is in Stream.h instead of Decrypt.h to avoid really annoying
+// include file dependency loops.
+enum CryptAlgorithm {
+  cryptRC4,
+  cryptAES
+};
+
+//------------------------------------------------------------------------
 // Stream (base class)
 //------------------------------------------------------------------------
 
@@ -99,6 +107,10 @@
   // Get the BaseStream of this stream.
   virtual BaseStream *getBaseStream() = 0;
 
+  // Get the stream after the last decoder (this may be a BaseStream
+  // or a DecryptStream).
+  virtual Stream *getUndecodedStream() = 0;
+
   // Get the dictionary associated with this stream.
   virtual Dict *getDict() = 0;
 
@@ -109,6 +121,9 @@
   virtual void getImageParams(int * /*bitsPerComponent*/,
 			      StreamColorSpaceMode * /*csMode*/) {}
 
+  // Return the next stream in the "stack".
+  virtual Stream *getNextStream() { return NULL; }
+
   // Add filters to this stream according to the parameters in <dict>.
   // Returns the new stream.
   Stream *addFilters(Object *dict);
@@ -136,20 +151,14 @@
   virtual void setPos(Guint pos, int dir = 0) = 0;
   virtual GBool isBinary(GBool last = gTrue) { return last; }
   virtual BaseStream *getBaseStream() { return this; }
+  virtual Stream *getUndecodedStream() { return this; }
   virtual Dict *getDict() { return dict.getDict(); }
+  virtual GooString *getFileName() { return NULL; }
 
   // Get/set position of first byte of stream within the file.
   virtual Guint getStart() = 0;
   virtual void moveStart(int delta) = 0;
 
-  // Set decryption for this stream.
-  virtual void doDecryption(Guchar *fileKey, int keyLength,
-			    int objNum, int objGen);
-
-protected:
-
-  Decrypt *decrypt;
-
 private:
 
   Object dict;
@@ -170,7 +179,9 @@
   virtual int getPos() { return str->getPos(); }
   virtual void setPos(Guint pos, int dir = 0);
   virtual BaseStream *getBaseStream() { return str->getBaseStream(); }
+  virtual Stream *getUndecodedStream() { return str->getUndecodedStream(); }
   virtual Dict *getDict() { return str->getDict(); }
+  virtual Stream *getNextStream() { return str; }
 
 protected:
 
@@ -316,8 +327,6 @@
   virtual void setPos(Guint pos, int dir = 0);
   virtual Guint getStart() { return start; }
   virtual void moveStart(int delta);
-  virtual void doDecryption(Guchar *fileKey, int keyLength,
-			    int objNum, int objGen);
 
 private:
 
@@ -531,7 +540,8 @@
   void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; }
 };
 
-#ifndef ENABLE_LIBJPEG
+#warning LIBJPEG DCTSTream is broken, fix it
+// #ifndef ENABLE_LIBJPEG
 //------------------------------------------------------------------------
 // DCTStream
 //------------------------------------------------------------------------
@@ -565,10 +575,11 @@
 class DCTStream: public FilterStream {
 public:
 
-  DCTStream(Stream *strA);
+  DCTStream(Stream *strA, int colorXformA);
   virtual ~DCTStream();
   virtual StreamKind getKind() { return strDCT; }
   virtual void reset();
+  virtual void close();
   virtual int getChar();
   virtual int lookChar();
   virtual GooString *getPSFilter(int psLevel, char *indent);
@@ -585,7 +596,9 @@
   DCTCompInfo compInfo[4];	// info for each component
   DCTScanInfo scanInfo;		// info for the current scan
   int numComps;			// number of components in image
-  int colorXform;		// need YCbCr-to-RGB transform?
+  int colorXform;		// color transform: -1 = unspecified
+				//                   0 = none
+				//                   1 = YUV/YUVK -> RGB/CMYK
   GBool gotJFIFMarker;		// set if APP0 JFIF marker was present
   GBool gotAdobeMarker;		// set if APP14 Adobe marker was present
   int restartInterval;		// restart interval, in MCUs
@@ -632,7 +645,8 @@
   int readMarker();
   int read16();
 };
-#endif
+
+// #endif
 
 #ifndef ENABLE_ZLIB
 //------------------------------------------------------------------------

Index: TextOutputDev.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/TextOutputDev.cc,v
retrieving revision 1.22
retrieving revision 1.22.4.1
diff -u -d -r1.22 -r1.22.4.1
--- TextOutputDev.cc	20 Sep 2006 20:22:19 -0000	1.22
+++ TextOutputDev.cc	6 Apr 2007 14:22:23 -0000	1.22.4.1
@@ -29,6 +29,7 @@
 #include "GlobalParams.h"
 #include "UnicodeMap.h"
 #include "UnicodeTypeTable.h"
+#include "Link.h"
 #include "TextOutputDev.h"
 #include "Page.h"
 
@@ -106,12 +107,64 @@
 // multiplied by this constant.
 #define maxWideCharSpacingMul 1.3
 
+// Upper limit on spacing between characters in a word.
+#define maxWideCharSpacing 0.4
+
 // Max difference in primary,secondary coordinates (as a fraction of
 // the font size) allowed for duplicated text (fake boldface, drop
 // shadows) which is to be discarded.
 #define dupMaxPriDelta 0.1
 #define dupMaxSecDelta 0.2
 
+// Max width of underlines (in points).
+#define maxUnderlineWidth 3
+
+// Min distance between baseline and underline (in points).
+//~ this should be font-size-dependent
+#define minUnderlineGap -2
+
+// Max distance between baseline and underline (in points).
+//~ this should be font-size-dependent
+#define maxUnderlineGap 4
+
+// Max horizontal distance between edge of word and start of underline
+// (in points).
+//~ this should be font-size-dependent
+#define underlineSlack 1
+
+// Max distance between edge of text and edge of link border
+#define hyperlinkSlack 2
+
+//------------------------------------------------------------------------
+// TextUnderline
+//------------------------------------------------------------------------
+
+class TextUnderline {
+public:
+
+  TextUnderline(double x0A, double y0A, double x1A, double y1A)
+    { x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; horiz = y0 == y1; }
+  ~TextUnderline() {}
+
+  double x0, y0, x1, y1;
+  GBool horiz;
+};
+
+//------------------------------------------------------------------------
+// TextLink
+//------------------------------------------------------------------------
+
+class TextLink {
+public:
+
+  TextLink(int xMinA, int yMinA, int xMaxA, int yMaxA, Link *linkA)
+    { xMin = xMinA; yMin = yMinA; xMax = xMaxA; yMax = yMaxA; link = linkA; }
+  ~TextLink() {}
+
+  int xMin, yMin, xMax, yMax;
+  Link *link;
+};
+
 //------------------------------------------------------------------------
 // TextFontInfo
 //------------------------------------------------------------------------
@@ -124,6 +177,7 @@
   fontName = (gfxFont && gfxFont->getOrigName())
                  ? gfxFont->getOrigName()->copy()
                  : (GooString *)NULL;
+  flags = gfxFont ? gfxFont->getFlags() : 0;
 #endif
 }
 
@@ -230,6 +284,9 @@
   colorG = colToDbl(rgb.g);
   colorB = colToDbl(rgb.b);
 #endif
+
+  underlined = gFalse;
+  link = NULL;
 }
 
 TextWord::~TextWord() {
@@ -386,6 +443,39 @@
   return s;
 }
 
+void TextWord::getCharBBox(int charIdx, double *xMinA, double *yMinA,
+			   double *xMaxA, double *yMaxA) {
+  if (charIdx < 0 || charIdx >= len) {
+    return;
+  }
+  switch (rot) {
+  case 0:
+    *xMinA = edge[charIdx];
+    *xMaxA = edge[charIdx + 1];
+    *yMinA = yMin;
+    *yMaxA = yMax;
+    break;
+  case 1:
+    *xMinA = xMin;
+    *xMaxA = xMax;
+    *yMinA = edge[charIdx];
+    *yMaxA = edge[charIdx + 1];
+    break;
+  case 2:
+    *xMinA = edge[charIdx + 1];
+    *xMaxA = edge[charIdx];
+    *yMinA = yMin;
+    *yMaxA = yMax;
+    break;
+  case 3:
+    *xMinA = xMin;
+    *xMaxA = xMax;
+    *yMinA = edge[charIdx + 1];
+    *yMaxA = edge[charIdx];
+    break;
+  }
+}
+
 #endif // TEXTOUT_WORD_LIST
 
 //------------------------------------------------------------------------
@@ -651,6 +741,9 @@
       space = maxCharSpacing * words->fontSize;
     } else {
       space = maxWideCharSpacingMul * minSpace;
+      if (space > maxWideCharSpacing * words->fontSize) {
+	space = maxWideCharSpacing * words->fontSize;
+      }
     }
 
     // merge words
@@ -662,8 +755,9 @@
 	word0 = word1;
 	word1 = word1->next;
       } else if (word0->font == word1->font &&
+		 word0->underlined == word1->underlined &&
 		 fabs(word0->fontSize - word1->fontSize) <
-		 maxWordFontSizeDelta * words->fontSize &&
+		   maxWordFontSizeDelta * words->fontSize &&
 		 word1->charPos == word0->charPos + word0->charLen) {
 	word0->merge(word1);
 	word0->next = word1->next;
@@ -740,6 +834,8 @@
   static int cmpYXPrimaryRot(const void *p1, const void *p2);
   static int cmpYXLineRot(const void *p1, const void *p2);
   static int cmpXYLineRot(const void *p1, const void *p2);
+  static int cmpXYColumnPrimaryRot(const void *p1, const void *p2);
+  static int cmpXYColumnLineRot(const void *p1, const void *p2);
 };
 
 void TextLineFrag::init(TextLine *lineA, int startA, int lenA) {
@@ -971,6 +1067,54 @@
   return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
 }
 
+int TextLineFrag::cmpXYColumnPrimaryRot(const void *p1, const void *p2) {
+  TextLineFrag *frag1 = (TextLineFrag *)p1;
+  TextLineFrag *frag2 = (TextLineFrag *)p2;
+  double cmp;
+
+  // if columns overlap, compare y values
+  if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] -
+				 frag2->line->col[frag2->start]) &&
+      frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+				 frag1->line->col[frag1->start])) {
+    cmp = 0; // make gcc happy
+    switch (frag1->line->blk->page->primaryRot) {
+    case 0: cmp = frag1->yMin - frag2->yMin; break;
+    case 1: cmp = frag2->xMax - frag1->xMax; break;
+    case 2: cmp = frag2->yMin - frag1->yMin; break;
+    case 3: cmp = frag1->xMax - frag2->xMax; break;
+    }
+    return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+  }
+
+  // otherwise, compare starting column
+  return frag1->col - frag2->col;
+}
+
+int TextLineFrag::cmpXYColumnLineRot(const void *p1, const void *p2) {
+  TextLineFrag *frag1 = (TextLineFrag *)p1;
+  TextLineFrag *frag2 = (TextLineFrag *)p2;
+  double cmp;
+
+  // if columns overlap, compare y values
+  if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] -
+				 frag2->line->col[frag2->start]) &&
+      frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+				 frag1->line->col[frag1->start])) {
+    cmp = 0; // make gcc happy
+    switch (frag1->line->rot) {
+    case 0: cmp = frag1->yMin - frag2->yMin; break;
+    case 1: cmp = frag2->xMax - frag1->xMax; break;
+    case 2: cmp = frag2->yMin - frag1->yMin; break;
+    case 3: cmp = frag1->xMax - frag2->xMax; break;
+    }
+    return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+  }
+
+  // otherwise, compare starting column
+  return frag1->col - frag2->col;
+}
+
 //------------------------------------------------------------------------
 // TextBlock
 //------------------------------------------------------------------------
@@ -1629,6 +1773,8 @@
   fonts = new GooList();
   lastFindXMin = lastFindYMin = 0;
   haveLastFind = gFalse;
+  underlines = new GooList();
+  links = new GooList();
 }
 
 TextPage::~TextPage() {
@@ -1641,6 +1787,8 @@
     }
   }
   delete fonts;
+  deleteGooList(underlines, TextUnderline);
+  deleteGooList(links, TextLink);
 }
 
 void TextPage::startPage(GfxState *state) {
@@ -1815,14 +1963,6 @@
   GBool overlap;
   int i;
 
-  // throw away chars that aren't inside the page bounds
-  state->transform(x, y, &x1, &y1);
-  if (x1 < 0 || x1 > pageWidth ||
-      y1 < 0 || y1 > pageHeight) {
-    charPos += nBytes;
-    return;
-  }
-
   // subtract char and word spacing from the dx,dy values
   sp = state->getCharSpace();
   if (c == (CharCode)0x20) {
@@ -1833,6 +1973,16 @@
   dy -= dy2;
   state->transformDelta(dx, dy, &w1, &h1);
 
+  // throw away chars that aren't inside the page bounds
+  // (and also do a sanity check on the character size)
+  state->transform(x, y, &x1, &y1);
+  if (x1 + w1 < 0 || x1 > pageWidth ||
+      y1 + h1 < 0 || y1 > pageHeight ||
+      w1 > pageWidth || h1 > pageHeight) {
+    charPos += nBytes;
+    return;
+  }
+
   // check the tiny chars limit
   if (!globalParams->getTextKeepTinyChars() &&
       fabs(w1) < 3 && fabs(h1) < 3) {
@@ -1845,7 +1995,7 @@
   // break words at space character
   if (uLen == 1 && u[0] == (Unicode)0x20) {
     if (curWord) {
-    ++curWord->charLen;
+      ++curWord->charLen;
     }
     charPos += nBytes;
     endWord();
@@ -1859,7 +2009,8 @@
   //     and secondary axes), or
   // (2) this character overlaps the previous one (duplicated text), or
   // (3) the previous character was an overlap (we want each duplicated
-  //     character to be in a word by itself at this stage)
+  //     character to be in a word by itself at this stage),
+  // (4) the font size has changed
   if (curWord && curWord->len > 0) {
     base = sp = delta = 0; // make gcc happy
     switch (curWord->rot) {
@@ -1889,7 +2040,8 @@
     if (overlap || lastCharOverlap ||
 	sp < -minDupBreakOverlap * curWord->fontSize ||
 	sp > minWordBreakSpace * curWord->fontSize ||
-	fabs(base - curWord->base) > 0.5) {
+	fabs(base - curWord->base) > 0.5 ||
+	curFontSize != curWord->fontSize) {
       endWord();
     }
     lastCharOverlap = overlap;
@@ -1966,7 +2118,15 @@
   }
 }
 
-void TextPage::coalesce(GBool physLayout) {
+void TextPage::addUnderline(double x0, double y0, double x1, double y1) {
+  underlines->append(new TextUnderline(x0, y0, x1, y1));
+}
+
+void TextPage::addLink(int xMin, int yMin, int xMax, int yMax, Link *link) {
+  links->append(new TextLink(xMin, yMin, xMax, yMax, link));
+}
+
+void TextPage::coalesce(GBool physLayout, GBool doHTML) {
   UnicodeMap *uMap;
   TextPool *pool;
   TextWord *word0, *word1, *word2;
@@ -1974,7 +2134,9 @@
   TextBlock *blkList, *blkStack, *blk, *lastBlk, *blk0, *blk1;
   TextBlock **blkArray;
   TextFlow *flow, *lastFlow;
-  int rot, poolMinBaseIdx, baseIdx, startBaseIdx;
+  TextUnderline *underline;
+  TextLink *link;
+  int rot, poolMinBaseIdx, baseIdx, startBaseIdx, endBaseIdx;
   double minBase, maxBase, newMinBase, newMaxBase;
   double fontSize, colSpace1, colSpace2, lineSpace, intraLineSpace, blkSpace;
   GBool found;
@@ -2002,9 +2164,9 @@
     pool = pools[rot];
     for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) {
       for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) {
-	printf("    word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d '",
+	printf("    word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d link=%p '",
 	       word0->xMin, word0->xMax, word0->yMin, word0->yMax,
-	       word0->base, word0->fontSize, rot*90);
+	       word0->base, word0->fontSize, rot*90, word0->link);
 	for (i = 0; i < word0->len; ++i) {
 	  fputc(word0->text[i] & 0xff, stdout);
 	}
@@ -2015,6 +2177,150 @@
   printf("\n");
 #endif
 
+#if 0 //~ for debugging
+  for (i = 0; i < underlines->getLength(); ++i) {
+    underline = (TextUnderline *)underlines->get(i);
+    printf("underline: x=%g..%g y=%g..%g horiz=%d\n",
+	   underline->x0, underline->x1, underline->y0, underline->y1,
+	   underline->horiz);
+  }
+#endif
+
+  if (doHTML) {
+
+    //----- handle underlining
+    for (i = 0; i < underlines->getLength(); ++i) {
+      underline = (TextUnderline *)underlines->get(i);
+      if (underline->horiz) {
+	// rot = 0
+	if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) {
+	  startBaseIdx = pools[0]->getBaseIdx(underline->y0 + minUnderlineGap);
+	  endBaseIdx = pools[0]->getBaseIdx(underline->y0 + maxUnderlineGap);
+	  for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	    for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) {
+	      //~ need to check the y value against the word baseline
+	      if (underline->x0 < word0->xMin + underlineSlack &&
+		  word0->xMax - underlineSlack < underline->x1) {
+		word0->underlined = gTrue;
+	      }
+	    }
+	  }
+	}
+
+	// rot = 2
+	if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) {
+	  startBaseIdx = pools[2]->getBaseIdx(underline->y0 - maxUnderlineGap);
+	  endBaseIdx = pools[2]->getBaseIdx(underline->y0 - minUnderlineGap);
+	  for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	    for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) {
+	      if (underline->x0 < word0->xMin + underlineSlack &&
+		  word0->xMax - underlineSlack < underline->x1) {
+		word0->underlined = gTrue;
+	      }
+	    }
+	  }
+	}
+      } else {
+	// rot = 1
+	if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) {
+	  startBaseIdx = pools[1]->getBaseIdx(underline->x0 - maxUnderlineGap);
+	  endBaseIdx = pools[1]->getBaseIdx(underline->x0 - minUnderlineGap);
+	  for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	    for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) {
+	      if (underline->y0 < word0->yMin + underlineSlack &&
+		  word0->yMax - underlineSlack < underline->y1) {
+		word0->underlined = gTrue;
+	      }
+	    }
+	  }
+	}
+
+	// rot = 3
+	if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) {
+	  startBaseIdx = pools[3]->getBaseIdx(underline->x0 + minUnderlineGap);
+	  endBaseIdx = pools[3]->getBaseIdx(underline->x0 + maxUnderlineGap);
+	  for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	    for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) {
+	      if (underline->y0 < word0->yMin + underlineSlack &&
+		  word0->yMax - underlineSlack < underline->y1) {
+		word0->underlined = gTrue;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+
+    //----- handle links
+    for (i = 0; i < links->getLength(); ++i) {
+      link = (TextLink *)links->get(i);
+
+      // rot = 0
+      if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) {
+	startBaseIdx = pools[0]->getBaseIdx(link->yMin);
+	endBaseIdx = pools[0]->getBaseIdx(link->yMax);
+	for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	  for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) {
+	    if (link->xMin < word0->xMin + hyperlinkSlack &&
+		word0->xMax - hyperlinkSlack < link->xMax &&
+		link->yMin < word0->yMin + hyperlinkSlack &&
+		word0->yMax - hyperlinkSlack < link->yMax) {
+	      word0->link = link->link;
+	    }
+	  }
+	}
+      }
+
+      // rot = 2
+      if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) {
+	startBaseIdx = pools[2]->getBaseIdx(link->yMin);
+	endBaseIdx = pools[2]->getBaseIdx(link->yMax);
+	for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	  for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) {
+	    if (link->xMin < word0->xMin + hyperlinkSlack &&
+		word0->xMax - hyperlinkSlack < link->xMax &&
+		link->yMin < word0->yMin + hyperlinkSlack &&
+		word0->yMax - hyperlinkSlack < link->yMax) {
+	      word0->link = link->link;
+	    }
+	  }
+	}
+      }
+
+      // rot = 1
+      if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) {
+	startBaseIdx = pools[1]->getBaseIdx(link->xMin);
+	endBaseIdx = pools[1]->getBaseIdx(link->xMax);
+	for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	  for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) {
+	    if (link->yMin < word0->yMin + hyperlinkSlack &&
+		word0->yMax - hyperlinkSlack < link->yMax &&
+		link->xMin < word0->xMin + hyperlinkSlack &&
+		word0->xMax - hyperlinkSlack < link->xMax) {
+	      word0->link = link->link;
+	    }
+	  }
+	}
+      }
+
+      // rot = 3
+      if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) {
+	startBaseIdx = pools[3]->getBaseIdx(link->xMin);
+	endBaseIdx = pools[3]->getBaseIdx(link->xMax);
+	for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+	  for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) {
+	    if (link->yMin < word0->yMin + hyperlinkSlack &&
+		word0->yMax - hyperlinkSlack < link->yMax &&
+		link->xMin < word0->xMin + hyperlinkSlack &&
+		word0->xMax - hyperlinkSlack < link->xMax) {
+	      word0->link = link->link;
+	    }
+	  }
+	}
+      }
+    }
+  }
+
   //----- assemble the blocks
 
   //~ add an outer loop for writing mode (vertical text)
@@ -2803,21 +3109,21 @@
 	      }
 	    }
 	  } else {
-	  if ((startAtTop ||
-	       yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
-	      (stopAtBottom ||
+	    if ((startAtTop ||
+		 yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
+		(stopAtBottom ||
 		 yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
 	      if (!found ||
 		  yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
-	      xMin0 = xMin1;
-	      xMax0 = xMax1;
-	      yMin0 = yMin1;
-	      yMax0 = yMax1;
-	      found = gTrue;
+		xMin0 = xMin1;
+		xMax0 = xMax1;
+		yMin0 = yMin1;
+		yMax0 = yMax1;
+		found = gTrue;
+	      }
 	    }
 	  }
 	}
-      }
 	if (backward) {
 	  --j;
 	  --p;
@@ -2861,7 +3167,7 @@
   char space[8], eol[16];
   int spaceLen, eolLen;
   int lastRot;
-  double x, y;
+  double x, y, delta;
   int col, idx0, idx1, i, j;
   GBool multiLine, oneRot;
 
@@ -3028,6 +3334,17 @@
       qsort(frags, nFrags, sizeof(TextLineFrag),
 	    &TextLineFrag::cmpYXPrimaryRot);
     }
+    i = 0;
+    while (i < nFrags) {
+      delta = maxIntraLineDelta * frags[i].line->words->fontSize;
+      for (j = i+1;
+	   j < nFrags && fabs(frags[j].base - frags[i].base) < delta;
+	   ++j) ;
+      qsort(frags + i, j - i, sizeof(TextLineFrag),
+	    oneRot ? &TextLineFrag::cmpXYColumnLineRot
+	           : &TextLineFrag::cmpXYColumnPrimaryRot);
+      i = j;
+    }
 
     col = 0;
     multiLine = gFalse;
@@ -3744,7 +4061,8 @@
   int spaceLen, eolLen, eopLen;
   GBool pageBreaks;
   GooString *s;
-  int col, i, d, n;
+  double delta;
+  int col, i, j, d, n;
 
   // get the output encoding
   if (!(uMap = globalParams->getTextEncoding())) {
@@ -3809,6 +4127,16 @@
       }
     }
     qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot);
+    i = 0;
+    while (i < nFrags) {
+      delta = maxIntraLineDelta * frags[i].line->words->fontSize;
+      for (j = i+1;
+	   j < nFrags && fabs(frags[j].base - frags[i].base) < delta;
+	   ++j) ;
+      qsort(frags + i, j - i, sizeof(TextLineFrag),
+	    &TextLineFrag::cmpXYColumnPrimaryRot);
+      i = j;
+    }
 
 #if 0 // for debugging
     printf("*** line fragments ***\n");
@@ -4094,7 +4422,7 @@
 // TextOutputDev
 //------------------------------------------------------------------------
 
-static void outputToFile(void *stream, char *text, int len) {
+static void TextOutputDev_outputToFile(void *stream, char *text, int len) {
   fwrite(text, 1, len, (FILE *)stream);
 }
 
@@ -4103,6 +4431,7 @@
   text = NULL;
   physLayout = physLayoutA;
   rawOrder = rawOrderA;
+  doHTML = gFalse;
   ok = gTrue;
 
   // open file
@@ -4121,7 +4450,7 @@
       ok = gFalse;
       return;
     }
-    outputFunc = &outputToFile;
+    outputFunc = &TextOutputDev_outputToFile;
   } else {
     outputStream = NULL;
   }
@@ -4137,6 +4466,7 @@
   needClose = gFalse;
   physLayout = physLayoutA;
   rawOrder = rawOrderA;
+  doHTML = gFalse;
   text = new TextPage(rawOrderA);
   ok = gTrue;
 }
@@ -4159,7 +4489,7 @@
 
 void TextOutputDev::endPage() {
   text->endPage();
-  text->coalesce(physLayout);
+  text->coalesce(physLayout, doHTML);
   if (outputStream) {
     text->dump(outputStream, outputFunc, physLayout);
   }
@@ -4182,6 +4512,153 @@
   text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
 }
 
+void TextOutputDev::stroke(GfxState *state) {
+  GfxPath *path;
+  GfxSubpath *subpath;
+  double x[2], y[2];
+
+  if (!doHTML) {
+    return;
+  }
+  path = state->getPath();
+  if (path->getNumSubpaths() != 1) {
+    return;
+  }
+  subpath = path->getSubpath(0);
+  if (subpath->getNumPoints() != 2) {
+    return;
+  }
+  state->transform(subpath->getX(0), subpath->getY(0), &x[0], &y[0]);
+  state->transform(subpath->getX(1), subpath->getY(1), &x[1], &y[1]);
+
+  // look for a vertical or horizontal line
+  if (x[0] == x[1] || y[0] == y[1]) {
+    text->addUnderline(x[0], y[0], x[1], y[1]);
+  }
+}
+
+void TextOutputDev::fill(GfxState *state) {
+  GfxPath *path;
+  GfxSubpath *subpath;
+  double x[5], y[5];
+  double rx0, ry0, rx1, ry1, t;
+  int i;
+
+  if (!doHTML) {
+    return;
+  }
+  path = state->getPath();
+  if (path->getNumSubpaths() != 1) {
+    return;
+  }
+  subpath = path->getSubpath(0);
+  if (subpath->getNumPoints() != 5) {
+    return;
+  }
+  for (i = 0; i < 5; ++i) {
+    if (subpath->getCurve(i)) {
+      return;
+    }
+    state->transform(subpath->getX(i), subpath->getY(i), &x[i], &y[i]);
+  }
+
+  // look for a rectangle
+  if (x[0] == x[1] && y[1] == y[2] && x[2] == x[3] && y[3] == y[4] &&
+      x[0] == x[4] && y[0] == y[4]) {
+    rx0 = x[0];
+    ry0 = y[0];
+    rx1 = x[2];
+    ry1 = y[1];
+  } else if (y[0] == y[1] && x[1] == x[2] && y[2] == y[3] && x[3] == x[4] &&
+	     x[0] == x[4] && y[0] == y[4]) {
+    rx0 = x[0];
+    ry0 = y[0];
+    rx1 = x[1];
+    ry1 = y[2];
+  } else {
+    return;
+  }
+  if (rx1 < rx0) {
+    t = rx0;
+    rx0 = rx1;
+    rx1 = t;
+  }
+  if (ry1 < ry0) {
+    t = ry0;
+    ry0 = ry1;
+    ry1 = t;
+  }
+
+  // skinny horizontal rectangle
+  if (ry1 - ry0 < rx1 - rx0) {
+    if (ry1 - ry0 < maxUnderlineWidth) {
+      ry0 = 0.5 * (ry0 + ry1);
+      text->addUnderline(rx0, ry0, rx1, ry0);
+    }
+
+  // skinny vertical rectangle
+  } else {
+    if (rx1 - rx0 < maxUnderlineWidth) {
+      rx0 = 0.5 * (rx0 + rx1);
+      text->addUnderline(rx0, ry0, rx0, ry1);
+    }
+  }
+}
+
+void TextOutputDev::eoFill(GfxState *state) {
+  if (!doHTML) {
+    return;
+  }
+  fill(state);
+}
+
+void TextOutputDev::processLink(Link *link, Catalog * /*catalog*/) {
+  double x1, y1, x2, y2;
+  int xMin, yMin, xMax, yMax, x, y;
+
+  if (!doHTML) {
+    return;
+  }
+  link->getRect(&x1, &y1, &x2, &y2);
+  cvtUserToDev(x1, y1, &x, &y);
+  xMin = xMax = x;
+  yMin = yMax = y;
+  cvtUserToDev(x1, y2, &x, &y);
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+  cvtUserToDev(x2, y1, &x, &y);
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+  cvtUserToDev(x2, y2, &x, &y);
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+  text->addLink(xMin, yMin, xMax, yMax, link);
+}
+
 GBool TextOutputDev::findText(Unicode *s, int len,
 			      GBool startAtTop, GBool stopAtBottom,
 			      GBool startAtLast, GBool stopAtLast,

Index: TextOutputDev.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/TextOutputDev.h,v
retrieving revision 1.12
retrieving revision 1.12.4.1
diff -u -d -r1.12 -r1.12.4.1
--- TextOutputDev.h	19 May 2006 22:04:17 -0000	1.12
+++ TextOutputDev.h	6 Apr 2007 14:22:23 -0000	1.12.4.1
@@ -26,6 +26,7 @@
 class GfxFont;
 class GfxState;
 class UnicodeMap;
+class Link;
 
 class TextWord;
 class TextPool;
@@ -53,11 +54,24 @@
 
   GBool matches(GfxState *state);
 
+#if TEXTOUT_WORD_LIST
+  // Get the font name (which may be NULL).
+  GooString *getFontName() { return fontName; }
+
+  // Get font descriptor flags.
+  GBool isFixedWidth() { return flags & fontFixedWidth; }
+  GBool isSerif() { return flags & fontSerif; }
+  GBool isSymbolic() { return flags & fontSymbolic; }
+  GBool isItalic() { return flags & fontItalic; }
+  GBool isBold() { return flags & fontBold; }
+#endif
+
 private:
 
   GfxFont *gfxFont;
 #if TEXTOUT_WORD_LIST
   GooString *fontName;
+  int flags;
 #endif
 
   friend class TextWord;
@@ -99,6 +113,12 @@
   void visitSelection(TextSelectionVisitor *visitor,
 		      PDFRectangle *selection);
 
+  // Get the TextFontInfo object associated with this word.
+  TextFontInfo *getFontInfo() { return font; }
+
+  // Get the next TextWord on the linked list.
+  TextWord *getNext() { return next; }
+
 #if TEXTOUT_WORD_LIST
   int getLength() { return len; }
   const Unicode *getChar(int idx) { return &text[idx]; }
@@ -108,11 +128,16 @@
     { *r = colorR; *g = colorG; *b = colorB; }
   void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
     { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+  void getCharBBox(int charIdx, double *xMinA, double *yMinA,
+		   double *xMaxA, double *yMaxA);
   double getFontSize() { return fontSize; }
   int getRotation() { return rot; }
   int getCharPos() { return charPos; }
   int getCharLen() { return charLen; }
+  GBool getSpaceAfter() { return spaceAfter; }
 #endif
+  GBool isUnderlined() { return underlined; }
+  Link *getLink() { return link; }
   double getEdge(int i) { return edge[i]; }
   double getBaseline () { return base; }
   GBool hasSpaceAfter  () { return spaceAfter; }
@@ -145,6 +170,9 @@
          colorB;
 #endif
 
+  GBool underlined;
+  Link *link;
+
   friend class TextPool;
   friend class TextLine;
   friend class TextBlock;
@@ -222,6 +250,15 @@
   void visitSelection(TextSelectionVisitor *visitor,
 		      PDFRectangle *selection);
 
+  // Get the head of the linked list of TextWords.
+  TextWord *getWords() { return words; }
+
+  // Get the next TextLine on the linked list.
+  TextLine *getNext() { return next; }
+
+  // Returns true if the last char of the line is a hyphen.
+  GBool isHyphenated() { return hyphenated; }
+
 private:
 
   TextBlock *blk;		// parent block
@@ -287,6 +324,12 @@
   void visitSelection(TextSelectionVisitor *visitor,
 		      PDFRectangle *selection);
 
+  // Get the head of the linked list of TextLines.
+  TextLine *getLines() { return lines; }
+
+  // Get the next TextBlock on the linked list.
+  TextBlock *getNext() { return next; }
+
 private:
 
   TextPage *page;		// the parent page
@@ -334,6 +377,12 @@
   // primary axis.
   GBool blockFits(TextBlock *blk, TextBlock *prevBlk);
 
+  // Get the head of the linked list of TextBlocks.
+  TextBlock *getBlocks() { return blocks; }
+
+  // Get the next TextFlow on the linked list.
+  TextFlow *getNext() { return next; }
+
 private:
 
   TextPage *page;		// the parent page
@@ -373,7 +422,7 @@
 
 private:
 
-  GooList *words;
+  GooList *words;			// [TextWord]
 };
 
 #endif // TEXTOUT_WORD_LIST
@@ -414,8 +463,14 @@
   // Add a word, sorting it into the list of words.
   void addWord(TextWord *word);
 
+  // Add a (potential) underline.
+  void addUnderline(double x0, double y0, double x1, double y1);
+
+  // Add a hyperlink.
+  void addLink(int xMin, int yMin, int xMax, int yMax, Link *link);
+
   // Coalesce strings that look like parts of the same line.
-  void coalesce(GBool physLayout);
+  void coalesce(GBool physLayout, GBool doHTML);
 
   // Find a string.  If <startAtTop> is true, starts looking at the
   // top of the page; else if <startAtLast> is true, starts looking
@@ -459,6 +514,9 @@
   void dump(void *outputStream, TextOutputFunc outputFunc,
 	    GBool physLayout);
 
+  // Get the head of the linked list of TextFlows.
+  TextFlow *getFlows() { return flows; }
+
 #if TEXTOUT_WORD_LIST
   // Build a flat word list, in content stream order (if
   // this->rawOrder is true), physical layout order (if <physLayout>
@@ -504,6 +562,9 @@
          lastFindYMin;
   GBool haveLastFind;
 
+  GooList *underlines;		// [TextUnderline]
+  GooList *links;		// [TextLink]
+
   friend class TextLine;
   friend class TextLineFrag;
   friend class TextBlock;
@@ -576,6 +637,14 @@
 			double originX, double originY,
 			CharCode c, int nBytes, Unicode *u, int uLen);
 
+  //----- path painting
+  virtual void stroke(GfxState *state);
+  virtual void fill(GfxState *state);
+  virtual void eoFill(GfxState *state);
+
+  //----- link borders
+  virtual void processLink(Link *link, Catalog *catalog);
+
   //----- special access
 
   // Find a string.  If <startAtTop> is true, starts looking at the
@@ -623,6 +692,9 @@
   // transferring ownership to the caller.
   TextPage *takeText();
 
+  // Turn extra processing for HTML conversion on or off.
+  void enableHTMLExtras(GBool doHTMLA) { doHTML = doHTMLA; }
+
 private:
 
   TextOutputFunc outputFunc;	// output function
@@ -633,6 +705,7 @@
   GBool physLayout;		// maintain original physical layout when
 				//   dumping text
   GBool rawOrder;		// keep text in content stream order
+  GBool doHTML;			// extra processing for HTML conversion
   GBool ok;			// set up ok?
 };
 

--- UGooString.cc DELETED ---

--- UGooString.h DELETED ---

Index: XRef.cc
===================================================================
RCS file: /cvs/poppler/poppler/poppler/XRef.cc,v
retrieving revision 1.14
retrieving revision 1.14.2.1
diff -u -d -r1.14 -r1.14.2.1
--- XRef.cc	24 Feb 2007 23:32:23 -0000	1.14
+++ XRef.cc	6 Apr 2007 14:22:23 -0000	1.14.2.1
@@ -24,7 +24,6 @@
 #include "Dict.h"
 #include "Error.h"
 #include "ErrorCodes.h"
-#include "UGooString.h"
 #include "XRef.h"
 
 //------------------------------------------------------------------------
@@ -124,7 +123,7 @@
   objStr.streamReset();
   obj1.initNull();
   str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first);
-  parser = new Parser(xref, new Lexer(xref, str));
+  parser = new Parser(xref, new Lexer(xref, str), gFalse);
   for (i = 0; i < nObjects; ++i) {
     parser->getObj(&obj1);
     parser->getObj(&obj2);
@@ -165,7 +164,7 @@
       str = new EmbedStream(objStr.getStream(), &obj1, gTrue,
 			    offsets[i+1] - offsets[i]);
     }
-    parser = new Parser(xref, new Lexer(xref, str));
+    parser = new Parser(xref, new Lexer(xref, str), gFalse);
     parser->getObj(&objs[i]);
     while (str->getChar() != EOF) ;
     delete parser;
@@ -331,7 +330,8 @@
   obj.initNull();
   parser = new Parser(NULL,
 	     new Lexer(NULL,
-	       str->makeSubStream(start + *pos, gFalse, 0, &obj)));
+	       str->makeSubStream(start + *pos, gFalse, 0, &obj)),
+	     gTrue);
   parser->getObj(&obj);
 
   // parse an old-style xref table
@@ -689,7 +689,7 @@
   size = 0;
   entries = NULL;
 
-  error(0, "PDF file is damaged - attempting to reconstruct xref table...");
+  error(-1, "PDF file is damaged - attempting to reconstruct xref table...");
   gotRoot = gFalse;
   streamEndsLen = streamEndsSize = 0;
 
@@ -701,12 +701,16 @@
     }
     p = buf;
 
+    // skip whitespace
+    while (*p && Lexer::isSpace(*p & 0xff)) ++p;
+
     // got trailer dictionary
     if (!strncmp(p, "trailer", 7)) {
       obj.initNull();
       parser = new Parser(NULL,
 		 new Lexer(NULL,
-		   str->makeSubStream(pos + 7, gFalse, 0, &obj)));
+		   str->makeSubStream(pos + 7, gFalse, 0, &obj)),
+		 gFalse);
       parser->getObj(&newTrailerDict);
       if (newTrailerDict.isDict()) {
 	newTrailerDict.dictLookupNF("Root", &obj);
@@ -799,7 +803,8 @@
 
 void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
 			 Guchar *fileKeyA, int keyLengthA,
-			 int encVersionA, int encRevisionA) {
+			 int encVersionA, int encRevisionA,
+			 CryptAlgorithm encAlgorithmA) {
   int i;
 
   encrypted = gTrue;
@@ -815,6 +820,7 @@
   }
   encVersion = encVersionA;
   encRevision = encRevisionA;
+  encAlgorithm = encAlgorithmA;
 }
 
 GBool XRef::okToPrint(GBool ignoreOwnerPW) {
@@ -883,7 +889,8 @@
     obj1.initNull();
     parser = new Parser(this,
 	       new Lexer(this,
-		 str->makeSubStream(start + e->offset, gFalse, 0, &obj1)));
+		 str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
+	       gTrue);
     parser->getObj(&obj1);
     parser->getObj(&obj2);
     parser->getObj(&obj3);
@@ -896,8 +903,8 @@
       delete parser;
       goto err;
     }
-    parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength,
-		   num, gen);
+    parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL,
+		   encAlgorithm, keyLength, num, gen);
     obj1.free();
     obj2.free();
     obj3.free();
@@ -959,7 +966,7 @@
   return gTrue;
 }
 
-int XRef::getNumEntry(int offset) const
+int XRef::getNumEntry(Guint offset) const
 {
   if (size > 0)
   {

Index: XRef.h
===================================================================
RCS file: /cvs/poppler/poppler/poppler/XRef.h,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -d -r1.7 -r1.7.2.1
--- XRef.h	24 Feb 2007 23:32:23 -0000	1.7
+++ XRef.h	6 Apr 2007 14:22:23 -0000	1.7.2.1
@@ -59,7 +59,8 @@
   // Set the encryption parameters.
   void setEncryption(int permFlagsA, GBool ownerPasswordOkA,
 		     Guchar *fileKeyA, int keyLengthA,
-		     int encVersionA, int encRevisionA);
+		     int encVersionA, int encRevisionA,
+		     CryptAlgorithm encAlgorithmA);
 
   // Is the file encrypted?
   GBool isEncrypted() { return encrypted; }
@@ -99,7 +100,7 @@
   GBool getStreamEnd(Guint streamStart, Guint *streamEnd);
 
   // Retuns the entry that belongs to the offset
-  int getNumEntry(int offset) const;
+  int getNumEntry(Guint offset) const;
 
   // Direct access.
   int getSize() { return size; }
@@ -130,6 +131,7 @@
   GBool encrypted;		// true if file is encrypted
   int encRevision;		
   int encVersion;		// encryption algorithm
+  CryptAlgorithm encAlgorithm;	// encryption algorithm
   int keyLength;		// length of key, in bytes
   int permFlags;		// permission bits
   Guchar fileKey[16];		// file decryption key



More information about the poppler mailing list