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
This commit is contained in:
bungeman@google.com 2013-08-06 22:53:04 +00:00
parent 2273f9b45f
commit 990d85f02b
14 changed files with 379 additions and 106 deletions

View File

@ -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;

View File

@ -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());

View File

@ -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);
}

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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<CFStringRef> cfLanguage;
AutoCFRelease<CFStringRef> 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.

View File

@ -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<LF_FULLFACESIZE, TCHAR> 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<LF_FULLFACESIZE, TCHAR> 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 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
;
}
static int CALLBACK enum_fonts_proc(const LOGFONT* lf, const TEXTMETRIC*,
DWORD fontType, LPARAM builderParam) {
if (valid_logfont_for_enum(*lf, fontType)) {
/** An EnumFontFamExProc implementation which interprets builderParam as
* an SkTDArray<ENUMLOGFONTEX>* 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<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)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<ENUMLOGFONTEX> 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<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)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));
}

View File

@ -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<IDWriteLocalizedStrings> fStrings;
};
SkTypeface::LocalizedStrings* DWriteFontTypeface::onGetFamilyNames() const {
SkTScopedComPtr<IDWriteLocalizedStrings> 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<IDWriteFont> font;
// TODO: perhaps use GetMatchingFonts and get the least simulated?
HRNM(fFontFamily->GetFirstMatchingFont(weight, width, slant, &font),
"Could not match font in family.");

View File

@ -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<const char>(&fName, stringTableOffset);
@ -460,20 +462,29 @@ bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) {
const char* nameString = SkTAddOffset<const char>(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;

View File

@ -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;
};

View File

@ -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<uint8_t> 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,
};

View File

@ -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<SkOTTableName> 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

View File

@ -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<SkTypeface> 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<uint8_t> 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<SkFontMgr> fm(SkFontMgr::RefDefault());
int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
for (int i = 0; i < count; ++i) {
SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i));
for (int j = 0; j < set->count(); ++j) {
SkString sname;
SkFontStyle fs;
set->getStyle(j, &fs, &sname);
SkAutoTUnref<SkTypeface> typeface(set->createTypeface(j));
SkString familyName;
typeface->getFamilyName(&familyName);
if (verbose) {
printf("[%s]\n", familyName.c_str());
}
SkAutoTDelete<SkTypeface::LocalizedStrings> 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<uint8_t> 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)