The attached patches implement Type 3 fonts in the cairo backend using a cairo user-font. The patches can also be pulled from the user-font branch at git://people.freedesktop.org/~ajohnson/poppler

This should fix the following bugs:

  https://bugs.freedesktop.org/show_bug.cgi?id=12769
  https://bugs.freedesktop.org/show_bug.cgi?id=17497
  https://bugs.freedesktop.org/show_bug.cgi?id=18116

The patches require cairo 1.8.2. There is a bug in cairo 1.8.2 when computing user-font glyph bounding boxes. If the Type 3 glyphs do not provide the bounding box (ie the d0 operator is used) the glyphs will not display correctly. This bug has been fixed in cairo git and will be in the next stable release (1.8.4).

>From b28526bde399bab9f9c8625c50d8a73377f4864d Mon Sep 17 00:00:00 2001
From: Adrian Johnson <[EMAIL PROTECTED]>
Date: Fri, 31 Oct 2008 20:55:14 +1030
Subject: [PATCH] Refactor CairoFont

Create a CairoFreeType subclass and move the FreeType specific code
into it.
---
 poppler/CairoFontEngine.cc |  197 +++++++++++++++++++++++++-------------------
 poppler/CairoFontEngine.h  |   26 +++++--
 2 files changed, 131 insertions(+), 92 deletions(-)

diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 8d5ad72..587275d 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -50,16 +50,106 @@
 #pragma implementation
 #endif
 
-static void fileWrite(void *stream, char *data, int len) {
-  fwrite(data, 1, len, (FILE *)stream);
-}
 
 //------------------------------------------------------------------------
 // CairoFont
 //------------------------------------------------------------------------
 
+CairoFont::CairoFont(Ref ref,
+		     cairo_font_face_t *cairo_font_face,
+		     Gushort *codeToGID,
+		     int codeToGIDLen,
+		     GBool substitute) : ref(ref),
+					 cairo_font_face(cairo_font_face),
+					 codeToGID(codeToGID),
+					 codeToGIDLen(codeToGIDLen),
+					 substitute(substitute)  { }
+
+CairoFont::~CairoFont() {
+  cairo_font_face_destroy (cairo_font_face);
+  gfree(codeToGID);
+}
+
+GBool
+CairoFont::matches(Ref &other) {
+  return (other.num == ref.num && other.gen == ref.gen);
+}
+
+cairo_font_face_t *
+CairoFont::getFontFace(void) {
+  return cairo_font_face;
+}
+
+unsigned long
+CairoFont::getGlyph(CharCode code,
+		    Unicode *u, int uLen) {
+  FT_UInt gid;
+
+  if (codeToGID && code < codeToGIDLen) {
+    gid = (FT_UInt)codeToGID[code];
+  } else {
+    gid = (FT_UInt)code;
+  }
+  return gid;
+}
+
+double
+CairoFont::getSubstitutionCorrection(GfxFont *gfxFont)
+{
+  double w1, w2,w3;
+  CharCode code;
+  char *name;
+
+  // for substituted fonts: adjust the font matrix -- compare the
+  // width of 'm' in the original font and the substituted font
+  if (isSubstitute() && !gfxFont->isCIDFont()) {
+    for (code = 0; code < 256; ++code) {
+      if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
+	  name[0] == 'm' && name[1] == '\0') {
+	break;
+      }
+    }
+    if (code < 256) {
+      w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
+      {
+	cairo_matrix_t m;
+	cairo_matrix_init_identity(&m);
+	cairo_font_options_t *options = cairo_font_options_create();
+	cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+	cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF);
+	cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options);
+
+	cairo_text_extents_t extents;
+	cairo_scaled_font_text_extents(scaled_font, "m", &extents);
+
+	cairo_scaled_font_destroy(scaled_font);
+	cairo_font_options_destroy(options);
+	w3 = extents.width;
+	w2 = extents.x_advance;
+      }
+      if (!gfxFont->isSymbolic()) {
+	// if real font is substantially narrower than substituted
+	// font, reduce the font size accordingly
+	if (w1 > 0.01 && w1 < 0.9 * w2) {
+	  w1 /= w2;
+	  return w1;
+	}
+      }
+    }
+  }
+  return 1.0;
+}
+
+//------------------------------------------------------------------------
+// CairoFreeTypeFont
+//------------------------------------------------------------------------
+
 static cairo_user_data_key_t _ft_cairo_key;
 
