diff options
author | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-21 22:48:32 +0000 |
---|---|---|
committer | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-21 22:48:32 +0000 |
commit | 694b855f5fe57b3da72b7c2c38c053cd388b00e0 (patch) | |
tree | 342d70ec63ee321292d4496ac896b3385584c266 /ports | |
parent | fb704091403ecef9f0db2e4f5319a27ac83225c2 (diff) | |
download | src-694b855f5fe57b3da72b7c2c38c053cd388b00e0.tar.gz |
A remotable font management interface and DirectWrite implementation.
The introduced SkRemotableFontMgr is a font management interface designed for simple and fast proxy support. SkFontMgr_Indirect bridges a SkRemotableFontMgr and a local SkFontMgr to present a SkFontMgr interface.
This change is to be followed by https://codereview.chromium.org/132113015/ and https://codereview.chromium.org/206693003 .
R=reed@google.com
Review URL: https://codereview.chromium.org/206683002
git-svn-id: http://skia.googlecode.com/svn/trunk/src@13897 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'ports')
-rwxr-xr-x | ports/SkFontHost_win.cpp | 18 | ||||
-rw-r--r-- | ports/SkFontHost_win_dw.cpp | 160 | ||||
-rw-r--r-- | ports/SkRemotableFontMgr_win_dw.cpp | 524 |
3 files changed, 567 insertions, 135 deletions
diff --git a/ports/SkFontHost_win.cpp b/ports/SkFontHost_win.cpp index 9dc720a6..8ed3b666 100755 --- a/ports/SkFontHost_win.cpp +++ b/ports/SkFontHost_win.cpp @@ -284,15 +284,6 @@ protected: class FontMemResourceTypeface : public LogFontTypeface { public: /** - * Takes ownership of fontMemResource. - */ - FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) : - LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) { - } - - HANDLE fFontMemResource; - - /** * The created FontMemResourceTypeface takes ownership of fontMemResource. */ static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) { @@ -309,6 +300,15 @@ protected: } private: + /** + * Takes ownership of fontMemResource. + */ + FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) : + LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) { + } + + HANDLE fFontMemResource; + typedef LogFontTypeface INHERITED; }; diff --git a/ports/SkFontHost_win_dw.cpp b/ports/SkFontHost_win_dw.cpp index 39b83e9d..462ca1d3 100644 --- a/ports/SkFontHost_win_dw.cpp +++ b/ports/SkFontHost_win_dw.cpp @@ -10,6 +10,7 @@ #include "SkAdvancedTypefaceMetrics.h" #include "SkColorFilter.h" +#include "SkDWrite.h" #include "SkDWriteFontFileStream.h" #include "SkDWriteGeometrySink.h" #include "SkDescriptor.h" @@ -42,77 +43,6 @@ static bool isLCD(const SkScalerContext::Rec& rec) { SkMask::kLCD32_Format == rec.fMaskFormat; } -/** Prefer to use this type to prevent template proliferation. */ -typedef SkAutoSTMalloc<16, WCHAR> SkSMallocWCHAR; - -/** Converts a utf8 string to a WCHAR string. */ -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; -} - -/** Converts a WCHAR string to a utf8 string. */ -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); - - // TODO: remove after https://code.google.com/p/skia/issues/detail?id=1989 is fixed. - // If we resize to 0 then the skname points to gEmptyRec (the unique empty SkString::Rec). - // gEmptyRec is static const and on Windows this means the value is in a read only page. - // Writing to it in the following call to WideCharToMultiByte will cause an access violation. - if (1 == len) { - return S_OK; - } - - 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; -} - -/////////////////////////////////////////////////////////////////////////////// - -static void create_dwrite_factory(IDWriteFactory** factory) { - typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; - DWriteCreateFactoryProc dWriteCreateFactoryProc = reinterpret_cast<DWriteCreateFactoryProc>( - GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory")); - - if (!dWriteCreateFactoryProc) { - HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); - if (!IS_ERROR(hr)) { - hr = ERROR_PROC_NOT_FOUND; - } - HRVM(hr, "Could not get DWriteCreateFactory proc."); - } - - HRVM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast<IUnknown**>(factory)), - "Could not create DirectWrite factory."); -} - -static IDWriteFactory* get_dwrite_factory() { - static IDWriteFactory* gDWriteFactory = NULL; - SK_DECLARE_STATIC_ONCE(once); - SkOnce(&once, create_dwrite_factory, &gDWriteFactory); - - return gDWriteFactory; -} - /////////////////////////////////////////////////////////////////////////////// class StreamFontFileLoader; @@ -215,7 +145,7 @@ private: }; const void* DWriteOffscreen::draw(const SkGlyph& glyph, bool isBW) { - IDWriteFactory* factory = get_dwrite_factory(); + IDWriteFactory* factory = sk_get_dwrite_factory(); SkASSERT(factory != NULL); if (fWidth < glyph.fWidth || fHeight < glyph.fHeight) { @@ -560,16 +490,19 @@ public: fontFileLoader, fontCollectionLoader)); } - ~DWriteFontTypeface() { +protected: + virtual void weak_dispose() const SK_OVERRIDE { if (fDWriteFontCollectionLoader.get() == NULL) return; - IDWriteFactory* factory = get_dwrite_factory(); + IDWriteFactory* factory = sk_get_dwrite_factory(); SkASSERT(factory != NULL); HRV(factory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get())); HRV(factory->UnregisterFontFileLoader(fDWriteFontFileLoader.get())); + + //SkTypefaceCache::Remove(this); + INHERITED::weak_dispose(); } -protected: virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE; virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE; @@ -585,6 +518,9 @@ protected: virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const SK_OVERRIDE; + +private: + typedef SkTypeface INHERITED; }; class SkScalerContext_DW : public SkScalerContext { @@ -816,7 +752,7 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { run.isSideways = FALSE; run.glyphOffsets = &offset; - IDWriteFactory* factory = get_dwrite_factory(); + IDWriteFactory* factory = sk_get_dwrite_factory(); SkASSERT(factory != NULL); const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; @@ -1067,7 +1003,7 @@ void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.get(), dwFamilyNamesLength+1)); SkString utf8FamilyName; - HRV(wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName)); + HRV(sk_wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName)); desc->setFamilyName(utf8FamilyName.c_str()); *isLocalStream = SkToBool(fDWriteFontFileLoader.get()); @@ -1177,7 +1113,7 @@ public: SkSMallocWCHAR wString(stringLength); HRBM(fStrings->GetString(fIndex, wString.get(), stringLength), "Could not get string."); - HRB(wchar_to_skstring(wString.get(), &localizedString->fString)); + HRB(sk_wchar_to_skstring(wString.get(), &localizedString->fString)); // Locale UINT32 localeLength; @@ -1187,7 +1123,7 @@ public: SkSMallocWCHAR wLocale(localeLength); HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLength), "Could not get locale."); - HRB(wchar_to_skstring(wLocale.get(), &localizedString->fLanguage)); + HRB(sk_wchar_to_skstring(wLocale.get(), &localizedString->fLanguage)); ++fIndex; return true; @@ -1292,7 +1228,7 @@ private: }; static SkTypeface* create_from_stream(SkStream* stream, int ttcIndex) { - IDWriteFactory* factory = get_dwrite_factory(); + IDWriteFactory* factory = sk_get_dwrite_factory(); if (NULL == factory) { return NULL; } @@ -1531,7 +1467,7 @@ SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics( wFamilyName[familyNameLength] = L' '; hr = faceNames->GetString(0, &wFamilyName[familyNameLength+1], size - faceNameLength + 1); - hr = wchar_to_skstring(wFamilyName.get(), &info->fFontName); + hr = sk_wchar_to_skstring(wFamilyName.get(), &info->fFontName); if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode)); @@ -1648,28 +1584,6 @@ SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics( /////////////////////////////////////////////////////////////////////////////// -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)); -} - SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont( IDWriteFontFace* fontFace, IDWriteFont* font, @@ -1698,7 +1612,7 @@ void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) con SkTScopedComPtr<IDWriteLocalizedStrings> familyNames; HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names."); - get_locale_string(familyNames.get(), fLocaleName.get(), familyName); + sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName); } SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const { @@ -1710,7 +1624,7 @@ SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const { SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const { SkSMallocWCHAR dwFamilyName; - HRN(cstring_to_wchar(familyName, &dwFamilyName)); + HRN(sk_cstring_to_wchar(familyName, &dwFamilyName)); UINT32 index; BOOL exists; @@ -1785,7 +1699,7 @@ SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[ SkTScopedComPtr<IDWriteFontFamily> fontFamily; if (familyName) { SkSMallocWCHAR wideFamilyName; - if (SUCCEEDED(cstring_to_wchar(familyName, &wideFamilyName))) { + if (SUCCEEDED(sk_cstring_to_wchar(familyName, &wideFamilyName))) { this->getByFamilyName(wideFamilyName, &fontFamily); } } @@ -1855,7 +1769,7 @@ void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* if (styleName) { SkTScopedComPtr<IDWriteLocalizedStrings> faceNames; if (SUCCEEDED(font->GetFaceNames(&faceNames))) { - get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName); + sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName); } } } @@ -1879,7 +1793,7 @@ SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) { 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."); + "Could not match font in family."); SkTScopedComPtr<IDWriteFontFace> fontFace; HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); @@ -1890,23 +1804,8 @@ SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) { /////////////////////////////////////////////////////////////////////////////// -typedef decltype(GetUserDefaultLocaleName)* GetUserDefaultLocaleNameProc; -static HRESULT GetGetUserDefaultLocaleNameProc(GetUserDefaultLocaleNameProc* proc) { - *proc = reinterpret_cast<GetUserDefaultLocaleNameProc>( - GetProcAddress(LoadLibraryW(L"Kernel32.dll"), "GetUserDefaultLocaleName") - ); - if (!*proc) { - HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); - if (!IS_ERROR(hr)) { - hr = ERROR_PROC_NOT_FOUND; - } - return hr; - } - return S_OK; -} - SkFontMgr* SkFontMgr_New_DirectWrite() { - IDWriteFactory* factory = get_dwrite_factory(); + IDWriteFactory* factory = sk_get_dwrite_factory(); if (NULL == factory) { return NULL; } @@ -1920,8 +1819,8 @@ SkFontMgr* SkFontMgr_New_DirectWrite() { int localeNameLen = 0; // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP. - GetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL; - HRESULT hr = GetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); + SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL; + HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); if (NULL == getUserDefaultLocaleNameProc) { SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); } else { @@ -1933,3 +1832,12 @@ SkFontMgr* SkFontMgr_New_DirectWrite() { return SkNEW_ARGS(SkFontMgr_DirectWrite, (sysFontCollection.get(), localeName, localeNameLen)); } + +#include "SkFontMgr_indirect.h" +SkFontMgr* SkFontMgr_New_DirectWriteRenderer(SkRemotableFontMgr* proxy) { + SkAutoTUnref<SkFontMgr> impl(SkFontMgr_New_DirectWrite()); + if (impl.get() == NULL) { + return NULL; + } + return SkNEW_ARGS(SkFontMgr_Indirect, (impl.get(), proxy)); +} diff --git a/ports/SkRemotableFontMgr_win_dw.cpp b/ports/SkRemotableFontMgr_win_dw.cpp new file mode 100644 index 00000000..50fc5d4a --- /dev/null +++ b/ports/SkRemotableFontMgr_win_dw.cpp @@ -0,0 +1,524 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkDataTable.h" +#include "SkDWrite.h" +#include "SkDWriteFontFileStream.h" +#include "SkHRESULT.h" +#include "SkRemotableFontMgr.h" +#include "SkStream.h" +#include "SkString.h" +#include "SkTArray.h" +#include "SkThread.h" +#include "SkTScopedComPtr.h" +#include "SkTypeface_win.h" +#include "SkTypes.h" +#include "SkUtils.h" + +#include <dwrite.h> + +struct DWriteStyle { + explicit DWriteStyle(const SkFontStyle& pattern) { + switch (pattern.slant()) { + case SkFontStyle::kUpright_Slant: + fSlant = DWRITE_FONT_STYLE_NORMAL; + break; + case SkFontStyle::kItalic_Slant: + fSlant = DWRITE_FONT_STYLE_ITALIC; + break; + default: + SkASSERT(false); + } + + fWeight = (DWRITE_FONT_WEIGHT)pattern.weight(); + fWidth = (DWRITE_FONT_STRETCH)pattern.width(); + } + DWRITE_FONT_STYLE fSlant; + DWRITE_FONT_WEIGHT fWeight; + DWRITE_FONT_STRETCH fWidth; +}; + +class SK_API SkRemotableFontMgr_DirectWrite : public SkRemotableFontMgr { +private: + struct DataId { + IUnknown* fLoader; // In COM only IUnknown pointers may be safely used for identity. + void* fKey; + UINT32 fKeySize; + + DataId() { } + + // This is actually a move!!! + explicit DataId(DataId& that) + : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize) + { + that.fLoader = NULL; + that.fKey = NULL; + SkDEBUGCODE(that.fKeySize = 0xFFFFFFFF;) + } + + ~DataId() { + if (fLoader) { + fLoader->Release(); + } + sk_free(fKey); + } + }; + + mutable SkTArray<DataId> fDataIdCache; + mutable SkMutex fDataIdCacheMutex; + + int FindOrAdd(IDWriteFontFileLoader* fontFileLoader, + const void* refKey, UINT32 refKeySize) const + { + SkTScopedComPtr<IUnknown> fontFileLoaderId; + HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId), + "Failed to re-convert to IDWriteFontFileLoader.", + SkFontIdentity::kInvalidDataId); + + SkAutoMutexAcquire ama(fDataIdCacheMutex); + int count = fDataIdCache.count(); + int i; + for (i = 0; i < count; ++i) { + const DataId& current = fDataIdCache[i]; + if (fontFileLoaderId.get() == current.fLoader && + refKeySize == current.fKeySize && + 0 == memcmp(refKey, current.fKey, refKeySize)) + { + return i; + } + } + DataId& added = fDataIdCache.push_back(); + added.fLoader = fontFileLoaderId.release(); // Ref is passed. + added.fKey = sk_malloc_throw(refKeySize); + memcpy(added.fKey, refKey, refKeySize); + added.fKeySize = refKeySize; + + return i; + } + +public: + SK_DECLARE_INST_COUNT(SkRemotableFontMgr_DirectWrite) + + /** localeNameLength must include the null terminator. */ + SkRemotableFontMgr_DirectWrite(IDWriteFontCollection* fontCollection, + WCHAR* localeName, int localeNameLength) + : fFontCollection(SkRefComPtr(fontCollection)) + , fLocaleName(localeNameLength) + { + memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR)); + } + + virtual SkDataTable* getFamilyNames() const SK_OVERRIDE { + int count = fFontCollection->GetFontFamilyCount(); + + SkDataTableBuilder names(1024); + for (int index = 0; index < count; ++index) { + SkTScopedComPtr<IDWriteFontFamily> fontFamily; + HRNM(fFontCollection->GetFontFamily(index, &fontFamily), + "Could not get requested family."); + + SkTScopedComPtr<IDWriteLocalizedStrings> familyNames; + HRNM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names."); + + SkString familyName; + sk_get_locale_string(familyNames.get(), fLocaleName.get(), &familyName); + + names.appendString(familyName); + } + return names.detachDataTable(); + } + + HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const { + SkTScopedComPtr<IDWriteFontFace> fontFace; + HRM(font->CreateFontFace(&fontFace), "Could not create font face."); + + UINT32 numFiles; + HR(fontFace->GetFiles(&numFiles, NULL)); + if (numFiles > 1) { + return E_FAIL; + } + + // data id + SkTScopedComPtr<IDWriteFontFile> fontFile; + HR(fontFace->GetFiles(&numFiles, &fontFile)); + + SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader; + HR(fontFile->GetLoader(&fontFileLoader)); + + const void* refKey; + UINT32 refKeySize; + HR(fontFile->GetReferenceKey(&refKey, &refKeySize)); + + fontId->fDataId = FindOrAdd(fontFileLoader.get(), refKey, refKeySize); + + // index + fontId->fTtcIndex = fontFace->GetIndex(); + + // style + 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(); + + fontId->fFontStyle = SkFontStyle(weight, width, slant); + return S_OK; + } + + virtual SkRemotableFontIdentitySet* getIndex(int familyIndex) const SK_OVERRIDE { + SkTScopedComPtr<IDWriteFontFamily> fontFamily; + HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily), + "Could not get requested family."); + + int count = fontFamily->GetFontCount(); + SkFontIdentity* fontIds; + SkAutoTUnref<SkRemotableFontIdentitySet> fontIdSet( + new SkRemotableFontIdentitySet(count, &fontIds)); + for (int fontIndex = 0; fontIndex < count; ++fontIndex) { + SkTScopedComPtr<IDWriteFont> font; + HRNM(fontFamily->GetFont(fontIndex, &font), "Could not get font."); + + HRN(FontToIdentity(font.get(), &fontIds[fontIndex])); + } + return fontIdSet.detach(); + } + + virtual SkFontIdentity matchIndexStyle(int familyIndex, + const SkFontStyle& pattern) const SK_OVERRIDE + { + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; + + SkTScopedComPtr<IDWriteFontFamily> fontFamily; + HR_GENERAL(fFontCollection->GetFontFamily(familyIndex, &fontFamily), + "Could not get requested family.", + identity); + + const DWriteStyle dwStyle(pattern); + SkTScopedComPtr<IDWriteFont> font; + HR_GENERAL(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, + dwStyle.fSlant, &font), + "Could not match font in family.", + identity); + + HR_GENERAL(FontToIdentity(font.get(), &identity), NULL, identity); + + return identity; + } + + static HRESULT getDefaultFontFamilyName(SkSMallocWCHAR* name) { + NONCLIENTMETRICSW metrics; + metrics.cbSize = sizeof(metrics); + if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, + sizeof(metrics), + &metrics, + 0)) { + return E_UNEXPECTED; + } + + size_t len = wcsnlen_s(metrics.lfMessageFont.lfFaceName, LF_FACESIZE) + 1; + if (0 != wcsncpy_s(name->reset(len), len, metrics.lfMessageFont.lfFaceName, _TRUNCATE)) { + return E_UNEXPECTED; + } + + return S_OK; + } + + virtual SkRemotableFontIdentitySet* matchName(const char familyName[]) const SK_OVERRIDE { + SkSMallocWCHAR dwFamilyName; + if (NULL == familyName) { + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), + NULL, SkRemotableFontIdentitySet::NewEmpty()); + } else { + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), + NULL, SkRemotableFontIdentitySet::NewEmpty()); + } + + UINT32 index; + BOOL exists; + HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), + "Failed while finding family by name.", + SkRemotableFontIdentitySet::NewEmpty()); + if (!exists) { + return SkRemotableFontIdentitySet::NewEmpty(); + } + + return this->getIndex(index); + } + + virtual SkFontIdentity matchNameStyle(const char familyName[], + const SkFontStyle& style) const SK_OVERRIDE + { + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; + + SkSMallocWCHAR dwFamilyName; + if (NULL == familyName) { + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity); + } else { + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity); + } + + UINT32 index; + BOOL exists; + HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), + "Failed while finding family by name.", + identity); + if (!exists) { + return identity; + } + + return this->matchIndexStyle(index, style); + } + + class FontFallbackRenderer : public IDWriteTextRenderer { + public: + FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite* outer, UINT32 character) + : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character) { + fIdentity.fDataId = SkFontIdentity::kInvalidDataId; + } + + // IDWriteTextRenderer methods + virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun( + void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + DWRITE_GLYPH_RUN const* glyphRun, + DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, + IUnknown* clientDrawingEffect) SK_OVERRIDE + { + SkTScopedComPtr<IDWriteFont> font; + HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font), + "Could not get font from font face."); + + // It is possible that the font passed does not actually have the requested character, + // due to no font being found and getting the fallback font. + // Check that the font actually contains the requested character. + BOOL exists; + HRM(font->HasCharacter(fCharacter, &exists), "Could not find character."); + + if (exists) { + HR(fOuter->FontToIdentity(font.get(), &fIdentity)); + } + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE DrawUnderline( + void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_UNDERLINE const* underline, + IUnknown* clientDrawingEffect) SK_OVERRIDE + { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough( + void* clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_STRIKETHROUGH const* strikethrough, + IUnknown* clientDrawingEffect) SK_OVERRIDE + { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE DrawInlineObject( + void* clientDrawingContext, + FLOAT originX, + FLOAT originY, + IDWriteInlineObject* inlineObject, + BOOL isSideways, + BOOL isRightToLeft, + IUnknown* clientDrawingEffect) SK_OVERRIDE + { return E_NOTIMPL; } + + // IDWritePixelSnapping methods + virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled( + void* clientDrawingContext, + BOOL* isDisabled) SK_OVERRIDE + { + *isDisabled = FALSE; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform( + void* clientDrawingContext, + DWRITE_MATRIX* transform) SK_OVERRIDE + { + const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; + *transform = ident; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip( + void* clientDrawingContext, + FLOAT* pixelsPerDip) SK_OVERRIDE + { + *pixelsPerDip = 1.0f; + return S_OK; + } + + // IUnknown methods + virtual ULONG STDMETHODCALLTYPE AddRef() SK_OVERRIDE { + return InterlockedIncrement(&fRefCount); + } + + virtual ULONG STDMETHODCALLTYPE Release() SK_OVERRIDE { + ULONG newCount = InterlockedDecrement(&fRefCount); + if (0 == newCount) { + delete this; + } + return newCount; + } + + virtual HRESULT STDMETHODCALLTYPE QueryInterface( + IID const& riid, void** ppvObject) SK_OVERRIDE + { + if (__uuidof(IUnknown) == riid || + __uuidof(IDWritePixelSnapping) == riid || + __uuidof(IDWriteTextRenderer) == riid) + { + *ppvObject = this; + this->AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_FAIL; + } + + const SkFontIdentity FallbackIdentity() { return fIdentity; } + + protected: + ULONG fRefCount; + SkAutoTUnref<const SkRemotableFontMgr_DirectWrite> fOuter; + UINT32 fCharacter; + SkFontIdentity fIdentity; + }; + + virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], + const SkFontStyle& pattern, + const char bpc47[], + SkUnichar character) const SK_OVERRIDE + { + SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; + + IDWriteFactory* dwFactory = sk_get_dwrite_factory(); + if (NULL == dwFactory) { + return identity; + } + + // TODO: use IDWriteFactory2::GetSystemFontFallback when available. + + const DWriteStyle dwStyle(pattern); + + SkSMallocWCHAR dwFamilyName; + if (NULL == familyName) { + HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity); + } else { + HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity); + } + + const SkSMallocWCHAR* dwBpc47; + SkSMallocWCHAR dwBpc47Local; + if (NULL == bpc47) { + dwBpc47 = &fLocaleName; + } else { + HR_GENERAL(sk_cstring_to_wchar(bpc47, &dwBpc47Local), NULL, identity); + dwBpc47 = &dwBpc47Local; + } + + SkTScopedComPtr<IDWriteTextFormat> fallbackFormat; + HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName, + fFontCollection.get(), + dwStyle.fWeight, + dwStyle.fSlant, + dwStyle.fWidth, + 72.0f, + *dwBpc47, + &fallbackFormat), + "Could not create text format.", + identity); + + WCHAR str[16]; + UINT32 strLen = SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str)); + SkTScopedComPtr<IDWriteTextLayout> fallbackLayout; + HR_GENERAL(dwFactory->CreateTextLayout(str, strLen, fallbackFormat.get(), + 200.0f, 200.0f, + &fallbackLayout), + "Could not create text layout.", + identity); + + SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer( + new FontFallbackRenderer(this, character)); + + HR_GENERAL(fallbackLayout->Draw(NULL, fontFallbackRenderer.get(), 50.0f, 50.0f), + "Could not draw layout with renderer.", + identity); + + return fontFallbackRenderer->FallbackIdentity(); + } + + virtual SkStreamAsset* getData(int dataId) const SK_OVERRIDE { + SkAutoMutexAcquire ama(fDataIdCacheMutex); + if (dataId >= fDataIdCache.count()) { + return NULL; + } + const DataId& id = fDataIdCache[dataId]; + + SkTScopedComPtr<IDWriteFontFileLoader> loader; + HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFileLoader failed"); + + SkTScopedComPtr<IDWriteFontFileStream> fontFileStream; + HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream), + "Could not create font file stream."); + + return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get())); + } + +private: + SkTScopedComPtr<IDWriteFontCollection> fFontCollection; + SkSMallocWCHAR fLocaleName; + + typedef SkRemotableFontMgr INHERITED; +}; + +SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() { + IDWriteFactory* factory = sk_get_dwrite_factory(); + if (NULL == factory) { + return NULL; + } + + 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 = 0; + + // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP. + SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL; + HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); + if (NULL == getUserDefaultLocaleNameProc) { + SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); + } else { + localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH); + if (localeNameLen) { + localeName = localeNameStorage; + }; + } + + return SkNEW_ARGS(SkRemotableFontMgr_DirectWrite, (sysFontCollection.get(), + localeName, localeNameLen)); +} |