Split SkFontHost_win_dw.
Split SkFontHost_win_dw into FontMgr, Typeface, and ScalerContext.
This makes working on these files easier, and moves away from the legacy
FontHost naming.
R=reed@google.com
Author: bungeman@google.com
Review URL: https://codereview.chromium.org/314193002
diff --git a/gyp/ports.gyp b/gyp/ports.gyp
index cc2d1f7..afc446c 100644
--- a/gyp/ports.gyp
+++ b/gyp/ports.gyp
@@ -37,7 +37,11 @@
'../src/ports/SkFontHost_win_dw.cpp',
'../src/ports/SkFontMgr_default_gdi.cpp',
'../src/ports/SkFontMgr_default_dw.cpp',
+ '../src/ports/SkFontMgr_win_dw.cpp',
'../src/ports/SkRemotableFontMgr_win_dw.cpp',
+ '../src/ports/SkScalerContext_win_dw.h',
+ '../src/ports/SkTypeface_win_dw.cpp',
+ '../src/ports/SkTypeface_win_dw.h',
'../src/ports/SkGlobalInitialization_default.cpp',
'../src/ports/SkMemory_malloc.cpp',
@@ -162,10 +166,14 @@
'../src/ports/SkFontHost_win_dw.cpp',
'../src/ports/SkFontMgr_default_gdi.cpp',
'../src/ports/SkFontMgr_default_dw.cpp',
+ '../src/ports/SkFontMgr_win_dw.cpp',
'../src/ports/SkOSFile_win.cpp',
'../src/ports/SkRemotableFontMgr_win_dw.cpp',
'../src/ports/SkTime_win.cpp',
'../src/ports/SkTLS_win.cpp',
+ '../src/ports/SkScalerContext_win_dw.h',
+ '../src/ports/SkTypeface_win_dw.cpp',
+ '../src/ports/SkTypeface_win_dw.h',
],
}],
[ 'skia_os == "android"', {
diff --git a/src/ports/SkFontHost_win_dw.cpp b/src/ports/SkFontHost_win_dw.cpp
index ea41d86..fa21df5 100644
--- a/src/ports/SkFontHost_win_dw.cpp
+++ b/src/ports/SkFontHost_win_dw.cpp
@@ -8,36 +8,20 @@
#include "SkTypes.h"
#undef GetGlyphIndices
-#include "SkAdvancedTypefaceMetrics.h"
-#include "SkColorFilter.h"
#include "SkDWrite.h"
-#include "SkDWriteFontFileStream.h"
#include "SkDWriteGeometrySink.h"
-#include "SkDescriptor.h"
#include "SkEndian.h"
-#include "SkFontDescriptor.h"
-#include "SkFontHost.h"
-#include "SkFontMgr.h"
-#include "SkFontStream.h"
#include "SkGlyph.h"
#include "SkHRESULT.h"
#include "SkMaskGamma.h"
#include "SkMatrix22.h"
-#include "SkOnce.h"
#include "SkOTTable_EBLC.h"
#include "SkOTTable_EBSC.h"
-#include "SkOTTable_head.h"
-#include "SkOTTable_hhea.h"
-#include "SkOTTable_OS_2.h"
-#include "SkOTTable_post.h"
#include "SkPath.h"
-#include "SkStream.h"
-#include "SkString.h"
+#include "SkScalerContext.h"
+#include "SkScalerContext_win_dw.h"
#include "SkTScopedComPtr.h"
-#include "SkThread.h"
-#include "SkTypeface_win.h"
-#include "SkTypefaceCache.h"
-#include "SkUtils.h"
+#include "SkTypeface_win_dw.h"
#include <dwrite.h>
@@ -46,578 +30,6 @@
SkMask::kLCD32_Format == rec.fMaskFormat;
}
-///////////////////////////////////////////////////////////////////////////////
-
-class StreamFontFileLoader;
-
-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;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-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;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static SkTypeface::Style get_style(IDWriteFont* font) {
- int style = SkTypeface::kNormal;
- DWRITE_FONT_WEIGHT weight = font->GetWeight();
- if (DWRITE_FONT_WEIGHT_DEMI_BOLD <= weight) {
- style |= SkTypeface::kBold;
- }
- DWRITE_FONT_STYLE angle = font->GetStyle();
- if (DWRITE_FONT_STYLE_OBLIQUE == angle || DWRITE_FONT_STYLE_ITALIC == angle) {
- style |= SkTypeface::kItalic;
- }
- return static_cast<SkTypeface::Style>(style);
-}
-
-class DWriteFontTypeface : public SkTypeface {
-private:
- DWriteFontTypeface(SkTypeface::Style style, SkFontID fontID,
- IDWriteFactory* factory,
- IDWriteFontFace* fontFace,
- IDWriteFont* font,
- IDWriteFontFamily* fontFamily,
- StreamFontFileLoader* fontFileLoader = NULL,
- IDWriteFontCollectionLoader* fontCollectionLoader = NULL)
- : SkTypeface(style, fontID, false)
- , fFactory(SkRefComPtr(factory))
- , fDWriteFontCollectionLoader(SkSafeRefComPtr(fontCollectionLoader))
- , fDWriteFontFileLoader(SkSafeRefComPtr(fontFileLoader))
- , fDWriteFontFamily(SkRefComPtr(fontFamily))
- , fDWriteFont(SkRefComPtr(font))
- , fDWriteFontFace(SkRefComPtr(fontFace))
- { }
-
-public:
- SkTScopedComPtr<IDWriteFactory> fFactory;
- SkTScopedComPtr<IDWriteFontCollectionLoader> fDWriteFontCollectionLoader;
- SkTScopedComPtr<StreamFontFileLoader> fDWriteFontFileLoader;
- SkTScopedComPtr<IDWriteFontFamily> fDWriteFontFamily;
- SkTScopedComPtr<IDWriteFont> fDWriteFont;
- SkTScopedComPtr<IDWriteFontFace> fDWriteFontFace;
-
- static DWriteFontTypeface* Create(IDWriteFactory* factory,
- IDWriteFontFace* fontFace,
- IDWriteFont* font,
- IDWriteFontFamily* fontFamily,
- StreamFontFileLoader* fontFileLoader = NULL,
- IDWriteFontCollectionLoader* fontCollectionLoader = NULL) {
- SkTypeface::Style style = get_style(font);
- SkFontID fontID = SkTypefaceCache::NewFontID();
- return SkNEW_ARGS(DWriteFontTypeface, (style, fontID,
- factory, fontFace, font, fontFamily,
- fontFileLoader, fontCollectionLoader));
- }
-
-protected:
- virtual void weak_dispose() const SK_OVERRIDE {
- if (fDWriteFontCollectionLoader.get()) {
- HRV(fFactory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get()));
- }
- if (fDWriteFontFileLoader.get()) {
- HRV(fFactory->UnregisterFontFileLoader(fDWriteFontFileLoader.get()));
- }
-
- //SkTypefaceCache::Remove(this);
- INHERITED::weak_dispose();
- }
-
- virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
- virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
- virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
- virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
- SkAdvancedTypefaceMetrics::PerGlyphInfo,
- const uint32_t*, uint32_t) const SK_OVERRIDE;
- virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
- virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
- uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
- virtual int onCountGlyphs() const SK_OVERRIDE;
- virtual int onGetUPEM() const SK_OVERRIDE;
- virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
- virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
- virtual size_t onGetTableData(SkFontTableTag, size_t offset,
- size_t length, void* data) const SK_OVERRIDE;
-
-private:
- typedef SkTypeface INHERITED;
-};
-
-class SkScalerContext_DW : public SkScalerContext {
-public:
- SkScalerContext_DW(DWriteFontTypeface*, const SkDescriptor* desc);
- virtual ~SkScalerContext_DW();
-
-protected:
- virtual unsigned generateGlyphCount() SK_OVERRIDE;
- virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
- virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
- virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
- virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
- virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
- virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
- SkPaint::FontMetrics* mY) SK_OVERRIDE;
-
-private:
- const void* drawDWMask(const SkGlyph& glyph);
-
- SkTDArray<uint8_t> fBits;
- /** The total matrix without the text height scale. */
- SkMatrix fSkXform;
- /** The total matrix without the text height scale. */
- DWRITE_MATRIX fXform;
- /** The non-rotational part of total matrix without the text height scale.
- * This is used to find the magnitude of gdi compatible advances.
- */
- DWRITE_MATRIX fGsA;
- /** The inverse of the rotational part of the total matrix.
- * This is used to find the direction of gdi compatible advances.
- */
- SkMatrix fG_inv;
- /** The text size to render with. */
- SkScalar fTextSizeRender;
- /** The text size to measure with. */
- SkScalar fTextSizeMeasure;
- SkAutoTUnref<DWriteFontTypeface> fTypeface;
- int fGlyphCount;
- DWRITE_RENDERING_MODE fRenderingMode;
- DWRITE_TEXTURE_TYPE fTextureType;
- DWRITE_MEASURING_MODE fMeasuringMode;
-};
-
-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 requestedStyle, 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;
-}
-
-class AutoDWriteTable {
-public:
- AutoDWriteTable(IDWriteFontFace* fontFace, UINT32 beTag) : fFontFace(fontFace), fExists(FALSE) {
- // Any errors are ignored, user must check fExists anyway.
- fontFace->TryGetFontTable(beTag,
- reinterpret_cast<const void **>(&fData), &fSize, &fLock, &fExists);
- }
- ~AutoDWriteTable() {
- if (fExists) {
- fFontFace->ReleaseFontTable(fLock);
- }
- }
-
- const uint8_t* fData;
- UINT32 fSize;
- BOOL fExists;
-private:
- // Borrowed reference, the user must ensure the fontFace stays alive.
- IDWriteFontFace* fFontFace;
- void* fLock;
-};
-template<typename T> class AutoTDWriteTable : public AutoDWriteTable {
-public:
- static const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3);
- AutoTDWriteTable(IDWriteFontFace* fontFace) : AutoDWriteTable(fontFace, tag) { }
-
- const T* get() const { return reinterpret_cast<const T*>(fData); }
- const T* operator->() const { return reinterpret_cast<const T*>(fData); }
-};
-
static bool hasBitmapStrike(DWriteFontTypeface* typeface, int size) {
{
AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
@@ -1209,820 +621,3 @@
path->transform(fSkXform);
}
-
-void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
- bool* isLocalStream) const {
- // Get the family name.
- SkTScopedComPtr<IDWriteLocalizedStrings> dwFamilyNames;
- HRV(fDWriteFontFamily->GetFamilyNames(&dwFamilyNames));
-
- UINT32 dwFamilyNamesLength;
- HRV(dwFamilyNames->GetStringLength(0, &dwFamilyNamesLength));
-
- SkSMallocWCHAR dwFamilyNameChar(dwFamilyNamesLength+1);
- HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.get(), dwFamilyNamesLength+1));
-
- SkString utf8FamilyName;
- HRV(sk_wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName));
-
- desc->setFamilyName(utf8FamilyName.c_str());
- *isLocalStream = SkToBool(fDWriteFontFileLoader.get());
-}
-
-static SkUnichar next_utf8(const void** chars) {
- return SkUTF8_NextUnichar((const char**)chars);
-}
-
-static SkUnichar next_utf16(const void** chars) {
- return SkUTF16_NextUnichar((const uint16_t**)chars);
-}
-
-static SkUnichar next_utf32(const void** chars) {
- const SkUnichar** uniChars = (const SkUnichar**)chars;
- SkUnichar uni = **uniChars;
- *uniChars += 1;
- return uni;
-}
-
-typedef SkUnichar (*EncodingProc)(const void**);
-
-static EncodingProc find_encoding_proc(SkTypeface::Encoding enc) {
- static const EncodingProc gProcs[] = {
- next_utf8, next_utf16, next_utf32
- };
- SkASSERT((size_t)enc < SK_ARRAY_COUNT(gProcs));
- return gProcs[enc];
-}
-
-int DWriteFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
- uint16_t glyphs[], int glyphCount) const
-{
- if (NULL == glyphs) {
- EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
- for (int i = 0; i < glyphCount; ++i) {
- const SkUnichar c = next_ucs4_proc(&chars);
- BOOL exists;
- fDWriteFont->HasCharacter(c, &exists);
- if (!exists) {
- return i;
- }
- }
- return glyphCount;
- }
-
- switch (encoding) {
- case SkTypeface::kUTF8_Encoding:
- case SkTypeface::kUTF16_Encoding: {
- static const int scratchCount = 256;
- UINT32 scratch[scratchCount];
- EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
- for (int baseGlyph = 0; baseGlyph < glyphCount; baseGlyph += scratchCount) {
- int glyphsLeft = glyphCount - baseGlyph;
- int limit = SkTMin(glyphsLeft, scratchCount);
- for (int i = 0; i < limit; ++i) {
- scratch[i] = next_ucs4_proc(&chars);
- }
- fDWriteFontFace->GetGlyphIndices(scratch, limit, &glyphs[baseGlyph]);
- }
- break;
- }
- case SkTypeface::kUTF32_Encoding: {
- const UINT32* utf32 = reinterpret_cast<const UINT32*>(chars);
- fDWriteFontFace->GetGlyphIndices(utf32, glyphCount, glyphs);
- break;
- }
- default:
- SK_CRASH();
- }
-
- for (int i = 0; i < glyphCount; ++i) {
- if (0 == glyphs[i]) {
- return i;
- }
- }
- return glyphCount;
-}
-
-int DWriteFontTypeface::onCountGlyphs() const {
- return fDWriteFontFace->GetGlyphCount();
-}
-
-int DWriteFontTypeface::onGetUPEM() const {
- DWRITE_FONT_METRICS metrics;
- fDWriteFontFace->GetMetrics(&metrics);
- return metrics.designUnitsPerEm;
-}
-
-class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings {
-public:
- /** Takes ownership of the IDWriteLocalizedStrings. */
- explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings)
- : fIndex(0), fStrings(strings)
- { }
-
- virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE {
- if (fIndex >= fStrings->GetCount()) {
- return false;
- }
-
- // String
- UINT32 stringLength;
- HRBM(fStrings->GetStringLength(fIndex, &stringLength), "Could not get string length.");
- stringLength += 1;
-
- SkSMallocWCHAR wString(stringLength);
- HRBM(fStrings->GetString(fIndex, wString.get(), stringLength), "Could not get string.");
-
- HRB(sk_wchar_to_skstring(wString.get(), &localizedString->fString));
-
- // Locale
- UINT32 localeLength;
- HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLength), "Could not get locale length.");
- localeLength += 1;
-
- SkSMallocWCHAR wLocale(localeLength);
- HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLength), "Could not get locale.");
-
- HRB(sk_wchar_to_skstring(wLocale.get(), &localizedString->fLanguage));
-
- ++fIndex;
- return true;
- }
-
-private:
- UINT32 fIndex;
- SkTScopedComPtr<IDWriteLocalizedStrings> fStrings;
-};
-
-SkTypeface::LocalizedStrings* DWriteFontTypeface::onCreateFamilyNameIterator() const {
- SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
- HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names.");
-
- return new LocalizedStrings_IDWriteLocalizedStrings(familyNames.release());
-}
-
-int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
- DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType();
- if (type != DWRITE_FONT_FACE_TYPE_CFF &&
- type != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
- type != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
- {
- return 0;
- }
-
- int ttcIndex;
- SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
- return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
-}
-
-size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
- size_t length, void* data) const
-{
- AutoDWriteTable table(fDWriteFontFace.get(), SkEndian_SwapBE32(tag));
- if (!table.fExists) {
- return 0;
- }
-
- if (offset > table.fSize) {
- return 0;
- }
- size_t size = SkTMin(length, table.fSize - offset);
- if (NULL != data) {
- memcpy(data, table.fData + offset, size);
- }
-
- return size;
-}
-
-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;
-};
-
-SkStream* DWriteFontTypeface::onOpenStream(int* ttcIndex) const {
- *ttcIndex = fDWriteFontFace->GetIndex();
-
- UINT32 numFiles;
- HRNM(fDWriteFontFace->GetFiles(&numFiles, NULL),
- "Could not get number of font files.");
- if (numFiles != 1) {
- return NULL;
- }
-
- SkTScopedComPtr<IDWriteFontFile> fontFile;
- HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files.");
-
- const void* fontFileKey;
- UINT32 fontFileKeySize;
- HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize),
- "Could not get font file reference key.");
-
- SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
- HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader.");
-
- SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
- HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize,
- &fontFileStream),
- "Could not create font file stream.");
-
- return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
-}
-
-SkScalerContext* DWriteFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
- return SkNEW_ARGS(SkScalerContext_DW, (const_cast<DWriteFontTypeface*>(this), desc));
-}
-
-void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const {
- if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
- rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
- {
- rec->fMaskFormat = SkMask::kA8_Format;
- }
-
- unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
- SkScalerContext::kForceAutohinting_Flag |
- SkScalerContext::kEmbolden_Flag |
- SkScalerContext::kLCD_BGROrder_Flag |
- SkScalerContext::kLCD_Vertical_Flag;
- rec->fFlags &= ~flagsWeDontSupport;
-
- SkPaint::Hinting h = rec->getHinting();
- // DirectWrite does not provide for hinting hints.
- h = SkPaint::kSlight_Hinting;
- rec->setHinting(h);
-
-#if SK_FONT_HOST_USE_SYSTEM_SETTINGS
- IDWriteFactory* factory = get_dwrite_factory();
- if (factory != NULL) {
- SkTScopedComPtr<IDWriteRenderingParams> defaultRenderingParams;
- if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) {
- float gamma = defaultRenderingParams->GetGamma();
- rec->setDeviceGamma(gamma);
- rec->setPaintGamma(gamma);
-
- rec->setContrast(defaultRenderingParams->GetEnhancedContrast());
- }
- }
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//PDF Support
-
-using namespace skia_advanced_typeface_metrics_utils;
-
-// Construct Glyph to Unicode table.
-// Unicode code points that require conjugate pairs in utf16 are not
-// supported.
-// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
-// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
-// of calling GetFontUnicodeRange().
-// TODO(bungeman): This never does what anyone wants.
-// What is really wanted is the text to glyphs mapping
-static void populate_glyph_to_unicode(IDWriteFontFace* fontFace,
- const unsigned glyphCount,
- SkTDArray<SkUnichar>* glyphToUnicode) {
- HRESULT hr = S_OK;
-
- //Do this like free type instead
- UINT32 count = 0;
- for (UINT32 c = 0; c < 0x10FFFF; ++c) {
- UINT16 glyph;
- hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
- if (glyph > 0) {
- ++count;
- }
- }
-
- SkAutoTArray<UINT32> chars(count);
- count = 0;
- for (UINT32 c = 0; c < 0x10FFFF; ++c) {
- UINT16 glyph;
- hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
- if (glyph > 0) {
- chars[count] = c;
- ++count;
- }
- }
-
- SkAutoTArray<UINT16> glyph(count);
- fontFace->GetGlyphIndices(chars.get(), count, glyph.get());
-
- USHORT maxGlyph = 0;
- for (USHORT j = 0; j < count; ++j) {
- if (glyph[j] > maxGlyph) maxGlyph = glyph[j];
- }
-
- glyphToUnicode->setCount(maxGlyph+1);
- for (USHORT j = 0; j < maxGlyph+1u; ++j) {
- (*glyphToUnicode)[j] = 0;
- }
-
- //'invert'
- for (USHORT j = 0; j < count; ++j) {
- if (glyph[j] < glyphCount && (*glyphToUnicode)[glyph[j]] == 0) {
- (*glyphToUnicode)[glyph[j]] = chars[j];
- }
- }
-}
-
-static bool getWidthAdvance(IDWriteFontFace* fontFace, int gId, int16_t* advance) {
- SkASSERT(advance);
-
- UINT16 glyphId = gId;
- DWRITE_GLYPH_METRICS gm;
- HRESULT hr = fontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm);
-
- if (FAILED(hr)) {
- *advance = 0;
- return false;
- }
-
- *advance = gm.advanceWidth;
- return true;
-}
-
-SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics(
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
- const uint32_t* glyphIDs,
- uint32_t glyphIDsCount) const {
-
- SkAdvancedTypefaceMetrics* info = NULL;
-
- HRESULT hr = S_OK;
-
- const unsigned glyphCount = fDWriteFontFace->GetGlyphCount();
-
- DWRITE_FONT_METRICS dwfm;
- fDWriteFontFace->GetMetrics(&dwfm);
-
- info = new SkAdvancedTypefaceMetrics;
- info->fEmSize = dwfm.designUnitsPerEm;
- info->fMultiMaster = false;
- info->fLastGlyphID = SkToU16(glyphCount - 1);
- info->fStyle = 0;
-
-
- SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
- SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
- hr = fDWriteFontFamily->GetFamilyNames(&familyNames);
- hr = fDWriteFont->GetFaceNames(&faceNames);
-
- UINT32 familyNameLength;
- hr = familyNames->GetStringLength(0, &familyNameLength);
-
- UINT32 faceNameLength;
- hr = faceNames->GetStringLength(0, &faceNameLength);
-
- 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);
-
- hr = sk_wchar_to_skstring(wFamilyName.get(), &info->fFontName);
-
- if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
- populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode));
- }
-
- DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
- if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE ||
- fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
- info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
- } else {
- info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
- info->fItalicAngle = 0;
- info->fAscent = dwfm.ascent;;
- info->fDescent = dwfm.descent;
- info->fStemV = 0;
- info->fCapHeight = dwfm.capHeight;
- info->fBBox = SkIRect::MakeEmpty();
- return info;
- }
-
- AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
- AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
- AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
- AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
- if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
- info->fItalicAngle = 0;
- info->fAscent = dwfm.ascent;;
- info->fDescent = dwfm.descent;
- info->fStemV = 0;
- info->fCapHeight = dwfm.capHeight;
- info->fBBox = SkIRect::MakeEmpty();
- return info;
- }
-
- //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
- //but have full width, latin half-width, and half-width kana.
- bool fixedWidth = (postTable->isFixedPitch &&
- (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
- //Monospace
- if (fixedWidth) {
- info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
- }
- //Italic
- if (os2Table->version.v0.fsSelection.field.Italic) {
- info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
- }
- //Script
- if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType.value) {
- info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
- //Serif
- } else if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType.value &&
- SkPanose::Data::TextAndDisplay::SerifStyle::Triangle <= os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value &&
- SkPanose::Data::TextAndDisplay::SerifStyle::NoFit != os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value) {
- info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
- }
-
- info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;
-
- info->fAscent = SkToS16(dwfm.ascent);
- info->fDescent = SkToS16(dwfm.descent);
- info->fCapHeight = SkToS16(dwfm.capHeight);
-
- info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
- (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
- (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
- (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));
-
- //TODO: is this even desired? It seems PDF only wants this value for Type1
- //fonts, and we only get here for TrueType fonts.
- info->fStemV = 0;
- /*
- // Figure out a good guess for StemV - Min width of i, I, !, 1.
- // This probably isn't very good with an italic font.
- int16_t min_width = SHRT_MAX;
- info->fStemV = 0;
- char stem_chars[] = {'i', 'I', '!', '1'};
- for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
- ABC abcWidths;
- if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
- int16_t width = abcWidths.abcB;
- if (width > 0 && width < min_width) {
- min_width = width;
- info->fStemV = min_width;
- }
- }
- }
- */
-
- // If Restricted, the font may not be embedded in a document.
- // If not Restricted, the font can be embedded.
- // If PreviewPrint, the embedding is read-only.
- if (os2Table->version.v0.fsType.field.Restricted) {
- info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
- } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
- if (fixedWidth) {
- appendRange(&info->fGlyphWidths, 0);
- int16_t advance;
- getWidthAdvance(fDWriteFontFace.get(), 1, &advance);
- info->fGlyphWidths->fAdvance.append(1, &advance);
- finishRange(info->fGlyphWidths.get(), 0,
- SkAdvancedTypefaceMetrics::WidthRange::kDefault);
- } else {
- info->fGlyphWidths.reset(
- getAdvanceData(fDWriteFontFace.get(),
- glyphCount,
- glyphIDs,
- glyphIDsCount,
- getWidthAdvance));
- }
- }
-
- return info;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-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);
-}
-
-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"
-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/src/ports/SkFontMgr_win_dw.cpp b/src/ports/SkFontMgr_win_dw.cpp
new file mode 100644
index 0000000..fe82258c
--- /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));
+}
diff --git a/src/ports/SkScalerContext_win_dw.h b/src/ports/SkScalerContext_win_dw.h
new file mode 100644
index 0000000..e3dbd29
--- /dev/null
+++ b/src/ports/SkScalerContext_win_dw.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkScalarContext_win_dw_DEFINED
+#define SkScalarContext_win_dw_DEFINED
+
+#include "SkScalar.h"
+#include "SkScalerContext.h"
+#include "SkTypeface_win_dw.h"
+#include "SkTypes.h"
+
+#include <dwrite.h>
+
+struct SkGlyph;
+class SkDescriptor;
+
+class SkScalerContext_DW : public SkScalerContext {
+public:
+ SkScalerContext_DW(DWriteFontTypeface*, const SkDescriptor* desc);
+ virtual ~SkScalerContext_DW();
+
+protected:
+ virtual unsigned generateGlyphCount() SK_OVERRIDE;
+ virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
+ virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
+ virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
+ virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
+ virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
+ virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
+ SkPaint::FontMetrics* mY) SK_OVERRIDE;
+
+private:
+ const void* drawDWMask(const SkGlyph& glyph);
+
+ SkTDArray<uint8_t> fBits;
+ /** The total matrix without the text height scale. */
+ SkMatrix fSkXform;
+ /** The total matrix without the text height scale. */
+ DWRITE_MATRIX fXform;
+ /** The non-rotational part of total matrix without the text height scale.
+ * This is used to find the magnitude of gdi compatible advances.
+ */
+ DWRITE_MATRIX fGsA;
+ /** The inverse of the rotational part of the total matrix.
+ * This is used to find the direction of gdi compatible advances.
+ */
+ SkMatrix fG_inv;
+ /** The text size to render with. */
+ SkScalar fTextSizeRender;
+ /** The text size to measure with. */
+ SkScalar fTextSizeMeasure;
+ SkAutoTUnref<DWriteFontTypeface> fTypeface;
+ int fGlyphCount;
+ DWRITE_RENDERING_MODE fRenderingMode;
+ DWRITE_TEXTURE_TYPE fTextureType;
+ DWRITE_MEASURING_MODE fMeasuringMode;
+};
+
+#endif
diff --git a/src/ports/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp
new file mode 100644
index 0000000..4937d3f
--- /dev/null
+++ b/src/ports/SkTypeface_win_dw.cpp
@@ -0,0 +1,499 @@
+/*
+ * 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 "SkDWriteFontFileStream.h"
+#include "SkFontDescriptor.h"
+#include "SkFontStream.h"
+#include "SkOTTable_head.h"
+#include "SkOTTable_hhea.h"
+#include "SkOTTable_OS_2.h"
+#include "SkOTTable_post.h"
+#include "SkScalerContext.h"
+#include "SkScalerContext_win_dw.h"
+#include "SkTypeface_win_dw.h"
+#include "SkTypes.h"
+#include "SkUtils.h"
+
+void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
+ bool* isLocalStream) const {
+ // Get the family name.
+ SkTScopedComPtr<IDWriteLocalizedStrings> dwFamilyNames;
+ HRV(fDWriteFontFamily->GetFamilyNames(&dwFamilyNames));
+
+ UINT32 dwFamilyNamesLength;
+ HRV(dwFamilyNames->GetStringLength(0, &dwFamilyNamesLength));
+
+ SkSMallocWCHAR dwFamilyNameChar(dwFamilyNamesLength+1);
+ HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.get(), dwFamilyNamesLength+1));
+
+ SkString utf8FamilyName;
+ HRV(sk_wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName));
+
+ desc->setFamilyName(utf8FamilyName.c_str());
+ *isLocalStream = SkToBool(fDWriteFontFileLoader.get());
+}
+
+static SkUnichar next_utf8(const void** chars) {
+ return SkUTF8_NextUnichar((const char**)chars);
+}
+
+static SkUnichar next_utf16(const void** chars) {
+ return SkUTF16_NextUnichar((const uint16_t**)chars);
+}
+
+static SkUnichar next_utf32(const void** chars) {
+ const SkUnichar** uniChars = (const SkUnichar**)chars;
+ SkUnichar uni = **uniChars;
+ *uniChars += 1;
+ return uni;
+}
+
+typedef SkUnichar (*EncodingProc)(const void**);
+
+static EncodingProc find_encoding_proc(SkTypeface::Encoding enc) {
+ static const EncodingProc gProcs[] = {
+ next_utf8, next_utf16, next_utf32
+ };
+ SkASSERT((size_t)enc < SK_ARRAY_COUNT(gProcs));
+ return gProcs[enc];
+}
+
+int DWriteFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
+ uint16_t glyphs[], int glyphCount) const
+{
+ if (NULL == glyphs) {
+ EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
+ for (int i = 0; i < glyphCount; ++i) {
+ const SkUnichar c = next_ucs4_proc(&chars);
+ BOOL exists;
+ fDWriteFont->HasCharacter(c, &exists);
+ if (!exists) {
+ return i;
+ }
+ }
+ return glyphCount;
+ }
+
+ switch (encoding) {
+ case SkTypeface::kUTF8_Encoding:
+ case SkTypeface::kUTF16_Encoding: {
+ static const int scratchCount = 256;
+ UINT32 scratch[scratchCount];
+ EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
+ for (int baseGlyph = 0; baseGlyph < glyphCount; baseGlyph += scratchCount) {
+ int glyphsLeft = glyphCount - baseGlyph;
+ int limit = SkTMin(glyphsLeft, scratchCount);
+ for (int i = 0; i < limit; ++i) {
+ scratch[i] = next_ucs4_proc(&chars);
+ }
+ fDWriteFontFace->GetGlyphIndices(scratch, limit, &glyphs[baseGlyph]);
+ }
+ break;
+ }
+ case SkTypeface::kUTF32_Encoding: {
+ const UINT32* utf32 = reinterpret_cast<const UINT32*>(chars);
+ fDWriteFontFace->GetGlyphIndices(utf32, glyphCount, glyphs);
+ break;
+ }
+ default:
+ SK_CRASH();
+ }
+
+ for (int i = 0; i < glyphCount; ++i) {
+ if (0 == glyphs[i]) {
+ return i;
+ }
+ }
+ return glyphCount;
+}
+
+int DWriteFontTypeface::onCountGlyphs() const {
+ return fDWriteFontFace->GetGlyphCount();
+}
+
+int DWriteFontTypeface::onGetUPEM() const {
+ DWRITE_FONT_METRICS metrics;
+ fDWriteFontFace->GetMetrics(&metrics);
+ return metrics.designUnitsPerEm;
+}
+
+class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings {
+public:
+ /** Takes ownership of the IDWriteLocalizedStrings. */
+ explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings)
+ : fIndex(0), fStrings(strings)
+ { }
+
+ virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE {
+ if (fIndex >= fStrings->GetCount()) {
+ return false;
+ }
+
+ // String
+ UINT32 stringLength;
+ HRBM(fStrings->GetStringLength(fIndex, &stringLength), "Could not get string length.");
+ stringLength += 1;
+
+ SkSMallocWCHAR wString(stringLength);
+ HRBM(fStrings->GetString(fIndex, wString.get(), stringLength), "Could not get string.");
+
+ HRB(sk_wchar_to_skstring(wString.get(), &localizedString->fString));
+
+ // Locale
+ UINT32 localeLength;
+ HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLength), "Could not get locale length.");
+ localeLength += 1;
+
+ SkSMallocWCHAR wLocale(localeLength);
+ HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLength), "Could not get locale.");
+
+ HRB(sk_wchar_to_skstring(wLocale.get(), &localizedString->fLanguage));
+
+ ++fIndex;
+ return true;
+ }
+
+private:
+ UINT32 fIndex;
+ SkTScopedComPtr<IDWriteLocalizedStrings> fStrings;
+};
+
+SkTypeface::LocalizedStrings* DWriteFontTypeface::onCreateFamilyNameIterator() const {
+ SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
+ HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names.");
+
+ return new LocalizedStrings_IDWriteLocalizedStrings(familyNames.release());
+}
+
+int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
+ DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType();
+ if (type != DWRITE_FONT_FACE_TYPE_CFF &&
+ type != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
+ type != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
+ {
+ return 0;
+ }
+
+ int ttcIndex;
+ SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
+ return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
+}
+
+size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
+ size_t length, void* data) const
+{
+ AutoDWriteTable table(fDWriteFontFace.get(), SkEndian_SwapBE32(tag));
+ if (!table.fExists) {
+ return 0;
+ }
+
+ if (offset > table.fSize) {
+ return 0;
+ }
+ size_t size = SkTMin(length, table.fSize - offset);
+ if (NULL != data) {
+ memcpy(data, table.fData + offset, size);
+ }
+
+ return size;
+}
+
+SkStream* DWriteFontTypeface::onOpenStream(int* ttcIndex) const {
+ *ttcIndex = fDWriteFontFace->GetIndex();
+
+ UINT32 numFiles;
+ HRNM(fDWriteFontFace->GetFiles(&numFiles, NULL),
+ "Could not get number of font files.");
+ if (numFiles != 1) {
+ return NULL;
+ }
+
+ SkTScopedComPtr<IDWriteFontFile> fontFile;
+ HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files.");
+
+ const void* fontFileKey;
+ UINT32 fontFileKeySize;
+ HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize),
+ "Could not get font file reference key.");
+
+ SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
+ HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader.");
+
+ SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
+ HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize,
+ &fontFileStream),
+ "Could not create font file stream.");
+
+ return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
+}
+
+SkScalerContext* DWriteFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
+ return SkNEW_ARGS(SkScalerContext_DW, (const_cast<DWriteFontTypeface*>(this), desc));
+}
+
+void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const {
+ if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
+ rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
+ {
+ rec->fMaskFormat = SkMask::kA8_Format;
+ }
+
+ unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
+ SkScalerContext::kForceAutohinting_Flag |
+ SkScalerContext::kEmbolden_Flag |
+ SkScalerContext::kLCD_BGROrder_Flag |
+ SkScalerContext::kLCD_Vertical_Flag;
+ rec->fFlags &= ~flagsWeDontSupport;
+
+ SkPaint::Hinting h = rec->getHinting();
+ // DirectWrite does not provide for hinting hints.
+ h = SkPaint::kSlight_Hinting;
+ rec->setHinting(h);
+
+#if SK_FONT_HOST_USE_SYSTEM_SETTINGS
+ IDWriteFactory* factory = get_dwrite_factory();
+ if (factory != NULL) {
+ SkTScopedComPtr<IDWriteRenderingParams> defaultRenderingParams;
+ if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) {
+ float gamma = defaultRenderingParams->GetGamma();
+ rec->setDeviceGamma(gamma);
+ rec->setPaintGamma(gamma);
+
+ rec->setContrast(defaultRenderingParams->GetEnhancedContrast());
+ }
+ }
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//PDF Support
+
+using namespace skia_advanced_typeface_metrics_utils;
+
+// Construct Glyph to Unicode table.
+// Unicode code points that require conjugate pairs in utf16 are not
+// supported.
+// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
+// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
+// of calling GetFontUnicodeRange().
+// TODO(bungeman): This never does what anyone wants.
+// What is really wanted is the text to glyphs mapping
+static void populate_glyph_to_unicode(IDWriteFontFace* fontFace,
+ const unsigned glyphCount,
+ SkTDArray<SkUnichar>* glyphToUnicode) {
+ HRESULT hr = S_OK;
+
+ //Do this like free type instead
+ UINT32 count = 0;
+ for (UINT32 c = 0; c < 0x10FFFF; ++c) {
+ UINT16 glyph;
+ hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
+ if (glyph > 0) {
+ ++count;
+ }
+ }
+
+ SkAutoTArray<UINT32> chars(count);
+ count = 0;
+ for (UINT32 c = 0; c < 0x10FFFF; ++c) {
+ UINT16 glyph;
+ hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
+ if (glyph > 0) {
+ chars[count] = c;
+ ++count;
+ }
+ }
+
+ SkAutoTArray<UINT16> glyph(count);
+ fontFace->GetGlyphIndices(chars.get(), count, glyph.get());
+
+ USHORT maxGlyph = 0;
+ for (USHORT j = 0; j < count; ++j) {
+ if (glyph[j] > maxGlyph) maxGlyph = glyph[j];
+ }
+
+ glyphToUnicode->setCount(maxGlyph+1);
+ for (USHORT j = 0; j < maxGlyph+1u; ++j) {
+ (*glyphToUnicode)[j] = 0;
+ }
+
+ //'invert'
+ for (USHORT j = 0; j < count; ++j) {
+ if (glyph[j] < glyphCount && (*glyphToUnicode)[glyph[j]] == 0) {
+ (*glyphToUnicode)[glyph[j]] = chars[j];
+ }
+ }
+}
+
+static bool getWidthAdvance(IDWriteFontFace* fontFace, int gId, int16_t* advance) {
+ SkASSERT(advance);
+
+ UINT16 glyphId = gId;
+ DWRITE_GLYPH_METRICS gm;
+ HRESULT hr = fontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm);
+
+ if (FAILED(hr)) {
+ *advance = 0;
+ return false;
+ }
+
+ *advance = gm.advanceWidth;
+ return true;
+}
+
+SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics(
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount) const {
+
+ SkAdvancedTypefaceMetrics* info = NULL;
+
+ HRESULT hr = S_OK;
+
+ const unsigned glyphCount = fDWriteFontFace->GetGlyphCount();
+
+ DWRITE_FONT_METRICS dwfm;
+ fDWriteFontFace->GetMetrics(&dwfm);
+
+ info = new SkAdvancedTypefaceMetrics;
+ info->fEmSize = dwfm.designUnitsPerEm;
+ info->fMultiMaster = false;
+ info->fLastGlyphID = SkToU16(glyphCount - 1);
+ info->fStyle = 0;
+
+
+ SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
+ SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
+ hr = fDWriteFontFamily->GetFamilyNames(&familyNames);
+ hr = fDWriteFont->GetFaceNames(&faceNames);
+
+ UINT32 familyNameLength;
+ hr = familyNames->GetStringLength(0, &familyNameLength);
+
+ UINT32 faceNameLength;
+ hr = faceNames->GetStringLength(0, &faceNameLength);
+
+ 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);
+
+ hr = sk_wchar_to_skstring(wFamilyName.get(), &info->fFontName);
+
+ if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
+ populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode));
+ }
+
+ DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
+ if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE ||
+ fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
+ info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
+ } else {
+ info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
+ info->fItalicAngle = 0;
+ info->fAscent = dwfm.ascent;;
+ info->fDescent = dwfm.descent;
+ info->fStemV = 0;
+ info->fCapHeight = dwfm.capHeight;
+ info->fBBox = SkIRect::MakeEmpty();
+ return info;
+ }
+
+ AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
+ AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
+ AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
+ AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
+ if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
+ info->fItalicAngle = 0;
+ info->fAscent = dwfm.ascent;;
+ info->fDescent = dwfm.descent;
+ info->fStemV = 0;
+ info->fCapHeight = dwfm.capHeight;
+ info->fBBox = SkIRect::MakeEmpty();
+ return info;
+ }
+
+ //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
+ //but have full width, latin half-width, and half-width kana.
+ bool fixedWidth = (postTable->isFixedPitch &&
+ (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
+ //Monospace
+ if (fixedWidth) {
+ info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
+ }
+ //Italic
+ if (os2Table->version.v0.fsSelection.field.Italic) {
+ info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
+ }
+ //Script
+ if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType.value) {
+ info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
+ //Serif
+ } else if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType.value &&
+ SkPanose::Data::TextAndDisplay::SerifStyle::Triangle <= os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value &&
+ SkPanose::Data::TextAndDisplay::SerifStyle::NoFit != os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value) {
+ info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
+ }
+
+ info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;
+
+ info->fAscent = SkToS16(dwfm.ascent);
+ info->fDescent = SkToS16(dwfm.descent);
+ info->fCapHeight = SkToS16(dwfm.capHeight);
+
+ info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
+ (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
+ (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
+ (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));
+
+ //TODO: is this even desired? It seems PDF only wants this value for Type1
+ //fonts, and we only get here for TrueType fonts.
+ info->fStemV = 0;
+ /*
+ // Figure out a good guess for StemV - Min width of i, I, !, 1.
+ // This probably isn't very good with an italic font.
+ int16_t min_width = SHRT_MAX;
+ info->fStemV = 0;
+ char stem_chars[] = {'i', 'I', '!', '1'};
+ for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
+ ABC abcWidths;
+ if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
+ int16_t width = abcWidths.abcB;
+ if (width > 0 && width < min_width) {
+ min_width = width;
+ info->fStemV = min_width;
+ }
+ }
+ }
+ */
+
+ // If Restricted, the font may not be embedded in a document.
+ // If not Restricted, the font can be embedded.
+ // If PreviewPrint, the embedding is read-only.
+ if (os2Table->version.v0.fsType.field.Restricted) {
+ info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
+ } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
+ if (fixedWidth) {
+ appendRange(&info->fGlyphWidths, 0);
+ int16_t advance;
+ getWidthAdvance(fDWriteFontFace.get(), 1, &advance);
+ info->fGlyphWidths->fAdvance.append(1, &advance);
+ finishRange(info->fGlyphWidths.get(), 0,
+ SkAdvancedTypefaceMetrics::WidthRange::kDefault);
+ } else {
+ info->fGlyphWidths.reset(
+ getAdvanceData(fDWriteFontFace.get(),
+ glyphCount,
+ glyphIDs,
+ glyphIDsCount,
+ getWidthAdvance));
+ }
+ }
+
+ return info;
+}
diff --git a/src/ports/SkTypeface_win_dw.h b/src/ports/SkTypeface_win_dw.h
new file mode 100644
index 0000000..b064ce5
--- /dev/null
+++ b/src/ports/SkTypeface_win_dw.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkTypeface_win_dw_DEFINED
+#define SkTypeface_win_dw_DEFINED
+
+#include "SkAdvancedTypefaceMetrics.h"
+#include "SkDWrite.h"
+#include "SkHRESULT.h"
+#include "SkTScopedComPtr.h"
+#include "SkTypeface.h"
+#include "SkTypefaceCache.h"
+#include "SkTypes.h"
+
+#include <dwrite.h>
+
+class SkFontDescriptor;
+struct SkScalerContextRec;
+
+static SkTypeface::Style get_style(IDWriteFont* font) {
+ int style = SkTypeface::kNormal;
+ DWRITE_FONT_WEIGHT weight = font->GetWeight();
+ if (DWRITE_FONT_WEIGHT_DEMI_BOLD <= weight) {
+ style |= SkTypeface::kBold;
+ }
+ DWRITE_FONT_STYLE angle = font->GetStyle();
+ if (DWRITE_FONT_STYLE_OBLIQUE == angle || DWRITE_FONT_STYLE_ITALIC == angle) {
+ style |= SkTypeface::kItalic;
+ }
+ return static_cast<SkTypeface::Style>(style);
+}
+
+class DWriteFontTypeface : public SkTypeface {
+private:
+ DWriteFontTypeface(SkTypeface::Style style, SkFontID fontID,
+ IDWriteFactory* factory,
+ IDWriteFontFace* fontFace,
+ IDWriteFont* font,
+ IDWriteFontFamily* fontFamily,
+ IDWriteFontFileLoader* fontFileLoader = NULL,
+ IDWriteFontCollectionLoader* fontCollectionLoader = NULL)
+ : SkTypeface(style, fontID, false)
+ , fFactory(SkRefComPtr(factory))
+ , fDWriteFontCollectionLoader(SkSafeRefComPtr(fontCollectionLoader))
+ , fDWriteFontFileLoader(SkSafeRefComPtr(fontFileLoader))
+ , fDWriteFontFamily(SkRefComPtr(fontFamily))
+ , fDWriteFont(SkRefComPtr(font))
+ , fDWriteFontFace(SkRefComPtr(fontFace))
+ { }
+
+public:
+ SkTScopedComPtr<IDWriteFactory> fFactory;
+ SkTScopedComPtr<IDWriteFontCollectionLoader> fDWriteFontCollectionLoader;
+ SkTScopedComPtr<IDWriteFontFileLoader> fDWriteFontFileLoader;
+ SkTScopedComPtr<IDWriteFontFamily> fDWriteFontFamily;
+ SkTScopedComPtr<IDWriteFont> fDWriteFont;
+ SkTScopedComPtr<IDWriteFontFace> fDWriteFontFace;
+
+ static DWriteFontTypeface* Create(IDWriteFactory* factory,
+ IDWriteFontFace* fontFace,
+ IDWriteFont* font,
+ IDWriteFontFamily* fontFamily,
+ IDWriteFontFileLoader* fontFileLoader = NULL,
+ IDWriteFontCollectionLoader* fontCollectionLoader = NULL) {
+ SkTypeface::Style style = get_style(font);
+ SkFontID fontID = SkTypefaceCache::NewFontID();
+ return SkNEW_ARGS(DWriteFontTypeface, (style, fontID,
+ factory, fontFace, font, fontFamily,
+ fontFileLoader, fontCollectionLoader));
+ }
+
+protected:
+ virtual void weak_dispose() const SK_OVERRIDE {
+ if (fDWriteFontCollectionLoader.get()) {
+ HRV(fFactory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get()));
+ }
+ if (fDWriteFontFileLoader.get()) {
+ HRV(fFactory->UnregisterFontFileLoader(fDWriteFontFileLoader.get()));
+ }
+
+ //SkTypefaceCache::Remove(this);
+ INHERITED::weak_dispose();
+ }
+
+ virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
+ virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
+ virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
+ virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
+ SkAdvancedTypefaceMetrics::PerGlyphInfo,
+ const uint32_t*, uint32_t) const SK_OVERRIDE;
+ virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
+ virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
+ uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
+ virtual int onCountGlyphs() const SK_OVERRIDE;
+ virtual int onGetUPEM() const SK_OVERRIDE;
+ virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
+ virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
+ virtual size_t onGetTableData(SkFontTableTag, size_t offset,
+ size_t length, void* data) const SK_OVERRIDE;
+
+private:
+ typedef SkTypeface INHERITED;
+};
+
+#endif
diff --git a/src/utils/win/SkDWrite.h b/src/utils/win/SkDWrite.h
index 06e9c8b..679447d 100644
--- a/src/utils/win/SkDWrite.h
+++ b/src/utils/win/SkDWrite.h
@@ -5,6 +5,9 @@
* found in the LICENSE file.
*/
+#ifndef SkDWrite_DEFINED
+#define SkDWrite_DEFINED
+
#include "SkTemplates.h"
#include <dwrite.h>
@@ -36,3 +39,38 @@
typedef decltype(GetUserDefaultLocaleName)* SkGetUserDefaultLocaleNameProc;
HRESULT SkGetGetUserDefaultLocaleNameProc(SkGetUserDefaultLocaleNameProc* proc);
+
+////////////////////////////////////////////////////////////////////////////////
+// Table handling
+
+class AutoDWriteTable {
+public:
+ AutoDWriteTable(IDWriteFontFace* fontFace, UINT32 beTag) : fFontFace(fontFace), fExists(FALSE) {
+ // Any errors are ignored, user must check fExists anyway.
+ fontFace->TryGetFontTable(beTag,
+ reinterpret_cast<const void **>(&fData), &fSize, &fLock, &fExists);
+ }
+ ~AutoDWriteTable() {
+ if (fExists) {
+ fFontFace->ReleaseFontTable(fLock);
+ }
+ }
+
+ const uint8_t* fData;
+ UINT32 fSize;
+ BOOL fExists;
+private:
+ // Borrowed reference, the user must ensure the fontFace stays alive.
+ IDWriteFontFace* fFontFace;
+ void* fLock;
+};
+template<typename T> class AutoTDWriteTable : public AutoDWriteTable {
+public:
+ static const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3);
+ AutoTDWriteTable(IDWriteFontFace* fontFace) : AutoDWriteTable(fontFace, tag) { }
+
+ const T* get() const { return reinterpret_cast<const T*>(fData); }
+ const T* operator->() const { return reinterpret_cast<const T*>(fData); }
+};
+
+#endif