use hires metrics when rotated (or subpixel is requested)
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 17 May 2011 14:04:41 +0000 (14:04 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 17 May 2011 14:04:41 +0000 (14:04 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@1342 2bbb7eff-a529-9590-31e7-b0007b416f81

src/ports/SkFontHost_win.cpp

index e274a98..f406f76 100755 (executable)
@@ -272,6 +272,10 @@ private:
     HFONT        fFont;
     SCRIPT_CACHE fSC;
     int          fGlyphCount;
+
+    HFONT        fHiResFont;
+    MAT2         fMat22Identity;
+    SkMatrix     fHiResMatrix;
 };
 
 static float mul2float(SkScalar a, SkScalar b) {
@@ -284,6 +288,16 @@ static FIXED float2FIXED(float x) {
 
 static SkMutex gFTMutex;
 
+#define HIRES_TEXTSIZE  2048
+#define HIRES_SHIFT     11
+static inline SkFixed HiResToFixed(int value) {
+    return value << (16 - HIRES_SHIFT);
+}
+
+static bool needHiResMetrics(const SkScalar mat[2][2]) {
+    return mat[1][0] || mat[0][1];
+}
+
 SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
         : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
         , fGlyphCount(-1) {
@@ -304,6 +318,7 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
     fMat22.eM22 = float2FIXED(-fXform.eM22);
 
     fDDC = ::CreateCompatibleDC(NULL);
+    SetGraphicsMode(fDDC, GM_ADVANCED);
     SetBkMode(fDDC, TRANSPARENT);
 
     // Scaling by the DPI is inconsistent with how Skia draws elsewhere
@@ -312,6 +327,21 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
     GetLogFontByID(fRec.fFontID, &lf);
     lf.lfHeight = -gCanonicalTextSize;
     fFont = CreateFontIndirect(&lf);
+
+    // if we're rotated, or want fractional widths, create a hires font
+    fHiResFont = 0;
+    if (needHiResMetrics(fRec.fPost2x2) || (fRec.fFlags & kSubpixelPositioning_Flag)) {
+        lf.lfHeight = -HIRES_TEXTSIZE;
+        fHiResFont = CreateFontIndirect(&lf);
+
+        fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
+        fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
+
+        // construct a matrix to go from HIRES logical units to our device units
+        fRec.getSingleMatrix(&fHiResMatrix);
+        SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
+        fHiResMatrix.preScale(scale, scale);
+    }
     fSavefont = (HFONT)SelectObject(fDDC, fFont);
 }
 
@@ -323,6 +353,9 @@ SkScalerContext_Windows::~SkScalerContext_Windows() {
     if (fFont) {
         ::DeleteObject(fFont);
     }
+    if (fHiResFont) {
+        ::DeleteObject(fHiResFont);
+    }
     if (fSC) {
         ::ScriptFreeCache(&fSC);
     }
@@ -369,7 +402,7 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
     SkASSERT(fDDC);
 
     GLYPHMETRICS gm;
-    memset(&gm, 0, sizeof(gm));
+    sk_bzero(&gm, sizeof(gm));
 
     glyph->fRsbDelta = 0;
     glyph->fLsbDelta = 0;
@@ -400,6 +433,19 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
             glyph->fTop -= 1;
             glyph->fLeft -= 1;
         }
+
+        if (fHiResFont) {
+            SelectObject(fDDC, fHiResFont);
+            sk_bzero(&gm, sizeof(gm));
+            ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity);
+            if (GDI_ERROR != ret) {
+                SkPoint advance;
+                fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
+                glyph->fAdvanceX = SkScalarToFixed(advance.fX);
+                glyph->fAdvanceY = SkScalarToFixed(advance.fY);
+            }
+            SelectObject(fDDC, fFont);
+        }
     } else {
         glyph->fWidth = 0;
     }
@@ -479,9 +525,9 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
         size_t size = glyph.fHeight * srcRB;
         memset(bits, 0xFF, size);
 
+        SetGraphicsMode(dc, GM_ADVANCED);
         SetBkMode(dc, TRANSPARENT);
         SetTextAlign(dc, TA_LEFT | TA_BASELINE);
-        SetGraphicsMode(dc, GM_ADVANCED);
 
         XFORM xform = fXform;
         xform.eDx = (float)-glyph.fLeft;