summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
authorbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-03-21 22:48:32 +0000
committerbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-03-21 22:48:32 +0000
commit694b855f5fe57b3da72b7c2c38c053cd388b00e0 (patch)
tree342d70ec63ee321292d4496ac896b3385584c266 /ports
parentfb704091403ecef9f0db2e4f5319a27ac83225c2 (diff)
downloadsrc-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-xports/SkFontHost_win.cpp18
-rw-r--r--ports/SkFontHost_win_dw.cpp160
-rw-r--r--ports/SkRemotableFontMgr_win_dw.cpp524
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));
+}