[poppler] Chinese characters broken

mpsuzuki at hiroshima-u.ac.jp mpsuzuki at hiroshima-u.ac.jp
Mon Aug 23 11:07:09 PDT 2010


Hi,

On Mon, 23 Aug 2010 21:33:28 +0900
mpsuzuki at hiroshima-u.ac.jp wrote:
>It seems that CairoOutputDev.cc disables FreeType
>hinter in each font object creation via Cairo API,
>by default. And yet I couldn't find appropriate
>Poppler API to enable it after font object creation,
>or change the default switch. I'm afraid there's
>no such in Poppler layer, and GLib binding cannot
>do such anymore. I will try to fix it. Please wait.

As the first step, I wrote a patch to add new method
CairoOutputDev::setFreeTypeHinting() which is almost
same with SplashOutputDev::setFreeTypeHinting().

The outline is following.

1) New private boolean "enableFreeTypeHinting" to
CairoOutputDev class. It is disabled by default,
and setFreeTypeHinting() can change it.

2) When CairoOutputDev instance creates CairoFontEngine
object, FreeType's hinter switch-set in CairoFontEngine
are set by enableFreeTypeHinting value. The switch set
is stored in new private 32bit integer "ft_load_flags_default".

3) When CairoFontEngine instance creates CairoFreeTypeFont
object, the default flag "ft_load_flags_default" is passed
to cairo_ft_font_face_create_for_ft_face().

4) New method CairoFreeTypeFont::create() taking 5 arguments
is added (original method taking 4 arguments. additional
argument is to take FT_LOAD_XXX flag). This is used by
CairoFontEngine to create CairoFreeTypeFont object with
engine's default flag.

5) For back compatibility, CairoFontEngine.h defines
POPPLER_CAIROFTFONT_FLAG_INIT for original hardwired flag.

When I invoke CairoOutputDev::setFreeTypeHinting() method
in pdftocairo, the glyph shape of SimSun font is changed.
I will work for GLib binding to invoke this method as the
2nd step.

Regards,
mpsuzuki


diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 02a4955..3959b72 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -267,6 +267,8 @@ public:
   GBool hasType3GlyphBBox () { return t3_glyph_has_bbox; }
   double *getType3GlyphBBox () { return t3_glyph_bbox; }
 
+  void setFreeTypeHinting (GBool enable);
+
 protected:
   void doPath(cairo_t *cairo, GfxState *state, GfxPath *path);
   cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface);
@@ -287,6 +289,7 @@ protected:
 
   static FT_Library ft_lib;
   static GBool ft_lib_initialized;
+  GBool enableFreeTypeHinting;
 
   CairoFontEngine *fontEngine;
   GBool fontEngine_owner;
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 65fac76..1b68ed8 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -148,6 +148,8 @@ CairoOutputDev::CairoOutputDev() {
 
   text = NULL;
   actualText = NULL;
+
+  enableFreeTypeHinting = gFalse;
 }
 
 CairoOutputDev::~CairoOutputDev() {
@@ -219,6 +221,13 @@ void CairoOutputDev::startDoc(XRef *xrefA, Catalog *catalogA,
       delete fontEngine;
     }
     fontEngine = new CairoFontEngine(ft_lib);
+    if ( enableFreeTypeHinting )
+    {
+      FT_Int32 flag = fontEngine->getDefaultFreeTypeLoadFlags();
+      flag &= ~FT_LOAD_NO_HINTING;
+      flag &= ~FT_LOAD_NO_AUTOHINT;
+      fontEngine->setDefaultFreeTypeLoadFlags( flag );
+    }
     fontEngine_owner = gTrue;
   }
 }
@@ -2691,3 +2700,8 @@ void CairoImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *
     cairo_destroy (cr);
   }
 }
+
+void CairoOutputDev::setFreeTypeHinting(GBool enable)
+{
+  enableFreeTypeHinting = enable;
+}
diff --git a/poppler/CairoFontEngine.h b/poppler/CairoFontEngine.h
index 552b5e6..7c12cfa 100644
--- a/poppler/CairoFontEngine.h
+++ b/poppler/CairoFontEngine.h
@@ -69,9 +69,14 @@ protected:
 
 //------------------------------------------------------------------------
 
+#define POPPLER_CAIROFTFONT_FLAG_INIT ( FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)
+
 class CairoFreeTypeFont : public CairoFont {
 public:
   static CairoFreeTypeFont *create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs);
+  static CairoFreeTypeFont *create(GfxFont *gfxFont, XRef *xref,
+				   FT_Library lib, FT_Int32 ft_load_flags,
+				   GBool useCIDs);
   virtual ~CairoFreeTypeFont();
 
 private:
@@ -116,10 +121,15 @@ public:
 
   CairoFont *getFont(GfxFont *gfxFont, XRef *xref, Catalog *catalog, GBool printing);
 
+  void setDefaultFreeTypeLoadFlags( FT_Int32 ft_load_flags );
+  FT_Int32 getDefaultFreeTypeLoadFlags();
+
 private:
   CairoFont *fontCache[cairoFontCacheSize];
   FT_Library lib;
   GBool useCIDs;
+  FT_Int32 ft_load_flags_default;
+
 };
 
 #endif
diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 0d8c905..5f5ff63 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -168,6 +168,7 @@ _ft_new_face_uncached (FT_Library lib,
 		       const char *filename,
 		       char *font_data,
 		       int font_data_len,
+		       FT_Int32 ft_load_flags,
 		       FT_Face *face_out,
 		       cairo_font_face_t **font_face_out)
 {
@@ -182,9 +183,7 @@ _ft_new_face_uncached (FT_Library lib,
       return gFalse;
   }
 
-  font_face = cairo_ft_font_face_create_for_ft_face (face,
-							  FT_LOAD_NO_HINTING |
-							  FT_LOAD_NO_BITMAP);
+  font_face = cairo_ft_font_face_create_for_ft_face (face, ft_load_flags);
   if (cairo_font_face_set_user_data (font_face,
 				     &_ft_cairo_key,
 				     face,
@@ -267,6 +266,7 @@ _ft_new_face (FT_Library lib,
 	      const char *filename,
 	      char *font_data,
 	      int font_data_len,
+	      FT_Int32 ft_load_flags,
 	      FT_Face *face_out,
 	      cairo_font_face_t **font_face_out)
 {
@@ -280,11 +280,13 @@ _ft_new_face (FT_Library lib,
     /* if we fail to mmap the file, just pass it to FreeType instead */
     tmpl.fd = open (filename, O_RDONLY);
     if (tmpl.fd == -1)
-      return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
+      return _ft_new_face_uncached (lib, filename, font_data, font_data_len, ft_load_flags,
+				    face_out, font_face_out);
 
     if (fstat (tmpl.fd, &st) == -1) {
       close (tmpl.fd);
-      return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
+      return _ft_new_face_uncached (lib, filename, font_data, font_data_len, ft_load_flags,
+				    face_out, font_face_out);
     }
 
     tmpl.bytes = (unsigned char *) mmap (NULL, st.st_size,
@@ -292,7 +294,8 @@ _ft_new_face (FT_Library lib,
 					 tmpl.fd, 0);
     if (tmpl.bytes == MAP_FAILED) {
       close (tmpl.fd);
-      return _ft_new_face_uncached (lib, filename, font_data, font_data_len, face_out, font_face_out);
+      return _ft_new_face_uncached (lib, filename, font_data, font_data_len, ft_load_flags,
+				    face_out, font_face_out);
     }
     tmpl.size = st.st_size;
   } else {
@@ -345,9 +348,7 @@ _ft_new_face (FT_Library lib,
     _ft_open_faces->prev = l;
   _ft_open_faces = l;
 
-  l->font_face = cairo_ft_font_face_create_for_ft_face (tmpl.face,
-							  FT_LOAD_NO_HINTING |
-							  FT_LOAD_NO_BITMAP);
+  l->font_face = cairo_ft_font_face_create_for_ft_face (tmpl.face, ft_load_flags);
   if (cairo_font_face_set_user_data (l->font_face,
 				     &_ft_cairo_key,
 				     l,
@@ -381,6 +382,12 @@ CairoFreeTypeFont::~CairoFreeTypeFont() { }
 
 CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
 					     FT_Library lib, GBool useCIDs) {
+  return create(gfxFont, xref, lib, POPPLER_CAIROFTFONT_FLAG_INIT, useCIDs);
+}
+
+CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
+					     FT_Library lib, FT_Int32 ft_load_flags,
+					     GBool useCIDs) {
   Ref embRef;
   Object refObj, strObj;
   GooString *fileName;
@@ -451,7 +458,8 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
   case fontType1:
   case fontType1C:
   case fontType1COT:
-    if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+    if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, ft_load_flags,
+			&face, &font_face)) {
       error(-1, "could not create type1 face");
       goto err2;
     }
@@ -507,7 +515,8 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
       codeToGIDLen = 256;
     }
     delete ff;
-    if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+    if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, ft_load_flags,
+			&face, &font_face)) {
       error(-1, "could not create truetype face\n");
       goto err2;
     }
@@ -532,7 +541,8 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref,
       }
     }
 
-    if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, &face, &font_face)) {
+    if (! _ft_new_face (lib, fileNameC, font_data, font_data_len, ft_load_flags,
+			&face, &font_face)) {
       gfree(codeToGID);
       codeToGID = NULL;
       error(-1, "could not create cid face\n");
@@ -745,6 +755,7 @@ CairoFontEngine::CairoFontEngine(FT_Library libA) {
   FT_Library_Version(lib, &major, &minor, &patch);
   useCIDs = major > 2 ||
             (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
+  ft_load_flags_default = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
 }
 
 CairoFontEngine::~CairoFontEngine() {
@@ -780,7 +791,8 @@ CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref, Catalog *catalog, GBool p
   if (fontType == fontType3)
     font = CairoType3Font::create (gfxFont, xref, catalog, this, printing);
   else
-    font = CairoFreeTypeFont::create (gfxFont, xref, lib, useCIDs);
+    font = CairoFreeTypeFont::create (gfxFont, xref, lib,
+				      ft_load_flags_default, useCIDs);
 
   //XXX: if font is null should we still insert it into the cache?
   if (fontCache[cairoFontCacheSize - 1]) {
@@ -792,3 +804,15 @@ CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref, Catalog *catalog, GBool p
   fontCache[0] = font;
   return font;
 }
+
+FT_Int32
+CairoFontEngine::getDefaultFreeTypeLoadFlags()
+{
+  return ft_load_flags_default;
+}
+
+void
+CairoFontEngine::setDefaultFreeTypeLoadFlags( FT_Int32 ft_load_flags )
+{
+  ft_load_flags_default = ft_load_flags;
+}


More information about the poppler mailing list