/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkTypes.h" #undef GetGlyphIndices #include "SkAdvancedTypefaceMetrics.h" #include "SkColorFilter.h" #include "SkDWriteFontFileStream.h" #include "SkDWriteGeometrySink.h" #include "SkDescriptor.h" #include "SkEndian.h" #include "SkFontDescriptor.h" #include "SkFontHost.h" #include "SkGlyph.h" #include "SkHRESULT.h" #include "SkMaskGamma.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 "SkTScopedComPtr.h" #include "SkThread.h" #include "SkTypeface_win.h" #include "SkTypefaceCache.h" #include "SkUtils.h" #include SK_DECLARE_STATIC_MUTEX(gFTMutex); static bool isLCD(const SkScalerContext::Rec& rec) { return SkMask::kLCD16_Format == rec.fMaskFormat || SkMask::kLCD32_Format == rec.fMaskFormat; } SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { // Zero means that we don't have any fallback fonts for this fontID. // This function is implemented on Android, but doesn't have much // meaning here. return 0; } /////////////////////////////////////////////////////////////////////////////// class DWriteOffscreen { public: DWriteOffscreen() : fWidth(0), fHeight(0) { } void init(IDWriteFontFace* fontFace, const DWRITE_MATRIX& xform, FLOAT fontSize) { fFontFace = fontFace; fFontSize = fontSize; fXform = xform; } const void* draw(const SkGlyph&, bool isBW); private: uint16_t fWidth; uint16_t fHeight; IDWriteFontFace* fFontFace; FLOAT fFontSize; DWRITE_MATRIX fXform; SkTDArray fBits; }; typedef HRESULT (WINAPI *DWriteCreateFactoryProc)( __in DWRITE_FACTORY_TYPE factoryType, __in REFIID iid, __out IUnknown **factory ); static HRESULT get_dwrite_factory(IDWriteFactory** factory) { static IDWriteFactory* gDWriteFactory = NULL; if (gDWriteFactory != NULL) { *factory = gDWriteFactory; return S_OK; } DWriteCreateFactoryProc dWriteCreateFactoryProc = reinterpret_cast( GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory") ) ; if (!dWriteCreateFactoryProc) { return E_UNEXPECTED; } HRM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast(&gDWriteFactory)), "Could not create DirectWrite factory."); *factory = gDWriteFactory; return S_OK; } const void* DWriteOffscreen::draw(const SkGlyph& glyph, bool isBW) { IDWriteFactory* factory; HRNM(get_dwrite_factory(&factory), "Could not get factory."); if (fWidth < glyph.fWidth || fHeight < glyph.fHeight) { fWidth = SkMax32(fWidth, glyph.fWidth); fHeight = SkMax32(fHeight, glyph.fHeight); if (isBW) { fBits.setCount(fWidth * fHeight); } else { fBits.setCount(fWidth * fHeight * 3); } } // erase memset(fBits.begin(), 0, fBits.count()); fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); FLOAT advance = 0.0f; UINT16 index = glyph.getGlyphID(); DWRITE_GLYPH_OFFSET offset; offset.advanceOffset = 0.0f; offset.ascenderOffset = 0.0f; DWRITE_GLYPH_RUN run; run.glyphCount = 1; run.glyphAdvances = &advance; run.fontFace = fFontFace; run.fontEmSize = fFontSize; run.bidiLevel = 0; run.glyphIndices = &index; run.isSideways = FALSE; run.glyphOffsets = &offset; DWRITE_RENDERING_MODE renderingMode; DWRITE_TEXTURE_TYPE textureType; if (isBW) { renderingMode = DWRITE_RENDERING_MODE_ALIASED; textureType = DWRITE_TEXTURE_ALIASED_1x1; } else { renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; textureType = DWRITE_TEXTURE_CLEARTYPE_3x1; } SkTScopedComPtr glyphRunAnalysis; HRNM(factory->CreateGlyphRunAnalysis(&run, 1.0f, // pixelsPerDip, &fXform, renderingMode, DWRITE_MEASURING_MODE_NATURAL, 0.0f, // baselineOriginX, 0.0f, // baselineOriginY, &glyphRunAnalysis), "Could not create glyph run analysis."); //NOTE: this assumes that the glyph has already been measured //with an exact same glyph run analysis. RECT bbox; bbox.left = glyph.fLeft; bbox.top = glyph.fTop; bbox.right = glyph.fLeft + glyph.fWidth; bbox.bottom = glyph.fTop + glyph.fHeight; HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, &bbox, fBits.begin(), fBits.count()), "Could not draw mask."); return fBits.begin(); } /////////////////////////////////////////////////////////////////////////////// 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 fStream; private: StreamFontFileLoader(SkStream* stream) : fRefCount(1), fStream(stream) { stream->ref(); } 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 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 fFactory; SkTScopedComPtr fCurrentFile; SkTScopedComPtr fFontFileLoader; bool fHasNext; }; StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader) : fRefCount(1) , fFactory(factory) , fCurrentFile() , fFontFileLoader(fontFileLoader) , fHasNext(true) { factory->AddRef(); fontFileLoader->AddRef(); } 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; } fCurrentFile.get()->AddRef(); *fontFile = 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(fontFileLoader) { fontFileLoader->AddRef(); } ULONG fRefCount; SkTScopedComPtr 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 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(style); } class DWriteFontTypeface : public SkTypeface { private: DWriteFontTypeface(SkTypeface::Style style, SkFontID fontID, IDWriteFontFace* fontFace, IDWriteFont* font, IDWriteFontFamily* fontFamily, StreamFontFileLoader* fontFileLoader = NULL, IDWriteFontCollectionLoader* fontCollectionLoader = NULL) : SkTypeface(style, fontID, false) , fDWriteFontCollectionLoader(fontCollectionLoader) , fDWriteFontFileLoader(fontFileLoader) , fDWriteFontFamily(fontFamily) , fDWriteFont(font) , fDWriteFontFace(fontFace) { if (fontCollectionLoader != NULL) { fontCollectionLoader->AddRef(); } if (fontFileLoader != NULL) { fontFileLoader->AddRef(); } fontFamily->AddRef(); font->AddRef(); fontFace->AddRef(); } public: SkTScopedComPtr fDWriteFontCollectionLoader; SkTScopedComPtr fDWriteFontFileLoader; SkTScopedComPtr fDWriteFontFamily; SkTScopedComPtr fDWriteFont; SkTScopedComPtr fDWriteFontFace; static DWriteFontTypeface* Create(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, fontFace, font, fontFamily, fontFileLoader, fontCollectionLoader)); } ~DWriteFontTypeface() { if (fDWriteFontCollectionLoader.get() == NULL) return; IDWriteFactory* factory; HRVM(get_dwrite_factory(&factory), "Could not get factory."); HRV(factory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get())); HRV(factory->UnregisterFontFileLoader(fDWriteFontFileLoader.get())); } }; class SkScalerContext_Windows : public SkScalerContext { public: SkScalerContext_Windows(const SkDescriptor* desc); virtual ~SkScalerContext_Windows(); 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: DWriteOffscreen fOffscreen; DWRITE_MATRIX fXform; SkAutoTUnref fTypeface; int fGlyphCount; }; #define SK_DWRITE_DEFAULT_FONT_NAMED 1 #define SK_DWRITE_DEFAULT_FONT_MESSAGE 2 #define SK_DWRITE_DEFAULT_FONT_THEME 3 #define SK_DWRITE_DEFAULT_FONT_SHELLDLG 4 #define SK_DWRITE_DEFAULT_FONT_GDI 5 #define SK_DWRITE_DEFAULT_FONT_STRATEGY SK_DWRITE_DEFAULT_FONT_MESSAGE static HRESULT get_default_font(IDWriteFont** font) { IDWriteFactory* factory; HRM(get_dwrite_factory(&factory), "Could not get factory."); #if SK_DWRITE_DEFAULT_FONT_STRATEGY == SK_DWRITE_DEFAULT_FONT_NAMED SkTScopedComPtr sysFonts; HRM(factory->GetSystemFontCollection(&sysFonts, false), "Could not get system font collection."); UINT32 index; BOOL exists; //hr = sysFonts->FindFamilyName(L"Georgia", &index, &exists); HRM(sysFonts->FindFamilyName(L"Microsoft Sans Serif", &index, &exists), "Could not access family names."); if (!exists) { SkDEBUGF(("The hard coded font family does not exist.")); return E_UNEXPECTED; } SkTScopedComPtr fontFamily; HRM(sysFonts->GetFontFamily(index, &fontFamily), "Could not load the requested font family."); HRM(fontFamily->GetFont(0, font), "Could not get first font from family."); #elif SK_DWRITE_DEFAULT_FONT_STRATEGY == SK_DWRITE_DEFAULT_FONT_MESSAGE SkTScopedComPtr gdi; HRM(factory->GetGdiInterop(&gdi), "Could not get GDI interop."); NONCLIENTMETRICSW metrics; metrics.cbSize = sizeof(metrics); if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) { return E_UNEXPECTED; } HRM(gdi->CreateFontFromLOGFONT(&metrics.lfMessageFont, font), "Could not create DWrite font from LOGFONT."); #elif SK_DWRITE_DEFAULT_FONT_STRATEGY == SK_DWRITE_DEFAULT_FONT_THEME //Theme body font? #elif SK_DWRITE_DEFAULT_FONT_STRATEGY == SK_DWRITE_DEFAULT_FONT_SHELLDLG //"MS Shell Dlg" or "MS Shell Dlg 2"? #elif SK_DWRITE_DEFAULT_FONT_STRATEGY == SK_DWRITE_DEFAULT_FONT_GDI //Never works. SkTScopedComPtr gdi; HRM(factory->GetGdiInterop(&gdi), "Could not get GDI interop."); static LOGFONTW gDefaultFont = {}; gDefaultFont.lfFaceName HRM(gdi->CreateFontFromLOGFONT(&gDefaultFont, font), "Could not create DWrite font from LOGFONT."; #endif return S_OK; } static bool are_same(IUnknown* a, IUnknown* b) { SkTScopedComPtr iunkA; if (FAILED(a->QueryInterface(&iunkA))) { return false; } SkTScopedComPtr 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(face); IDWriteFont* dwFont = reinterpret_cast(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 dwFaceFontFace; SkTScopedComPtr 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 dwFaceFontFile; SkTScopedComPtr dwFontFile; HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, &dwFaceFontFile)); HRB(dwFontFace->GetFiles(&dwNumFiles, &dwFontFile)); //for (each file) { //we currently only admit fonts from one file. SkTScopedComPtr dwFaceFontFileLoader; SkTScopedComPtr 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 dwFaceFontFamily; SkTScopedComPtr dwFontFamily; HRB(dwFace->fDWriteFont->GetFontFamily(&dwFaceFontFamily)); HRB(dwFont->GetFontFamily(&dwFontFamily)); SkTScopedComPtr dwFaceFontFamilyNames; SkTScopedComPtr dwFaceFontNames; HRB(dwFaceFontFamily->GetFamilyNames(&dwFaceFontFamilyNames)); HRB(dwFace->fDWriteFont->GetFaceNames(&dwFaceFontNames)); SkTScopedComPtr dwFontFamilyNames; SkTScopedComPtr 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; } SkTDArray dwFaceFontFamilyNameChar(new wchar_t[dwFaceFontFamilyNameLength+1], dwFaceFontFamilyNameLength+1); SkTDArray dwFaceFontNameChar(new wchar_t[dwFaceFontNameLength+1], dwFaceFontNameLength+1); HRB(dwFaceFontFamilyNames->GetString(0, dwFaceFontFamilyNameChar.begin(), dwFaceFontFamilyNameChar.count())); HRB(dwFaceFontNames->GetString(0, dwFaceFontNameChar.begin(), dwFaceFontNameChar.count())); SkTDArray dwFontFamilyNameChar(new wchar_t[dwFontFamilyNameLength+1], dwFontFamilyNameLength+1); SkTDArray dwFontNameChar(new wchar_t[dwFontNameLength+1], dwFontNameLength+1); HRB(dwFontFamilyNames->GetString(0, dwFontFamilyNameChar.begin(), dwFontFamilyNameChar.count())); HRB(dwFontNames->GetString(0, dwFontNameChar.begin(), dwFontNameChar.count())); return wcscmp(dwFaceFontFamilyNameChar.begin(), dwFontFamilyNameChar.begin()) == 0 && wcscmp(dwFaceFontNameChar.begin(), dwFontNameChar.begin()) == 0; } SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFontFace* fontFace, IDWriteFont* font, IDWriteFontFamily* fontFamily, StreamFontFileLoader* fontFileLoader = NULL, IDWriteFontCollectionLoader* fontCollectionLoader = NULL) { SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByDWriteFont, font); if (NULL == face) { face = DWriteFontTypeface::Create(fontFace, font, fontFamily, fontFileLoader, fontCollectionLoader); SkTypefaceCache::Add(face, get_style(font), fontCollectionLoader != NULL); } return face; } void SkDWriteFontFromTypeface(const SkTypeface* face, IDWriteFont** font) { if (NULL == face) { HRVM(get_default_font(font), "Could not get default font."); } else { *font = static_cast(face)->fDWriteFont.get(); (*font)->AddRef(); } } static DWriteFontTypeface* GetDWriteFontByID(SkFontID fontID) { return static_cast(SkTypefaceCache::FindByID(fontID)); } SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) : SkScalerContext(desc) , fGlyphCount(-1) { SkAutoMutexAcquire ac(gFTMutex); fXform.m11 = SkScalarToFloat(fRec.fPost2x2[0][0]); fXform.m12 = SkScalarToFloat(fRec.fPost2x2[1][0]); fXform.m21 = SkScalarToFloat(fRec.fPost2x2[0][1]); fXform.m22 = SkScalarToFloat(fRec.fPost2x2[1][1]); fXform.dx = 0; fXform.dy = 0; fTypeface.reset(GetDWriteFontByID(fRec.fFontID)); fTypeface.get()->ref(); fOffscreen.init(fTypeface->fDWriteFontFace.get(), fXform, SkScalarToFloat(fRec.fTextSize)); } SkScalerContext_Windows::~SkScalerContext_Windows() { } unsigned SkScalerContext_Windows::generateGlyphCount() { if (fGlyphCount < 0) { fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount(); } return fGlyphCount; } uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) { uint16_t index = 0; fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast(&uni), 1, &index); return index; } void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) { //Delta is the difference between the right/left side bearing metric //and where the right/left side bearing ends up after hinting. //DirectWrite does not provide this information. glyph->fRsbDelta = 0; glyph->fLsbDelta = 0; glyph->fAdvanceX = 0; glyph->fAdvanceY = 0; uint16_t glyphId = glyph->getGlyphID(); DWRITE_GLYPH_METRICS gm; HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), "Could not get design metrics."); DWRITE_FONT_METRICS dwfm; fTypeface->fDWriteFontFace->GetMetrics(&dwfm); SkScalar advanceX = SkScalarMulDiv(fRec.fTextSize, SkIntToScalar(gm.advanceWidth), SkIntToScalar(dwfm.designUnitsPerEm)); if (!(fRec.fFlags & kSubpixelPositioning_Flag)) { advanceX = SkScalarRoundToScalar(advanceX); } SkVector vecs[1] = { { advanceX, 0 } }; SkMatrix mat; fRec.getMatrixFrom2x2(&mat); mat.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX); glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY); } void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { glyph->fWidth = 0; this->generateAdvance(glyph); //Measure raster size. fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); FLOAT advance = 0; UINT16 glyphId = glyph->getGlyphID(); DWRITE_GLYPH_OFFSET offset; offset.advanceOffset = 0.0f; offset.ascenderOffset = 0.0f; DWRITE_GLYPH_RUN run; run.glyphCount = 1; run.glyphAdvances = &advance; run.fontFace = fTypeface->fDWriteFontFace.get(); run.fontEmSize = SkScalarToFloat(fRec.fTextSize); run.bidiLevel = 0; run.glyphIndices = &glyphId; run.isSideways = FALSE; run.glyphOffsets = &offset; IDWriteFactory* factory; HRVM(get_dwrite_factory(&factory), "Could not get factory."); const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; DWRITE_RENDERING_MODE renderingMode; DWRITE_TEXTURE_TYPE textureType; if (isBW) { renderingMode = DWRITE_RENDERING_MODE_ALIASED; textureType = DWRITE_TEXTURE_ALIASED_1x1; } else { renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; textureType = DWRITE_TEXTURE_CLEARTYPE_3x1; } SkTScopedComPtr glyphRunAnalysis; HRVM(factory->CreateGlyphRunAnalysis(&run, 1.0f, // pixelsPerDip, &fXform, renderingMode, DWRITE_MEASURING_MODE_NATURAL, 0.0f, // baselineOriginX, 0.0f, // baselineOriginY, &glyphRunAnalysis), "Could not create glyph run analysis."); RECT bbox; HRVM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, &bbox), "Could not get texture bounds."); glyph->fWidth = SkToU16(bbox.right - bbox.left); glyph->fHeight = SkToU16(bbox.bottom - bbox.top); glyph->fLeft = SkToS16(bbox.left); glyph->fTop = SkToS16(bbox.top); } void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { if (!(mx || my)) return; DWRITE_FONT_METRICS dwfm; fTypeface->fDWriteFontFace->GetMetrics(&dwfm); if (mx) { mx->fTop = SkScalarMulDiv(-fRec.fTextSize, SkIntToScalar(dwfm.ascent), SkIntToScalar(dwfm.designUnitsPerEm)); mx->fAscent = mx->fTop; mx->fDescent = SkScalarMulDiv(fRec.fTextSize, SkIntToScalar(dwfm.descent), SkIntToScalar(dwfm.designUnitsPerEm)); mx->fBottom = mx->fDescent; //TODO, can be less than zero mx->fLeading = SkScalarMulDiv(fRec.fTextSize, SkIntToScalar(dwfm.lineGap), SkIntToScalar(dwfm.designUnitsPerEm)); } if (my) { my->fTop = SkScalarMulDiv(-fRec.fTextSize, SkIntToScalar(dwfm.ascent), SkIntToScalar(dwfm.designUnitsPerEm)); my->fAscent = my->fTop; my->fDescent = SkScalarMulDiv(fRec.fTextSize, SkIntToScalar(dwfm.descent), SkIntToScalar(dwfm.designUnitsPerEm)); my->fBottom = my->fDescent; //TODO, can be less than zero my->fLeading = SkScalarMulDiv(fRec.fTextSize, SkIntToScalar(dwfm.lineGap), SkIntToScalar(dwfm.designUnitsPerEm)); } } /////////////////////////////////////////////////////////////////////////////// #include "SkColorPriv.h" static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) { const int width = glyph.fWidth; const size_t dstRB = (width + 7) >> 3; uint8_t* SK_RESTRICT dst = static_cast(glyph.fImage); int byteCount = width >> 3; int bitCount = width & 7; for (int y = 0; y < glyph.fHeight; ++y) { if (byteCount > 0) { for (int i = 0; i < byteCount; ++i) { unsigned byte = 0; byte |= src[0] & (1 << 7); byte |= src[1] & (1 << 6); byte |= src[2] & (1 << 5); byte |= src[3] & (1 << 4); byte |= src[4] & (1 << 3); byte |= src[5] & (1 << 2); byte |= src[6] & (1 << 1); byte |= src[7] & (1 << 0); dst[i] = byte; src += 8; } } if (bitCount > 0) { unsigned byte = 0; unsigned mask = 0x80; for (int i = 0; i < bitCount; i++) { byte |= (src[i]) & mask; mask >>= 1; } dst[byteCount] = byte; } src += bitCount; dst += dstRB; } } template static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) { const size_t dstRB = glyph.rowBytes(); const U16CPU width = glyph.fWidth; uint8_t* SK_RESTRICT dst = static_cast(glyph.fImage); for (U16CPU y = 0; y < glyph.fHeight; y++) { for (U16CPU i = 0; i < width; i++) { U8CPU r = *(src++); U8CPU g = *(src++); U8CPU b = *(src++); dst[i] = sk_apply_lut_if((r + g + b) / 3, table8); } dst = (uint8_t*)((char*)dst + dstRB); } } template static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { const size_t dstRB = glyph.rowBytes(); const U16CPU width = glyph.fWidth; uint16_t* SK_RESTRICT dst = static_cast(glyph.fImage); for (U16CPU y = 0; y < glyph.fHeight; y++) { for (U16CPU i = 0; i < width; i++) { U8CPU r = sk_apply_lut_if(*(src++), tableR); U8CPU g = sk_apply_lut_if(*(src++), tableG); U8CPU b = sk_apply_lut_if(*(src++), tableB); dst[i] = SkPack888ToRGB16(r, g, b); } dst = (uint16_t*)((char*)dst + dstRB); } } template static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { const size_t dstRB = glyph.rowBytes(); const U16CPU width = glyph.fWidth; SkPMColor* SK_RESTRICT dst = static_cast(glyph.fImage); for (U16CPU y = 0; y < glyph.fHeight; y++) { for (U16CPU i = 0; i < width; i++) { U8CPU r = sk_apply_lut_if(*(src++), tableR); U8CPU g = sk_apply_lut_if(*(src++), tableG); U8CPU b = sk_apply_lut_if(*(src++), tableB); dst[i] = SkPackARGB32(0xFF, r, g, b); } dst = (SkPMColor*)((char*)dst + dstRB); } } void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { SkAutoMutexAcquire ac(gFTMutex); const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; const bool isAA = !isLCD(fRec); //Create the mask. const void* bits = fOffscreen.draw(glyph, isBW); if (!bits) { sk_bzero(glyph.fImage, glyph.computeImageSize()); return; } //Copy the mask into the glyph. int width = glyph.fWidth; size_t dstRB = glyph.rowBytes(); const uint8_t* src = (const uint8_t*)bits; if (isBW) { bilevel_to_bw(src, glyph); } else if (isAA) { if (fPreBlend.isApplicable()) { rgb_to_a8(src, glyph, fPreBlend.fG); } else { rgb_to_a8(src, glyph, fPreBlend.fG); } } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { if (fPreBlend.isApplicable()) { rgb_to_lcd16(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); } else { rgb_to_lcd16(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); } } else { SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); if (fPreBlend.isApplicable()) { rgb_to_lcd32(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); } else { rgb_to_lcd32(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); } } } void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { SkAutoMutexAcquire ac(gFTMutex); SkASSERT(&glyph && path); path->reset(); SkTScopedComPtr geometryToPath; HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), "Could not create geometry to path converter."); uint16_t glyphId = glyph.getGlyphID(); //TODO: convert to<->from DIUs? This would make a difference if hinting. //It may not be needed, it appears that DirectWrite only hints at em size. HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fRec.fTextSize), &glyphId, NULL, //advances NULL, //offsets 1, //num glyphs FALSE, //sideways FALSE, //rtl geometryToPath.get()), "Could not create glyph outline."); SkMatrix mat; fRec.getMatrixFrom2x2(&mat); path->transform(mat); } void SkFontHost::Serialize(const SkTypeface* rawFace, SkWStream* stream) { const DWriteFontTypeface* face = static_cast(rawFace); SkFontDescriptor descriptor(face->style()); // Get the family name. SkTScopedComPtr dwFamilyNames; HRV(face->fDWriteFontFamily->GetFamilyNames(&dwFamilyNames)); UINT32 dwFamilyNamesLength; HRV(dwFamilyNames->GetStringLength(0, &dwFamilyNamesLength)); SkTDArray dwFamilyNameChar(new wchar_t[dwFamilyNamesLength+1], dwFamilyNamesLength+1); HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.begin(), dwFamilyNameChar.count())); // Convert the family name to utf8. // Get the buffer size needed first. int str_len = WideCharToMultiByte(CP_UTF8, 0, dwFamilyNameChar.begin(), -1, NULL, 0, NULL, NULL); // Allocate a buffer (str_len already has terminating null accounted for). SkTDArray utf8FamilyName(new char[str_len], str_len); // Now actually convert the string. str_len = WideCharToMultiByte(CP_UTF8, 0, dwFamilyNameChar.begin(), -1, utf8FamilyName.begin(), str_len, NULL, NULL); descriptor.setFamilyName(utf8FamilyName.begin()); //TODO: FileName and PostScriptName currently unsupported. descriptor.serialize(stream); if (NULL != face->fDWriteFontFileLoader.get()) { // store the entire font in the fontData SkStream* fontStream = face->fDWriteFontFileLoader->fStream.get(); const uint32_t length = fontStream->getLength(); stream->writePackedUInt(length); stream->writeStream(fontStream, length); } else { stream->writePackedUInt(0); } } SkTypeface* SkFontHost::Deserialize(SkStream* stream) { SkFontDescriptor descriptor(stream); const uint32_t customFontDataLength = stream->readPackedUInt(); if (customFontDataLength > 0) { // generate a new stream to store the custom typeface SkAutoTUnref fontStream(SkNEW_ARGS(SkMemoryStream, (customFontDataLength - 1))); stream->read((void*)fontStream->getMemoryBase(), customFontDataLength - 1); return CreateTypefaceFromStream(fontStream.get()); } return SkFontHost::CreateTypeface(NULL, descriptor.getFamilyName(), descriptor.getStyle()); } SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { IDWriteFactory* factory; HRN(get_dwrite_factory(&factory)); SkTScopedComPtr fontFileLoader; HRN(StreamFontFileLoader::Create(stream, &fontFileLoader)); HRN(factory->RegisterFontFileLoader(fontFileLoader.get())); SkTScopedComPtr streamFontCollectionLoader; HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &streamFontCollectionLoader)); HRN(factory->RegisterFontCollectionLoader(streamFontCollectionLoader.get())); SkTScopedComPtr streamFontCollection; HRN(factory->CreateCustomFontCollection(streamFontCollectionLoader.get(), NULL, 0, &streamFontCollection)); SkTScopedComPtr fontFamily; HRN(streamFontCollection->GetFontFamily(0, &fontFamily)); SkTScopedComPtr font; HRN(fontFamily->GetFont(0, &font)); SkTScopedComPtr fontFace; HRN(font->CreateFontFace(&fontFace)); return SkCreateTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get(), fontFileLoader.get(), streamFontCollectionLoader.get()); } SkStream* SkFontHost::OpenStream(SkFontID uniqueID) { DWriteFontTypeface* typeface = GetDWriteFontByID(uniqueID); if (NULL == typeface) { return NULL; } UINT32 numFiles; HRNM(typeface->fDWriteFontFace->GetFiles(&numFiles, NULL), "Could not get number of font files."); if (numFiles != 1) { return NULL; } SkTScopedComPtr fontFile; HRNM(typeface->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 fontFileLoader; HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader."); SkTScopedComPtr fontFileStream; HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize, &fontFileStream), "Could not create font file stream."); return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get())); } SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return SkNEW_ARGS(SkScalerContext_Windows, (desc)); } static HRESULT get_by_family_name(const char familyName[], IDWriteFontFamily** fontFamily) { IDWriteFactory* factory; HR(get_dwrite_factory(&factory)); SkTScopedComPtr sysFontCollection; HR(factory->GetSystemFontCollection(&sysFontCollection, FALSE)); // Get the buffer size needed first. int wlen = ::MultiByteToWideChar(CP_UTF8, 0, familyName,-1, NULL, 0); if (0 == wlen) { return HRESULT_FROM_WIN32(GetLastError()); } // Allocate a buffer SkTDArray wideFamilyName(new wchar_t[wlen], wlen); // Now actually convert the string. wlen = ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, wideFamilyName.begin(), wlen); if (0 == wlen) { return HRESULT_FROM_WIN32(GetLastError()); } UINT32 index; BOOL exists; HR(sysFontCollection->FindFamilyName(wideFamilyName.begin(), &index, &exists)); if (exists) { HR(sysFontCollection->GetFontFamily(index, fontFamily)); return S_OK; } return S_FALSE; } /** Return the closest matching typeface given either an existing family (specified by a typeface in that family) or by a familyName, and a requested style. 1) If familyFace is null, use familyName. 2) If familyName is null, use familyFace. 3) If both are null, return the default font that best matches style This MUST not return NULL. */ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) { HRESULT hr; SkTScopedComPtr fontFamily; SkTScopedComPtr fontCollectionLoader; SkTScopedComPtr fontFileLoader; if (familyFace) { const DWriteFontTypeface* face = static_cast(familyFace); face->fDWriteFontFamily.get()->AddRef(); *(&fontFamily) = face->fDWriteFontFamily.get(); if (face->fDWriteFontCollectionLoader.get() != NULL) { face->fDWriteFontCollectionLoader.get()->AddRef(); *(&fontCollectionLoader) = face->fDWriteFontCollectionLoader.get(); face->fDWriteFontFileLoader.get()->AddRef(); *(&fontFileLoader) = face->fDWriteFontFileLoader.get(); } } else if (familyName) { hr = get_by_family_name(familyName, &fontFamily); } if (NULL == fontFamily.get()) { //No good family found, go with default. SkTScopedComPtr font; hr = get_default_font(&font); hr = font->GetFontFamily(&fontFamily); } SkTScopedComPtr font; DWRITE_FONT_WEIGHT weight = (style & SkTypeface::kBold) ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL; DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_UNDEFINED; DWRITE_FONT_STYLE italic = (style & SkTypeface::kItalic) ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; hr = fontFamily->GetFirstMatchingFont(weight, stretch, italic, &font); SkTScopedComPtr fontFace; hr = font->CreateFontFace(&fontFace); return SkCreateTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get()); } SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { printf("SkFontHost::CreateTypefaceFromFile unimplemented"); return NULL; } void SkFontHost::FilterRec(SkScalerContext::Rec* rec, SkTypeface*) { unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | SkScalerContext::kAutohinting_Flag | SkScalerContext::kEmbeddedBitmapText_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; if (SUCCEEDED(get_dwrite_factory(&factory))) { SkTScopedComPtr defaultRenderingParams; if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) { float gamma = defaultRenderingParams->GetGamma(); rec->setDeviceGamma(SkFloatToScalar(gamma)); rec->setPaintGamma(SkFloatToScalar(gamma)); rec->setContrast(SkFloatToScalar(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* 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 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 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 (size_t 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; } template class AutoDWriteTable { public: AutoDWriteTable(IDWriteFontFace* fontFace) : fFontFace(fontFace) , fExists(FALSE) { //fontFace->AddRef(); const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3); HRESULT hr = fontFace->TryGetFontTable(tag, reinterpret_cast(&fData), &fSize, &fLock, &fExists); } ~AutoDWriteTable() { if (fExists) { fFontFace->ReleaseFontTable(fLock); } } const T* operator->() const { return fData; } const T* fData; UINT32 fSize; BOOL fExists; private: //SkTScopedComPtr fFontFace; IDWriteFontFace* fFontFace; void* fLock; }; // static SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( uint32_t fontID, SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, const uint32_t* glyphIDs, uint32_t glyphIDsCount) { SkAdvancedTypefaceMetrics* info = NULL; HRESULT hr = S_OK; DWriteFontTypeface* typeface = GetDWriteFontByID(fontID); const unsigned glyphCount = typeface->fDWriteFontFace->GetGlyphCount(); DWRITE_FONT_METRICS dwfm; typeface->fDWriteFontFace->GetMetrics(&dwfm); info = new SkAdvancedTypefaceMetrics; info->fEmSize = dwfm.designUnitsPerEm; info->fMultiMaster = false; info->fLastGlyphID = SkToU16(glyphCount - 1); info->fStyle = 0; SkTScopedComPtr familyNames; SkTScopedComPtr faceNames; hr = typeface->fDWriteFontFamily->GetFamilyNames(&familyNames); hr = typeface->fDWriteFont->GetFaceNames(&faceNames); UINT32 familyNameLength; hr = familyNames->GetStringLength(0, &familyNameLength); UINT32 faceNameLength; hr = faceNames->GetStringLength(0, &faceNameLength); size_t size = familyNameLength+1+faceNameLength+1; SkTDArray wFamilyName(new wchar_t[size], size); hr = familyNames->GetString(0, wFamilyName.begin(), size); wFamilyName[familyNameLength] = L' '; hr = faceNames->GetString(0, &wFamilyName[familyNameLength+1], size - faceNameLength + 1); size_t str_len = WideCharToMultiByte(CP_UTF8, 0, wFamilyName.begin(), -1, NULL, 0, NULL, NULL); if (0 == str_len) { //TODO: error } SkTDArray familyName(new char[str_len], str_len); str_len = WideCharToMultiByte(CP_UTF8, 0, wFamilyName.begin(), -1, familyName.begin(), str_len, NULL, NULL); if (0 == str_len) { //TODO: error } info->fFontName.set(familyName.begin(), str_len); if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { populate_glyph_to_unicode(typeface->fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode)); } DWRITE_FONT_FACE_TYPE fontType = typeface->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; } AutoDWriteTable headTable(typeface->fDWriteFontFace.get()); AutoDWriteTable postTable(typeface->fDWriteFontFace.get()); AutoDWriteTable hheaTable(typeface->fDWriteFontFace.get()); AutoDWriteTable os2Table(typeface->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(typeface->fDWriteFontFace.get(), 1, &advance); info->fGlyphWidths->fAdvance.append(1, &advance); finishRange(info->fGlyphWidths.get(), 0, SkAdvancedTypefaceMetrics::WidthRange::kDefault); } else { info->fGlyphWidths.reset( getAdvanceData(typeface->fDWriteFontFace.get(), glyphCount, glyphIDs, glyphIDsCount, getWidthAdvance)); } } return info; }