Implement onCountGlyphs and onGetUPEM on Windows.

R=vandebo@chromium.org

Review URL: https://codereview.chromium.org/19231003

git-svn-id: http://skia.googlecode.com/svn/trunk@10089 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h
index c84ae28..0fd2ddb 100644
--- a/include/core/SkTypeface.h
+++ b/include/core/SkTypeface.h
@@ -272,9 +272,9 @@
 
     virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[],
                                 int glyphCount) const;
-    virtual int onCountGlyphs() const;
+    virtual int onCountGlyphs() const = 0;
 
-    virtual int onGetUPEM() const;
+    virtual int onGetUPEM() const = 0;
 
     virtual int onGetTableTags(SkFontTableTag tags[]) const;
     virtual size_t onGetTableData(SkFontTableTag, size_t offset,
diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp
index dcdd5e2..2943238 100644
--- a/src/core/SkTypeface.cpp
+++ b/src/core/SkTypeface.cpp
@@ -214,11 +214,6 @@
     return 0;
 }
 
-int SkTypeface::onCountGlyphs() const {
-    SkDebugf("onCountGlyphs unimplemented\n");
-    return 0;
-}
-
 int SkTypeface::onGetUPEM() const {
     int upem = 0;
 
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index d07307e..2238593 100755
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -15,6 +15,7 @@
 #include "SkFontHost.h"
 #include "SkGlyph.h"
 #include "SkMaskGamma.h"
+#include "SkOTTable_maxp.h"
 #include "SkOTUtils.h"
 #include "SkPath.h"
 #include "SkStream.h"
@@ -140,12 +141,21 @@
     return SkFixedToFIXED(SkScalarToFixed(x));
 }
 
-static unsigned calculateOutlineGlyphCount(HDC hdc) {
+static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
+    TEXTMETRIC textMetric;
+    if (0 == GetTextMetrics(hdc, &textMetric)) {
+        textMetric.tmPitchAndFamily = TMPF_VECTOR;
+        call_ensure_accessible(lf);
+        GetTextMetrics(hdc, &textMetric);
+    }
+
+    if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
+        return textMetric.tmLastChar;
+    }
+
     // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
-    const DWORD maxpTag =
-        SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p'));
     uint16_t glyphs;
-    if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
+    if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
         return SkEndian_SwapBE16(glyphs);
     }
 
@@ -167,6 +177,28 @@
     return min;
 }
 
+static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
+    TEXTMETRIC textMetric;
+    if (0 == GetTextMetrics(hdc, &textMetric)) {
+        textMetric.tmPitchAndFamily = TMPF_VECTOR;
+        call_ensure_accessible(lf);
+        GetTextMetrics(hdc, &textMetric);
+    }
+
+    if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
+        return textMetric.tmMaxCharWidth;
+    }
+
+    OUTLINETEXTMETRIC otm;
+    unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
+    if (0 == otmRet) {
+        call_ensure_accessible(lf);
+        otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
+    }
+
+    return (0 == otmRet) ? 0 : otm.otmEMSquare;
+}
+
 class LogFontTypeface : public SkTypeface {
 public:
     LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) :
@@ -228,6 +260,8 @@
                                 SkAdvancedTypefaceMetrics::PerGlyphInfo,
                                 const uint32_t*, uint32_t) const SK_OVERRIDE;
     virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
+    virtual int onCountGlyphs() const SK_OVERRIDE;
+    virtual int onGetUPEM() const SK_OVERRIDE;
 };
 
 class FontMemResourceTypeface : public LogFontTypeface {
@@ -724,10 +758,8 @@
 
 unsigned SkScalerContext_Windows::generateGlyphCount() {
     if (fGlyphCount < 0) {
-        if (fType == SkScalerContext_Windows::kBitmap_Type) {
-           return fTM.tmLastChar;
-        }
-        fGlyphCount = calculateOutlineGlyphCount(fDDC);
+        fGlyphCount = calculateGlyphCount(
+                          fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
     }
     return fGlyphCount;
 }
@@ -1446,7 +1478,7 @@
     if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
         goto Error;
     }
-    glyphCount = calculateOutlineGlyphCount(hdc);
+    glyphCount = calculateGlyphCount(hdc, fLogFont);
 
     info = new SkAdvancedTypefaceMetrics;
     info->fEmSize = otm.otmEMSquare;
@@ -1684,6 +1716,34 @@
     return stream;
 }
 
