Index: src/ports/SkFontHost_win_dw.cpp |
=================================================================== |
--- src/ports/SkFontHost_win_dw.cpp (revision 8915) |
+++ src/ports/SkFontHost_win_dw.cpp (working copy) |
@@ -41,6 +41,37 @@ |
SkMask::kLCD32_Format == rec.fMaskFormat; |
} |
+/** Prefer to use this type to prevent template proliferation. */ |
+typedef SkAutoSTMalloc<16, WCHAR> SkSMallocWCHAR; |
+ |
+static HRESULT cstring_to_wchar(const char* skname, SkSMallocWCHAR* name) { |
+ int wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, NULL, 0); |
+ if (0 == wlen) { |
+ HRM(HRESULT_FROM_WIN32(GetLastError()), |
+ "Could not get length for wchar to utf-8 conversion."); |
+ } |
+ name->reset(wlen); |
+ wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, name->get(), wlen); |
+ if (0 == wlen) { |
+ HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert wchar to utf-8."); |
+ } |
+ return S_OK; |
+} |
+ |
+static HRESULT wchar_to_skstring(WCHAR* name, SkString* skname) { |
+ int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); |
+ if (0 == len) { |
+ HRM(HRESULT_FROM_WIN32(GetLastError()), |
+ "Could not get length for utf-8 to wchar conversion."); |
+ } |
+ skname->resize(len - 1); |
+ len = WideCharToMultiByte(CP_UTF8, 0, name, -1, skname->writable_str(), len, NULL, NULL); |
+ if (0 == len) { |
+ HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert utf-8 to wchar."); |
+ } |
+ return S_OK; |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
class DWriteOffscreen { |
@@ -669,18 +700,18 @@ |
return false; |
} |
- SkTDArray<wchar_t> dwFaceFontFamilyNameChar(new wchar_t[dwFaceFontFamilyNameLength+1], dwFaceFontFamilyNameLength+1); |
- SkTDArray<wchar_t> dwFaceFontNameChar(new wchar_t[dwFaceFontNameLength+1], dwFaceFontNameLength+1); |
- HRB(dwFaceFontFamilyNames->GetString(0, dwFaceFontFamilyNameChar.begin(), dwFaceFontFamilyNameChar.count())); |
- HRB(dwFaceFontNames->GetString(0, dwFaceFontNameChar.begin(), dwFaceFontNameChar.count())); |
+ SkSMallocWCHAR dwFaceFontFamilyNameChar(dwFaceFontFamilyNameLength+1); |
+ SkSMallocWCHAR dwFaceFontNameChar(dwFaceFontNameLength+1); |
+ HRB(dwFaceFontFamilyNames->GetString(0, dwFaceFontFamilyNameChar.get(), dwFaceFontFamilyNameLength+1)); |
+ HRB(dwFaceFontNames->GetString(0, dwFaceFontNameChar.get(), dwFaceFontNameLength+1)); |
- SkTDArray<wchar_t> dwFontFamilyNameChar(new wchar_t[dwFontFamilyNameLength+1], dwFontFamilyNameLength+1); |
- SkTDArray<wchar_t> dwFontNameChar(new wchar_t[dwFontNameLength+1], dwFontNameLength+1); |
- HRB(dwFontFamilyNames->GetString(0, dwFontFamilyNameChar.begin(), dwFontFamilyNameChar.count())); |
- HRB(dwFontNames->GetString(0, dwFontNameChar.begin(), dwFontNameChar.count())); |
+ SkSMallocWCHAR dwFontFamilyNameChar(dwFontFamilyNameLength+1); |
+ SkSMallocWCHAR dwFontNameChar(dwFontNameLength+1); |
+ HRB(dwFontFamilyNames->GetString(0, dwFontFamilyNameChar.get(), dwFontFamilyNameLength+1)); |
+ HRB(dwFontNames->GetString(0, dwFontNameChar.get(), dwFontNameLength+1)); |
- return wcscmp(dwFaceFontFamilyNameChar.begin(), dwFontFamilyNameChar.begin()) == 0 && |
- wcscmp(dwFaceFontNameChar.begin(), dwFontNameChar.begin()) == 0; |
+ return wcscmp(dwFaceFontFamilyNameChar.get(), dwFontFamilyNameChar.get()) == 0 && |
+ wcscmp(dwFaceFontNameChar.get(), dwFontNameChar.get()) == 0; |
} |
SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFontFace* fontFace, |
@@ -1049,24 +1080,17 @@ |
UINT32 dwFamilyNamesLength; |
HRV(dwFamilyNames->GetStringLength(0, &dwFamilyNamesLength)); |
- SkTDArray<wchar_t> dwFamilyNameChar(new wchar_t[dwFamilyNamesLength+1], dwFamilyNamesLength+1); |
- HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.begin(), dwFamilyNameChar.count())); |
+ SkSMallocWCHAR dwFamilyNameChar(dwFamilyNamesLength+1); |
+ HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.get(), dwFamilyNamesLength+1)); |
- // Convert the family name to utf8. |
- // Get the buffer size needed first. |
- int str_len = WideCharToMultiByte(CP_UTF8, 0, dwFamilyNameChar.begin(), -1, |
- NULL, 0, NULL, NULL); |
- // Allocate a buffer (str_len already has terminating null accounted for). |
- SkTDArray<char> utf8FamilyName(new char[str_len], str_len); |
- // Now actually convert the string. |
- str_len = WideCharToMultiByte(CP_UTF8, 0, dwFamilyNameChar.begin(), -1, |
- utf8FamilyName.begin(), str_len, NULL, NULL); |
+ SkString utf8FamilyName; |
+ HRV(wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName)); |
- desc->setFamilyName(utf8FamilyName.begin()); |
+ desc->setFamilyName(utf8FamilyName.c_str()); |
*isLocalStream = SkToBool(fDWriteFontFileLoader.get()); |
} |
-SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { |
+static SkTypeface* create_from_stream(SkStream* stream) { |
IDWriteFactory* factory; |
HRN(get_dwrite_factory(&factory)); |
@@ -1095,6 +1119,10 @@ |
fontFileLoader.get(), streamFontCollectionLoader.get()); |
} |
+SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { |
+ return create_from_stream(stream); |
+} |
+ |
SkStream* DWriteFontTypeface::onOpenStream(int* ttcIndex) const { |
*ttcIndex = 0; |
@@ -1135,23 +1163,12 @@ |
SkTScopedComPtr<IDWriteFontCollection> sysFontCollection; |
HR(factory->GetSystemFontCollection(&sysFontCollection, FALSE)); |
- // Get the buffer size needed first. |
- int wlen = ::MultiByteToWideChar(CP_UTF8, 0, familyName,-1, NULL, 0); |
- if (0 == wlen) { |
- return HRESULT_FROM_WIN32(GetLastError()); |
- } |
- // Allocate a buffer |
- SkTDArray<wchar_t> wideFamilyName(new wchar_t[wlen], wlen); |
- // Now actually convert the string. |
- wlen = ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, |
- wideFamilyName.begin(), wlen); |
- if (0 == wlen) { |
- return HRESULT_FROM_WIN32(GetLastError()); |
- } |
+ SkSMallocWCHAR wideFamilyName; |
+ HR(cstring_to_wchar(familyName, &wideFamilyName)); |
UINT32 index; |
BOOL exists; |
- HR(sysFontCollection->FindFamilyName(wideFamilyName.begin(), &index, &exists)); |
+ HR(sysFontCollection->FindFamilyName(wideFamilyName.get(), &index, &exists)); |
if (exists) { |
HR(sysFontCollection->GetFontFamily(index, fontFamily)); |
@@ -1389,22 +1406,13 @@ |
UINT32 faceNameLength; |
hr = faceNames->GetStringLength(0, &faceNameLength); |
- size_t size = familyNameLength+1+faceNameLength+1; |
- SkTDArray<wchar_t> wFamilyName(new wchar_t[size], size); |
- hr = familyNames->GetString(0, wFamilyName.begin(), size); |
+ UINT32 size = familyNameLength+1+faceNameLength+1; |
+ SkSMallocWCHAR wFamilyName(size); |
+ hr = familyNames->GetString(0, wFamilyName.get(), size); |
wFamilyName[familyNameLength] = L' '; |
hr = faceNames->GetString(0, &wFamilyName[familyNameLength+1], size - faceNameLength + 1); |
- size_t str_len = WideCharToMultiByte(CP_UTF8, 0, wFamilyName.begin(), -1, NULL, 0, NULL, NULL); |
- if (0 == str_len) { |
- //TODO: error |
- } |
- SkTDArray<char> familyName(new char[str_len], str_len); |
- str_len = WideCharToMultiByte(CP_UTF8, 0, wFamilyName.begin(), -1, familyName.begin(), str_len, NULL, NULL); |
- if (0 == str_len) { |
- //TODO: error |
- } |
- info->fFontName.set(familyName.begin(), str_len); |
+ hr = wchar_to_skstring(wFamilyName.get(), &info->fFontName); |
if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { |
populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode)); |
@@ -1523,7 +1531,202 @@ |
#include "SkFontMgr.h" |
+static void get_locale_string(IDWriteLocalizedStrings* names, const WCHAR* preferedLocale, |
+ SkString* skname) { |
+ UINT32 nameIndex = 0; |
+ if (preferedLocale) { |
+ // Ignore any errors and continue with index 0 if there is a problem. |
+ BOOL nameExists; |
+ names->FindLocaleName(preferedLocale, &nameIndex, &nameExists); |
+ if (!nameExists) { |
+ nameIndex = 0; |
+ } |
+ } |
+ |
+ UINT32 nameLength; |
+ HRVM(names->GetStringLength(nameIndex, &nameLength), "Could not get name length."); |
+ nameLength += 1; |
+ |
+ SkSMallocWCHAR name(nameLength); |
+ HRVM(names->GetString(nameIndex, name.get(), nameLength), "Could not get string."); |
+ |
+ HRV(wchar_to_skstring(name.get(), skname)); |
+} |
+ |
+class SkFontMgr_DirectWrite; |
+ |
+class SkFontStyleSet_DirectWrite : public SkFontStyleSet { |
+public: |
+ SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr, IDWriteFontFamily* fontFamily) |
+ : fFontMgr(SkRef(fontMgr)) |
+ , fFontFamily(SkRefComPtr(fontFamily)) |
+ { } |
+ |
+ virtual int count() SK_OVERRIDE { |
+ return fFontFamily->GetFontCount(); |
+ } |
+ |
+ virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName); |
+ |
+ virtual SkTypeface* createTypeface(int index) SK_OVERRIDE { |
+ SkTScopedComPtr<IDWriteFont> font; |
+ HRNM(fFontFamily->GetFont(index, &font), "Could not get font."); |
+ |
+ SkTScopedComPtr<IDWriteFontFace> fontFace; |
+ HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); |
+ |
+ return SkCreateTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()); |
+ } |
+ |
+ virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { |
+ DWRITE_FONT_STYLE slant; |
+ switch (pattern.slant()) { |
+ case SkFontStyle::kUpright_Slant: |
+ slant = DWRITE_FONT_STYLE_NORMAL; |
+ break; |
+ case SkFontStyle::kItalic_Slant: |
+ slant = DWRITE_FONT_STYLE_ITALIC; |
+ break; |
+ default: |
+ SkASSERT(false); |
+ } |
+ |
+ DWRITE_FONT_WEIGHT weight = (DWRITE_FONT_WEIGHT)pattern.weight(); |
+ DWRITE_FONT_STRETCH width = (DWRITE_FONT_STRETCH)pattern.width(); |
+ |
+ SkTScopedComPtr<IDWriteFont> font; |
+ HRNM(fFontFamily->GetFirstMatchingFont(weight, width, slant, &font), |
+ "Could not match font in family."); |
+ |
+ SkTScopedComPtr<IDWriteFontFace> fontFace; |
+ HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); |
+ |
+ return SkCreateTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()); |
+ } |
+ |
+private: |
+ SkAutoTUnref<const SkFontMgr_DirectWrite> fFontMgr; |
+ SkTScopedComPtr<IDWriteFontFamily> fFontFamily; |
+}; |
+ |
+class SkFontMgr_DirectWrite : public SkFontMgr { |
+public: |
+ /** localeNameLength must include the null terminator. */ |
+ SkFontMgr_DirectWrite(IDWriteFontCollection* fontCollection, |
+ WCHAR* localeName, int localeNameLength) |
+ : fFontCollection(SkRefComPtr(fontCollection)) |
+ , fLocaleName(localeNameLength) |
+ { |
+ memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR)); |
+ } |
+ |
+private: |
+ friend class SkFontStyleSet_DirectWrite; |
+ SkTScopedComPtr<IDWriteFontCollection> fFontCollection; |
+ SkSMallocWCHAR fLocaleName; |
+ |
+protected: |
+ virtual int onCountFamilies() SK_OVERRIDE { |
+ return fFontCollection->GetFontFamilyCount(); |
+ } |
+ virtual void onGetFamilyName(int index, SkString* familyName) SK_OVERRIDE { |
+ SkTScopedComPtr<IDWriteFontFamily> fontFamily; |
+ HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family."); |
+ |
+ SkTScopedComPtr<IDWriteLocalizedStrings> familyNames; |
+ HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names."); |
+ |
+ get_locale_string(familyNames.get(), fLocaleName.get(), familyName); |
+ } |
+ virtual SkFontStyleSet* onCreateStyleSet(int index) SK_OVERRIDE { |
+ SkTScopedComPtr<IDWriteFontFamily> fontFamily; |
+ HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family."); |
+ |
+ return SkNEW_ARGS(SkFontStyleSet_DirectWrite, (this, fontFamily.get())); |
+ } |
+ virtual SkFontStyleSet* onMatchFamily(const char familyName[]) SK_OVERRIDE { |
+ SkSMallocWCHAR dwFamilyName; |
+ HRN(cstring_to_wchar(familyName, &dwFamilyName)); |
+ |
+ UINT32 index; |
+ BOOL exists; |
+ HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), |
+ "Failed while finding family by name."); |
+ if (!exists) { |
+ return NULL; |
+ } |
+ |
+ return this->onCreateStyleSet(index); |
+ } |
+ |
+ virtual SkTypeface* onMatchFamilyStyle(const char familyName[], |
+ const SkFontStyle& fontstyle) SK_OVERRIDE { |
+ SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName)); |
+ return sset->matchStyle(fontstyle); |
+ } |
+ virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, |
+ const SkFontStyle& fontstyle) SK_OVERRIDE { |
+ SkString familyName; |
+ SkFontStyleSet_DirectWrite sset( |
+ this, ((DWriteFontTypeface*)familyMember)->fDWriteFontFamily.get() |
+ ); |
+ return sset.matchStyle(fontstyle); |
+ } |
+ virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) SK_OVERRIDE { |
+ return create_from_stream(stream); |
+ } |
+ virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) SK_OVERRIDE { |
+ SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data))); |
+ return this->createFromStream(stream, ttcIndex); |
+ } |
+ virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) SK_OVERRIDE { |
+ SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path)); |
+ return this->createFromStream(stream, ttcIndex); |
+ } |
+}; |
+ |
+void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) { |
+ SkTScopedComPtr<IDWriteFont> font; |
+ HRVM(fFontFamily->GetFont(index, &font), "Could not get font."); |
+ |
+ SkFontStyle::Slant slant; |
+ switch (font->GetStyle()) { |
+ case DWRITE_FONT_STYLE_NORMAL: |
+ slant = SkFontStyle::kUpright_Slant; |
+ break; |
+ case DWRITE_FONT_STYLE_OBLIQUE: |
+ case DWRITE_FONT_STYLE_ITALIC: |
+ slant = SkFontStyle::kItalic_Slant; |
+ break; |
+ default: |
+ SkASSERT(false); |
+ } |
+ |
+ int weight = font->GetWeight(); |
+ int width = font->GetStretch(); |
+ |
+ *fs = SkFontStyle(weight, width, slant); |
+ |
+ SkTScopedComPtr<IDWriteLocalizedStrings> faceNames; |
+ if (SUCCEEDED(font->GetFaceNames(&faceNames))) { |
+ get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName); |
+ } |
+} |
+ |
SkFontMgr* SkFontMgr::Factory() { |
- // todo |
- return NULL; |
+ IDWriteFactory* factory; |
+ HRNM(get_dwrite_factory(&factory), "Could not get factory."); |
+ |
+ SkTScopedComPtr<IDWriteFontCollection> sysFontCollection; |
+ HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE), |
+ "Could not get system font collection."); |
+ |
+ WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH]; |
+ WCHAR* localeName = NULL; |
+ int localeNameLen = GetUserDefaultLocaleName(localeNameStorage, LOCALE_NAME_MAX_LENGTH); |
+ if (localeNameLen) { |
+ localeName = localeNameStorage; |
+ }; |
+ |
+ return SkNEW_ARGS(SkFontMgr_DirectWrite, (sysFontCollection.get(), localeName, localeNameLen)); |
} |