+static void fileWrite(void *stream, char *data, int len) {
+  fwrite(data, 1, len, (FILE *)stream);
+}
+
 static void
 _ft_done_face_uncached (void *closure)
 {
@@ -234,7 +324,22 @@ _ft_new_face (FT_Library lib,
 #define _ft_new_face _ft_new_face_uncached
 #endif
 
-CairoFont *CairoFont::create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs) {
+CairoFreeTypeFont::CairoFreeTypeFont(Ref ref,
+				     cairo_font_face_t *cairo_font_face,
+				     FT_Face face,
+				     Gushort *codeToGID,
+				     int codeToGIDLen,
+				     GBool substitute) : CairoFont(ref,
+								   cairo_font_face,
+								   codeToGID,
+								   codeToGIDLen,
+								   substitute),
+							 face(face) { }
+
+CairoFreeTypeFont::~CairoFreeTypeFont() { }
+
+CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
+					     FT_Library lib, GBool useCIDs) {
   Ref embRef;
   Object refObj, strObj;
   GooString *tmpFileName, *fileName,*tmpFileName2;
@@ -415,7 +520,7 @@ CairoFont *CairoFont::create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool
     delete tmpFileName;
   }
 
-  return new CairoFont(ref,
+  return new CairoFreeTypeFont(ref,
 		       font_face, face,
 		       codeToGID, codeToGIDLen,
 		       substitute);
@@ -426,85 +531,6 @@ CairoFont *CairoFont::create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool
   return NULL;
 }
 
-CairoFont::CairoFont(Ref ref, cairo_font_face_t *cairo_font_face, FT_Face face,
-    Gushort *codeToGID, int codeToGIDLen, GBool substitute) : ref(ref), cairo_font_face(cairo_font_face),
-					    face(face), codeToGID(codeToGID),
-					    codeToGIDLen(codeToGIDLen), substitute(substitute) { }
-
-CairoFont::~CairoFont() {
-  cairo_font_face_destroy (cairo_font_face);
-  gfree(codeToGID);
-}
-
-GBool
-CairoFont::matches(Ref &other) {
-  return (other.num == ref.num && other.gen == ref.gen);
-}
-
-cairo_font_face_t *
-CairoFont::getFontFace(void) {
-  return cairo_font_face;
-}
-
-unsigned long
-CairoFont::getGlyph(CharCode code,
-		    Unicode *u, int uLen) {
-  FT_UInt gid;
-
-  if (codeToGID && code < codeToGIDLen) {
-    gid = (FT_UInt)codeToGID[code];
-  } else {
-    gid = (FT_UInt)code;
-  }
-  return gid;
-}
-
-double
-CairoFont::getSubstitutionCorrection(GfxFont *gfxFont)
-{
-  double w1, w2,w3;
-  CharCode code;
-  char *name;
-
-  // for substituted fonts: adjust the font matrix -- compare the
-  // width of 'm' in the original font and the substituted font
-  if (isSubstitute() && !gfxFont->isCIDFont()) {
-    for (code = 0; code < 256; ++code) {
-      if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
-	  name[0] == 'm' && name[1] == '\0') {
-	break;
-      }
-    }
-    if (code < 256) {
-      w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
-      {
-	cairo_matrix_t m;
-	cairo_matrix_init_identity(&m);
-	cairo_font_options_t *options = cairo_font_options_create();
-	cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
-	cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF);
-	cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options);
-
-	cairo_text_extents_t extents;
-	cairo_scaled_font_text_extents(scaled_font, "m", &extents);
-
-	cairo_scaled_font_destroy(scaled_font);
-	cairo_font_options_destroy(options);
-	w3 = extents.width;
-	w2 = extents.x_advance;
-      }
-      if (!gfxFont->isSymbolic()) {
-	// if real font is substantially narrower than substituted
-	// font, reduce the font size accordingly
-	if (w1 > 0.01 && w1 < 0.9 * w2) {
-	  w1 /= w2;
-	  return w1;
-	}
-      }
-    }
-  }
-  return 1.0;
-}
 
 //------------------------------------------------------------------------
 // CairoFontEngine