+int LogFontTypeface::onCountGlyphs() const {
+    HDC hdc = ::CreateCompatibleDC(NULL);
+    HFONT font = CreateFontIndirect(&fLogFont);
+    HFONT savefont = (HFONT)SelectObject(hdc, font);
+
+    unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
+
+    SelectObject(hdc, savefont);
+    DeleteObject(font);
+    DeleteDC(hdc);
+
+    return glyphCount;
+}
+
+int LogFontTypeface::onGetUPEM() const {
+    HDC hdc = ::CreateCompatibleDC(NULL);
+    HFONT font = CreateFontIndirect(&fLogFont);
+    HFONT savefont = (HFONT)SelectObject(hdc, font);
+
+    unsigned int upem = calculateUPEM(hdc, fLogFont);
+
+    SelectObject(hdc, savefont);
+    DeleteObject(font);
+    DeleteDC(hdc);
+
+    return upem;
+}
+
 SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
     SkScalerContext_Windows* ctx = SkNEW_ARGS(SkScalerContext_Windows,
                                                 (const_cast<LogFontTypeface*>(this), desc));
diff --git a/src/ports/SkFontHost_win_dw.cpp b/src/ports/SkFontHost_win_dw.cpp
index 29fa098..3772a09 100644
--- a/src/ports/SkFontHost_win_dw.cpp
+++ b/src/ports/SkFontHost_win_dw.cpp
@@ -492,6 +492,8 @@
                                 SkAdvancedTypefaceMetrics::PerGlyphInfo,
                                 const uint32_t*, uint32_t) const SK_OVERRIDE;
     virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
+    virtual int onCountGlyphs() const SK_OVERRIDE;
+    virtual int onGetUPEM() const SK_OVERRIDE;
 };
 
 class SkScalerContext_Windows : public SkScalerContext {
@@ -1071,6 +1073,16 @@
     *isLocalStream = SkToBool(fDWriteFontFileLoader.get());
 }
 
+int DWriteFontTypeface::onCountGlyphs() const {
+    return fDWriteFontFace->GetGlyphCount();
+}
+
+int DWriteFontTypeface::onGetUPEM() const {
+    DWRITE_FONT_METRICS metrics;
+    fDWriteFontFace->GetMetrics(&metrics);
+    return metrics.designUnitsPerEm;
+}
+
 template <typename T> class SkAutoIDWriteUnregister {
 public:
     SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
diff --git a/tests/FontHostTest.cpp b/tests/FontHostTest.cpp
index 9a186dd..7358b10 100644
--- a/tests/FontHostTest.cpp
+++ b/tests/FontHostTest.cpp
@@ -29,20 +29,18 @@
 };
 
 // Test that getUnitsPerEm() agrees with a direct lookup in the 'head' table
-// (if that table is available.
+// (if that table is available).
 static void test_unitsPerEm(skiatest::Reporter* reporter, SkTypeface* face) {
-    int nativeUPEM = face->getUnitsPerEm();;
+    int nativeUPEM = face->getUnitsPerEm();
 
     int tableUPEM = -1;
     size_t size = face->getTableSize(kFontTableTag_head);
     if (size) {
-        SkAutoMalloc storage(size);
-        char* ptr = (char*)storage.get();
-        face->getTableData(kFontTableTag_head, 0, size, ptr);
         // unitsPerEm is at offset 18 into the 'head' table.
-        tableUPEM = SkEndian_SwapBE16(*(uint16_t*)&ptr[18]);
+        uint16_t rawUPEM;
+        face->getTableData(kFontTableTag_head, 18, sizeof(rawUPEM), &rawUPEM);
+        tableUPEM = SkEndian_SwapBE16(rawUPEM);
     }
-//    SkDebugf("--- typeface returned %d upem [%X]\n", nativeUPEM, face->uniqueID());
 
     if (tableUPEM >= 0) {
         REPORTER_ASSERT(reporter, tableUPEM == nativeUPEM);
@@ -52,6 +50,28 @@
     }
 }
 
+// Test that countGlyphs() agrees with a direct lookup in the 'maxp' table
+// (if that table is available).
+static void test_countGlyphs(skiatest::Reporter* reporter, SkTypeface* face) {
+    int nativeGlyphs = face->countGlyphs();
+
+    int tableGlyphs = -1;
+    size_t size = face->getTableSize(kFontTableTag_maxp);
+    if (size) {
+        // glyphs is at offset 4 into the 'maxp' table.
+        uint16_t rawGlyphs;
+        face->getTableData(kFontTableTag_maxp, 4, sizeof(rawGlyphs), &rawGlyphs);
+        tableGlyphs = SkEndian_SwapBE16(rawGlyphs);
+    }
+
+    if (tableGlyphs >= 0) {
+        REPORTER_ASSERT(reporter, tableGlyphs == nativeGlyphs);
+    } else {
+        // not sure this is a bug, but lets report it for now as info.
+        SkDebugf("--- typeface returned 0 glyphs [%X]\n", face->uniqueID());
+    }
+}
+
 static void test_fontstream(skiatest::Reporter* reporter,
                             SkStream* stream, int ttcIndex) {
     int n = SkFontStream::GetTableTags(stream, ttcIndex, NULL);
@@ -157,6 +177,7 @@
 #endif
             test_tables(reporter, face);
             test_unitsPerEm(reporter, face);
+            test_countGlyphs(reporter, face);
             face->unref();
         }
     }