From 990d85f02ba6efaf6f3d75262d7ed650edc8afd5 Mon Sep 17 00:00:00 2001 From: "bungeman@google.com" Date: Tue, 6 Aug 2013 22:53:04 +0000 Subject: Add getFamilyNames to SkTypeface. Review URL: https://codereview.chromium.org/21716005 git-svn-id: http://skia.googlecode.com/svn/trunk@10589 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkTypeface.h | 17 +++++ src/core/SkTypeface.cpp | 4 + src/fonts/SkGScalerContext.cpp | 4 + src/fonts/SkGScalerContext.h | 2 + src/ports/SkFontHost_FreeType.cpp | 13 ++++ src/ports/SkFontHost_FreeType_common.h | 2 + src/ports/SkFontHost_mac.cpp | 26 +++++++ src/ports/SkFontHost_win.cpp | 129 ++++++++++++++++----------------- src/ports/SkFontHost_win_dw.cpp | 50 +++++++++++++ src/sfnt/SkOTTable_name.cpp | 27 +++++-- src/sfnt/SkOTTable_name.h | 6 ++ src/sfnt/SkOTUtils.cpp | 42 +++++++++++ src/sfnt/SkOTUtils.h | 52 +++++++++++++ tests/FontNamesTest.cpp | 115 ++++++++++++++++++++--------- 14 files changed, 381 insertions(+), 108 deletions(-) diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h index 3cfa6ac3c6..a0ca182154 100644 --- a/include/core/SkTypeface.h +++ b/include/core/SkTypeface.h @@ -225,6 +225,21 @@ public: */ int getUnitsPerEm() const; + struct LocalizedString { + SkString fString; + SkString fLanguage; + }; + class LocalizedStrings : ::SkNoncopyable { + public: + virtual bool next(LocalizedString* localizedString) = 0; + }; + /** + * Returns an iterator which will attempt to enumerate all of the + * family names specified by the font. + * It is the caller's responsibility to SK_DELETE the returned pointer. + */ + LocalizedStrings* getFamilyNames() const; + /** * Return the family name for this typeface. It will always be returned * encoded as UTF8, but the language of the name is whatever the host @@ -295,6 +310,8 @@ protected: virtual int onGetUPEM() const = 0; + virtual LocalizedStrings* onGetFamilyNames() const = 0; + virtual int onGetTableTags(SkFontTableTag tags[]) const = 0; virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const = 0; diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp index 34ff853c5c..507c1bf2a6 100644 --- a/src/core/SkTypeface.cpp +++ b/src/core/SkTypeface.cpp @@ -194,6 +194,10 @@ int SkTypeface::getUnitsPerEm() const { return this->onGetUPEM(); } +SkTypeface::LocalizedStrings* SkTypeface::getFamilyNames() const { + return this->onGetFamilyNames(); +} + void SkTypeface::getFamilyName(SkString* name) const { bool isLocal = false; SkFontDescriptor desc(this->style()); diff --git a/src/fonts/SkGScalerContext.cpp b/src/fonts/SkGScalerContext.cpp index 882c70b121..34a55e6d31 100644 --- a/src/fonts/SkGScalerContext.cpp +++ b/src/fonts/SkGScalerContext.cpp @@ -202,6 +202,10 @@ int SkGTypeface::onGetUPEM() const { return fProxy->getUnitsPerEm(); } +SkTypeface::LocalizedStrings* SkGTypeface::onGetFamilyNames() const { + return fProxy->getFamilyNames(); +} + int SkGTypeface::onGetTableTags(SkFontTableTag tags[]) const { return fProxy->getTableTags(tags); } diff --git a/src/fonts/SkGScalerContext.h b/src/fonts/SkGScalerContext.h index 1aa1df369e..0a06b7c12b 100644 --- a/src/fonts/SkGScalerContext.h +++ b/src/fonts/SkGScalerContext.h @@ -32,6 +32,8 @@ protected: virtual int onCountGlyphs() const SK_OVERRIDE; virtual int onGetUPEM() const SK_OVERRIDE; + virtual SkTypeface::LocalizedStrings* onGetFamilyNames() const SK_OVERRIDE; + virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const SK_OVERRIDE; diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp index 3a32ea40c4..c5542a9ddf 100644 --- a/src/ports/SkFontHost_FreeType.cpp +++ b/src/ports/SkFontHost_FreeType.cpp @@ -17,6 +17,7 @@ #include "SkGlyph.h" #include "SkMask.h" #include "SkMaskGamma.h" +#include "SkOTUtils.h" #include "SkAdvancedTypefaceMetrics.h" #include "SkScalerContext.h" #include "SkStream.h" @@ -1402,6 +1403,18 @@ int SkTypeface_FreeType::onCountGlyphs() const { return fGlyphCount; } +SkTypeface::LocalizedStrings* SkTypeface_FreeType::onGetFamilyNames() const { + SkTypeface::LocalizedStrings* nameIter = + SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); + if (NULL == nameIter) { + SkString familyName; + this->getFamilyName(&familyName); + SkString language("und"); //undetermined + nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language); + } + return nameIter; +} + int SkTypeface_FreeType::onGetTableTags(SkFontTableTag tags[]) const { AutoFTAccess fta(this); FT_Face face = fta.face(); diff --git a/src/ports/SkFontHost_FreeType_common.h b/src/ports/SkFontHost_FreeType_common.h index d3df9ce85b..5c069d042d 100644 --- a/src/ports/SkFontHost_FreeType_common.h +++ b/src/ports/SkFontHost_FreeType_common.h @@ -64,6 +64,8 @@ protected: int glyphCount) const SK_OVERRIDE; virtual int onCountGlyphs() const SK_OVERRIDE; + virtual LocalizedStrings* onGetFamilyNames() const SK_OVERRIDE; + virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const SK_OVERRIDE; diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index 71fa5ebdb0..9600730f67 100755 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -95,6 +95,7 @@ public: operator CFRef() const { return fCFRef; } CFRef get() const { return fCFRef; } + CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; } private: CFRef fCFRef; }; @@ -453,6 +454,7 @@ protected: virtual int onGetUPEM() const SK_OVERRIDE; virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; + virtual SkTypeface::LocalizedStrings* onGetFamilyNames() const SK_OVERRIDE; virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const SK_OVERRIDE; @@ -1748,6 +1750,30 @@ int SkTypeface_Mac::onGetUPEM() const { return CGFontGetUnitsPerEm(cgFont); } +SkTypeface::LocalizedStrings* SkTypeface_Mac::onGetFamilyNames() const { + SkTypeface::LocalizedStrings* nameIter = + SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); + if (NULL == nameIter) { + AutoCFRelease cfLanguage; + AutoCFRelease cfFamilyName( + CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage)); + + SkString skLanguage; + SkString skFamilyName; + if (cfLanguage.get()) { + CFStringToSkString(cfLanguage.get(), &skLanguage); + } else { + skLanguage = "und"; //undetermined + } + if (cfFamilyName.get()) { + CFStringToSkString(cfFamilyName.get(), &skFamilyName); + } + + nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage); + } + return nameIter; +} + // If, as is the case with web fonts, the CTFont data isn't available, // the CGFont data may work. While the CGFont may always provide the // right result, leave the CTFont code path to minimize disruption. diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index fe646d74b9..d52774ca6d 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -16,6 +16,7 @@ #include "SkGlyph.h" #include "SkMaskGamma.h" #include "SkOTTable_maxp.h" +#include "SkOTTable_name.h" #include "SkOTUtils.h" #include "SkPath.h" #include "SkSFNTHeader.h" @@ -96,6 +97,26 @@ static void tchar_to_skstring(const TCHAR t[], SkString* s) { #endif } +static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) { + int fontNameLen; //length of fontName in TCHARS. + if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { + call_ensure_accessible(lf); + if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { + fontNameLen = 0; + } + } + + SkAutoSTArray fontName(fontNameLen+1); + if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { + call_ensure_accessible(lf); + if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { + fontName[0] = 0; + } + } + + tchar_to_skstring(fontName.get(), familyName); +} + static void make_canonical(LOGFONT* lf) { lf->lfHeight = -2048; lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; @@ -223,10 +244,6 @@ public: (textMetric.tmPitchAndFamily & TMPF_DEVICE)); } - void getFamilyName(SkString* name) const { - tchar_to_skstring(fLogFont.lfFaceName, name); - } - LOGFONT fLogFont; bool fSerializeAsStream; bool fCanBeLCD; @@ -251,6 +268,7 @@ protected: virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE; virtual int onCountGlyphs() const SK_OVERRIDE; virtual int onGetUPEM() const SK_OVERRIDE; + virtual SkTypeface::LocalizedStrings* onGetFamilyNames() const SK_OVERRIDE; virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const SK_OVERRIDE; @@ -1715,21 +1733,8 @@ void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, HDC deviceContext = ::CreateCompatibleDC(NULL); HFONT savefont = (HFONT)SelectObject(deviceContext, font); - int fontNameLen; //length of fontName in TCHARS. - if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { - call_ensure_accessible(fLogFont); - if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { - fontNameLen = 0; - } - } - - SkAutoSTArray fontName(fontNameLen+1); - if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { - call_ensure_accessible(fLogFont); - if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { - fontName[0] = 0; - } - } + SkString familyName; + dcfontname_to_skstring(deviceContext, fLogFont, &familyName); if (deviceContext) { ::SelectObject(deviceContext, savefont); @@ -1739,9 +1744,6 @@ void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, ::DeleteObject(font); } - SkString familyName; - tchar_to_skstring(fontName.get(), &familyName); - desc->setFamilyName(familyName.c_str()); *isLocalStream = this->fSerializeAsStream; } @@ -2054,6 +2056,18 @@ int LogFontTypeface::onGetUPEM() const { return upem; } +SkTypeface::LocalizedStrings* LogFontTypeface::onGetFamilyNames() const { + SkTypeface::LocalizedStrings* nameIter = + SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); + if (NULL == nameIter) { + SkString familyName; + this->getFamilyName(&familyName); + SkString language("und"); //undetermined + nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language); + } + return nameIter; +} + int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const { SkSFNTHeader header; if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) { @@ -2191,21 +2205,25 @@ SkTypeface* LogFontTypeface::onRefMatchingStyle(Style style) const { #include "SkFontMgr.h" #include "SkDataTable.h" -static bool valid_logfont_for_enum(const LOGFONT& lf, DWORD fontType) { - return TRUETYPE_FONTTYPE == fontType - && lf.lfFaceName[0] - && lf.lfFaceName[0] != '@' - && OUT_STROKE_PRECIS == lf.lfOutPrecision - // without the chraset check, we got LOTS of dups of the same font - // is there a better check (other than searching the array for - // the same name? - && 0 == lf.lfCharSet - ; -} - -static int CALLBACK enum_fonts_proc(const LOGFONT* lf, const TEXTMETRIC*, - DWORD fontType, LPARAM builderParam) { - if (valid_logfont_for_enum(*lf, fontType)) { +static bool valid_logfont_for_enum(const LOGFONT& lf) { + // TODO: Vector FON is unsupported and should not be listed. + return + // Ignore implicit vertical variants. + lf.lfFaceName[0] && lf.lfFaceName[0] != '@' + + // DEFAULT_CHARSET is used to get all fonts, but also implies all + // character sets. Filter assuming all fonts support ANSI_CHARSET. + && ANSI_CHARSET == lf.lfCharSet + ; +} + +/** An EnumFontFamExProc implementation which interprets builderParam as + * an SkTDArray* and appends logfonts which + * pass the valid_logfont_for_enum predicate. + */ +static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*, + DWORD fontType, LPARAM builderParam) { + if (valid_logfont_for_enum(*lf)) { SkTDArray* array = (SkTDArray*)builderParam; *array->append() = *(ENUMLOGFONTEX*)lf; } @@ -2221,8 +2239,13 @@ static SkFontStyle compute_fontstyle(const LOGFONT& lf) { class SkFontStyleSetGDI : public SkFontStyleSet { public: SkFontStyleSetGDI(const TCHAR familyName[]) { + LOGFONT lf; + sk_bzero(&lf, sizeof(lf)); + lf.lfCharSet = DEFAULT_CHARSET; + _tcscpy_s(lf.lfFaceName, familyName); + HDC hdc = ::CreateCompatibleDC(NULL); - ::EnumFonts(hdc, familyName, enum_fonts_proc, (LPARAM)&fArray); + ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0); ::DeleteDC(hdc); } @@ -2260,29 +2283,9 @@ private: SkTDArray fArray; }; -static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC* tm, - DWORD fontType, LPARAM builderParam) { - if (valid_logfont_for_enum(*lf, fontType)) { - SkTDArray* array = (SkTDArray*)builderParam; - *array->append() = *(ENUMLOGFONTEX*)lf; -#if 0 - SkString str; - tchar_to_skstring(lf->lfFaceName, &str); - SkDebugf("fam:%s height:%d width:%d esc:%d orien:%d weight:%d ital:%d char:%d clip:%d qual:%d pitch:%d\n", - str.c_str(), lf->lfHeight, lf->lfWidth, lf->lfEscapement, lf->lfOrientation, - lf->lfWeight, lf->lfItalic, lf->lfCharSet, lf->lfClipPrecision, lf->lfQuality, - lf->lfPitchAndFamily); -#endif - } - return 1; // non-zero means continue -} - class SkFontMgrGDI : public SkFontMgr { - void init() { - if (!fLogFontArray.isEmpty()) { - return; - } - +public: + SkFontMgrGDI() { LOGFONT lf; sk_bzero(&lf, sizeof(lf)); lf.lfCharSet = DEFAULT_CHARSET; @@ -2292,23 +2295,17 @@ class SkFontMgrGDI : public SkFontMgr { ::DeleteDC(hdc); } -public: - SkFontMgrGDI() {} - protected: virtual int onCountFamilies() SK_OVERRIDE { - this->init(); return fLogFontArray.count(); } virtual void onGetFamilyName(int index, SkString* familyName) SK_OVERRIDE { - this->init(); SkASSERT((unsigned)index < (unsigned)fLogFontArray.count()); tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName); } virtual SkFontStyleSet* onCreateStyleSet(int index) SK_OVERRIDE { - this->init(); SkASSERT((unsigned)index < (unsigned)fLogFontArray.count()); return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName)); } diff --git a/src/ports/SkFontHost_win_dw.cpp b/src/ports/SkFontHost_win_dw.cpp index beec056e93..cee8b362b2 100644 --- a/src/ports/SkFontHost_win_dw.cpp +++ b/src/ports/SkFontHost_win_dw.cpp @@ -495,6 +495,7 @@ protected: virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE; virtual int onCountGlyphs() const SK_OVERRIDE; virtual int onGetUPEM() const SK_OVERRIDE; + virtual SkTypeface::LocalizedStrings* onGetFamilyNames() const SK_OVERRIDE; virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const SK_OVERRIDE; @@ -1088,6 +1089,54 @@ int DWriteFontTypeface::onGetUPEM() const { return metrics.designUnitsPerEm; } +class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings { +public: + /** Takes ownership of the IDWriteLocalizedStrings. */ + explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings) + : fIndex(0), fStrings(strings) + { } + + virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE { + if (fIndex >= fStrings->GetCount()) { + return false; + } + + // String + UINT32 stringLength; + HRBM(fStrings->GetStringLength(fIndex, &stringLength), "Could not get string length."); + stringLength += 1; + + SkSMallocWCHAR wString(stringLength); + HRBM(fStrings->GetString(fIndex, wString.get(), stringLength), "Could not get string."); + + HRB(wchar_to_skstring(wString.get(), &localizedString->fString)); + + // Locale + UINT32 localeLength; + HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLength), "Could not get locale length."); + localeLength += 1; + + SkSMallocWCHAR wLocale(localeLength); + HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLength), "Could not get locale."); + + HRB(wchar_to_skstring(wLocale.get(), &localizedString->fLanguage)); + + ++fIndex; + return true; + } + +private: + UINT32 fIndex; + SkTScopedComPtr fStrings; +}; + +SkTypeface::LocalizedStrings* DWriteFontTypeface::onGetFamilyNames() const { + SkTScopedComPtr familyNames; + HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names."); + + return new LocalizedStrings_IDWriteLocalizedStrings(familyNames.release()); +} + int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const { DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType(); if (type != DWRITE_FONT_FACE_TYPE_CFF && @@ -1656,6 +1705,7 @@ public: DWRITE_FONT_STRETCH width = (DWRITE_FONT_STRETCH)pattern.width(); SkTScopedComPtr font; + // TODO: perhaps use GetMatchingFonts and get the least simulated? HRNM(fFontFamily->GetFirstMatchingFont(weight, width, slant, &font), "Could not match font in family."); diff --git a/src/sfnt/SkOTTable_name.cpp b/src/sfnt/SkOTTable_name.cpp index e0440754ca..b536c0a115 100644 --- a/src/sfnt/SkOTTable_name.cpp +++ b/src/sfnt/SkOTTable_name.cpp @@ -451,6 +451,8 @@ bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) { ++fIndex; } while (fType != -1 && nameRecord->nameID.fontSpecific != fType); + record.type = nameRecord->nameID.fontSpecific; + const uint16_t stringTableOffset = SkEndian_SwapBE16(fName.stringOffset); const char* stringTable = SkTAddOffset(&fName, stringTableOffset); @@ -460,20 +462,29 @@ bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) { const char* nameString = SkTAddOffset(stringTable, nameOffset); switch (nameRecord->platformID.value) { case SkOTTableName::Record::PlatformID::Windows: - SkASSERT(SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 - == nameRecord->encodingID.windows.value - || SkOTTableName::Record::EncodingID::Windows::UnicodeUCS4 - == nameRecord->encodingID.windows.value - || SkOTTableName::Record::EncodingID::Windows::Symbol - == nameRecord->encodingID.windows.value); + if (SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 + != nameRecord->encodingID.windows.value + && SkOTTableName::Record::EncodingID::Windows::UnicodeUCS4 + != nameRecord->encodingID.windows.value + && SkOTTableName::Record::EncodingID::Windows::Symbol + != nameRecord->encodingID.windows.value) + { + record.name.reset(); + break; + } case SkOTTableName::Record::PlatformID::Unicode: case SkOTTableName::Record::PlatformID::ISO: SkStringFromUTF16BE((const uint16_t*)nameString, nameLength, record.name); break; case SkOTTableName::Record::PlatformID::Macintosh: - SkASSERT(SkOTTableName::Record::EncodingID::Macintosh::Roman - == nameRecord->encodingID.macintosh.value); + // TODO: need better decoding, especially on Mac. + if (SkOTTableName::Record::EncodingID::Macintosh::Roman + != nameRecord->encodingID.macintosh.value) + { + record.name.reset(); + break; + } SkStringFromMacRoman((const uint8_t*)nameString, nameLength, record.name); break; diff --git a/src/sfnt/SkOTTable_name.h b/src/sfnt/SkOTTable_name.h index 8dde1a4fc7..f3dae4085a 100644 --- a/src/sfnt/SkOTTable_name.h +++ b/src/sfnt/SkOTTable_name.h @@ -554,7 +554,13 @@ struct SkOTTableName { : fName(name), fIndex(0), fType(type) { } + void reset(SkOTTableName::Record::NameID::Predefined::Value type) { + fIndex = 0; + fType = type; + } + struct Record { + SK_OT_USHORT type; SkString name; SkString language; }; diff --git a/src/sfnt/SkOTUtils.cpp b/src/sfnt/SkOTUtils.cpp index c7716fffd5..004a888310 100644 --- a/src/sfnt/SkOTUtils.cpp +++ b/src/sfnt/SkOTUtils.cpp @@ -159,3 +159,45 @@ SkData* SkOTUtils::RenameFont(SkStream* fontData, const char* fontName, int font return rewrittenFontData.detach(); } + + +SkOTUtils::LocalizedStrings_NameTable* +SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(const SkTypeface& typeface) { + static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e'); + size_t nameTableSize = typeface.getTableSize(nameTag); + if (0 == nameTableSize) { + return NULL; + } + SkAutoTDeleteArray nameTableData(new uint8_t[nameTableSize]); + size_t copied = typeface.getTableData(nameTag, 0, nameTableSize, nameTableData.get()); + if (copied != nameTableSize) { + return NULL; + } + + return new SkOTUtils::LocalizedStrings_NameTable((SkOTTableName*)nameTableData.detach(), + SkOTUtils::LocalizedStrings_NameTable::familyNameTypes, + SK_ARRAY_COUNT(SkOTUtils::LocalizedStrings_NameTable::familyNameTypes)); +} + +bool SkOTUtils::LocalizedStrings_NameTable::next(SkTypeface::LocalizedString* localizedString) { + do { + SkOTTableName::Iterator::Record record; + if (fFamilyNameIter.next(record)) { + localizedString->fString = record.name; + localizedString->fLanguage = record.language; + return true; + } + if (fTypesCount == fTypesIndex + 1) { + return false; + } + ++fTypesIndex; + fFamilyNameIter.reset(fTypes[fTypesIndex]); + } while (true); +} + +SkOTTableName::Record::NameID::Predefined::Value +SkOTUtils::LocalizedStrings_NameTable::familyNameTypes[3] = { + SkOTTableName::Record::NameID::Predefined::FontFamilyName, + SkOTTableName::Record::NameID::Predefined::PreferredFamily, + SkOTTableName::Record::NameID::Predefined::WWSFamilyName, +}; diff --git a/src/sfnt/SkOTUtils.h b/src/sfnt/SkOTUtils.h index 3c5ada25eb..4825fbeb2f 100644 --- a/src/sfnt/SkOTUtils.h +++ b/src/sfnt/SkOTUtils.h @@ -9,6 +9,9 @@ #define SkOTUtils_DEFINED #include "SkOTTableTypes.h" +#include "SkOTTable_name.h" +#include "SkTypeface.h" + class SkData; class SkStream; @@ -32,6 +35,55 @@ struct SkOTUtils { * fontName and fontNameLen must be specified in terms of ASCII chars. */ static SkData* RenameFont(SkStream* fontData, const char* fontName, int fontNameLen); + + /** An implementation of LocalizedStrings which obtains it's data from a 'name' table. */ + class LocalizedStrings_NameTable : public SkTypeface::LocalizedStrings { + public: + /** Takes ownership of the nameTableData and will free it with SK_DELETE. */ + LocalizedStrings_NameTable(SkOTTableName* nameTableData, + SkOTTableName::Record::NameID::Predefined::Value types[], + int typesCount) + : fTypes(types), fTypesCount(typesCount), fTypesIndex(0) + , fNameTableData(nameTableData), fFamilyNameIter(*nameTableData, fTypes[fTypesIndex]) + { } + + /** Creates an iterator over all the family names in the 'name' table of a typeface. + * If no valid 'name' table can be found, returns NULL. + */ + static LocalizedStrings_NameTable* CreateForFamilyNames(const SkTypeface& typeface); + + virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE; + private: + static SkOTTableName::Record::NameID::Predefined::Value familyNameTypes[3]; + + SkOTTableName::Record::NameID::Predefined::Value* fTypes; + int fTypesCount; + int fTypesIndex; + SkAutoTDeleteArray fNameTableData; + SkOTTableName::Iterator fFamilyNameIter; + }; + + /** An implementation of LocalizedStrings which has one name. */ + class LocalizedStrings_SingleName : public SkTypeface::LocalizedStrings { + public: + LocalizedStrings_SingleName(SkString name, SkString language) + : fName(name), fLanguage(language), fHasNext(true) + { } + + virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE { + localizedString->fString = fName; + localizedString->fLanguage = fLanguage; + + bool hadNext = fHasNext; + fHasNext = false; + return hadNext; + } + + private: + SkString fName; + SkString fLanguage; + bool fHasNext; + }; }; #endif diff --git a/tests/FontNamesTest.cpp b/tests/FontNamesTest.cpp index 3845c3b6c5..18ba35695e 100644 --- a/tests/FontNamesTest.cpp +++ b/tests/FontNamesTest.cpp @@ -7,6 +7,8 @@ #include "Test.h" +#include "SkCommandLineFlags.h" +#include "SkFontMgr.h" #include "SkOTTable_name.h" #include "SkTypeface.h" @@ -108,40 +110,7 @@ struct FontNamesTest { }, }; -static void TestFontNames(skiatest::Reporter* reporter) { - static const char* interestingFont[] = { - "Arial", - "Times New Roman", - "MS PGothic", // Has Japanese name. - "Wingdings", // Uses 'Symbol' name encoding. - }; - static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e'); - - for (size_t i = 0; i < SK_ARRAY_COUNT(interestingFont); ++i) { - SkAutoTUnref typeface(SkTypeface::CreateFromName(interestingFont[i], - SkTypeface::kNormal)); - if (NULL == typeface.get()) { - continue; - } - size_t nameTableSize = typeface->getTableSize(nameTag); - if (0 == nameTableSize) { - continue; - } - uint8_t* nameTableData = new uint8_t[nameTableSize]; - SkAutoTDeleteArray ada(nameTableData); - size_t copied = typeface->getTableData(nameTag, 0, nameTableSize, nameTableData); - if (copied != nameTableSize) { - continue; - } - - SkOTTableName::Iterator iter(*((SkOTTableName*)nameTableData), - SkOTTableName::Record::NameID::Predefined::FontFamilyName); - SkOTTableName::Iterator::Record record; - while (iter.next(record)) { - //printf("%s <%s>\n", record.name.c_str(), record.language.c_str()); - } - } - +static void test_synthetic(skiatest::Reporter* reporter, bool verbose) { for (size_t i = 0; i < SK_ARRAY_COUNT(test); ++i) { SkOTTableName::Iterator iter(*test[i].data, test[i].nameID.predefined.value); SkOTTableName::Iterator::Record record; @@ -170,6 +139,84 @@ static void TestFontNames(skiatest::Reporter* reporter) { } } +#define MAX_FAMILIES 1000 +static void test_systemfonts(skiatest::Reporter* reporter, bool verbose) { + static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e'); + + SkAutoTUnref fm(SkFontMgr::RefDefault()); + int count = SkMin32(fm->countFamilies(), MAX_FAMILIES); + for (int i = 0; i < count; ++i) { + SkAutoTUnref set(fm->createStyleSet(i)); + for (int j = 0; j < set->count(); ++j) { + SkString sname; + SkFontStyle fs; + set->getStyle(j, &fs, &sname); + + SkAutoTUnref typeface(set->createTypeface(j)); + + SkString familyName; + typeface->getFamilyName(&familyName); + if (verbose) { + printf("[%s]\n", familyName.c_str()); + } + + SkAutoTDelete familyNamesIter(typeface->getFamilyNames()); + SkTypeface::LocalizedString familyNameLocalized; + while (familyNamesIter->next(&familyNameLocalized)) { + if (verbose) { + printf("(%s) <%s>\n", familyNameLocalized.fString.c_str(), + familyNameLocalized.fLanguage.c_str()); + } + } + + size_t nameTableSize = typeface->getTableSize(nameTag); + if (0 == nameTableSize) { + continue; + } + SkAutoTMalloc nameTableData(nameTableSize); + size_t copied = typeface->getTableData(nameTag, 0, nameTableSize, nameTableData.get()); + if (copied != nameTableSize) { + continue; + } + + SkOTTableName::Iterator::Record record; + SkOTTableName::Iterator familyNameIter(*((SkOTTableName*)nameTableData.get()), + SkOTTableName::Record::NameID::Predefined::FontFamilyName); + while (familyNameIter.next(record)) { + REPORTER_ASSERT_MESSAGE(reporter, + SkOTTableName::Record::NameID::Predefined::FontFamilyName == record.type, + "Requested family name, got something else." + ); + if (verbose) { + printf("{%s} <%s>\n", record.name.c_str(), record.language.c_str()); + } + } + + SkOTTableName::Iterator styleNameIter(*((SkOTTableName*)nameTableData.get()), + SkOTTableName::Record::NameID::Predefined::FontSubfamilyName); + while (styleNameIter.next(record)) { + REPORTER_ASSERT_MESSAGE(reporter, + SkOTTableName::Record::NameID::Predefined::FontSubfamilyName == record.type, + "Requested subfamily name, got something else." + ); + if (verbose) { + printf("{{%s}} <%s>\n", record.name.c_str(), record.language.c_str()); + } + } + + if (verbose) { + printf("\n"); + } + } + } +} + +DEFINE_bool(verboseFontNames, false, "verbose FontNames test."); + +static void TestFontNames(skiatest::Reporter* reporter) { + test_synthetic(reporter, FLAGS_verboseFontNames); + test_systemfonts(reporter, FLAGS_verboseFontNames); +} #include "TestClassDef.h" DEFINE_TESTCLASS("FontNames", FontNamesTestClass, TestFontNames) -- cgit v1.2.3