michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkTypes.h" michael@0: #undef GetGlyphIndices michael@0: michael@0: #include "SkAdvancedTypefaceMetrics.h" michael@0: #include "SkColorFilter.h" michael@0: #include "SkDWriteFontFileStream.h" michael@0: #include "SkDWriteGeometrySink.h" michael@0: #include "SkDescriptor.h" michael@0: #include "SkEndian.h" michael@0: #include "SkFontDescriptor.h" michael@0: #include "SkFontHost.h" michael@0: #include "SkFontMgr.h" michael@0: #include "SkFontStream.h" michael@0: #include "SkGlyph.h" michael@0: #include "SkHRESULT.h" michael@0: #include "SkMaskGamma.h" michael@0: #include "SkOnce.h" michael@0: #include "SkOTTable_head.h" michael@0: #include "SkOTTable_hhea.h" michael@0: #include "SkOTTable_OS_2.h" michael@0: #include "SkOTTable_post.h" michael@0: #include "SkPath.h" michael@0: #include "SkStream.h" michael@0: #include "SkString.h" michael@0: #include "SkTScopedComPtr.h" michael@0: #include "SkThread.h" michael@0: #include "SkTypeface_win.h" michael@0: #include "SkTypefaceCache.h" michael@0: #include "SkUtils.h" michael@0: michael@0: #include michael@0: michael@0: static bool isLCD(const SkScalerContext::Rec& rec) { michael@0: return SkMask::kLCD16_Format == rec.fMaskFormat || michael@0: SkMask::kLCD32_Format == rec.fMaskFormat; michael@0: } michael@0: michael@0: /** Prefer to use this type to prevent template proliferation. */ michael@0: typedef SkAutoSTMalloc<16, WCHAR> SkSMallocWCHAR; michael@0: michael@0: /** Converts a utf8 string to a WCHAR string. */ michael@0: static HRESULT cstring_to_wchar(const char* skname, SkSMallocWCHAR* name) { michael@0: int wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, NULL, 0); michael@0: if (0 == wlen) { michael@0: HRM(HRESULT_FROM_WIN32(GetLastError()), michael@0: "Could not get length for wchar to utf-8 conversion."); michael@0: } michael@0: name->reset(wlen); michael@0: wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, name->get(), wlen); michael@0: if (0 == wlen) { michael@0: HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert wchar to utf-8."); michael@0: } michael@0: return S_OK; michael@0: } michael@0: michael@0: /** Converts a WCHAR string to a utf8 string. */ michael@0: static HRESULT wchar_to_skstring(WCHAR* name, SkString* skname) { michael@0: int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); michael@0: if (0 == len) { michael@0: HRM(HRESULT_FROM_WIN32(GetLastError()), michael@0: "Could not get length for utf-8 to wchar conversion."); michael@0: } michael@0: skname->resize(len - 1); michael@0: michael@0: // TODO: remove after https://code.google.com/p/skia/issues/detail?id=1989 is fixed. michael@0: // If we resize to 0 then the skname points to gEmptyRec (the unique empty SkString::Rec). michael@0: // gEmptyRec is static const and on Windows this means the value is in a read only page. michael@0: // Writing to it in the following call to WideCharToMultiByte will cause an access violation. michael@0: if (1 == len) { michael@0: return S_OK; michael@0: } michael@0: michael@0: len = WideCharToMultiByte(CP_UTF8, 0, name, -1, skname->writable_str(), len, NULL, NULL); michael@0: if (0 == len) { michael@0: HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert utf-8 to wchar."); michael@0: } michael@0: return S_OK; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static void create_dwrite_factory(IDWriteFactory** factory) { michael@0: typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; michael@0: DWriteCreateFactoryProc dWriteCreateFactoryProc = reinterpret_cast( michael@0: GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory")); michael@0: michael@0: if (!dWriteCreateFactoryProc) { michael@0: HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); michael@0: if (!IS_ERROR(hr)) { michael@0: hr = ERROR_PROC_NOT_FOUND; michael@0: } michael@0: HRVM(hr, "Could not get DWriteCreateFactory proc."); michael@0: } michael@0: michael@0: HRVM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED, michael@0: __uuidof(IDWriteFactory), michael@0: reinterpret_cast(factory)), michael@0: "Could not create DirectWrite factory."); michael@0: } michael@0: michael@0: static IDWriteFactory* get_dwrite_factory() { michael@0: static IDWriteFactory* gDWriteFactory = NULL; michael@0: SK_DECLARE_STATIC_ONCE(once); michael@0: SkOnce(&once, create_dwrite_factory, &gDWriteFactory); michael@0: michael@0: return gDWriteFactory; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class StreamFontFileLoader; michael@0: michael@0: class SkFontMgr_DirectWrite : public SkFontMgr { michael@0: public: michael@0: /** localeNameLength must include the null terminator. */ michael@0: SkFontMgr_DirectWrite(IDWriteFontCollection* fontCollection, michael@0: WCHAR* localeName, int localeNameLength) michael@0: : fFontCollection(SkRefComPtr(fontCollection)) michael@0: , fLocaleName(localeNameLength) michael@0: { michael@0: memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR)); michael@0: } michael@0: michael@0: SkTypeface* createTypefaceFromDWriteFont(IDWriteFontFace* fontFace, michael@0: IDWriteFont* font, michael@0: IDWriteFontFamily* fontFamily, michael@0: StreamFontFileLoader* = NULL, michael@0: IDWriteFontCollectionLoader* = NULL) const; michael@0: michael@0: protected: michael@0: virtual int onCountFamilies() const SK_OVERRIDE; michael@0: virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE; michael@0: virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE; michael@0: virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE; michael@0: virtual SkTypeface* onMatchFamilyStyle(const char familyName[], michael@0: const SkFontStyle& fontstyle) const SK_OVERRIDE; michael@0: virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, michael@0: const SkFontStyle& fontstyle) const SK_OVERRIDE; michael@0: virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE; michael@0: virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE; michael@0: virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE; michael@0: virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], michael@0: unsigned styleBits) const SK_OVERRIDE; michael@0: michael@0: private: michael@0: HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const; michael@0: HRESULT getDefaultFontFamily(IDWriteFontFamily** fontFamily) const; michael@0: michael@0: void Add(SkTypeface* face, SkTypeface::Style requestedStyle, bool strong) const { michael@0: SkAutoMutexAcquire ama(fTFCacheMutex); michael@0: fTFCache.add(face, requestedStyle, strong); michael@0: } michael@0: michael@0: SkTypeface* FindByProcAndRef(SkTypefaceCache::FindProc proc, void* ctx) const { michael@0: SkAutoMutexAcquire ama(fTFCacheMutex); michael@0: SkTypeface* typeface = fTFCache.findByProcAndRef(proc, ctx); michael@0: return typeface; michael@0: } michael@0: michael@0: SkTScopedComPtr fFontCollection; michael@0: SkSMallocWCHAR fLocaleName; michael@0: mutable SkMutex fTFCacheMutex; michael@0: mutable SkTypefaceCache fTFCache; michael@0: michael@0: friend class SkFontStyleSet_DirectWrite; michael@0: }; michael@0: michael@0: class SkFontStyleSet_DirectWrite : public SkFontStyleSet { michael@0: public: michael@0: SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr, michael@0: IDWriteFontFamily* fontFamily) michael@0: : fFontMgr(SkRef(fontMgr)) michael@0: , fFontFamily(SkRefComPtr(fontFamily)) michael@0: { } michael@0: michael@0: virtual int count() SK_OVERRIDE; michael@0: virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE; michael@0: virtual SkTypeface* createTypeface(int index) SK_OVERRIDE; michael@0: virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE; michael@0: michael@0: private: michael@0: SkAutoTUnref fFontMgr; michael@0: SkTScopedComPtr fFontFamily; michael@0: }; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class DWriteOffscreen { michael@0: public: michael@0: DWriteOffscreen() : fWidth(0), fHeight(0) { michael@0: } michael@0: michael@0: void init(IDWriteFontFace* fontFace, const DWRITE_MATRIX& xform, FLOAT fontSize) { michael@0: fFontFace = fontFace; michael@0: fFontSize = fontSize; michael@0: fXform = xform; michael@0: } michael@0: michael@0: const void* draw(const SkGlyph&, bool isBW); michael@0: michael@0: private: michael@0: uint16_t fWidth; michael@0: uint16_t fHeight; michael@0: IDWriteFontFace* fFontFace; michael@0: FLOAT fFontSize; michael@0: DWRITE_MATRIX fXform; michael@0: SkTDArray fBits; michael@0: }; michael@0: michael@0: const void* DWriteOffscreen::draw(const SkGlyph& glyph, bool isBW) { michael@0: IDWriteFactory* factory = get_dwrite_factory(); michael@0: SkASSERT(factory != NULL); michael@0: michael@0: if (fWidth < glyph.fWidth || fHeight < glyph.fHeight) { michael@0: fWidth = SkMax32(fWidth, glyph.fWidth); michael@0: fHeight = SkMax32(fHeight, glyph.fHeight); michael@0: michael@0: if (isBW) { michael@0: fBits.setCount(fWidth * fHeight); michael@0: } else { michael@0: fBits.setCount(fWidth * fHeight * 3); michael@0: } michael@0: } michael@0: michael@0: // erase michael@0: memset(fBits.begin(), 0, fBits.count()); michael@0: michael@0: fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); michael@0: fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); michael@0: michael@0: FLOAT advance = 0.0f; michael@0: michael@0: UINT16 index = glyph.getGlyphID(); michael@0: michael@0: DWRITE_GLYPH_OFFSET offset; michael@0: offset.advanceOffset = 0.0f; michael@0: offset.ascenderOffset = 0.0f; michael@0: michael@0: DWRITE_GLYPH_RUN run; michael@0: run.glyphCount = 1; michael@0: run.glyphAdvances = &advance; michael@0: run.fontFace = fFontFace; michael@0: run.fontEmSize = fFontSize; michael@0: run.bidiLevel = 0; michael@0: run.glyphIndices = &index; michael@0: run.isSideways = FALSE; michael@0: run.glyphOffsets = &offset; michael@0: michael@0: DWRITE_RENDERING_MODE renderingMode; michael@0: DWRITE_TEXTURE_TYPE textureType; michael@0: if (isBW) { michael@0: renderingMode = DWRITE_RENDERING_MODE_ALIASED; michael@0: textureType = DWRITE_TEXTURE_ALIASED_1x1; michael@0: } else { michael@0: renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; michael@0: textureType = DWRITE_TEXTURE_CLEARTYPE_3x1; michael@0: } michael@0: SkTScopedComPtr glyphRunAnalysis; michael@0: HRNM(factory->CreateGlyphRunAnalysis(&run, michael@0: 1.0f, // pixelsPerDip, michael@0: &fXform, michael@0: renderingMode, michael@0: DWRITE_MEASURING_MODE_NATURAL, michael@0: 0.0f, // baselineOriginX, michael@0: 0.0f, // baselineOriginY, michael@0: &glyphRunAnalysis), michael@0: "Could not create glyph run analysis."); michael@0: michael@0: //NOTE: this assumes that the glyph has already been measured michael@0: //with an exact same glyph run analysis. michael@0: RECT bbox; michael@0: bbox.left = glyph.fLeft; michael@0: bbox.top = glyph.fTop; michael@0: bbox.right = glyph.fLeft + glyph.fWidth; michael@0: bbox.bottom = glyph.fTop + glyph.fHeight; michael@0: HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, michael@0: &bbox, michael@0: fBits.begin(), michael@0: fBits.count()), michael@0: "Could not draw mask."); michael@0: return fBits.begin(); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class StreamFontFileLoader : public IDWriteFontFileLoader { michael@0: public: michael@0: // IUnknown methods michael@0: virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); michael@0: virtual ULONG STDMETHODCALLTYPE AddRef(); michael@0: virtual ULONG STDMETHODCALLTYPE Release(); michael@0: michael@0: // IDWriteFontFileLoader methods michael@0: virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey( michael@0: void const* fontFileReferenceKey, michael@0: UINT32 fontFileReferenceKeySize, michael@0: IDWriteFontFileStream** fontFileStream); michael@0: michael@0: static HRESULT Create(SkStream* stream, StreamFontFileLoader** streamFontFileLoader) { michael@0: *streamFontFileLoader = new StreamFontFileLoader(stream); michael@0: if (NULL == streamFontFileLoader) { michael@0: return E_OUTOFMEMORY; michael@0: } michael@0: return S_OK; michael@0: } michael@0: michael@0: SkAutoTUnref fStream; michael@0: michael@0: private: michael@0: StreamFontFileLoader(SkStream* stream) : fRefCount(1), fStream(SkRef(stream)) { } michael@0: michael@0: ULONG fRefCount; michael@0: }; michael@0: michael@0: HRESULT StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) { michael@0: if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { michael@0: *ppvObject = this; michael@0: AddRef(); michael@0: return S_OK; michael@0: } else { michael@0: *ppvObject = NULL; michael@0: return E_NOINTERFACE; michael@0: } michael@0: } michael@0: michael@0: ULONG StreamFontFileLoader::AddRef() { michael@0: return InterlockedIncrement(&fRefCount); michael@0: } michael@0: michael@0: ULONG StreamFontFileLoader::Release() { michael@0: ULONG newCount = InterlockedDecrement(&fRefCount); michael@0: if (0 == newCount) { michael@0: delete this; michael@0: } michael@0: return newCount; michael@0: } michael@0: michael@0: HRESULT StreamFontFileLoader::CreateStreamFromKey( michael@0: void const* fontFileReferenceKey, michael@0: UINT32 fontFileReferenceKeySize, michael@0: IDWriteFontFileStream** fontFileStream) michael@0: { michael@0: SkTScopedComPtr stream; michael@0: HR(SkDWriteFontFileStreamWrapper::Create(fStream, &stream)); michael@0: *fontFileStream = stream.release(); michael@0: return S_OK; michael@0: } michael@0: michael@0: class StreamFontFileEnumerator : public IDWriteFontFileEnumerator { michael@0: public: michael@0: // IUnknown methods michael@0: virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); michael@0: virtual ULONG STDMETHODCALLTYPE AddRef(); michael@0: virtual ULONG STDMETHODCALLTYPE Release(); michael@0: michael@0: // IDWriteFontFileEnumerator methods michael@0: virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile); michael@0: virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile); michael@0: michael@0: static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader, michael@0: StreamFontFileEnumerator** streamFontFileEnumerator) { michael@0: *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader); michael@0: if (NULL == streamFontFileEnumerator) { michael@0: return E_OUTOFMEMORY; michael@0: } michael@0: return S_OK; michael@0: } michael@0: private: michael@0: StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader); michael@0: ULONG fRefCount; michael@0: michael@0: SkTScopedComPtr fFactory; michael@0: SkTScopedComPtr fCurrentFile; michael@0: SkTScopedComPtr fFontFileLoader; michael@0: bool fHasNext; michael@0: }; michael@0: michael@0: StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory, michael@0: IDWriteFontFileLoader* fontFileLoader) michael@0: : fRefCount(1) michael@0: , fFactory(SkRefComPtr(factory)) michael@0: , fCurrentFile() michael@0: , fFontFileLoader(SkRefComPtr(fontFileLoader)) michael@0: , fHasNext(true) michael@0: { } michael@0: michael@0: HRESULT StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) { michael@0: if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) { michael@0: *ppvObject = this; michael@0: AddRef(); michael@0: return S_OK; michael@0: } else { michael@0: *ppvObject = NULL; michael@0: return E_NOINTERFACE; michael@0: } michael@0: } michael@0: michael@0: ULONG StreamFontFileEnumerator::AddRef() { michael@0: return InterlockedIncrement(&fRefCount); michael@0: } michael@0: michael@0: ULONG StreamFontFileEnumerator::Release() { michael@0: ULONG newCount = InterlockedDecrement(&fRefCount); michael@0: if (0 == newCount) { michael@0: delete this; michael@0: } michael@0: return newCount; michael@0: } michael@0: michael@0: HRESULT StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) { michael@0: *hasCurrentFile = FALSE; michael@0: michael@0: if (!fHasNext) { michael@0: return S_OK; michael@0: } michael@0: fHasNext = false; michael@0: michael@0: UINT32 dummy = 0; michael@0: HR(fFactory->CreateCustomFontFileReference( michael@0: &dummy, //cannot be NULL michael@0: sizeof(dummy), //even if this is 0 michael@0: fFontFileLoader.get(), michael@0: &fCurrentFile)); michael@0: michael@0: *hasCurrentFile = TRUE; michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) { michael@0: if (fCurrentFile.get() == NULL) { michael@0: *fontFile = NULL; michael@0: return E_FAIL; michael@0: } michael@0: michael@0: *fontFile = SkRefComPtr(fCurrentFile.get()); michael@0: return S_OK; michael@0: } michael@0: michael@0: class StreamFontCollectionLoader : public IDWriteFontCollectionLoader { michael@0: public: michael@0: // IUnknown methods michael@0: virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); michael@0: virtual ULONG STDMETHODCALLTYPE AddRef(); michael@0: virtual ULONG STDMETHODCALLTYPE Release(); michael@0: michael@0: // IDWriteFontCollectionLoader methods michael@0: virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey( michael@0: IDWriteFactory* factory, michael@0: void const* collectionKey, michael@0: UINT32 collectionKeySize, michael@0: IDWriteFontFileEnumerator** fontFileEnumerator); michael@0: michael@0: static HRESULT Create(IDWriteFontFileLoader* fontFileLoader, michael@0: StreamFontCollectionLoader** streamFontCollectionLoader) { michael@0: *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader); michael@0: if (NULL == streamFontCollectionLoader) { michael@0: return E_OUTOFMEMORY; michael@0: } michael@0: return S_OK; michael@0: } michael@0: private: michael@0: StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader) michael@0: : fRefCount(1) michael@0: , fFontFileLoader(SkRefComPtr(fontFileLoader)) michael@0: { } michael@0: michael@0: ULONG fRefCount; michael@0: SkTScopedComPtr fFontFileLoader; michael@0: }; michael@0: michael@0: HRESULT StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) { michael@0: if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) { michael@0: *ppvObject = this; michael@0: AddRef(); michael@0: return S_OK; michael@0: } else { michael@0: *ppvObject = NULL; michael@0: return E_NOINTERFACE; michael@0: } michael@0: } michael@0: michael@0: ULONG StreamFontCollectionLoader::AddRef() { michael@0: return InterlockedIncrement(&fRefCount); michael@0: } michael@0: michael@0: ULONG StreamFontCollectionLoader::Release() { michael@0: ULONG newCount = InterlockedDecrement(&fRefCount); michael@0: if (0 == newCount) { michael@0: delete this; michael@0: } michael@0: return newCount; michael@0: } michael@0: michael@0: HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey( michael@0: IDWriteFactory* factory, michael@0: void const* collectionKey, michael@0: UINT32 collectionKeySize, michael@0: IDWriteFontFileEnumerator** fontFileEnumerator) michael@0: { michael@0: SkTScopedComPtr enumerator; michael@0: HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator)); michael@0: *fontFileEnumerator = enumerator.release(); michael@0: return S_OK; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static SkTypeface::Style get_style(IDWriteFont* font) { michael@0: int style = SkTypeface::kNormal; michael@0: DWRITE_FONT_WEIGHT weight = font->GetWeight(); michael@0: if (DWRITE_FONT_WEIGHT_DEMI_BOLD <= weight) { michael@0: style |= SkTypeface::kBold; michael@0: } michael@0: DWRITE_FONT_STYLE angle = font->GetStyle(); michael@0: if (DWRITE_FONT_STYLE_OBLIQUE == angle || DWRITE_FONT_STYLE_ITALIC == angle) { michael@0: style |= SkTypeface::kItalic; michael@0: } michael@0: return static_cast(style); michael@0: } michael@0: michael@0: class DWriteFontTypeface : public SkTypeface { michael@0: private: michael@0: DWriteFontTypeface(SkTypeface::Style style, SkFontID fontID, michael@0: IDWriteFontFace* fontFace, michael@0: IDWriteFont* font, michael@0: IDWriteFontFamily* fontFamily, michael@0: StreamFontFileLoader* fontFileLoader = NULL, michael@0: IDWriteFontCollectionLoader* fontCollectionLoader = NULL) michael@0: : SkTypeface(style, fontID, false) michael@0: , fDWriteFontCollectionLoader(SkSafeRefComPtr(fontCollectionLoader)) michael@0: , fDWriteFontFileLoader(SkSafeRefComPtr(fontFileLoader)) michael@0: , fDWriteFontFamily(SkRefComPtr(fontFamily)) michael@0: , fDWriteFont(SkRefComPtr(font)) michael@0: , fDWriteFontFace(SkRefComPtr(fontFace)) michael@0: { } michael@0: michael@0: public: michael@0: SkTScopedComPtr fDWriteFontCollectionLoader; michael@0: SkTScopedComPtr fDWriteFontFileLoader; michael@0: SkTScopedComPtr fDWriteFontFamily; michael@0: SkTScopedComPtr fDWriteFont; michael@0: SkTScopedComPtr fDWriteFontFace; michael@0: michael@0: static DWriteFontTypeface* Create(IDWriteFontFace* fontFace, michael@0: IDWriteFont* font, michael@0: IDWriteFontFamily* fontFamily, michael@0: StreamFontFileLoader* fontFileLoader = NULL, michael@0: IDWriteFontCollectionLoader* fontCollectionLoader = NULL) { michael@0: SkTypeface::Style style = get_style(font); michael@0: SkFontID fontID = SkTypefaceCache::NewFontID(); michael@0: return SkNEW_ARGS(DWriteFontTypeface, (style, fontID, michael@0: fontFace, font, fontFamily, michael@0: fontFileLoader, fontCollectionLoader)); michael@0: } michael@0: michael@0: ~DWriteFontTypeface() { michael@0: if (fDWriteFontCollectionLoader.get() == NULL) return; michael@0: michael@0: IDWriteFactory* factory = get_dwrite_factory(); michael@0: SkASSERT(factory != NULL); michael@0: HRV(factory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get())); michael@0: HRV(factory->UnregisterFontFileLoader(fDWriteFontFileLoader.get())); michael@0: } michael@0: michael@0: protected: michael@0: virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; michael@0: virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE; michael@0: virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE; michael@0: virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( michael@0: SkAdvancedTypefaceMetrics::PerGlyphInfo, michael@0: const uint32_t*, uint32_t) const SK_OVERRIDE; michael@0: virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE; michael@0: virtual int onCharsToGlyphs(const void* chars, Encoding encoding, michael@0: uint16_t glyphs[], int glyphCount) const SK_OVERRIDE; michael@0: virtual int onCountGlyphs() const SK_OVERRIDE; michael@0: virtual int onGetUPEM() const SK_OVERRIDE; michael@0: virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE; michael@0: virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; michael@0: virtual size_t onGetTableData(SkFontTableTag, size_t offset, michael@0: size_t length, void* data) const SK_OVERRIDE; michael@0: }; michael@0: michael@0: class SkScalerContext_DW : public SkScalerContext { michael@0: public: michael@0: SkScalerContext_DW(DWriteFontTypeface*, const SkDescriptor* desc); michael@0: virtual ~SkScalerContext_DW(); michael@0: michael@0: protected: michael@0: virtual unsigned generateGlyphCount() SK_OVERRIDE; michael@0: virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; michael@0: virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; michael@0: virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; michael@0: virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; michael@0: virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; michael@0: virtual void generateFontMetrics(SkPaint::FontMetrics* mX, michael@0: SkPaint::FontMetrics* mY) SK_OVERRIDE; michael@0: michael@0: private: michael@0: DWriteOffscreen fOffscreen; michael@0: DWRITE_MATRIX fXform; michael@0: SkAutoTUnref fTypeface; michael@0: int fGlyphCount; michael@0: }; michael@0: michael@0: static bool are_same(IUnknown* a, IUnknown* b) { michael@0: SkTScopedComPtr iunkA; michael@0: if (FAILED(a->QueryInterface(&iunkA))) { michael@0: return false; michael@0: } michael@0: michael@0: SkTScopedComPtr iunkB; michael@0: if (FAILED(b->QueryInterface(&iunkB))) { michael@0: return false; michael@0: } michael@0: michael@0: return iunkA.get() == iunkB.get(); michael@0: } michael@0: static bool FindByDWriteFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) { michael@0: //Check to see if the two fonts are identical. michael@0: DWriteFontTypeface* dwFace = reinterpret_cast(face); michael@0: IDWriteFont* dwFont = reinterpret_cast(ctx); michael@0: if (are_same(dwFace->fDWriteFont.get(), dwFont)) { michael@0: return true; michael@0: } michael@0: michael@0: //Check if the two fonts share the same loader and have the same key. michael@0: SkTScopedComPtr dwFaceFontFace; michael@0: SkTScopedComPtr dwFontFace; michael@0: HRB(dwFace->fDWriteFont->CreateFontFace(&dwFaceFontFace)); michael@0: HRB(dwFont->CreateFontFace(&dwFontFace)); michael@0: if (are_same(dwFaceFontFace.get(), dwFontFace.get())) { michael@0: return true; michael@0: } michael@0: michael@0: UINT32 dwFaceNumFiles; michael@0: UINT32 dwNumFiles; michael@0: HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, NULL)); michael@0: HRB(dwFontFace->GetFiles(&dwNumFiles, NULL)); michael@0: if (dwFaceNumFiles != dwNumFiles) { michael@0: return false; michael@0: } michael@0: michael@0: SkTScopedComPtr dwFaceFontFile; michael@0: SkTScopedComPtr dwFontFile; michael@0: HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, &dwFaceFontFile)); michael@0: HRB(dwFontFace->GetFiles(&dwNumFiles, &dwFontFile)); michael@0: michael@0: //for (each file) { //we currently only admit fonts from one file. michael@0: SkTScopedComPtr dwFaceFontFileLoader; michael@0: SkTScopedComPtr dwFontFileLoader; michael@0: HRB(dwFaceFontFile->GetLoader(&dwFaceFontFileLoader)); michael@0: HRB(dwFontFile->GetLoader(&dwFontFileLoader)); michael@0: if (!are_same(dwFaceFontFileLoader.get(), dwFontFileLoader.get())) { michael@0: return false; michael@0: } michael@0: //} michael@0: michael@0: const void* dwFaceFontRefKey; michael@0: UINT32 dwFaceFontRefKeySize; michael@0: const void* dwFontRefKey; michael@0: UINT32 dwFontRefKeySize; michael@0: HRB(dwFaceFontFile->GetReferenceKey(&dwFaceFontRefKey, &dwFaceFontRefKeySize)); michael@0: HRB(dwFontFile->GetReferenceKey(&dwFontRefKey, &dwFontRefKeySize)); michael@0: if (dwFaceFontRefKeySize != dwFontRefKeySize) { michael@0: return false; michael@0: } michael@0: if (0 != memcmp(dwFaceFontRefKey, dwFontRefKey, dwFontRefKeySize)) { michael@0: return false; michael@0: } michael@0: michael@0: //TODO: better means than comparing name strings? michael@0: //NOTE: .tfc and fake bold/italic will end up here. michael@0: SkTScopedComPtr dwFaceFontFamily; michael@0: SkTScopedComPtr dwFontFamily; michael@0: HRB(dwFace->fDWriteFont->GetFontFamily(&dwFaceFontFamily)); michael@0: HRB(dwFont->GetFontFamily(&dwFontFamily)); michael@0: michael@0: SkTScopedComPtr dwFaceFontFamilyNames; michael@0: SkTScopedComPtr dwFaceFontNames; michael@0: HRB(dwFaceFontFamily->GetFamilyNames(&dwFaceFontFamilyNames)); michael@0: HRB(dwFace->fDWriteFont->GetFaceNames(&dwFaceFontNames)); michael@0: michael@0: SkTScopedComPtr dwFontFamilyNames; michael@0: SkTScopedComPtr dwFontNames; michael@0: HRB(dwFontFamily->GetFamilyNames(&dwFontFamilyNames)); michael@0: HRB(dwFont->GetFaceNames(&dwFontNames)); michael@0: michael@0: UINT32 dwFaceFontFamilyNameLength; michael@0: UINT32 dwFaceFontNameLength; michael@0: HRB(dwFaceFontFamilyNames->GetStringLength(0, &dwFaceFontFamilyNameLength)); michael@0: HRB(dwFaceFontNames->GetStringLength(0, &dwFaceFontNameLength)); michael@0: michael@0: UINT32 dwFontFamilyNameLength; michael@0: UINT32 dwFontNameLength; michael@0: HRB(dwFontFamilyNames->GetStringLength(0, &dwFontFamilyNameLength)); michael@0: HRB(dwFontNames->GetStringLength(0, &dwFontNameLength)); michael@0: michael@0: if (dwFaceFontFamilyNameLength != dwFontFamilyNameLength || michael@0: dwFaceFontNameLength != dwFontNameLength) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: SkSMallocWCHAR dwFaceFontFamilyNameChar(dwFaceFontFamilyNameLength+1); michael@0: SkSMallocWCHAR dwFaceFontNameChar(dwFaceFontNameLength+1); michael@0: HRB(dwFaceFontFamilyNames->GetString(0, dwFaceFontFamilyNameChar.get(), dwFaceFontFamilyNameLength+1)); michael@0: HRB(dwFaceFontNames->GetString(0, dwFaceFontNameChar.get(), dwFaceFontNameLength+1)); michael@0: michael@0: SkSMallocWCHAR dwFontFamilyNameChar(dwFontFamilyNameLength+1); michael@0: SkSMallocWCHAR dwFontNameChar(dwFontNameLength+1); michael@0: HRB(dwFontFamilyNames->GetString(0, dwFontFamilyNameChar.get(), dwFontFamilyNameLength+1)); michael@0: HRB(dwFontNames->GetString(0, dwFontNameChar.get(), dwFontNameLength+1)); michael@0: michael@0: return wcscmp(dwFaceFontFamilyNameChar.get(), dwFontFamilyNameChar.get()) == 0 && michael@0: wcscmp(dwFaceFontNameChar.get(), dwFontNameChar.get()) == 0; michael@0: } michael@0: michael@0: SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, michael@0: const SkDescriptor* desc) michael@0: : SkScalerContext(typeface, desc) michael@0: , fTypeface(SkRef(typeface)) michael@0: , fGlyphCount(-1) { michael@0: michael@0: fXform.m11 = SkScalarToFloat(fRec.fPost2x2[0][0]); michael@0: fXform.m12 = SkScalarToFloat(fRec.fPost2x2[1][0]); michael@0: fXform.m21 = SkScalarToFloat(fRec.fPost2x2[0][1]); michael@0: fXform.m22 = SkScalarToFloat(fRec.fPost2x2[1][1]); michael@0: fXform.dx = 0; michael@0: fXform.dy = 0; michael@0: michael@0: fOffscreen.init(fTypeface->fDWriteFontFace.get(), fXform, SkScalarToFloat(fRec.fTextSize)); michael@0: } michael@0: michael@0: SkScalerContext_DW::~SkScalerContext_DW() { michael@0: } michael@0: michael@0: unsigned SkScalerContext_DW::generateGlyphCount() { michael@0: if (fGlyphCount < 0) { michael@0: fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount(); michael@0: } michael@0: return fGlyphCount; michael@0: } michael@0: michael@0: uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) { michael@0: uint16_t index = 0; michael@0: fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast(&uni), 1, &index); michael@0: return index; michael@0: } michael@0: michael@0: void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { michael@0: //Delta is the difference between the right/left side bearing metric michael@0: //and where the right/left side bearing ends up after hinting. michael@0: //DirectWrite does not provide this information. michael@0: glyph->fRsbDelta = 0; michael@0: glyph->fLsbDelta = 0; michael@0: michael@0: glyph->fAdvanceX = 0; michael@0: glyph->fAdvanceY = 0; michael@0: michael@0: uint16_t glyphId = glyph->getGlyphID(); michael@0: DWRITE_GLYPH_METRICS gm; michael@0: HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), michael@0: "Could not get design metrics."); michael@0: michael@0: DWRITE_FONT_METRICS dwfm; michael@0: fTypeface->fDWriteFontFace->GetMetrics(&dwfm); michael@0: michael@0: SkScalar advanceX = SkScalarMulDiv(fRec.fTextSize, michael@0: SkIntToScalar(gm.advanceWidth), michael@0: SkIntToScalar(dwfm.designUnitsPerEm)); michael@0: michael@0: if (!(fRec.fFlags & kSubpixelPositioning_Flag)) { michael@0: advanceX = SkScalarRoundToScalar(advanceX); michael@0: } michael@0: michael@0: SkVector vecs[1] = { { advanceX, 0 } }; michael@0: SkMatrix mat; michael@0: fRec.getMatrixFrom2x2(&mat); michael@0: mat.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); michael@0: michael@0: glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX); michael@0: glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY); michael@0: } michael@0: michael@0: void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { michael@0: glyph->fWidth = 0; michael@0: michael@0: this->generateAdvance(glyph); michael@0: michael@0: //Measure raster size. michael@0: fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); michael@0: fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); michael@0: michael@0: FLOAT advance = 0; michael@0: michael@0: UINT16 glyphId = glyph->getGlyphID(); michael@0: michael@0: DWRITE_GLYPH_OFFSET offset; michael@0: offset.advanceOffset = 0.0f; michael@0: offset.ascenderOffset = 0.0f; michael@0: michael@0: DWRITE_GLYPH_RUN run; michael@0: run.glyphCount = 1; michael@0: run.glyphAdvances = &advance; michael@0: run.fontFace = fTypeface->fDWriteFontFace.get(); michael@0: run.fontEmSize = SkScalarToFloat(fRec.fTextSize); michael@0: run.bidiLevel = 0; michael@0: run.glyphIndices = &glyphId; michael@0: run.isSideways = FALSE; michael@0: run.glyphOffsets = &offset; michael@0: michael@0: IDWriteFactory* factory = get_dwrite_factory(); michael@0: SkASSERT(factory != NULL); michael@0: michael@0: const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; michael@0: DWRITE_RENDERING_MODE renderingMode; michael@0: DWRITE_TEXTURE_TYPE textureType; michael@0: if (isBW) { michael@0: renderingMode = DWRITE_RENDERING_MODE_ALIASED; michael@0: textureType = DWRITE_TEXTURE_ALIASED_1x1; michael@0: } else { michael@0: renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; michael@0: textureType = DWRITE_TEXTURE_CLEARTYPE_3x1; michael@0: } michael@0: michael@0: SkTScopedComPtr glyphRunAnalysis; michael@0: HRVM(factory->CreateGlyphRunAnalysis(&run, michael@0: 1.0f, // pixelsPerDip, michael@0: &fXform, michael@0: renderingMode, michael@0: DWRITE_MEASURING_MODE_NATURAL, michael@0: 0.0f, // baselineOriginX, michael@0: 0.0f, // baselineOriginY, michael@0: &glyphRunAnalysis), michael@0: "Could not create glyph run analysis."); michael@0: michael@0: RECT bbox; michael@0: HRVM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, &bbox), michael@0: "Could not get texture bounds."); michael@0: michael@0: glyph->fWidth = SkToU16(bbox.right - bbox.left); michael@0: glyph->fHeight = SkToU16(bbox.bottom - bbox.top); michael@0: glyph->fLeft = SkToS16(bbox.left); michael@0: glyph->fTop = SkToS16(bbox.top); michael@0: } michael@0: michael@0: void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx, michael@0: SkPaint::FontMetrics* my) { michael@0: if (!(mx || my)) michael@0: return; michael@0: michael@0: if (mx) { michael@0: sk_bzero(mx, sizeof(*mx)); michael@0: } michael@0: if (my) { michael@0: sk_bzero(my, sizeof(*my)); michael@0: } michael@0: michael@0: DWRITE_FONT_METRICS dwfm; michael@0: fTypeface->fDWriteFontFace->GetMetrics(&dwfm); michael@0: michael@0: SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); michael@0: if (mx) { michael@0: mx->fTop = -fRec.fTextSize * SkIntToScalar(dwfm.ascent) / upem; michael@0: mx->fAscent = mx->fTop; michael@0: mx->fDescent = fRec.fTextSize * SkIntToScalar(dwfm.descent) / upem; michael@0: mx->fBottom = mx->fDescent; michael@0: mx->fLeading = fRec.fTextSize * SkIntToScalar(dwfm.lineGap) / upem; michael@0: mx->fXHeight = fRec.fTextSize * SkIntToScalar(dwfm.xHeight) / upem; michael@0: mx->fUnderlineThickness = fRec.fTextSize * SkIntToScalar(dwfm.underlinePosition) / upem; michael@0: mx->fUnderlinePosition = -(fRec.fTextSize * SkIntToScalar(dwfm.underlineThickness) / upem); michael@0: michael@0: mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; michael@0: mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; michael@0: } michael@0: michael@0: if (my) { michael@0: my->fTop = -fRec.fTextSize * SkIntToScalar(dwfm.ascent) / upem; michael@0: my->fAscent = my->fTop; michael@0: my->fDescent = fRec.fTextSize * SkIntToScalar(dwfm.descent) / upem; michael@0: my->fBottom = my->fDescent; michael@0: my->fLeading = fRec.fTextSize * SkIntToScalar(dwfm.lineGap) / upem; michael@0: my->fXHeight = fRec.fTextSize * SkIntToScalar(dwfm.xHeight) / upem; michael@0: my->fUnderlineThickness = fRec.fTextSize * SkIntToScalar(dwfm.underlinePosition) / upem; michael@0: my->fUnderlinePosition = -(fRec.fTextSize * SkIntToScalar(dwfm.underlineThickness) / upem); michael@0: michael@0: my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; michael@0: my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #include "SkColorPriv.h" michael@0: michael@0: static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { michael@0: const int width = glyph.fWidth; michael@0: const size_t dstRB = (width + 7) >> 3; michael@0: uint8_t* SK_RESTRICT dst = static_cast(glyph.fImage); michael@0: michael@0: int byteCount = width >> 3; michael@0: int bitCount = width & 7; michael@0: michael@0: for (int y = 0; y < glyph.fHeight; ++y) { michael@0: if (byteCount > 0) { michael@0: for (int i = 0; i < byteCount; ++i) { michael@0: unsigned byte = 0; michael@0: byte |= src[0] & (1 << 7); michael@0: byte |= src[1] & (1 << 6); michael@0: byte |= src[2] & (1 << 5); michael@0: byte |= src[3] & (1 << 4); michael@0: byte |= src[4] & (1 << 3); michael@0: byte |= src[5] & (1 << 2); michael@0: byte |= src[6] & (1 << 1); michael@0: byte |= src[7] & (1 << 0); michael@0: dst[i] = byte; michael@0: src += 8; michael@0: } michael@0: } michael@0: if (bitCount > 0) { michael@0: unsigned byte = 0; michael@0: unsigned mask = 0x80; michael@0: for (int i = 0; i < bitCount; i++) { michael@0: byte |= (src[i]) & mask; michael@0: mask >>= 1; michael@0: } michael@0: dst[byteCount] = byte; michael@0: } michael@0: src += bitCount; michael@0: dst += dstRB; michael@0: } michael@0: } michael@0: michael@0: template michael@0: static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { michael@0: const size_t dstRB = glyph.rowBytes(); michael@0: const U16CPU width = glyph.fWidth; michael@0: uint8_t* SK_RESTRICT dst = static_cast(glyph.fImage); michael@0: michael@0: for (U16CPU y = 0; y < glyph.fHeight; y++) { michael@0: for (U16CPU i = 0; i < width; i++) { michael@0: U8CPU r = *(src++); michael@0: U8CPU g = *(src++); michael@0: U8CPU b = *(src++); michael@0: dst[i] = sk_apply_lut_if((r + g + b) / 3, table8); michael@0: } michael@0: dst = (uint8_t*)((char*)dst + dstRB); michael@0: } michael@0: } michael@0: michael@0: template michael@0: static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, michael@0: const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { michael@0: const size_t dstRB = glyph.rowBytes(); michael@0: const U16CPU width = glyph.fWidth; michael@0: uint16_t* SK_RESTRICT dst = static_cast(glyph.fImage); michael@0: michael@0: for (U16CPU y = 0; y < glyph.fHeight; y++) { michael@0: for (U16CPU i = 0; i < width; i++) { michael@0: U8CPU r = sk_apply_lut_if(*(src++), tableR); michael@0: U8CPU g = sk_apply_lut_if(*(src++), tableG); michael@0: U8CPU b = sk_apply_lut_if(*(src++), tableB); michael@0: dst[i] = SkPack888ToRGB16(r, g, b); michael@0: } michael@0: dst = (uint16_t*)((char*)dst + dstRB); michael@0: } michael@0: } michael@0: michael@0: template michael@0: static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, michael@0: const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { michael@0: const size_t dstRB = glyph.rowBytes(); michael@0: const U16CPU width = glyph.fWidth; michael@0: SkPMColor* SK_RESTRICT dst = static_cast(glyph.fImage); michael@0: michael@0: for (U16CPU y = 0; y < glyph.fHeight; y++) { michael@0: for (U16CPU i = 0; i < width; i++) { michael@0: U8CPU r = sk_apply_lut_if(*(src++), tableR); michael@0: U8CPU g = sk_apply_lut_if(*(src++), tableG); michael@0: U8CPU b = sk_apply_lut_if(*(src++), tableB); michael@0: dst[i] = SkPackARGB32(0xFF, r, g, b); michael@0: } michael@0: dst = (SkPMColor*)((char*)dst + dstRB); michael@0: } michael@0: } michael@0: michael@0: void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { michael@0: const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; michael@0: const bool isAA = !isLCD(fRec); michael@0: michael@0: //Create the mask. michael@0: const void* bits = fOffscreen.draw(glyph, isBW); michael@0: if (!bits) { michael@0: sk_bzero(glyph.fImage, glyph.computeImageSize()); michael@0: return; michael@0: } michael@0: michael@0: //Copy the mask into the glyph. michael@0: const uint8_t* src = (const uint8_t*)bits; michael@0: if (isBW) { michael@0: bilevel_to_bw(src, glyph); michael@0: } else if (isAA) { michael@0: if (fPreBlend.isApplicable()) { michael@0: rgb_to_a8(src, glyph, fPreBlend.fG); michael@0: } else { michael@0: rgb_to_a8(src, glyph, fPreBlend.fG); michael@0: } michael@0: } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { michael@0: if (fPreBlend.isApplicable()) { michael@0: rgb_to_lcd16(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); michael@0: } else { michael@0: rgb_to_lcd16(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); michael@0: } michael@0: } else { michael@0: SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); michael@0: if (fPreBlend.isApplicable()) { michael@0: rgb_to_lcd32(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); michael@0: } else { michael@0: rgb_to_lcd32(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { michael@0: SkASSERT(&glyph && path); michael@0: michael@0: path->reset(); michael@0: michael@0: SkTScopedComPtr geometryToPath; michael@0: HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), michael@0: "Could not create geometry to path converter."); michael@0: uint16_t glyphId = glyph.getGlyphID(); michael@0: //TODO: convert to<->from DIUs? This would make a difference if hinting. michael@0: //It may not be needed, it appears that DirectWrite only hints at em size. michael@0: HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fRec.fTextSize), michael@0: &glyphId, michael@0: NULL, //advances michael@0: NULL, //offsets michael@0: 1, //num glyphs michael@0: FALSE, //sideways michael@0: FALSE, //rtl michael@0: geometryToPath.get()), michael@0: "Could not create glyph outline."); michael@0: michael@0: SkMatrix mat; michael@0: fRec.getMatrixFrom2x2(&mat); michael@0: path->transform(mat); michael@0: } michael@0: michael@0: void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, michael@0: bool* isLocalStream) const { michael@0: // Get the family name. michael@0: SkTScopedComPtr dwFamilyNames; michael@0: HRV(fDWriteFontFamily->GetFamilyNames(&dwFamilyNames)); michael@0: michael@0: UINT32 dwFamilyNamesLength; michael@0: HRV(dwFamilyNames->GetStringLength(0, &dwFamilyNamesLength)); michael@0: michael@0: SkSMallocWCHAR dwFamilyNameChar(dwFamilyNamesLength+1); michael@0: HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.get(), dwFamilyNamesLength+1)); michael@0: michael@0: SkString utf8FamilyName; michael@0: HRV(wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName)); michael@0: michael@0: desc->setFamilyName(utf8FamilyName.c_str()); michael@0: *isLocalStream = SkToBool(fDWriteFontFileLoader.get()); michael@0: } michael@0: michael@0: static SkUnichar next_utf8(const void** chars) { michael@0: return SkUTF8_NextUnichar((const char**)chars); michael@0: } michael@0: michael@0: static SkUnichar next_utf16(const void** chars) { michael@0: return SkUTF16_NextUnichar((const uint16_t**)chars); michael@0: } michael@0: michael@0: static SkUnichar next_utf32(const void** chars) { michael@0: const SkUnichar** uniChars = (const SkUnichar**)chars; michael@0: SkUnichar uni = **uniChars; michael@0: *uniChars += 1; michael@0: return uni; michael@0: } michael@0: michael@0: typedef SkUnichar (*EncodingProc)(const void**); michael@0: michael@0: static EncodingProc find_encoding_proc(SkTypeface::Encoding enc) { michael@0: static const EncodingProc gProcs[] = { michael@0: next_utf8, next_utf16, next_utf32 michael@0: }; michael@0: SkASSERT((size_t)enc < SK_ARRAY_COUNT(gProcs)); michael@0: return gProcs[enc]; michael@0: } michael@0: michael@0: int DWriteFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding, michael@0: uint16_t glyphs[], int glyphCount) const michael@0: { michael@0: if (NULL == glyphs) { michael@0: EncodingProc next_ucs4_proc = find_encoding_proc(encoding); michael@0: for (int i = 0; i < glyphCount; ++i) { michael@0: const SkUnichar c = next_ucs4_proc(&chars); michael@0: BOOL exists; michael@0: fDWriteFont->HasCharacter(c, &exists); michael@0: if (!exists) { michael@0: return i; michael@0: } michael@0: } michael@0: return glyphCount; michael@0: } michael@0: michael@0: switch (encoding) { michael@0: case SkTypeface::kUTF8_Encoding: michael@0: case SkTypeface::kUTF16_Encoding: { michael@0: static const int scratchCount = 256; michael@0: UINT32 scratch[scratchCount]; michael@0: EncodingProc next_ucs4_proc = find_encoding_proc(encoding); michael@0: for (int baseGlyph = 0; baseGlyph < glyphCount; baseGlyph += scratchCount) { michael@0: int glyphsLeft = glyphCount - baseGlyph; michael@0: int limit = SkTMin(glyphsLeft, scratchCount); michael@0: for (int i = 0; i < limit; ++i) { michael@0: scratch[i] = next_ucs4_proc(&chars); michael@0: } michael@0: fDWriteFontFace->GetGlyphIndices(scratch, limit, &glyphs[baseGlyph]); michael@0: } michael@0: break; michael@0: } michael@0: case SkTypeface::kUTF32_Encoding: { michael@0: const UINT32* utf32 = reinterpret_cast(chars); michael@0: fDWriteFontFace->GetGlyphIndices(utf32, glyphCount, glyphs); michael@0: break; michael@0: } michael@0: default: michael@0: SK_CRASH(); michael@0: } michael@0: michael@0: for (int i = 0; i < glyphCount; ++i) { michael@0: if (0 == glyphs[i]) { michael@0: return i; michael@0: } michael@0: } michael@0: return glyphCount; michael@0: } michael@0: michael@0: int DWriteFontTypeface::onCountGlyphs() const { michael@0: return fDWriteFontFace->GetGlyphCount(); michael@0: } michael@0: michael@0: int DWriteFontTypeface::onGetUPEM() const { michael@0: DWRITE_FONT_METRICS metrics; michael@0: fDWriteFontFace->GetMetrics(&metrics); michael@0: return metrics.designUnitsPerEm; michael@0: } michael@0: michael@0: class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings { michael@0: public: michael@0: /** Takes ownership of the IDWriteLocalizedStrings. */ michael@0: explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings) michael@0: : fIndex(0), fStrings(strings) michael@0: { } michael@0: michael@0: virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE { michael@0: if (fIndex >= fStrings->GetCount()) { michael@0: return false; michael@0: } michael@0: michael@0: // String michael@0: UINT32 stringLength; michael@0: HRBM(fStrings->GetStringLength(fIndex, &stringLength), "Could not get string length."); michael@0: stringLength += 1; michael@0: michael@0: SkSMallocWCHAR wString(stringLength); michael@0: HRBM(fStrings->GetString(fIndex, wString.get(), stringLength), "Could not get string."); michael@0: michael@0: HRB(wchar_to_skstring(wString.get(), &localizedString->fString)); michael@0: michael@0: // Locale michael@0: UINT32 localeLength; michael@0: HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLength), "Could not get locale length."); michael@0: localeLength += 1; michael@0: michael@0: SkSMallocWCHAR wLocale(localeLength); michael@0: HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLength), "Could not get locale."); michael@0: michael@0: HRB(wchar_to_skstring(wLocale.get(), &localizedString->fLanguage)); michael@0: michael@0: ++fIndex; michael@0: return true; michael@0: } michael@0: michael@0: private: michael@0: UINT32 fIndex; michael@0: SkTScopedComPtr fStrings; michael@0: }; michael@0: michael@0: SkTypeface::LocalizedStrings* DWriteFontTypeface::onCreateFamilyNameIterator() const { michael@0: SkTScopedComPtr familyNames; michael@0: HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names."); michael@0: michael@0: return new LocalizedStrings_IDWriteLocalizedStrings(familyNames.release()); michael@0: } michael@0: michael@0: int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const { michael@0: DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType(); michael@0: if (type != DWRITE_FONT_FACE_TYPE_CFF && michael@0: type != DWRITE_FONT_FACE_TYPE_TRUETYPE && michael@0: type != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: int ttcIndex; michael@0: SkAutoTUnref stream(this->openStream(&ttcIndex)); michael@0: return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0; michael@0: } michael@0: michael@0: class AutoDWriteTable { michael@0: public: michael@0: AutoDWriteTable(IDWriteFontFace* fontFace, UINT32 beTag) : fFontFace(fontFace), fExists(FALSE) { michael@0: // Any errors are ignored, user must check fExists anyway. michael@0: fontFace->TryGetFontTable(beTag, michael@0: reinterpret_cast(&fData), &fSize, &fLock, &fExists); michael@0: } michael@0: ~AutoDWriteTable() { michael@0: if (fExists) { michael@0: fFontFace->ReleaseFontTable(fLock); michael@0: } michael@0: } michael@0: michael@0: const uint8_t* fData; michael@0: UINT32 fSize; michael@0: BOOL fExists; michael@0: private: michael@0: // Borrowed reference, the user must ensure the fontFace stays alive. michael@0: IDWriteFontFace* fFontFace; michael@0: void* fLock; michael@0: }; michael@0: michael@0: size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset, michael@0: size_t length, void* data) const michael@0: { michael@0: AutoDWriteTable table(fDWriteFontFace.get(), SkEndian_SwapBE32(tag)); michael@0: if (!table.fExists) { michael@0: return 0; michael@0: } michael@0: michael@0: if (offset > table.fSize) { michael@0: return 0; michael@0: } michael@0: size_t size = SkTMin(length, table.fSize - offset); michael@0: if (NULL != data) { michael@0: memcpy(data, table.fData + offset, size); michael@0: } michael@0: michael@0: return size; michael@0: } michael@0: michael@0: template class SkAutoIDWriteUnregister { michael@0: public: michael@0: SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister) michael@0: : fFactory(factory), fUnregister(unregister) michael@0: { } michael@0: michael@0: ~SkAutoIDWriteUnregister() { michael@0: if (fUnregister) { michael@0: unregister(fFactory, fUnregister); michael@0: } michael@0: } michael@0: michael@0: T* detatch() { michael@0: T* old = fUnregister; michael@0: fUnregister = NULL; michael@0: return old; michael@0: } michael@0: michael@0: private: michael@0: HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) { michael@0: return factory->UnregisterFontFileLoader(unregister); michael@0: } michael@0: michael@0: HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) { michael@0: return factory->UnregisterFontCollectionLoader(unregister); michael@0: } michael@0: michael@0: IDWriteFactory* fFactory; michael@0: T* fUnregister; michael@0: }; michael@0: michael@0: static SkTypeface* create_from_stream(SkStream* stream, int ttcIndex) { michael@0: IDWriteFactory* factory = get_dwrite_factory(); michael@0: if (NULL == factory) { michael@0: return NULL; michael@0: } michael@0: michael@0: SkTScopedComPtr fontFileLoader; michael@0: HRN(StreamFontFileLoader::Create(stream, &fontFileLoader)); michael@0: HRN(factory->RegisterFontFileLoader(fontFileLoader.get())); michael@0: SkAutoIDWriteUnregister autoUnregisterFontFileLoader( michael@0: factory, fontFileLoader.get()); michael@0: michael@0: SkTScopedComPtr fontCollectionLoader; michael@0: HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader)); michael@0: HRN(factory->RegisterFontCollectionLoader(fontCollectionLoader.get())); michael@0: SkAutoIDWriteUnregister autoUnregisterFontCollectionLoader( michael@0: factory, fontCollectionLoader.get()); michael@0: michael@0: SkTScopedComPtr fontCollection; michael@0: HRN(factory->CreateCustomFontCollection(fontCollectionLoader.get(), NULL, 0, &fontCollection)); michael@0: michael@0: // Find the first non-simulated font which has the given ttc index. michael@0: UINT32 familyCount = fontCollection->GetFontFamilyCount(); michael@0: for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) { michael@0: SkTScopedComPtr fontFamily; michael@0: HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily)); michael@0: michael@0: UINT32 fontCount = fontFamily->GetFontCount(); michael@0: for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) { michael@0: SkTScopedComPtr font; michael@0: HRN(fontFamily->GetFont(fontIndex, &font)); michael@0: if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) { michael@0: continue; michael@0: } michael@0: michael@0: SkTScopedComPtr fontFace; michael@0: HRN(font->CreateFontFace(&fontFace)); michael@0: michael@0: UINT32 faceIndex = fontFace->GetIndex(); michael@0: if (faceIndex == ttcIndex) { michael@0: return DWriteFontTypeface::Create(fontFace.get(), font.get(), fontFamily.get(), michael@0: autoUnregisterFontFileLoader.detatch(), michael@0: autoUnregisterFontCollectionLoader.detatch()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return NULL; michael@0: } michael@0: michael@0: SkStream* DWriteFontTypeface::onOpenStream(int* ttcIndex) const { michael@0: *ttcIndex = fDWriteFontFace->GetIndex(); michael@0: michael@0: UINT32 numFiles; michael@0: HRNM(fDWriteFontFace->GetFiles(&numFiles, NULL), michael@0: "Could not get number of font files."); michael@0: if (numFiles != 1) { michael@0: return NULL; michael@0: } michael@0: michael@0: SkTScopedComPtr fontFile; michael@0: HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files."); michael@0: michael@0: const void* fontFileKey; michael@0: UINT32 fontFileKeySize; michael@0: HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize), michael@0: "Could not get font file reference key."); michael@0: michael@0: SkTScopedComPtr fontFileLoader; michael@0: HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader."); michael@0: michael@0: SkTScopedComPtr fontFileStream; michael@0: HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize, michael@0: &fontFileStream), michael@0: "Could not create font file stream."); michael@0: michael@0: return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get())); michael@0: } michael@0: michael@0: SkScalerContext* DWriteFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const { michael@0: return SkNEW_ARGS(SkScalerContext_DW, (const_cast(this), desc)); michael@0: } michael@0: michael@0: void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const { michael@0: if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag || michael@0: rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) michael@0: { michael@0: rec->fMaskFormat = SkMask::kA8_Format; michael@0: } michael@0: michael@0: unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | michael@0: SkScalerContext::kForceAutohinting_Flag | michael@0: SkScalerContext::kEmbeddedBitmapText_Flag | michael@0: SkScalerContext::kEmbolden_Flag | michael@0: SkScalerContext::kLCD_BGROrder_Flag | michael@0: SkScalerContext::kLCD_Vertical_Flag; michael@0: rec->fFlags &= ~flagsWeDontSupport; michael@0: michael@0: SkPaint::Hinting h = rec->getHinting(); michael@0: // DirectWrite does not provide for hinting hints. michael@0: h = SkPaint::kSlight_Hinting; michael@0: rec->setHinting(h); michael@0: michael@0: #if SK_FONT_HOST_USE_SYSTEM_SETTINGS michael@0: IDWriteFactory* factory = get_dwrite_factory(); michael@0: if (factory != NULL) { michael@0: SkTScopedComPtr defaultRenderingParams; michael@0: if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) { michael@0: float gamma = defaultRenderingParams->GetGamma(); michael@0: rec->setDeviceGamma(gamma); michael@0: rec->setPaintGamma(gamma); michael@0: michael@0: rec->setContrast(defaultRenderingParams->GetEnhancedContrast()); michael@0: } michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: //PDF Support michael@0: michael@0: using namespace skia_advanced_typeface_metrics_utils; michael@0: michael@0: // Construct Glyph to Unicode table. michael@0: // Unicode code points that require conjugate pairs in utf16 are not michael@0: // supported. michael@0: // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may michael@0: // require parsing the TTF cmap table (platform 4, encoding 12) directly instead michael@0: // of calling GetFontUnicodeRange(). michael@0: // TODO(bungeman): This never does what anyone wants. michael@0: // What is really wanted is the text to glyphs mapping michael@0: static void populate_glyph_to_unicode(IDWriteFontFace* fontFace, michael@0: const unsigned glyphCount, michael@0: SkTDArray* glyphToUnicode) { michael@0: HRESULT hr = S_OK; michael@0: michael@0: //Do this like free type instead michael@0: UINT32 count = 0; michael@0: for (UINT32 c = 0; c < 0x10FFFF; ++c) { michael@0: UINT16 glyph; michael@0: hr = fontFace->GetGlyphIndices(&c, 1, &glyph); michael@0: if (glyph > 0) { michael@0: ++count; michael@0: } michael@0: } michael@0: michael@0: SkAutoTArray chars(count); michael@0: count = 0; michael@0: for (UINT32 c = 0; c < 0x10FFFF; ++c) { michael@0: UINT16 glyph; michael@0: hr = fontFace->GetGlyphIndices(&c, 1, &glyph); michael@0: if (glyph > 0) { michael@0: chars[count] = c; michael@0: ++count; michael@0: } michael@0: } michael@0: michael@0: SkAutoTArray glyph(count); michael@0: fontFace->GetGlyphIndices(chars.get(), count, glyph.get()); michael@0: michael@0: USHORT maxGlyph = 0; michael@0: for (USHORT j = 0; j < count; ++j) { michael@0: if (glyph[j] > maxGlyph) maxGlyph = glyph[j]; michael@0: } michael@0: michael@0: glyphToUnicode->setCount(maxGlyph+1); michael@0: for (USHORT j = 0; j < maxGlyph+1u; ++j) { michael@0: (*glyphToUnicode)[j] = 0; michael@0: } michael@0: michael@0: //'invert' michael@0: for (USHORT j = 0; j < count; ++j) { michael@0: if (glyph[j] < glyphCount && (*glyphToUnicode)[glyph[j]] == 0) { michael@0: (*glyphToUnicode)[glyph[j]] = chars[j]; michael@0: } michael@0: } michael@0: } michael@0: michael@0: static bool getWidthAdvance(IDWriteFontFace* fontFace, int gId, int16_t* advance) { michael@0: SkASSERT(advance); michael@0: michael@0: UINT16 glyphId = gId; michael@0: DWRITE_GLYPH_METRICS gm; michael@0: HRESULT hr = fontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm); michael@0: michael@0: if (FAILED(hr)) { michael@0: *advance = 0; michael@0: return false; michael@0: } michael@0: michael@0: *advance = gm.advanceWidth; michael@0: return true; michael@0: } michael@0: michael@0: template class AutoTDWriteTable : public AutoDWriteTable { michael@0: public: michael@0: static const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3); michael@0: AutoTDWriteTable(IDWriteFontFace* fontFace) : AutoDWriteTable(fontFace, tag) { } michael@0: michael@0: const T* operator->() const { return reinterpret_cast(fData); } michael@0: }; michael@0: michael@0: SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics( michael@0: SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, michael@0: const uint32_t* glyphIDs, michael@0: uint32_t glyphIDsCount) const { michael@0: michael@0: SkAdvancedTypefaceMetrics* info = NULL; michael@0: michael@0: HRESULT hr = S_OK; michael@0: michael@0: const unsigned glyphCount = fDWriteFontFace->GetGlyphCount(); michael@0: michael@0: DWRITE_FONT_METRICS dwfm; michael@0: fDWriteFontFace->GetMetrics(&dwfm); michael@0: michael@0: info = new SkAdvancedTypefaceMetrics; michael@0: info->fEmSize = dwfm.designUnitsPerEm; michael@0: info->fMultiMaster = false; michael@0: info->fLastGlyphID = SkToU16(glyphCount - 1); michael@0: info->fStyle = 0; michael@0: michael@0: michael@0: SkTScopedComPtr familyNames; michael@0: SkTScopedComPtr faceNames; michael@0: hr = fDWriteFontFamily->GetFamilyNames(&familyNames); michael@0: hr = fDWriteFont->GetFaceNames(&faceNames); michael@0: michael@0: UINT32 familyNameLength; michael@0: hr = familyNames->GetStringLength(0, &familyNameLength); michael@0: michael@0: UINT32 faceNameLength; michael@0: hr = faceNames->GetStringLength(0, &faceNameLength); michael@0: michael@0: UINT32 size = familyNameLength+1+faceNameLength+1; michael@0: SkSMallocWCHAR wFamilyName(size); michael@0: hr = familyNames->GetString(0, wFamilyName.get(), size); michael@0: wFamilyName[familyNameLength] = L' '; michael@0: hr = faceNames->GetString(0, &wFamilyName[familyNameLength+1], size - faceNameLength + 1); michael@0: michael@0: hr = wchar_to_skstring(wFamilyName.get(), &info->fFontName); michael@0: michael@0: if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { michael@0: populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode)); michael@0: } michael@0: michael@0: DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType(); michael@0: if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE || michael@0: fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) { michael@0: info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; michael@0: } else { michael@0: info->fType = SkAdvancedTypefaceMetrics::kOther_Font; michael@0: info->fItalicAngle = 0; michael@0: info->fAscent = dwfm.ascent;; michael@0: info->fDescent = dwfm.descent; michael@0: info->fStemV = 0; michael@0: info->fCapHeight = dwfm.capHeight; michael@0: info->fBBox = SkIRect::MakeEmpty(); michael@0: return info; michael@0: } michael@0: michael@0: AutoTDWriteTable headTable(fDWriteFontFace.get()); michael@0: AutoTDWriteTable postTable(fDWriteFontFace.get()); michael@0: AutoTDWriteTable hheaTable(fDWriteFontFace.get()); michael@0: AutoTDWriteTable os2Table(fDWriteFontFace.get()); michael@0: if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) { michael@0: info->fItalicAngle = 0; michael@0: info->fAscent = dwfm.ascent;; michael@0: info->fDescent = dwfm.descent; michael@0: info->fStemV = 0; michael@0: info->fCapHeight = dwfm.capHeight; michael@0: info->fBBox = SkIRect::MakeEmpty(); michael@0: return info; michael@0: } michael@0: michael@0: //There exist CJK fonts which set the IsFixedPitch and Monospace bits, michael@0: //but have full width, latin half-width, and half-width kana. michael@0: bool fixedWidth = (postTable->isFixedPitch && michael@0: (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics))); michael@0: //Monospace michael@0: if (fixedWidth) { michael@0: info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; michael@0: } michael@0: //Italic michael@0: if (os2Table->version.v0.fsSelection.field.Italic) { michael@0: info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; michael@0: } michael@0: //Script michael@0: if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType.value) { michael@0: info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; michael@0: //Serif michael@0: } else if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType.value && michael@0: SkPanose::Data::TextAndDisplay::SerifStyle::Triangle <= os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value && michael@0: SkPanose::Data::TextAndDisplay::SerifStyle::NoFit != os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value) { michael@0: info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; michael@0: } michael@0: michael@0: info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16; michael@0: michael@0: info->fAscent = SkToS16(dwfm.ascent); michael@0: info->fDescent = SkToS16(dwfm.descent); michael@0: info->fCapHeight = SkToS16(dwfm.capHeight); michael@0: michael@0: info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin), michael@0: (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax), michael@0: (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax), michael@0: (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin)); michael@0: michael@0: //TODO: is this even desired? It seems PDF only wants this value for Type1 michael@0: //fonts, and we only get here for TrueType fonts. michael@0: info->fStemV = 0; michael@0: /* michael@0: // Figure out a good guess for StemV - Min width of i, I, !, 1. michael@0: // This probably isn't very good with an italic font. michael@0: int16_t min_width = SHRT_MAX; michael@0: info->fStemV = 0; michael@0: char stem_chars[] = {'i', 'I', '!', '1'}; michael@0: for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) { michael@0: ABC abcWidths; michael@0: if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) { michael@0: int16_t width = abcWidths.abcB; michael@0: if (width > 0 && width < min_width) { michael@0: min_width = width; michael@0: info->fStemV = min_width; michael@0: } michael@0: } michael@0: } michael@0: */ michael@0: michael@0: // If Restricted, the font may not be embedded in a document. michael@0: // If not Restricted, the font can be embedded. michael@0: // If PreviewPrint, the embedding is read-only. michael@0: if (os2Table->version.v0.fsType.field.Restricted) { michael@0: info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; michael@0: } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { michael@0: if (fixedWidth) { michael@0: appendRange(&info->fGlyphWidths, 0); michael@0: int16_t advance; michael@0: getWidthAdvance(fDWriteFontFace.get(), 1, &advance); michael@0: info->fGlyphWidths->fAdvance.append(1, &advance); michael@0: finishRange(info->fGlyphWidths.get(), 0, michael@0: SkAdvancedTypefaceMetrics::WidthRange::kDefault); michael@0: } else { michael@0: info->fGlyphWidths.reset( michael@0: getAdvanceData(fDWriteFontFace.get(), michael@0: glyphCount, michael@0: glyphIDs, michael@0: glyphIDsCount, michael@0: getWidthAdvance)); michael@0: } michael@0: } michael@0: michael@0: return info; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static void get_locale_string(IDWriteLocalizedStrings* names, const WCHAR* preferedLocale, michael@0: SkString* skname) { michael@0: UINT32 nameIndex = 0; michael@0: if (preferedLocale) { michael@0: // Ignore any errors and continue with index 0 if there is a problem. michael@0: BOOL nameExists; michael@0: names->FindLocaleName(preferedLocale, &nameIndex, &nameExists); michael@0: if (!nameExists) { michael@0: nameIndex = 0; michael@0: } michael@0: } michael@0: michael@0: UINT32 nameLength; michael@0: HRVM(names->GetStringLength(nameIndex, &nameLength), "Could not get name length."); michael@0: nameLength += 1; michael@0: michael@0: SkSMallocWCHAR name(nameLength); michael@0: HRVM(names->GetString(nameIndex, name.get(), nameLength), "Could not get string."); michael@0: michael@0: HRV(wchar_to_skstring(name.get(), skname)); michael@0: } michael@0: michael@0: SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont( michael@0: IDWriteFontFace* fontFace, michael@0: IDWriteFont* font, michael@0: IDWriteFontFamily* fontFamily, michael@0: StreamFontFileLoader* fontFileLoader, michael@0: IDWriteFontCollectionLoader* fontCollectionLoader) const { michael@0: SkTypeface* face = FindByProcAndRef(FindByDWriteFont, font); michael@0: if (NULL == face) { michael@0: face = DWriteFontTypeface::Create(fontFace, font, fontFamily, michael@0: fontFileLoader, fontCollectionLoader); michael@0: if (face) { michael@0: Add(face, get_style(font), fontCollectionLoader != NULL); michael@0: } michael@0: } michael@0: return face; michael@0: } michael@0: michael@0: int SkFontMgr_DirectWrite::onCountFamilies() const { michael@0: return fFontCollection->GetFontFamilyCount(); michael@0: } michael@0: michael@0: void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const { michael@0: SkTScopedComPtr fontFamily; michael@0: HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family."); michael@0: michael@0: SkTScopedComPtr familyNames; michael@0: HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names."); michael@0: michael@0: get_locale_string(familyNames.get(), fLocaleName.get(), familyName); michael@0: } michael@0: michael@0: SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const { michael@0: SkTScopedComPtr fontFamily; michael@0: HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family."); michael@0: michael@0: return SkNEW_ARGS(SkFontStyleSet_DirectWrite, (this, fontFamily.get())); michael@0: } michael@0: michael@0: SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const { michael@0: SkSMallocWCHAR dwFamilyName; michael@0: HRN(cstring_to_wchar(familyName, &dwFamilyName)); michael@0: michael@0: UINT32 index; michael@0: BOOL exists; michael@0: HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), michael@0: "Failed while finding family by name."); michael@0: if (!exists) { michael@0: return NULL; michael@0: } michael@0: michael@0: return this->onCreateStyleSet(index); michael@0: } michael@0: michael@0: SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[], michael@0: const SkFontStyle& fontstyle) const { michael@0: SkAutoTUnref sset(this->matchFamily(familyName)); michael@0: return sset->matchStyle(fontstyle); michael@0: } michael@0: michael@0: SkTypeface* SkFontMgr_DirectWrite::onMatchFaceStyle(const SkTypeface* familyMember, michael@0: const SkFontStyle& fontstyle) const { michael@0: SkString familyName; michael@0: SkFontStyleSet_DirectWrite sset( michael@0: this, ((DWriteFontTypeface*)familyMember)->fDWriteFontFamily.get() michael@0: ); michael@0: return sset.matchStyle(fontstyle); michael@0: } michael@0: michael@0: SkTypeface* SkFontMgr_DirectWrite::onCreateFromStream(SkStream* stream, int ttcIndex) const { michael@0: return create_from_stream(stream, ttcIndex); michael@0: } michael@0: michael@0: SkTypeface* SkFontMgr_DirectWrite::onCreateFromData(SkData* data, int ttcIndex) const { michael@0: SkAutoTUnref stream(SkNEW_ARGS(SkMemoryStream, (data))); michael@0: return this->createFromStream(stream, ttcIndex); michael@0: } michael@0: michael@0: SkTypeface* SkFontMgr_DirectWrite::onCreateFromFile(const char path[], int ttcIndex) const { michael@0: SkAutoTUnref stream(SkStream::NewFromFile(path)); michael@0: return this->createFromStream(stream, ttcIndex); michael@0: } michael@0: michael@0: HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[], michael@0: IDWriteFontFamily** fontFamily) const { michael@0: UINT32 index; michael@0: BOOL exists; michael@0: HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists)); michael@0: michael@0: if (exists) { michael@0: HR(fFontCollection->GetFontFamily(index, fontFamily)); michael@0: return S_OK; michael@0: } michael@0: return S_FALSE; michael@0: } michael@0: michael@0: HRESULT SkFontMgr_DirectWrite::getDefaultFontFamily(IDWriteFontFamily** fontFamily) const { michael@0: NONCLIENTMETRICSW metrics; michael@0: metrics.cbSize = sizeof(metrics); michael@0: if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, michael@0: sizeof(metrics), michael@0: &metrics, michael@0: 0)) { michael@0: return E_UNEXPECTED; michael@0: } michael@0: HRM(this->getByFamilyName(metrics.lfMessageFont.lfFaceName, fontFamily), michael@0: "Could not create DWrite font family from LOGFONT."); michael@0: michael@0: return S_OK; michael@0: } michael@0: michael@0: SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[], michael@0: unsigned styleBits) const { michael@0: SkTScopedComPtr fontFamily; michael@0: if (familyName) { michael@0: SkSMallocWCHAR wideFamilyName; michael@0: if (SUCCEEDED(cstring_to_wchar(familyName, &wideFamilyName))) { michael@0: this->getByFamilyName(wideFamilyName, &fontFamily); michael@0: } michael@0: } michael@0: michael@0: if (NULL == fontFamily.get()) { michael@0: // No family with given name, try default. michael@0: HRNM(this->getDefaultFontFamily(&fontFamily), "Could not get default font family."); michael@0: } michael@0: michael@0: SkTScopedComPtr font; michael@0: DWRITE_FONT_WEIGHT weight = (styleBits & SkTypeface::kBold) michael@0: ? DWRITE_FONT_WEIGHT_BOLD michael@0: : DWRITE_FONT_WEIGHT_NORMAL; michael@0: DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL; michael@0: DWRITE_FONT_STYLE italic = (styleBits & SkTypeface::kItalic) michael@0: ? DWRITE_FONT_STYLE_ITALIC michael@0: : DWRITE_FONT_STYLE_NORMAL; michael@0: HRNM(fontFamily->GetFirstMatchingFont(weight, stretch, italic, &font), michael@0: "Could not get matching font."); michael@0: michael@0: SkTScopedComPtr fontFace; michael@0: HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); michael@0: michael@0: return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get()); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: int SkFontStyleSet_DirectWrite::count() { michael@0: return fFontFamily->GetFontCount(); michael@0: } michael@0: michael@0: SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) { michael@0: SkTScopedComPtr font; michael@0: HRNM(fFontFamily->GetFont(index, &font), "Could not get font."); michael@0: michael@0: SkTScopedComPtr fontFace; michael@0: HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); michael@0: michael@0: return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()); michael@0: } michael@0: michael@0: void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) { michael@0: SkTScopedComPtr font; michael@0: HRVM(fFontFamily->GetFont(index, &font), "Could not get font."); michael@0: michael@0: SkFontStyle::Slant slant; michael@0: switch (font->GetStyle()) { michael@0: case DWRITE_FONT_STYLE_NORMAL: michael@0: slant = SkFontStyle::kUpright_Slant; michael@0: break; michael@0: case DWRITE_FONT_STYLE_OBLIQUE: michael@0: case DWRITE_FONT_STYLE_ITALIC: michael@0: slant = SkFontStyle::kItalic_Slant; michael@0: break; michael@0: default: michael@0: SkASSERT(false); michael@0: } michael@0: michael@0: int weight = font->GetWeight(); michael@0: int width = font->GetStretch(); michael@0: michael@0: *fs = SkFontStyle(weight, width, slant); michael@0: michael@0: SkTScopedComPtr faceNames; michael@0: if (SUCCEEDED(font->GetFaceNames(&faceNames))) { michael@0: get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName); michael@0: } michael@0: } michael@0: michael@0: SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) { michael@0: DWRITE_FONT_STYLE slant; michael@0: switch (pattern.slant()) { michael@0: case SkFontStyle::kUpright_Slant: michael@0: slant = DWRITE_FONT_STYLE_NORMAL; michael@0: break; michael@0: case SkFontStyle::kItalic_Slant: michael@0: slant = DWRITE_FONT_STYLE_ITALIC; michael@0: break; michael@0: default: michael@0: SkASSERT(false); michael@0: } michael@0: michael@0: DWRITE_FONT_WEIGHT weight = (DWRITE_FONT_WEIGHT)pattern.weight(); michael@0: DWRITE_FONT_STRETCH width = (DWRITE_FONT_STRETCH)pattern.width(); michael@0: michael@0: SkTScopedComPtr font; michael@0: // TODO: perhaps use GetMatchingFonts and get the least simulated? michael@0: HRNM(fFontFamily->GetFirstMatchingFont(weight, width, slant, &font), michael@0: "Could not match font in family."); michael@0: michael@0: SkTScopedComPtr fontFace; michael@0: HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); michael@0: michael@0: return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), michael@0: fFontFamily.get()); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: typedef decltype(GetUserDefaultLocaleName)* GetUserDefaultLocaleNameProc; michael@0: static HRESULT GetGetUserDefaultLocaleNameProc(GetUserDefaultLocaleNameProc* proc) { michael@0: *proc = reinterpret_cast( michael@0: GetProcAddress(LoadLibraryW(L"Kernel32.dll"), "GetUserDefaultLocaleName") michael@0: ); michael@0: if (!*proc) { michael@0: HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); michael@0: if (!IS_ERROR(hr)) { michael@0: hr = ERROR_PROC_NOT_FOUND; michael@0: } michael@0: return hr; michael@0: } michael@0: return S_OK; michael@0: } michael@0: michael@0: SkFontMgr* SkFontMgr_New_DirectWrite() { michael@0: IDWriteFactory* factory = get_dwrite_factory(); michael@0: if (NULL == factory) { michael@0: return NULL; michael@0: } michael@0: michael@0: SkTScopedComPtr sysFontCollection; michael@0: HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE), michael@0: "Could not get system font collection."); michael@0: michael@0: WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH]; michael@0: WCHAR* localeName = NULL; michael@0: int localeNameLen = 0; michael@0: michael@0: // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP. michael@0: GetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL; michael@0: HRESULT hr = GetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); michael@0: if (NULL == getUserDefaultLocaleNameProc) { michael@0: SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); michael@0: } else { michael@0: localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH); michael@0: if (localeNameLen) { michael@0: localeName = localeNameStorage; michael@0: }; michael@0: } michael@0: michael@0: return SkNEW_ARGS(SkFontMgr_DirectWrite, (sysFontCollection.get(), localeName, localeNameLen)); michael@0: }