From 4732df69415fbece99b3d4c033dc3bebe73d0117 Mon Sep 17 00:00:00 2001 From: "bungeman@google.com" Date: Thu, 23 Jan 2014 15:22:42 +0000 Subject: [PATCH] Basic support for vector FON. 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 | 67 ++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index 82b99d601d..aaf667a260 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -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 + * a 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);