Bug 1471261 - Add global locking around FT_Load_Glyph to work around postscript hinter global data. r=lsalzman draft
authorRyan Hunt <rhunt@eqrion.net>
Tue, 26 Jun 2018 11:30:13 -0400
changeset 810902 bec9491d4191f153d1ebd8a72428b5aac8ddc726
parent 810901 26b0dde99e35fa216c8ad72c8d1d570f729d1af3
push id114157
push userbmo:rhunt@eqrion.net
push dateTue, 26 Jun 2018 18:54:49 +0000
reviewerslsalzman
bugs1471261
milestone63.0a1
Bug 1471261 - Add global locking around FT_Load_Glyph to work around postscript hinter global data. r=lsalzman MozReview-Commit-ID: 9ohfqUnPxMc
gfx/2d/2D.h
gfx/2d/Factory.cpp
gfx/cairo/cairo/src/cairo-ft-font.c
gfx/cairo/cairo/src/cairo-type1-subset.c
gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
gfx/thebes/gfxFT2FontBase.cpp
gfx/thebes/gfxFT2Fonts.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -47,16 +47,18 @@ struct _cairo_scaled_font;
 typedef _cairo_scaled_font cairo_scaled_font_t;
 
 struct FT_LibraryRec_;
 typedef FT_LibraryRec_* FT_Library;
 
 struct FT_FaceRec_;
 typedef FT_FaceRec_* FT_Face;
 
+typedef int FT_Error;
+
 struct ID3D11Texture2D;
 struct ID3D11Device;
 struct ID2D1Device;
 struct IDWriteFactory;
 struct IDWriteRenderingParams;
 struct IDWriteFontFace;
 
 class GrContext;
@@ -1773,16 +1775,17 @@ public:
   static FT_Library NewFTLibrary();
   static void ReleaseFTLibrary(FT_Library aFTLibrary);
   static void LockFTLibrary(FT_Library aFTLibrary);
   static void UnlockFTLibrary(FT_Library aFTLibrary);
 
   static FT_Face NewFTFace(FT_Library aFTLibrary, const char* aFileName, int aFaceIndex);
   static FT_Face NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData, size_t aDataSize, int aFaceIndex);
   static void ReleaseFTFace(FT_Face aFace);
+  static FT_Error LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags);
 
 private:
   static FT_Library mFTLibrary;
   static Mutex* mFTLock;
 public:
 #endif
 
 #ifdef WIN32
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -184,16 +184,22 @@ mozilla_NewFTFaceFromData(FT_Library aFT
 }
 
 void
 mozilla_ReleaseFTFace(FT_Face aFace)
 {
   mozilla::gfx::Factory::ReleaseFTFace(aFace);
 }
 
+FT_Error
+mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags)
+{
+  return mozilla::gfx::Factory::LoadFTGlyph(aFace, aGlyphIndex, aFlags);
+}
+
 void
 mozilla_LockFTLibrary(FT_Library aFTLibrary)
 {
   mozilla::gfx::Factory::LockFTLibrary(aFTLibrary);
 }
 
 void
 mozilla_UnlockFTLibrary(FT_Library aFTLibrary)
@@ -774,16 +780,24 @@ Factory::ReleaseFTFace(FT_Face aFace)
   if (mFTLock) {
     mFTLock->Lock();
   }
   FT_Done_Face(aFace);
   if (mFTLock) {
     mFTLock->Unlock();
   }
 }
+
+FT_Error
+Factory::LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags)
+{
+  MOZ_ASSERT(mFTLock);
+  MutexAutoLock lock(*mFTLock);
+  return FT_Load_Glyph(aFace, aGlyphIndex, aFlags);
+}
 #endif
 
 #ifdef WIN32
 already_AddRefed<DrawTarget>
 Factory::CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat)
 {
   MOZ_ASSERT(aTexture);
 
--- a/gfx/cairo/cairo/src/cairo-ft-font.c
+++ b/gfx/cairo/cairo/src/cairo-ft-font.c
@@ -103,16 +103,17 @@ static setLcdFilterFunc setLcdFilter;
 #define MAX_OPEN_FACES 10
 /* This is the maximum font size we allow to be passed to FT_Set_Char_Size
  */
 #define MAX_FONT_SIZE 2000
 
 extern FT_Face mozilla_NewFTFace(FT_Library aFTLibrary, const char* aFileName, int aFaceIndex);
 extern FT_Face mozilla_NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData, size_t aDataSize, int aFaceIndex);
 extern void mozilla_ReleaseFTFace(FT_Face aFace);
