[PATCH] Implement Type 3 fonts in cairo backend using cairo user-fonts

Adrian Johnson ajohnson at redneon.com
Fri Oct 31 08:27:32 PDT 2008


---
 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


--------------090504070501070603020308
Content-Type: text/x-patch;
 name="0007-Require-cairo-1.8.2-for-user-font-support.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename*0="0007-Require-cairo-1.8.2-for-user-font-support.patch"



More information about the poppler mailing list