Bug 1274111 - use freetype directly for calculating glyph sizes in SkFontHost_cairo. r=gwright
authorLee Salzman <lsalzman@mozilla.com>
Wed, 01 Jun 2016 14:52:58 -0400
changeset 338992 2a0eda9a4bb60ed7c318a4d45247f5fe78de2256
parent 338991 03f8bccf10ea3980d6942dfb88bfab29d776c91d
child 338993 817695430906243ef1f46f3c8df49f2b86f489ef
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgwright
bugs1274111
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1274111 - use freetype directly for calculating glyph sizes in SkFontHost_cairo. r=gwright
gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
--- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
@@ -7,23 +7,25 @@
  */
 
 #include "cairo.h"
 #include "cairo-ft.h"
 
 #include "SkFontHost_FreeType_common.h"
 
 #include "SkAdvancedTypefaceMetrics.h"
+#include "SkFDot6.h"
 #include "SkFontHost.h"
 #include "SkPath.h"
 #include "SkScalerContext.h"
 #include "SkTypefaceCache.h"
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
+#include FT_OUTLINE_H
 
 #ifndef SK_FONTHOST_CAIRO_STANDALONE
 #define SK_FONTHOST_CAIRO_STANDALONE 1
 #endif
 
 static cairo_user_data_key_t kSkTypefaceKey;
 
 class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
@@ -62,16 +64,27 @@ public:
         return fFace;
     }
 
 private:
     cairo_scaled_font_t* fScaledFont;
     FT_Face fFace;
 };
 
+static bool bothZero(SkScalar a, SkScalar b) {
+    return 0 == a && 0 == b;
+}
+
+// returns false if there is any non-90-rotation or skew
+static bool isAxisAligned(const SkScalerContext::Rec& rec) {
+    return 0 == rec.fPreSkewX &&
+           (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
+            bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
+}
+
 class SkCairoFTTypeface : public SkTypeface {
 public:
     static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, const SkFontStyle& style, bool isFixedWidth) {
         SkASSERT(fontFace != NULL);
         SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT);
 
         SkFontID newId = SkTypefaceCache::NewFontID();
 
@@ -92,18 +105,22 @@ public:
         return NULL;
     }
 
     virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const override
     {
         return new SkScalerContext_CairoFT(const_cast<SkCairoFTTypeface*>(this), desc);
     }
 
-    virtual void onFilterRec(SkScalerContextRec*) const override
+    virtual void onFilterRec(SkScalerContextRec* rec) const override
     {
+        // rotated text looks bad with hinting, so we disable it as needed
+        if (!isAxisAligned(*rec)) {
+            rec->setHinting(SkPaint::kNo_Hinting);
+        }
     }
 
     virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const override
     {
         SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n"));
     }
 
     virtual int onCharsToGlyphs(void const*, SkTypeface::Encoding, uint16_t*, int) const override
@@ -280,28 +297,56 @@ uint16_t SkScalerContext_CairoFT::genera
 void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph)
 {
     generateMetrics(glyph);
 }
 
 void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
 {
     SkASSERT(fScaledFont != NULL);
-    cairo_text_extents_t extents;
-    cairo_glyph_t cairoGlyph = { glyph->getGlyphID(), 0.0, 0.0 };
-    cairo_scaled_font_glyph_extents(fScaledFont, &cairoGlyph, 1, &extents);
+
+    glyph->zeroMetrics();
+
+    CairoLockedFTFace faceLock(fScaledFont);
+    FT_Face face = faceLock.getFace();
+
+    FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
+    if (err != 0) {
+        return;
+    }
 
-    glyph->fAdvanceX = SkDoubleToFixed(extents.x_advance);
-    glyph->fAdvanceY = SkDoubleToFixed(extents.y_advance);
-    glyph->fWidth = SkToU16(SkScalarCeilToInt(extents.width));
-    glyph->fHeight = SkToU16(SkScalarCeilToInt(extents.height));
-    glyph->fLeft = SkToS16(SkScalarCeilToInt(extents.x_bearing));
-    glyph->fTop = SkToS16(SkScalarCeilToInt(extents.y_bearing));
-    glyph->fLsbDelta = 0;
-    glyph->fRsbDelta = 0;
+    switch (face->glyph->format) {
+    case FT_GLYPH_FORMAT_OUTLINE:
+        if (!face->glyph->outline.n_contours) {
+            break;
+        }
+        FT_BBox bbox;
+        FT_Outline_Get_CBox(&face->glyph->outline, &bbox);
+        bbox.xMin &= ~63;
+        bbox.yMin &= ~63;
+        bbox.xMax = (bbox.xMax + 63) & ~63;
+        bbox.yMax = (bbox.yMax + 63) & ~63;
+        glyph->fWidth  = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
+        glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
+        glyph->fTop    = -SkToS16(SkFDot6Floor(bbox.yMax));
+        glyph->fLeft   = SkToS16(SkFDot6Floor(bbox.xMin));
+        break;
+    case FT_GLYPH_FORMAT_BITMAP:
+        glyph->fWidth  = SkToU16(face->glyph->bitmap.width);
+        glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
+        glyph->fTop    = -SkToS16(face->glyph->bitmap_top);
+        glyph->fLeft   = SkToS16(face->glyph->bitmap_left);
+        break;
+    default:
+        SkDEBUGFAIL("unknown glyph format");
+        return;
+    }
+
+    glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
+    glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
 }
 
 void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
 {
     SkASSERT(fScaledFont != NULL);
     CairoLockedFTFace faceLock(fScaledFont);
     FT_Face face = faceLock.getFace();