| Index: src/ports/SkFontMgr_win_dw.cpp
|
| diff --git a/src/ports/SkFontMgr_win_dw.cpp b/src/ports/SkFontMgr_win_dw.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fe82258c6803e9aaaeb54fad4f9e346fa4a6895e
|
| --- /dev/null
|
| +++ b/src/ports/SkFontMgr_win_dw.cpp
|
| @@ -0,0 +1,774 @@
|
| +/*
|
| + * 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 "SkDWrite.h"
|
| +#include "SkDWriteFontFileStream.h"
|
| +#include "SkFontMgr.h"
|
| +#include "SkHRESULT.h"
|
| +#include "SkStream.h"
|
| +#include "SkTScopedComPtr.h"
|
| +#include "SkThread.h"
|
| +#include "SkTypeface.h"
|
| +#include "SkTypefaceCache.h"
|
| +#include "SkTypeface_win_dw.h"
|
| +#include "SkTypes.h"
|
| +
|
| +#include <dwrite.h>
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +class StreamFontFileLoader : public IDWriteFontFileLoader {
|
| +public:
|
| + // IUnknown methods
|
| + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
|
| + virtual ULONG STDMETHODCALLTYPE AddRef();
|
| + virtual ULONG STDMETHODCALLTYPE Release();
|
| +
|
| + // IDWriteFontFileLoader methods
|
| + virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
|
| + void const* fontFileReferenceKey,
|
| + UINT32 fontFileReferenceKeySize,
|
| + IDWriteFontFileStream** fontFileStream);
|
| +
|
| + static HRESULT Create(SkStream* stream, StreamFontFileLoader** streamFontFileLoader) {
|
| + *streamFontFileLoader = new StreamFontFileLoader(stream);
|
| + if (NULL == streamFontFileLoader) {
|
| + return E_OUTOFMEMORY;
|
| + }
|
| + return S_OK;
|
| + }
|
| +
|
| + SkAutoTUnref<SkStream> fStream;
|
| +
|
| +private:
|
| + StreamFontFileLoader(SkStream* stream) : fRefCount(1), fStream(SkRef(stream)) { }
|
| +
|
| + ULONG fRefCount;
|
| +};
|
| +
|
| +HRESULT StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
|
| + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
|
| + *ppvObject = this;
|
| + AddRef();
|
| + return S_OK;
|
| + } else {
|
| + *ppvObject = NULL;
|
| + return E_NOINTERFACE;
|
| + }
|
| +}
|
| +
|
| +ULONG StreamFontFileLoader::AddRef() {
|
| + return InterlockedIncrement(&fRefCount);
|
| +}
|
| +
|
| +ULONG StreamFontFileLoader::Release() {
|
| + ULONG newCount = InterlockedDecrement(&fRefCount);
|
| + if (0 == newCount) {
|
| + delete this;
|
| + }
|
| + return newCount;
|
| +}
|
| +
|
| +HRESULT StreamFontFileLoader::CreateStreamFromKey(
|
| + void const* fontFileReferenceKey,
|
| + UINT32 fontFileReferenceKeySize,
|
| + IDWriteFontFileStream** fontFileStream)
|
| +{
|
| + SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
|
| + HR(SkDWriteFontFileStreamWrapper::Create(fStream, &stream));
|
| + *fontFileStream = stream.release();
|
| + return S_OK;
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
|
| +public:
|
| + // IUnknown methods
|
| + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
|
| + virtual ULONG STDMETHODCALLTYPE AddRef();
|
| + virtual ULONG STDMETHODCALLTYPE Release();
|
| +
|
| + // IDWriteFontFileEnumerator methods
|
| + virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile);
|
| + virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile);
|
| +
|
| + static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
|
| + StreamFontFileEnumerator** streamFontFileEnumerator) {
|
| + *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
|
| + if (NULL == streamFontFileEnumerator) {
|
| + return E_OUTOFMEMORY;
|
| + }
|
| + return S_OK;
|
| + }
|
| +private:
|
| + StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
|
| + ULONG fRefCount;
|
| +
|
| + SkTScopedComPtr<IDWriteFactory> fFactory;
|
| + SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
|
| + SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
|
| + bool fHasNext;
|
| +};
|
| +
|
| +StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
|
| + IDWriteFontFileLoader* fontFileLoader)
|
| + : fRefCount(1)
|
| + , fFactory(SkRefComPtr(factory))
|
| + , fCurrentFile()
|
| + , fFontFileLoader(SkRefComPtr(fontFileLoader))
|
| + , fHasNext(true)
|
| +{ }
|
| +
|
| +HRESULT StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
|
| + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) {
|
| + *ppvObject = this;
|
| + AddRef();
|
| + return S_OK;
|
| + } else {
|
| + *ppvObject = NULL;
|
| + return E_NOINTERFACE;
|
| + }
|
| +}
|
| +
|
| +ULONG StreamFontFileEnumerator::AddRef() {
|
| + return InterlockedIncrement(&fRefCount);
|
| +}
|
| +
|
| +ULONG StreamFontFileEnumerator::Release() {
|
| + ULONG newCount = InterlockedDecrement(&fRefCount);
|
| + if (0 == newCount) {
|
| + delete this;
|
| + }
|
| + return newCount;
|
| +}
|
| +
|
| +HRESULT StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
|
| + *hasCurrentFile = FALSE;
|
| +
|
| + if (!fHasNext) {
|
| + return S_OK;
|
| + }
|
| + fHasNext = false;
|
| +
|
| + UINT32 dummy = 0;
|
| + HR(fFactory->CreateCustomFontFileReference(
|
| + &dummy, //cannot be NULL
|
| + sizeof(dummy), //even if this is 0
|
| + fFontFileLoader.get(),
|
| + &fCurrentFile));
|
| +
|
| + *hasCurrentFile = TRUE;
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) {
|
| + if (fCurrentFile.get() == NULL) {
|
| + *fontFile = NULL;
|
| + return E_FAIL;
|
| + }
|
| +
|
| + *fontFile = SkRefComPtr(fCurrentFile.get());
|
| + return S_OK;
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
|
| +public:
|
| + // IUnknown methods
|
| + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
|
| + virtual ULONG STDMETHODCALLTYPE AddRef();
|
| + virtual ULONG STDMETHODCALLTYPE Release();
|
| +
|
| + // IDWriteFontCollectionLoader methods
|
| + virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
|
| + IDWriteFactory* factory,
|
| + void const* collectionKey,
|
| + UINT32 collectionKeySize,
|
| + IDWriteFontFileEnumerator** fontFileEnumerator);
|
| +
|
| + static HRESULT Create(IDWriteFontFileLoader* fontFileLoader,
|
| + StreamFontCollectionLoader** streamFontCollectionLoader) {
|
| + *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader);
|
| + if (NULL == streamFontCollectionLoader) {
|
| + return E_OUTOFMEMORY;
|
| + }
|
| + return S_OK;
|
| + }
|
| +private:
|
| + StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader)
|
| + : fRefCount(1)
|
| + , fFontFileLoader(SkRefComPtr(fontFileLoader))
|
| + { }
|
| +
|
| + ULONG fRefCount;
|
| + SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
|
| +};
|
| +
|
| +HRESULT StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
|
| + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
|
| + *ppvObject = this;
|
| + AddRef();
|
| + return S_OK;
|
| + } else {
|
| + *ppvObject = NULL;
|
| + return E_NOINTERFACE;
|
| + }
|
| +}
|
| +
|
| +ULONG StreamFontCollectionLoader::AddRef() {
|
| + return InterlockedIncrement(&fRefCount);
|
| +}
|
| +
|
| +ULONG StreamFontCollectionLoader::Release() {
|
| + ULONG newCount = InterlockedDecrement(&fRefCount);
|
| + if (0 == newCount) {
|
| + delete this;
|
| + }
|
| + return newCount;
|
| +}
|
| +
|
| +HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey(
|
| + IDWriteFactory* factory,
|
| + void const* collectionKey,
|
| + UINT32 collectionKeySize,
|
| + IDWriteFontFileEnumerator** fontFileEnumerator)
|
| +{
|
| + SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
|
| + HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
|
| + *fontFileEnumerator = enumerator.release();
|
| + return S_OK;
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +class SkFontMgr_DirectWrite : public SkFontMgr {
|
| +public:
|
| + /** localeNameLength must include the null terminator. */
|
| + SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection,
|
| + WCHAR* localeName, int localeNameLength)
|
| + : fFactory(SkRefComPtr(factory))
|
| + , fFontCollection(SkRefComPtr(fontCollection))
|
| + , fLocaleName(localeNameLength)
|
| + {
|
| + memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
|
| + }
|
| +
|
| + /** Creates a typeface using a typeface cache. */
|
| + SkTypeface* createTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
|
| + IDWriteFont* font,
|
| + IDWriteFontFamily* fontFamily) const;
|
| +
|
| +protected:
|
| + virtual int onCountFamilies() const SK_OVERRIDE;
|
| + virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE;
|
| + virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE;
|
| + virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE;
|
| + virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
|
| + const SkFontStyle& fontstyle) const SK_OVERRIDE;
|
| + virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
|
| + const SkFontStyle& fontstyle) const SK_OVERRIDE;
|
| + virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE;
|
| + virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE;
|
| + virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE;
|
| + virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
|
| + unsigned styleBits) const SK_OVERRIDE;
|
| +
|
| +private:
|
| + HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
|
| + HRESULT getDefaultFontFamily(IDWriteFontFamily** fontFamily) const;
|
| +
|
| + void Add(SkTypeface* face, SkTypeface::Style requestedStyle, bool strong) const {
|
| + SkAutoMutexAcquire ama(fTFCacheMutex);
|
| + fTFCache.add(face, requestedStyle, strong);
|
| + }
|
| +
|
| + SkTypeface* FindByProcAndRef(SkTypefaceCache::FindProc proc, void* ctx) const {
|
| + SkAutoMutexAcquire ama(fTFCacheMutex);
|
| + SkTypeface* typeface = fTFCache.findByProcAndRef(proc, ctx);
|
| + return typeface;
|
| + }
|
| +
|
| + SkTScopedComPtr<IDWriteFactory> fFactory;
|
| + SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
|
| + SkSMallocWCHAR fLocaleName;
|
| + mutable SkMutex fTFCacheMutex;
|
| + mutable SkTypefaceCache fTFCache;
|
| +
|
| + friend class SkFontStyleSet_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;
|
| + virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE;
|
| + virtual SkTypeface* createTypeface(int index) SK_OVERRIDE;
|
| + virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE;
|
| +
|
| +private:
|
| + SkAutoTUnref<const SkFontMgr_DirectWrite> fFontMgr;
|
| + SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
|
| +};
|
| +
|
| +static bool are_same(IUnknown* a, IUnknown* b) {
|
| + SkTScopedComPtr<IUnknown> iunkA;
|
| + if (FAILED(a->QueryInterface(&iunkA))) {
|
| + return false;
|
| + }
|
| +
|
| + SkTScopedComPtr<IUnknown> iunkB;
|
| + if (FAILED(b->QueryInterface(&iunkB))) {
|
| + return false;
|
| + }
|
| +
|
| + return iunkA.get() == iunkB.get();
|
| +}
|
| +
|
| +static bool FindByDWriteFont(SkTypeface* face, SkTypeface::Style, void* ctx) {
|
| + //Check to see if the two fonts are identical.
|
| + DWriteFontTypeface* dwFace = reinterpret_cast<DWriteFontTypeface*>(face);
|
| + IDWriteFont* dwFont = reinterpret_cast<IDWriteFont*>(ctx);
|
| + if (are_same(dwFace->fDWriteFont.get(), dwFont)) {
|
| + return true;
|
| + }
|
| +
|
| + //Check if the two fonts share the same loader and have the same key.
|
| + SkTScopedComPtr<IDWriteFontFace> dwFaceFontFace;
|
| + SkTScopedComPtr<IDWriteFontFace> dwFontFace;
|
| + HRB(dwFace->fDWriteFont->CreateFontFace(&dwFaceFontFace));
|
| + HRB(dwFont->CreateFontFace(&dwFontFace));
|
| + if (are_same(dwFaceFontFace.get(), dwFontFace.get())) {
|
| + return true;
|
| + }
|
| +
|
| + UINT32 dwFaceNumFiles;
|
| + UINT32 dwNumFiles;
|
| + HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, NULL));
|
| + HRB(dwFontFace->GetFiles(&dwNumFiles, NULL));
|
| + if (dwFaceNumFiles != dwNumFiles) {
|
| + return false;
|
| + }
|
| +
|
| + SkTScopedComPtr<IDWriteFontFile> dwFaceFontFile;
|
| + SkTScopedComPtr<IDWriteFontFile> dwFontFile;
|
| + HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, &dwFaceFontFile));
|
| + HRB(dwFontFace->GetFiles(&dwNumFiles, &dwFontFile));
|
| +
|
| + //for (each file) { //we currently only admit fonts from one file.
|
| + SkTScopedComPtr<IDWriteFontFileLoader> dwFaceFontFileLoader;
|
| + SkTScopedComPtr<IDWriteFontFileLoader> dwFontFileLoader;
|
| + HRB(dwFaceFontFile->GetLoader(&dwFaceFontFileLoader));
|
| + HRB(dwFontFile->GetLoader(&dwFontFileLoader));
|
| + if (!are_same(dwFaceFontFileLoader.get(), dwFontFileLoader.get())) {
|
| + return false;
|
| + }
|
| + //}
|
| +
|
| + const void* dwFaceFontRefKey;
|
| + UINT32 dwFaceFontRefKeySize;
|
| + const void* dwFontRefKey;
|
| + UINT32 dwFontRefKeySize;
|
| + HRB(dwFaceFontFile->GetReferenceKey(&dwFaceFontRefKey, &dwFaceFontRefKeySize));
|
| + HRB(dwFontFile->GetReferenceKey(&dwFontRefKey, &dwFontRefKeySize));
|
| + if (dwFaceFontRefKeySize != dwFontRefKeySize) {
|
| + return false;
|
| + }
|
| + if (0 != memcmp(dwFaceFontRefKey, dwFontRefKey, dwFontRefKeySize)) {
|
| + return false;
|
| + }
|
| +
|
| + //TODO: better means than comparing name strings?
|
| + //NOTE: .tfc and fake bold/italic will end up here.
|
| + SkTScopedComPtr<IDWriteFontFamily> dwFaceFontFamily;
|
| + SkTScopedComPtr<IDWriteFontFamily> dwFontFamily;
|
| + HRB(dwFace->fDWriteFont->GetFontFamily(&dwFaceFontFamily));
|
| + HRB(dwFont->GetFontFamily(&dwFontFamily));
|
| +
|
| + SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontFamilyNames;
|
| + SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontNames;
|
| + HRB(dwFaceFontFamily->GetFamilyNames(&dwFaceFontFamilyNames));
|
| + HRB(dwFace->fDWriteFont->GetFaceNames(&dwFaceFontNames));
|
| +
|
| + SkTScopedComPtr<IDWriteLocalizedStrings> dwFontFamilyNames;
|
| + SkTScopedComPtr<IDWriteLocalizedStrings> dwFontNames;
|
| + HRB(dwFontFamily->GetFamilyNames(&dwFontFamilyNames));
|
| + HRB(dwFont->GetFaceNames(&dwFontNames));
|
| +
|
| + UINT32 dwFaceFontFamilyNameLength;
|
| + UINT32 dwFaceFontNameLength;
|
| + HRB(dwFaceFontFamilyNames->GetStringLength(0, &dwFaceFontFamilyNameLength));
|
| + HRB(dwFaceFontNames->GetStringLength(0, &dwFaceFontNameLength));
|
| +
|
| + UINT32 dwFontFamilyNameLength;
|
| + UINT32 dwFontNameLength;
|
| + HRB(dwFontFamilyNames->GetStringLength(0, &dwFontFamilyNameLength));
|
| + HRB(dwFontNames->GetStringLength(0, &dwFontNameLength));
|
| +
|
| + if (dwFaceFontFamilyNameLength != dwFontFamilyNameLength ||
|
| + dwFaceFontNameLength != dwFontNameLength)
|
| + {
|
| + return false;
|
| + }
|
| +
|
| + SkSMallocWCHAR dwFaceFontFamilyNameChar(dwFaceFontFamilyNameLength+1);
|
| + SkSMallocWCHAR dwFaceFontNameChar(dwFaceFontNameLength+1);
|
| + HRB(dwFaceFontFamilyNames->GetString(0, dwFaceFontFamilyNameChar.get(), dwFaceFontFamilyNameLength+1));
|
| + HRB(dwFaceFontNames->GetString(0, dwFaceFontNameChar.get(), dwFaceFontNameLength+1));
|
| +
|
| + 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.get(), dwFontFamilyNameChar.get()) == 0 &&
|
| + wcscmp(dwFaceFontNameChar.get(), dwFontNameChar.get()) == 0;
|
| +}
|
| +
|
| +SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont(
|
| + IDWriteFontFace* fontFace,
|
| + IDWriteFont* font,
|
| + IDWriteFontFamily* fontFamily) const {
|
| + SkTypeface* face = FindByProcAndRef(FindByDWriteFont, font);
|
| + if (NULL == face) {
|
| + face = DWriteFontTypeface::Create(fFactory.get(), fontFace, font, fontFamily);
|
| + if (face) {
|
| + Add(face, get_style(font), true);
|
| + }
|
| + }
|
| + return face;
|
| +}
|
| +
|
| +int SkFontMgr_DirectWrite::onCountFamilies() const {
|
| + return fFontCollection->GetFontFamilyCount();
|
| +}
|
| +
|
| +void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
|
| + 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.");
|
| +
|
| + sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
|
| +}
|
| +
|
| +SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
|
| + SkTScopedComPtr<IDWriteFontFamily> fontFamily;
|
| + HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
|
| +
|
| + return SkNEW_ARGS(SkFontStyleSet_DirectWrite, (this, fontFamily.get()));
|
| +}
|
| +
|
| +SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
|
| + SkSMallocWCHAR dwFamilyName;
|
| + HRN(sk_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);
|
| +}
|
| +
|
| +SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
|
| + const SkFontStyle& fontstyle) const {
|
| + SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
|
| + return sset->matchStyle(fontstyle);
|
| +}
|
| +
|
| +SkTypeface* SkFontMgr_DirectWrite::onMatchFaceStyle(const SkTypeface* familyMember,
|
| + const SkFontStyle& fontstyle) const {
|
| + SkString familyName;
|
| + SkFontStyleSet_DirectWrite sset(
|
| + this, ((DWriteFontTypeface*)familyMember)->fDWriteFontFamily.get()
|
| + );
|
| + return sset.matchStyle(fontstyle);
|
| +}
|
| +
|
| +template <typename T> class SkAutoIDWriteUnregister {
|
| +public:
|
| + SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
|
| + : fFactory(factory), fUnregister(unregister)
|
| + { }
|
| +
|
| + ~SkAutoIDWriteUnregister() {
|
| + if (fUnregister) {
|
| + unregister(fFactory, fUnregister);
|
| + }
|
| + }
|
| +
|
| + T* detatch() {
|
| + T* old = fUnregister;
|
| + fUnregister = NULL;
|
| + return old;
|
| + }
|
| +
|
| +private:
|
| + HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) {
|
| + return factory->UnregisterFontFileLoader(unregister);
|
| + }
|
| +
|
| + HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) {
|
| + return factory->UnregisterFontCollectionLoader(unregister);
|
| + }
|
| +
|
| + IDWriteFactory* fFactory;
|
| + T* fUnregister;
|
| +};
|
| +
|
| +SkTypeface* SkFontMgr_DirectWrite::onCreateFromStream(SkStream* stream, int ttcIndex) const {
|
| + SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
|
| + HRN(StreamFontFileLoader::Create(stream, &fontFileLoader));
|
| + HRN(fFactory->RegisterFontFileLoader(fontFileLoader.get()));
|
| + SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader(
|
| + fFactory.get(), fontFileLoader.get());
|
| +
|
| + SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader;
|
| + HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader));
|
| + HRN(fFactory->RegisterFontCollectionLoader(fontCollectionLoader.get()));
|
| + SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader(
|
| + fFactory.get(), fontCollectionLoader.get());
|
| +
|
| + SkTScopedComPtr<IDWriteFontCollection> fontCollection;
|
| + HRN(fFactory->CreateCustomFontCollection(fontCollectionLoader.get(), NULL, 0, &fontCollection));
|
| +
|
| + // Find the first non-simulated font which has the given ttc index.
|
| + UINT32 familyCount = fontCollection->GetFontFamilyCount();
|
| + for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
|
| + SkTScopedComPtr<IDWriteFontFamily> fontFamily;
|
| + HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily));
|
| +
|
| + UINT32 fontCount = fontFamily->GetFontCount();
|
| + for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
|
| + SkTScopedComPtr<IDWriteFont> font;
|
| + HRN(fontFamily->GetFont(fontIndex, &font));
|
| + if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
|
| + continue;
|
| + }
|
| +
|
| + SkTScopedComPtr<IDWriteFontFace> fontFace;
|
| + HRN(font->CreateFontFace(&fontFace));
|
| +
|
| + UINT32 faceIndex = fontFace->GetIndex();
|
| + if (faceIndex == ttcIndex) {
|
| + return DWriteFontTypeface::Create(fFactory.get(),
|
| + fontFace.get(), font.get(), fontFamily.get(),
|
| + autoUnregisterFontFileLoader.detatch(),
|
| + autoUnregisterFontCollectionLoader.detatch());
|
| + }
|
| + }
|
| + }
|
| +
|
| + return NULL;
|
| +}
|
| +
|
| +SkTypeface* SkFontMgr_DirectWrite::onCreateFromData(SkData* data, int ttcIndex) const {
|
| + SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
|
| + return this->createFromStream(stream, ttcIndex);
|
| +}
|
| +
|
| +SkTypeface* SkFontMgr_DirectWrite::onCreateFromFile(const char path[], int ttcIndex) const {
|
| + SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
|
| + return this->createFromStream(stream, ttcIndex);
|
| +}
|
| +
|
| +HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
|
| + IDWriteFontFamily** fontFamily) const {
|
| + UINT32 index;
|
| + BOOL exists;
|
| + HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
|
| +
|
| + if (exists) {
|
| + HR(fFontCollection->GetFontFamily(index, fontFamily));
|
| + }
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT SkFontMgr_DirectWrite::getDefaultFontFamily(IDWriteFontFamily** fontFamily) const {
|
| + NONCLIENTMETRICSW metrics;
|
| + metrics.cbSize = sizeof(metrics);
|
| + if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
|
| + sizeof(metrics),
|
| + &metrics,
|
| + 0)) {
|
| + return E_UNEXPECTED;
|
| + }
|
| + HRM(this->getByFamilyName(metrics.lfMessageFont.lfFaceName, fontFamily),
|
| + "Could not create DWrite font family from LOGFONT.");
|
| + return S_OK;
|
| +}
|
| +
|
| +SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[],
|
| + unsigned styleBits) const {
|
| + SkTScopedComPtr<IDWriteFontFamily> fontFamily;
|
| + if (familyName) {
|
| + SkSMallocWCHAR wideFamilyName;
|
| + if (SUCCEEDED(sk_cstring_to_wchar(familyName, &wideFamilyName))) {
|
| + this->getByFamilyName(wideFamilyName, &fontFamily);
|
| + }
|
| + }
|
| +
|
| + if (NULL == fontFamily.get()) {
|
| + // No family with given name, try default.
|
| + HRNM(this->getDefaultFontFamily(&fontFamily), "Could not get default font family.");
|
| + }
|
| +
|
| + if (NULL == fontFamily.get()) {
|
| + // Could not obtain the default font.
|
| + HRNM(fFontCollection->GetFontFamily(0, &fontFamily),
|
| + "Could not get default-default font family.");
|
| + }
|
| +
|
| + SkTScopedComPtr<IDWriteFont> font;
|
| + DWRITE_FONT_WEIGHT weight = (styleBits & SkTypeface::kBold)
|
| + ? DWRITE_FONT_WEIGHT_BOLD
|
| + : DWRITE_FONT_WEIGHT_NORMAL;
|
| + DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL;
|
| + DWRITE_FONT_STYLE italic = (styleBits & SkTypeface::kItalic)
|
| + ? DWRITE_FONT_STYLE_ITALIC
|
| + : DWRITE_FONT_STYLE_NORMAL;
|
| + HRNM(fontFamily->GetFirstMatchingFont(weight, stretch, italic, &font),
|
| + "Could not get matching font.");
|
| +
|
| + SkTScopedComPtr<IDWriteFontFace> fontFace;
|
| + HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
|
| +
|
| + return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +int SkFontStyleSet_DirectWrite::count() {
|
| + return fFontFamily->GetFontCount();
|
| +}
|
| +
|
| +SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) {
|
| + 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 fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
|
| +}
|
| +
|
| +void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
|
| + SkTScopedComPtr<IDWriteFont> font;
|
| + HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
|
| +
|
| + if (fs) {
|
| + 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);
|
| + }
|
| +
|
| + if (styleName) {
|
| + SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
|
| + if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
|
| + sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
|
| + }
|
| + }
|
| +}
|
| +
|
| +SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
|
| + 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;
|
| + // TODO: perhaps use GetMatchingFonts and get the least simulated?
|
| + 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 fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(),
|
| + fFontFamily.get());
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory) {
|
| + if (NULL == factory) {
|
| + 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(SkFontMgr_DirectWrite, (factory, sysFontCollection.get(),
|
| + localeName, localeNameLen));
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +#include "SkFontMgr_indirect.h"
|
| +#include "SkTypeface_win.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));
|
| +}
|
|
|