@@ -560,7 +586,7 @@ CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref) {
     }
   }
   
-  font = CairoFont::create (gfxFont, xref, lib, useCIDs);
+  font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs);
   //XXX: if font is null should we still insert it into the cache?
   if (fontCache[cairoFontCacheSize - 1]) {
     delete fontCache[cairoFontCacheSize - 1];
@@ -571,4 +597,3 @@ CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref) {
   fontCache[0] = font;
   return font;
 }
-
diff --git a/poppler/CairoFontEngine.h b/poppler/CairoFontEngine.h
index 5ecdcdf..8b7a99f 100644
--- a/poppler/CairoFontEngine.h
+++ b/poppler/CairoFontEngine.h
@@ -38,8 +38,12 @@
 
 class CairoFont {
 public:
-  static CairoFont *create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs);
-  ~CairoFont();
+  CairoFont(Ref ref,
+	      cairo_font_face_t *face,
+	      Gushort *codeToGID,
+	      int codeToGIDLen,
+	      GBool substitute);
+  virtual ~CairoFont();
 
   GBool matches(Ref &other);
   cairo_font_face_t *getFontFace(void);
@@ -47,12 +51,9 @@ public:
   double getSubstitutionCorrection(GfxFont *gfxFont);
 
   GBool isSubstitute() { return substitute; }
-private:
-  CairoFont(Ref ref, cairo_font_face_t *cairo_font_face, FT_Face face,
-      Gushort *codeToGID, int codeToGIDLen, GBool substitute);
+protected:
   Ref ref;
   cairo_font_face_t *cairo_font_face;
-  FT_Face face;
 
   Gushort *codeToGID;
   int codeToGIDLen;
@@ -62,6 +63,19 @@ private:
 
 //------------------------------------------------------------------------
 
+class CairoFreeTypeFont : public CairoFont {
+public:
+  static CairoFreeTypeFont *create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs);
+  virtual ~CairoFreeTypeFont();
+
+private:
+  CairoFreeTypeFont(Ref ref, cairo_font_face_t *cairo_font_face, FT_Face face,
+	    Gushort *codeToGID, int codeToGIDLen, GBool substitute);
+  FT_Face face;
+};
+
+//------------------------------------------------------------------------
+
 #define cairoFontCacheSize 64
 
 //------------------------------------------------------------------------
-- 
1.5.6.3

>From 315db439df1866e688071d4e65f985fd14c3526d Mon Sep 17 00:00:00 2001
From: Adrian Johnson <[EMAIL PROTECTED]>
Date: Fri, 31 Oct 2008 21:11:01 +1030
Subject: [PATCH] Use correct return type in _ft_new_face