+extern FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags);
 extern void mozilla_LockFTLibrary(FT_Library aFTLibrary);
 extern void mozilla_UnlockFTLibrary(FT_Library aFTLibrary);
 
 /**
  * SECTION:cairo-ft
  * @Title: FreeType Fonts
  * @Short_Description: Font support for FreeType
  * @See_Also: #cairo_font_face_t
@@ -2339,17 +2340,17 @@ static cairo_int_status_t
      * maybe we should cache color and grayscale bitmaps separately
      * such that users of the font (ie. the surface) can choose which
      * version to use based on target content type.
      */
 
     load_flags |= FT_LOAD_COLOR;
 #endif
 
-    error = FT_Load_Glyph (scaled_font->unscaled->face,
+    error = mozilla_LoadFTGlyph (scaled_font->unscaled->face,
 			   _cairo_scaled_glyph_index(scaled_glyph),
 			   load_flags);
     /* XXX ignoring all other errors for now.  They are not fatal, typically
      * just a glyph-not-found. */
     if (error == FT_Err_Out_Of_Memory) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto FAIL;
     }
@@ -2493,17 +2494,17 @@ static cairo_int_status_t
     if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
 	cairo_path_fixed_t *path = NULL; /* hide compiler warning */
 
 	/*
 	 * A kludge -- the above code will trash the outline,
 	 * so reload it. This will probably never occur though
 	 */
 	if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) {
-	    error = FT_Load_Glyph (face,
+	    error = mozilla_LoadFTGlyph (face,
 				   _cairo_scaled_glyph_index(scaled_glyph),
 				   load_flags | FT_LOAD_NO_BITMAP);
 	    /* XXX ignoring all other errors for now.  They are not fatal, typically
 	     * just a glyph-not-found. */
 	    if (error == FT_Err_Out_Of_Memory) {
 		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 		goto FAIL;
 	    }
--- a/gfx/cairo/cairo/src/cairo-type1-subset.c
+++ b/gfx/cairo/cairo/src/cairo-type1-subset.c
@@ -56,16 +56,18 @@
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_OUTLINE_H
 #include FT_TYPE1_TABLES_H
 
 #include <ctype.h>
 
+extern FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags);
+
 typedef struct _cairo_type1_font_subset {
     cairo_scaled_font_subset_t *scaled_font_subset;
 
     struct {
 	cairo_unscaled_font_t *unscaled_font;
 	unsigned int font_id;
 	char *base_font;
 	unsigned int num_glyphs;
@@ -550,17 +552,17 @@ cairo_type1_font_subset_get_glyph_names_
     char buffer[256];
     FT_Error error;
 
     /* Get glyph names and width using the freetype API */
     for (i = 0; i < font->base.num_glyphs; i++) {
 	if (font->glyphs[i].name != NULL)
 	    continue;
 
-	error = FT_Load_Glyph (font->face, i,
+	error = mozilla_LoadFTGlyph (font->face, i,
 			       FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING |
 			       FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
 	if (error != FT_Err_Ok) {
 	    /* propagate fatal errors from FreeType */
 	    if (error == FT_Err_Out_Of_Memory)
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
--- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
@@ -59,16 +59,23 @@ typedef enum FT_LcdFilter_
 #endif
 
 static cairo_user_data_key_t kSkTypefaceKey;
 
 static bool gFontHintingEnabled = true;
 static FT_Error (*gSetLcdFilter)(FT_Library, FT_LcdFilter) = nullptr;
 static void (*gGlyphSlotEmbolden)(FT_GlyphSlot) = nullptr;
 
+extern "C"
+{
+    void mozilla_LockFTLibrary(FT_Library aLibrary);
+    void mozilla_UnlockFTLibrary(FT_Library aLibrary);
+    FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags);
+}
+
 void SkInitCairoFT(bool fontHintingEnabled)
 {
     gFontHintingEnabled = fontHintingEnabled;
 #if SK_CAN_USE_DLOPEN
     gSetLcdFilter = (FT_Error (*)(FT_Library, FT_LcdFilter))dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter");
     gGlyphSlotEmbolden = (void (*)(FT_GlyphSlot))dlsym(RTLD_DEFAULT, "FT_GlyphSlot_Embolden");
 #else
     gSetLcdFilter = &FT_Library_SetLcdFilter;
@@ -630,17 +637,17 @@ void SkScalerContext_CairoFT::generateMe
 {
     SkASSERT(fScaledFont != nullptr);
 
     glyph->zeroMetrics();
 
     CairoLockedFTFace faceLock(fScaledFont);
     FT_Face face = faceLock.getFace();
 
-    FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
+    FT_Error err = mozilla_LoadFTGlyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
     if (err != 0) {
         return;
     }
 
     prepareGlyph(face->glyph);
 
     if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
         glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x);
@@ -734,60 +741,62 @@ void SkScalerContext_CairoFT::generateMe
 }
 
 void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
 {
     SkASSERT(fScaledFont != nullptr);
     CairoLockedFTFace faceLock(fScaledFont);
     FT_Face face = faceLock.getFace();
 
-    FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags);
+    FT_Error err = mozilla_LoadFTGlyph(face, glyph.getGlyphID(), fLoadGlyphFlags);
 
     if (err != 0) {
         memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
         return;
     }
 
     prepareGlyph(face->glyph);
 
     bool useLcdFilter =
         face->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
         isLCD(glyph) &&
         gSetLcdFilter;
     if (useLcdFilter) {
+        mozilla_LockFTLibrary(face->glyph->library);
         gSetLcdFilter(face->glyph->library, fLcdFilter);
     }
 
     SkMatrix matrix;
     if (face->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
         fHaveShape) {
         matrix = fShapeMatrix;
     } else {
         matrix.setIdentity();
     }
     generateGlyphImage(face, glyph, matrix);
 
     if (useLcdFilter) {
         gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE);
+        mozilla_UnlockFTLibrary(face->glyph->library);
     }
 }
 
 void SkScalerContext_CairoFT::generatePath(const SkGlyphID glyphID, SkPath* path)
 {
     SkASSERT(fScaledFont != nullptr);
     CairoLockedFTFace faceLock(fScaledFont);
     FT_Face face = faceLock.getFace();
 
     SkASSERT(path);
 
     uint32_t flags = fLoadGlyphFlags;
     flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
     flags &= ~FT_LOAD_RENDER;   // don't scan convert (we just want the outline)
 
-    FT_Error err = FT_Load_Glyph(face, glyphID, flags);
+    FT_Error err = mozilla_LoadFTGlyph(face, glyphID, flags);
 
     if (err != 0) {
         path->reset();
         return;
     }
 
     prepareGlyph(face->glyph);
 
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -535,17 +535,17 @@ gfxFT2FontBase::GetFTGlyphAdvance(uint16
         !(face.get()->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
         return false;
     }
 
     bool hinting = gfxPlatform::GetPlatform()->FontHintingEnabled();
     int32_t flags =
         hinting ? FT_LOAD_ADVANCE_ONLY
                 : FT_LOAD_ADVANCE_ONLY | FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
-    FT_Error ftError = FT_Load_Glyph(face.get(), aGID, flags);
+    FT_Error ftError = Factory::LoadFTGlyph(face.get(), aGID, flags);
     if (ftError != FT_Err_Ok) {
         // FT_Face was somehow broken/invalid? Don't try to access glyph slot.
         // This probably shouldn't happen, but does: see bug 1440938.
         NS_WARNING("failed to load glyph!");
         return false;
     }
 
     // Due to freetype bug 52683 we MUST use the linearHoriAdvance field when
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -211,17 +211,17 @@ gfxFT2Font::FillGlyphDataForChar(FT_Face
         NS_ASSERTION(gid != 0, "We don't have a glyph, but font indicated that it supported this char in tables?");
         gd->glyphIndex = 0;
         return;
     }
 
     FT_Int32 flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
                      FT_LOAD_DEFAULT :
                      (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
-    FT_Error err = FT_Load_Glyph(face, gid, flags);
+    FT_Error err = Factory::LoadFTGlyph(face, gid, flags);
 
     if (err) {
         // hmm, this is weird, we failed to load a glyph that we had?
         NS_WARNING("Failed to load glyph that we got from Get_Char_index");
 
         gd->glyphIndex = 0;
         return;
     }