bug 568191 - add padding to glyph extents in cairo dwrite backend to allow for antialiasing. r=bas
authorJonathan Kew <jfkthame@gmail.com>
Thu, 10 Jun 2010 19:19:51 +0100
changeset 43475 ffa8bc798d99557e82ec7862e9ccdf555e1dde91
parent 43474 7b15545cf9aaf59f1c7148872f0fa1071b611010
child 43476 6efd0963eae957d88ef96f2e1597b1142f3cf824
push id13727
push userjkew@mozilla.com
push dateThu, 10 Jun 2010 18:25:00 +0000
treeherdermozilla-central@6efd0963eae9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs568191
milestone1.9.3a6pre
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 568191 - add padding to glyph extents in cairo dwrite backend to allow for antialiasing. r=bas
gfx/cairo/cairo/src/cairo-dwrite-font.cpp
gfx/thebes/public/gfxDWriteFonts.h
gfx/thebes/src/gfxDWriteFonts.cpp
--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
+++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
@@ -582,22 +582,37 @@ cairo_int_status_t
     DWRITE_FONT_METRICS fontMetrics;
     font_face->dwriteface->GetMetrics(&fontMetrics);
     HRESULT hr = font_face->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
     if (FAILED(hr)) {
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     // TODO: Treat swap_xy.
-    extents.width = (FLOAT)(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing) / fontMetrics.designUnitsPerEm;
-    extents.height = (FLOAT)(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing) / fontMetrics.designUnitsPerEm;
+    extents.width = (FLOAT)(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing) /
+        fontMetrics.designUnitsPerEm;
+    extents.height = (FLOAT)(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing) /
+        fontMetrics.designUnitsPerEm;
     extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm;
     extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm;
     extents.y_advance = 0.0;
-    extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) / fontMetrics.designUnitsPerEm;
+    extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) /
+        fontMetrics.designUnitsPerEm;
+
+    // We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics
+    // for the glyph outline, without accounting for hinting/gridfitting/antialiasing,
+    // and therefore it does not always cover all pixels that will actually be touched.
+    if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE &&
+        extents.width > 0 && extents.height > 0) {
+        extents.width += scaled_font->mat_inverse.xx * 2;
+        extents.x_bearing -= scaled_font->mat_inverse.xx;
+        extents.height += scaled_font->mat_inverse.yy * 2;
+        extents.y_bearing -= scaled_font->mat_inverse.yy;
+    }
+
     _cairo_scaled_glyph_set_metrics (scaled_glyph,
 				     &scaled_font->base,
 				     &extents);
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
 /**
  * Stack-based helper implementing IDWriteGeometrySink.
--- a/gfx/thebes/public/gfxDWriteFonts.h
+++ b/gfx/thebes/public/gfxDWriteFonts.h
@@ -47,19 +47,22 @@
 /**
  * \brief Class representing a font face for a font entry.
  */
 class gfxDWriteFont : public gfxFont 
 {
 public:
     gfxDWriteFont(gfxFontEntry *aFontEntry,
                   const gfxFontStyle *aFontStyle,
-                  PRBool aNeedsBold = PR_FALSE);
+                  PRBool aNeedsBold = PR_FALSE,
+                  AntialiasOption = kAntialiasDefault);
     ~gfxDWriteFont();
 
+    virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption);
+
     virtual nsString GetUniqueName();
 
     virtual const gfxFont::Metrics& GetMetrics();
 
     virtual PRUint32 GetSpaceGlyph();
 
     virtual PRBool SetupCairoFont(gfxContext *aContext);
 
@@ -78,11 +81,12 @@ protected:
 
     nsRefPtr<IDWriteFontFace> mFontFace;
     cairo_font_face_t *mCairoFontFace;
     cairo_scaled_font_t *mCairoScaledFont;
 
     gfxFloat mAdjustedSize;
     gfxFont::Metrics mMetrics;
     PRBool mNeedsOblique;
+    PRBool mNeedsBold;
 };
 
 #endif
--- a/gfx/thebes/src/gfxDWriteFonts.cpp
+++ b/gfx/thebes/src/gfxDWriteFonts.cpp
@@ -41,26 +41,47 @@
 #include "gfxContext.h"
 #include <dwrite.h>
 
 #include "gfxDWriteTextAnalysis.h"
 
 // Chosen this as to resemble DWrite's own oblique face style.
 #define OBLIQUE_SKEW_FACTOR 0.3
 
+// This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common,
+// but we can't declare it in the gfxFont.h or gfxFontUtils.h headers
+// because those are exported, and the cairo headers aren't.
+static inline cairo_antialias_t
+GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption)
+{
+    switch (anAntialiasOption) {
+    default:
+    case gfxFont::kAntialiasDefault:
+        return CAIRO_ANTIALIAS_DEFAULT;
+    case gfxFont::kAntialiasNone:
+        return CAIRO_ANTIALIAS_NONE;
+    case gfxFont::kAntialiasGrayscale:
+        return CAIRO_ANTIALIAS_GRAY;
+    case gfxFont::kAntialiasSubpixel:
+        return CAIRO_ANTIALIAS_SUBPIXEL;
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFont
 gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
                              const gfxFontStyle *aFontStyle,
-                             PRBool aNeedsBold)
-    : gfxFont(aFontEntry, aFontStyle)
+                             PRBool aNeedsBold,
+                             AntialiasOption anAAOption)
+    : gfxFont(aFontEntry, aFontStyle, anAAOption)
     , mAdjustedSize(0.0f)
     , mCairoFontFace(nsnull)
     , mCairoScaledFont(nsnull)
     , mNeedsOblique(PR_FALSE)
+    , mNeedsBold(aNeedsBold)
 {
     gfxDWriteFontEntry *fe =
         static_cast<gfxDWriteFontEntry*>(aFontEntry);
     nsresult rv;
     DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE;
     if ((GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) &&
         !fe->IsItalic()) {
             // For this we always use the font_matrix for uniformity. Not the
@@ -90,16 +111,23 @@ gfxDWriteFont::~gfxDWriteFont()
     if (mCairoFontFace) {
         cairo_font_face_destroy(mCairoFontFace);
     }
     if (mCairoScaledFont) {
         cairo_scaled_font_destroy(mCairoScaledFont);
     }
 }
 
+gfxFont*
+gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
+{
+    return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()),
+                             &mStyle, mNeedsBold, anAAOption);
+}
+
 nsString
 gfxDWriteFont::GetUniqueName()
 {
     return mFontEntry->Name();
 }
 
 const gfxFont::Metrics&
 gfxDWriteFont::GetMetrics()
@@ -266,16 +294,21 @@ gfxDWriteFont::CairoScaledFont()
                               0,                //yx
                               -1 * skewfactor,  //xy
                               1,                //yy
                               0,                //x0
                               0);               //y0
             cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
         }
 
+        if (mAntialiasOption != kAntialiasDefault) {
+            cairo_font_options_set_antialias(fontOptions,
+                GetCairoAntialiasOption(mAntialiasOption));
+        }
+
         mCairoScaledFont = cairo_scaled_font_create(CairoFontFace(),
                                                     &sizeMatrix,
                                                     &identityMatrix,
                                                     fontOptions);
         cairo_font_options_destroy(fontOptions);
     }
 
     NS_ASSERTION(mAdjustedSize == 0.0 ||