Basic support for vector FON.
authorbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 23 Jan 2014 15:22:42 +0000 (15:22 +0000)
committerbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 23 Jan 2014 15:22:42 +0000 (15:22 +0000)
This change gives vector FON fonts slightly better support than bitmap
FON fonts which we already have some support for.

This also fixes the calculation of the y component of advances for
bitmap and vector FON glyphs.

git-svn-id: http://skia.googlecode.com/svn/trunk@13150 2bbb7eff-a529-9590-31e7-b0007b416f81

src/ports/SkFontHost_win.cpp

index 82b99d6..aaf667a 100755 (executable)
@@ -152,6 +152,10 @@ static inline FIXED SkScalarToFIXED(SkScalar x) {
     return SkFixedToFIXED(SkScalarToFixed(x));
 }
 
+static inline SkScalar SkFIXEDToScalar(FIXED x) {
+    return SkFixedToScalar(SkFIXEDToFixed(x));
+}
+
 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
     TEXTMETRIC textMetric;
     if (0 == GetTextMetrics(hdc, &textMetric)) {
@@ -583,7 +587,7 @@ private:
      */
     SkMatrix     fG_inv;
     enum Type {
-        kTrueType_Type, kBitmap_Type,
+        kTrueType_Type, kBitmap_Type, kLine_Type
     } fType;
     TEXTMETRIC fTM;
 };
@@ -717,21 +721,24 @@ SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
             fTM.tmPitchAndFamily = TMPF_TRUETYPE;
         }
     }
-    // Used a logfont on a memory context, should never get a device font.
-    // Therefore all TMPF_DEVICE will be PostScript fonts.
-
-    // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE must be set,
-    // otherwise we have a vector FON, which we don't support.
-    // This was determined by testing with Type1 PFM/PFB and OpenTypeCFF OTF,
-    // as well as looking at Wine bugs and sources.
-    SkASSERT(!(fTM.tmPitchAndFamily & TMPF_VECTOR) ||
-              (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)));
 
     XFORM xform;
     if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
-        // Truetype or PostScript.
-        // Stroked FON also gets here (TMPF_VECTOR), but we don't handle it.
-        fType = SkScalerContext_GDI::kTrueType_Type;
+        // Used a logfont on a memory context, should never get a device font.
+        // Therefore all TMPF_DEVICE will be PostScript fonts.
+
+        // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
+        // we have an outline font. Otherwise we have a vector FON, which is
+        // scalable, but not an outline font.
+        // This was determined by testing with Type1 PFM/PFB and
+        // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
+        if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
+            // Truetype or PostScript.
+            fType = SkScalerContext_GDI::kTrueType_Type;
+        } else {
+            // Stroked FON.
+            fType = SkScalerContext_GDI::kLine_Type;
+        }
 
         // fPost2x2 is column-major, left handed (y down).
         // XFORM 2x2 is row-major, left handed (y down).
@@ -833,8 +840,8 @@ uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
          *
          *  When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
          *  glyph, then the 'default character's glyph is returned instead. The 'default character'
-         *  is available in fTM.tmDefaultChar. FON fonts have adefault character, and there exists a
-         *  usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
+         *  is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
+         *  usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
          *  'default character' specified by the font, then often the first character found is used.
          *
          *  When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
@@ -845,7 +852,11 @@ uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
         DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
         if (result == GDI_ERROR
             || 0xFFFF == index
-            || (0x1F == index && fType == SkScalerContext_GDI::kBitmap_Type /*&& winVer < Vista */))
+            || (0x1F == index &&
+               (fType == SkScalerContext_GDI::kBitmap_Type ||
+                fType == SkScalerContext_GDI::kLine_Type)
+               /*&& winVer < Vista */)
+           )
         {
             index = 0;
         }
@@ -885,7 +896,7 @@ void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
 void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
     SkASSERT(fDDC);
 
-    if (fType == SkScalerContext_GDI::kBitmap_Type) {
+    if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
         SIZE size;
         WORD glyphs = glyph->getGlyphID(0);
         if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
@@ -896,12 +907,30 @@ void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
         glyph->fHeight = SkToS16(size.cy);
 
         glyph->fTop = SkToS16(-fTM.tmAscent);
+        // Bitmap FON cannot underhang, but vector FON may.
+        // There appears no means of determining underhang of vector FON.
         glyph->fLeft = SkToS16(0);
         glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
         glyph->fAdvanceY = 0;
 
+        // Vector FON will transform nicely, but bitmap FON do not.
+        if (fType == SkScalerContext_GDI::kLine_Type) {
+            SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
+                                             glyph->fWidth, glyph->fHeight);
+            SkMatrix m;
+            m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
+                     -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
+                     0,  0, SkScalarToPersp(SK_Scalar1));
+            m.mapRect(&bounds);
+            bounds.roundOut();
+            glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
+            glyph->fTop = SkScalarTruncToInt(bounds.fTop);
+            glyph->fWidth = SkScalarTruncToInt(bounds.width());
+            glyph->fHeight = SkScalarTruncToInt(bounds.height());
+        }
+
         // Apply matrix to advance.
-        glyph->fAdvanceY = SkFixedMul(SkFIXEDToFixed(fMat22.eM21), glyph->fAdvanceX);
+        glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX);
         glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
 
         return;
@@ -988,7 +1017,7 @@ void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint:
     SkASSERT(fDDC);
 
 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
-    if (fType == SkScalerContext_GDI::kBitmap_Type) {
+    if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
 #endif
         if (mx) {
             mx->fTop = SkIntToScalar(-fTM.tmAscent);