---
 poppler/CairoFontEngine.cc |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 587275d..61e00a3 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -313,7 +313,7 @@ _ft_new_face (FT_Library lib,
   {
     cairo_font_face_destroy (l->font_face);
     _ft_done_face (l);
-    return NULL;
+    return gFalse;
   }
 
   *face_out = l->face;
-- 
1.5.6.3

>From 6bdd271569aebfd01aea6c6875a839a58c0314e5 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <[EMAIL PROTECTED]>
Date: Fri, 31 Oct 2008 22:44:41 +1030
Subject: [PATCH] Allow multiple instances of CairoOutputDev to be created

for the same document that shares the same CairoFontEngine.
---
 poppler/CairoOutputDev.cc |   16 +++++++++++-----
 poppler/CairoOutputDev.h  |    4 +++-
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 03cc059..25335b7 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -114,6 +114,7 @@ CairoOutputDev::CairoOutputDev() {
   }
 
   fontEngine = NULL;
+  fontEngine_owner = gFalse;
   glyphs = NULL;
   fill_pattern = NULL;
   stroke_pattern = NULL;
@@ -134,7 +135,7 @@ CairoOutputDev::CairoOutputDev() {
 }
 
 CairoOutputDev::~CairoOutputDev() {
-  if (fontEngine) {
+  if (fontEngine_owner && fontEngine) {
     delete fontEngine;
   }
 
@@ -171,12 +172,17 @@ void CairoOutputDev::setCairo(cairo_t *cairo)
   }
 }
 
-void CairoOutputDev::startDoc(XRef *xrefA) {
+void CairoOutputDev::startDoc(XRef *xrefA, CairoFontEngine *parentFontEngine) {
   xref = xrefA;
-  if (fontEngine) {
-    delete fontEngine;
+  if (parentFontEngine) {
+    fontEngine = parentFontEngine;
+  } else {
+    if (fontEngine) {
+      delete fontEngine;
+    }
+    fontEngine = new CairoFontEngine(ft_lib);
+    fontEngine_owner = gTrue;
   }
-  fontEngine = new CairoFontEngine(ft_lib);
 }
 
 void CairoOutputDev::startPage(int pageNum, GfxState *state) {
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 9a18613..27b39ed 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -207,7 +207,7 @@ public:
   //----- special access
 
   // Called to indicate that a new PDF document has been loaded.
-  void startDoc(XRef *xrefA);
+  void startDoc(XRef *xrefA, CairoFontEngine *fontEngine = NULL);
  
   GBool isReverseVideo() { return gFalse; }
   
@@ -229,6 +229,8 @@ protected:
   static GBool ft_lib_initialized;
 
   CairoFontEngine *fontEngine;
+  GBool fontEngine_owner;
+
   cairo_t *cairo;
   cairo_matrix_t orig_matrix;
   GBool needFontUpdate;                // set when the font needs to be updated
-- 
1.5.6.3

>From 5606c3e096b809eb075089d1f31c7c7698809cb6 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <[EMAIL PROTECTED]>
Date: Sat, 1 Nov 2008 00:26:40 +1030
Subject: [PATCH] Make the catalog available to CairoFontEngine

---
 glib/poppler-document.cc   |    3 ++-
 poppler/CairoFontEngine.cc |    2 +-
 poppler/CairoFontEngine.h  |    3 ++-
 poppler/CairoOutputDev.cc  |    7 +++++--
 poppler/CairoOutputDev.h   |    3 ++-
 test/pdf-inspector.cc      |    2 +-
 6 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index 7637af4..ef5deb0 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -106,14 +106,15 @@ _poppler_document_new_from_pdfdoc (PDFDoc  *newDoc,
 
 #if defined (HAVE_CAIRO)
   document->output_dev = new CairoOutputDev ();
+  document->output_dev->startDoc(document->doc->getXRef (), document->doc->getCatalog ());
 #elif defined (HAVE_SPLASH)
   SplashColor white;
   white[0] = 255;
   white[1] = 255;
   white[2] = 255;
   document->output_dev = new SplashOutputDev(splashModeRGB8, 4, gFalse, white);
-#endif
   document->output_dev->startDoc(document->doc->getXRef ());
+#endif
 
   return document;
 }
diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 61e00a3..75340b8 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -561,7 +561,7 @@ CairoFontEngine::~CairoFontEngine() {
 }
 
 CairoFont *
-CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref) {
+CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref, Catalog *catalog) {
   int i, j;
   Ref ref;
   CairoFont *font;
diff --git a/poppler/CairoFontEngine.h b/poppler/CairoFontEngine.h
index 8b7a99f..1f25026 100644
--- a/poppler/CairoFontEngine.h
+++ b/poppler/CairoFontEngine.h
@@ -35,6 +35,7 @@
 #include <cairo-ft.h>
 
 #include "GfxFont.h"
+#include "Catalog.h"
 
 class CairoFont {
 public:
@@ -89,7 +90,7 @@ public:
   CairoFontEngine(FT_Library libA);
   ~CairoFontEngine();
 
-  CairoFont *getFont(GfxFont *gfxFont, XRef *xref);
+  CairoFont *getFont(GfxFont *gfxFont, XRef *xref, Catalog *catalog);
 
 private:
   CairoFont *fontCache[cairoFontCacheSize];
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 25335b7..eec5167 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -107,6 +107,7 @@ GBool CairoOutputDev::ft_lib_initialized = gFalse;
 
 CairoOutputDev::CairoOutputDev() {
   xref = NULL;
+  catalog = NULL;
 
   if (!ft_lib_initialized) {
     FT_Init_FreeType(&ft_lib);
@@ -172,8 +173,10 @@ void CairoOutputDev::setCairo(cairo_t *cairo)
   }
 }
 
-void CairoOutputDev::startDoc(XRef *xrefA, CairoFontEngine *parentFontEngine) {
+void CairoOutputDev::startDoc(XRef *xrefA, Catalog *catalogA,
+			      CairoFontEngine *parentFontEngine) {
   xref = xrefA;
+  catalog = catalogA;
   if (parentFontEngine) {
     fontEngine = parentFontEngine;
   } else {
@@ -414,7 +417,7 @@ void CairoOutputDev::updateFont(GfxState *state) {
   if (state->getFont()->getType() == fontType3)	 
     return;
 
-  currentFont = fontEngine->getFont (state->getFont(), xref);
+  currentFont = fontEngine->getFont (state->getFont(), xref, catalog);
 
   if (!currentFont)
     return;
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 27b39ed..d70740d 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -207,7 +207,7 @@ public:
   //----- special access
 
   // Called to indicate that a new PDF document has been loaded.
-  void startDoc(XRef *xrefA, CairoFontEngine *fontEngine = NULL);
+  void startDoc(XRef *xrefA, Catalog *catalogA, CairoFontEngine *fontEngine = NULL);
  
   GBool isReverseVideo() { return gFalse; }
   
@@ -224,6 +224,7 @@ protected:
   CairoFont *currentFont;
   
   XRef *xref;			// xref table for current document
+  Catalog *catalog;
 
   static FT_Library ft_lib;
   static GBool ft_lib_initialized;
diff --git a/test/pdf-inspector.cc b/test/pdf-inspector.cc
index 3965380..3eb8650 100644
--- a/test/pdf-inspector.cc
+++ b/test/pdf-inspector.cc
@@ -292,7 +292,7 @@ PdfInspector::load(const char *file_name)
       gtk_spin_button_set_range (GTK_SPIN_BUTTON (spin), 0, doc->getNumPages()-1);
       gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0);
 
-      output->startDoc (doc->getXRef());
+      output->startDoc (doc->getXRef(), doc->getCatalog());
     }
   else
     {      
-- 
1.5.6.3

>From fc1693a7a4b905ea68a39ebf50ef80feda250569 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <[EMAIL PROTECTED]>
Date: Sat, 1 Nov 2008 01:21:39 +1030
Subject: [PATCH] Add CairoOutputDev functions for getting Type 3 glyph metrics

---
 poppler/CairoOutputDev.cc |   10 ++++++++++
 poppler/CairoOutputDev.h  |    7 +++++++
 2 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index eec5167..3a9d452 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -126,6 +126,7 @@ CairoOutputDev::CairoOutputDev() {
   currentFont = NULL;
   prescaleImages = gTrue;
   printing = gTrue;
+  t3_glyph_has_bbox = gFalse;
 
   groupColorSpaceStack = NULL;
   group = NULL;
@@ -675,10 +676,19 @@ void CairoOutputDev::endType3Char(GfxState *state) {
 }
 
 void CairoOutputDev::type3D0(GfxState *state, double wx, double wy) {
+  t3_glyph_wx = wx;
+  t3_glyph_wy = wy;
 }
 
 void CairoOutputDev::type3D1(GfxState *state, double wx, double wy,
 			     double llx, double lly, double urx, double ury) {
+  t3_glyph_wx = wx;
+  t3_glyph_wy = wy;
+  t3_glyph_bbox[0] = llx;
+  t3_glyph_bbox[1] = lly;
+  t3_glyph_bbox[2] = urx;
+  t3_glyph_bbox[3] = ury;
+  t3_glyph_has_bbox = gTrue;
 }
 
 void CairoOutputDev::endTextObject(GfxState *state) {
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index d70740d..b57f734 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -214,6 +214,10 @@ public:
   void setCairo (cairo_t *cr);
   void setPrinting (GBool printing) { this->printing = printing; }
 
+  void getType3GlyphWidth (double *wx, double *wy) { *wx = t3_glyph_wx; *wy = t3_glyph_wy; }
+  GBool hasType3GlyphBBox () { return t3_glyph_has_bbox; }
+  double *getType3GlyphBBox () { return t3_glyph_bbox; }
+
 protected:
   void doPath(cairo_t *cairo, GfxState *state, GfxPath *path);
   
@@ -240,6 +244,9 @@ protected:
   cairo_glyph_t *glyphs;
   int glyphCount;
   cairo_path_t *textClipPath;
+  double t3_glyph_wx, t3_glyph_wy;
+  GBool t3_glyph_has_bbox;
+  double t3_glyph_bbox[4];
 
   GBool prescaleImages;
 
-- 
1.5.6.3

>From 4cf94efec13f952fde9545321b2c3d741fd91bb3 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <[EMAIL PROTECTED]>
Date: Sat, 1 Nov 2008 01:57:32 +1030
Subject: [PATCH] Implement Type 3 fonts in cairo backend using cairo user-fonts

---
 poppler/CairoFontEngine.cc |  174 ++++++++++++++++++++++++++++++++++++++++++--
 poppler/CairoFontEngine.h  |   18 +++++
 poppler/CairoOutputDev.cc  |    9 ++-
 poppler/CairoOutputDev.h   |    4 +-
 4 files changed, 194 insertions(+), 11 deletions(-)

diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 75340b8..dc975be 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -32,12 +32,16 @@
 #include "config.h"
 #include <string.h>
 #include "CairoFontEngine.h"
+#include "CairoOutputDev.h"
 #include "CharCodeToUnicode.h"
 #include "GlobalParams.h"
 #include <fofi/FoFiTrueType.h>
 #include <fofi/FoFiType1C.h>
 #include "goo/gfile.h"
 #include "Error.h"
+#include "XRef.h"
+#include "Gfx.h"
+#include "Page.h"
 
 #if HAVE_FCNTL_H && HAVE_SYS_MMAN_H && HAVE_SYS_STAT_H
 #include <fcntl.h>
@@ -531,6 +535,163 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
   return NULL;
 }
 
+//------------------------------------------------------------------------
+// CairoType3Font
+//------------------------------------------------------------------------
+
+static const cairo_user_data_key_t type3_font_key = {0};
+
+typedef struct _type3_font_info {
+  GfxFont *font;
+  XRef *xref;
+  Catalog *catalog;
+  CairoFontEngine *fontEngine;
+} type3_font_info_t;
+
+static void
+_free_type3_font_info(void *closure)
+{
+  type3_font_info_t *info = (type3_font_info_t *) closure;
+
+  info->font->decRefCnt();
+  free (info);
+}
+
+static cairo_status_t
+_render_type3_glyph (cairo_scaled_font_t  *scaled_font,
+		     unsigned long         glyph,
+		     cairo_t              *cr,
+		     cairo_text_extents_t *metrics)
+{
+  Dict *charProcs;
+  Object charProc;
+  CairoOutputDev *output_dev;
+  cairo_matrix_t matrix;
+  double *mat;
+  double wx, wy;
+  PDFRectangle box;
+  type3_font_info_t *info;
+  GfxFont *font;
+  Dict *resDict;
+  Gfx *gfx;
+
+  info = (type3_font_info_t *)
+    cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
+				   &type3_font_key);
+
+  font = info->font;
+  resDict = ((Gfx8BitFont *)font)->getResources();
+  charProcs = ((Gfx8BitFont *)(info->font))->getCharProcs();
+  if (!charProcs)
+    return CAIRO_STATUS_USER_FONT_ERROR;
+
+  if ((int)glyph >= charProcs->getLength())
+    return CAIRO_STATUS_USER_FONT_ERROR;
+
+  mat = font->getFontMatrix();
+  matrix.xx = mat[0];
+  matrix.yx = mat[1];
+  matrix.xy = mat[2];
+  matrix.yy = mat[3];
+  matrix.x0 = mat[4];
+  matrix.y0 = mat[5];
+  cairo_transform (cr, &matrix);
+  cairo_matrix_init_scale (&matrix, 1, -1);
+  cairo_transform (cr, &matrix);
+
+  output_dev = new CairoOutputDev();
+  output_dev->setCairo(cr);
+
+  box.x1 = mat[0];
+  box.y1 = mat[1];
+  box.x2 = mat[2];
+  box.y2 = mat[3];
+  gfx = new Gfx(info->xref, output_dev, resDict, info->catalog, &box, NULL);
+  output_dev->startDoc(info->xref, info->catalog, info->fontEngine);
+  output_dev->startPage (1, gfx->getState());
+  output_dev->setInType3Char(gTrue);
+  gfx->display(charProcs->getVal(glyph, &charProc));
+
+  output_dev->getType3GlyphWidth (&wx, &wy);
+  metrics->x_advance = wx;
+  metrics->y_advance = wy;
+  if (output_dev->hasType3GlyphBBox()) {
+    double *bbox = output_dev->getType3GlyphBBox();
+
+    cairo_matrix_transform_point (&matrix, &bbox[0], &bbox[1]);
+    cairo_matrix_transform_point (&matrix, &bbox[2], &bbox[3]);
+    metrics->x_bearing = bbox[0];
+    metrics->y_bearing = bbox[1];
+    metrics->width = bbox[2] - bbox[0];
+    metrics->height = bbox[3] - bbox[1];
+  }
+
+  delete gfx;
+  delete output_dev;
+  charProc.free();
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+
+CairoType3Font *CairoType3Font::create(GfxFont *gfxFont, XRef *xref,
+				       Catalog *catalog, CairoFontEngine *fontEngine) {
+  Object refObj, strObj;
+  type3_font_info_t *info;
+  cairo_font_face_t *font_face;
+  Ref ref;
+  Gushort *codeToGID;
+  int codeToGIDLen;
+  int i, j;
+  char **enc;
+  Dict *charProcs;
+  char *name;
+
+  charProcs = ((Gfx8BitFont *)gfxFont)->getCharProcs();
+  info = (type3_font_info_t *) malloc(sizeof(*info));
+  ref = *gfxFont->getID();
+  font_face = cairo_user_font_face_create();
+  cairo_user_font_face_set_render_glyph_func (font_face, _render_type3_glyph);
+  gfxFont->incRefCnt();
+  info->font = gfxFont;
+  info->xref = xref;
+  info->catalog = catalog;
+  info->fontEngine = fontEngine;
+
+  cairo_font_face_set_user_data (font_face, &type3_font_key, (void *) info, _free_type3_font_info);
+
+  enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
+  codeToGID = (Gushort *)gmallocn(256, sizeof(int));
+  codeToGIDLen = 256;
+  for (i = 0; i < 256; ++i) {
+    codeToGID[i] = 0;
+    if ((name = enc[i])) {
+      for (j = 0; j < charProcs->getLength(); j++) {
+	if (strcmp(name, charProcs->getKey(j)) == 0) {
+	  codeToGID[i] = (Gushort) j;
+	}
+      }
+    }
+  }
+
+  return new CairoType3Font(ref, xref, catalog, font_face, codeToGID, codeToGIDLen);
+}
+
+CairoType3Font::CairoType3Font(Ref ref,
+			       XRef *xref,
+			       Catalog *cat,
+			       cairo_font_face_t *cairo_font_face,
+			       Gushort *codeToGID,
+			       int codeToGIDLen) : CairoFont(ref,
+							     cairo_font_face,
+							     codeToGID,
+							     codeToGIDLen,
+							     gFalse),
+						   xref(xref),
+						   catalog(catalog) { }
+
+CairoType3Font::~CairoType3Font() { }
+
 
 //------------------------------------------------------------------------
 // CairoFontEngine
@@ -567,12 +728,6 @@ CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref, Catalog *catalog) {
   CairoFont *font;
   GfxFontType fontType;
   
-  fontType = gfxFont->getType();
-  if (fontType == fontType3) {
-    /* Need to figure this out later */
-    //    return NULL;
-  }
-
   ref = *gfxFont->getID();
 
   for (i = 0; i < cairoFontCacheSize; ++i) {
@@ -586,7 +741,12 @@ CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref, Catalog *catalog) {
     }
   }
   
-  font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs);
+  fontType = gfxFont->getType();
+  if (fontType == fontType3)
+    font = CairoType3Font::create (gfxFont, xref, catalog, this);
+  else
+    font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs);
+
   //XXX: if font is null should we still insert it into the cache?
   if (fontCache[cairoFontCacheSize - 1]) {
     delete fontCache[cairoFontCacheSize - 1];
diff --git a/poppler/CairoFontEngine.h b/poppler/CairoFontEngine.h
index 1f25026..2474dc6 100644
--- a/poppler/CairoFontEngine.h
+++ b/poppler/CairoFontEngine.h
@@ -37,6 +37,8 @@
 #include "GfxFont.h"
 #include "Catalog.h"
 
+class CairoFontEngine;
+
 class CairoFont {
 public:
   CairoFont(Ref ref,
@@ -77,6 +79,22 @@ private:
 
 //------------------------------------------------------------------------
 
+class CairoType3Font : public CairoFont {
+public:
+  static CairoType3Font *create(GfxFont *gfxFont, XRef *xref,
+				Catalog *catalog, CairoFontEngine *fontEngine);
+  virtual ~CairoType3Font();
+
+private:
+  CairoType3Font(Ref ref, XRef *xref, Catalog *catalog,
+		 cairo_font_face_t *cairo_font_face,
+		 Gushort *codeToGID, int codeToGIDLen);
+  XRef *xref;
+  Catalog *catalog;
+};
+
+//------------------------------------------------------------------------
+
 #define cairoFontCacheSize 64
 
 //------------------------------------------------------------------------
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 3a9d452..70911b5 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -126,6 +126,7 @@ CairoOutputDev::CairoOutputDev() {
   currentFont = NULL;
   prescaleImages = gTrue;
   printing = gTrue;
+  inType3Char = gFalse;
   t3_glyph_has_bbox = gFalse;
 
   groupColorSpaceStack = NULL;
@@ -415,9 +416,6 @@ void CairoOutputDev::updateFont(GfxState *state) {
 
   needFontUpdate = gFalse;
 
-  if (state->getFont()->getType() == fontType3)	 
-    return;
-
   currentFont = fontEngine->getFont (state->getFont(), xref, catalog);
 
   if (!currentFont)
@@ -440,6 +438,11 @@ void CairoOutputDev::updateFont(GfxState *state) {
   matrix.yy = -m[3] * fontSize;
   matrix.x0 = 0;
   matrix.y0 = 0;
+  if (inType3Char) {
+    cairo_matrix_t m;
+    cairo_matrix_init_scale (&m, 1, -1);
+    cairo_matrix_multiply (&matrix, &m, &matrix);
+  }
   cairo_set_font_matrix (cairo, &matrix);
 }
 
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index b57f734..878d3e3 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -99,7 +99,7 @@ public:
 
   // Does this device use beginType3Char/endType3Char?  Otherwise,
   // text in Type 3 fonts will be drawn with drawChar/drawString.
-  virtual GBool interpretType3Chars() { return gTrue; }
+  virtual GBool interpretType3Chars() { return gFalse; }
 
   //----- initialization and control
 
@@ -214,6 +214,7 @@ public:
   void setCairo (cairo_t *cr);
   void setPrinting (GBool printing) { this->printing = printing; }
 
+  void setInType3Char(GBool inType3Char) { this->inType3Char = inType3Char; }
   void getType3GlyphWidth (double *wx, double *wy) { *wx = t3_glyph_wx; *wy = t3_glyph_wy; }
   GBool hasType3GlyphBBox () { return t3_glyph_has_bbox; }
   double *getType3GlyphBBox () { return t3_glyph_bbox; }
@@ -244,6 +245,7 @@ protected:
   cairo_glyph_t *glyphs;
   int glyphCount;
   cairo_path_t *textClipPath;
+  GBool inType3Char;		// inside a Type 3 CharProc
   double t3_glyph_wx, t3_glyph_wy;
   GBool t3_glyph_has_bbox;
   double t3_glyph_bbox[4];
-- 
1.5.6.3

>From 520cc5e74b244cf7b5d5ce6443a622594ef7b4d9 Mon Sep 17 00:00:00 2001
From: Adrian Johnson <[EMAIL PROTECTED]>
Date: Sat, 1 Nov 2008 01:59:07 +1030
Subject: [PATCH] Require cairo 1.8.2 for user-font support

---
 configure.ac |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8b7ebe7..71794ca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -200,7 +200,7 @@ if test x$enable_splash_output = xyes; then
   AC_DEFINE(HAVE_SPLASH)
 fi
 
-CAIRO_VERSION="1.4"
+CAIRO_VERSION="1.8.2"
 AC_SUBST(CAIRO_VERSION)
 AC_ARG_ENABLE(cairo-output,
               AC_HELP_STRING([--disable-cairo-output],
-- 
1.5.6.3

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

Reply via email to