aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ports
diff options
context:
space:
mode:
authorGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-08-16 16:13:40 +0000
committerGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-08-16 16:13:40 +0000
commite8f0592ae8b37e94d99f49816eb22e9fafde6d86 (patch)
treebab72f66f6918bdacd66e14163dce1215a5f26ba /src/ports
parent0557d9ea94d5435a9072c9b4141a05190d648442 (diff)
DirectWrite font host for skia.
Diffstat (limited to 'src/ports')
-rw-r--r--src/ports/SkFontHost_win_dw.cpp1519
1 files changed, 1519 insertions, 0 deletions
diff --git a/src/ports/SkFontHost_win_dw.cpp b/src/ports/SkFontHost_win_dw.cpp
new file mode 100644
index 0000000000..c3a13a020e
--- /dev/null
+++ b/src/ports/SkFontHost_win_dw.cpp
@@ -0,0 +1,1519 @@
+/*
+ * 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 "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 <dwrite.h>
+
+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<uint8_t> 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<DWriteCreateFactoryProc>(
+ GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory")
+ )
+ ;
+
+ if (!dWriteCreateFactoryProc) {
+ return E_UNEXPECTED;
+ }
+
+ HRM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(&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<IDWriteGlyphRunAnalysis> 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();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkTypeface::Style get_style(IDWriteFont* font) {
+ int style = SkTypeface::kNormal;
+ DWRITE_FONT_WEIGHT weight = font->GetWeight();
+ if (DWRITE_FONT_WEIGHT_DEMI_BOLD <= weight) {
+ style |= SkTypeface::kBold;
+ }
+ DWRITE_FONT_STYLE angle = font->GetStyle();
+ if (DWRITE_FONT_STYLE_OBLIQUE == angle || DWRITE_FONT_STYLE_ITALIC == angle) {
+ style |= SkTypeface::kItalic;
+ }
+ return static_cast<SkTypeface::Style>(style);
+}
+
+class DWriteFontTypeface : public SkTypeface {
+private:
+ DWriteFontTypeface(SkTypeface::Style style, SkFontID fontID,
+ IDWriteFontFace* fontFace,
+ IDWriteFont* font,
+ IDWriteFontFamily* fontFamily,
+ IDWriteFontFileLoader* 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<IDWriteFontCollectionLoader> fDWriteFontCollectionLoader;
+ SkTScopedComPtr<IDWriteFontFileLoader> fDWriteFontFileLoader;
+ SkTScopedComPtr<IDWriteFontFamily> fDWriteFontFamily;
+ SkTScopedComPtr<IDWriteFont> fDWriteFont;
+ SkTScopedComPtr<IDWriteFontFace> fDWriteFontFace;
+
+ static DWriteFontTypeface* Create(IDWriteFontFace* fontFace,
+ IDWriteFont* font,
+ IDWriteFontFamily* fontFamily,
+ IDWriteFontFileLoader* fontFileLoader = NULL,
+ IDWriteFontCollectionLoader* fontCollectionLoader = NULL) {
+ SkTypeface::Style style = get_style(font);
+ SkFontID fontID = SkTypefaceCache::NewFontID();
+ return SkNEW_ARGS(DWriteFontTypeface, (style, fontID, 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,
+ SkMaskGamma::PreBlend* maskPreBlend) 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<DWriteFontTypeface> 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<IDWriteFontCollection> 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<IDWriteFontFamily> 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<IDWriteGdiInterop> 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<IDWriteGdiInterop> 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<IUnknown> iunkA;
+ if (FAILED(a->QueryInterface(&iunkA))) {
+ return false;
+ }
+
+ SkTScopedComPtr<IUnknown> iunkB;
+ if (FAILED(b->QueryInterface(&iunkB))) {
+ return false;
+ }
+
+ return iunkA.get() == iunkB.get();
+}
+static bool FindByDWriteFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
+ //Check to see if the two fonts are identical.
+ DWriteFontTypeface* dwFace = reinterpret_cast<DWriteFontTypeface*>(face);
+ IDWriteFont* dwFont = reinterpret_cast<IDWriteFont*>(ctx);
+ if (are_same(dwFace->fDWriteFont.get(), dwFont)) {
+ return true;
+ }
+
+ //Check if the two fonts share the same loader and have the same key.
+ SkTScopedComPtr<IDWriteFontFace> dwFaceFontFace;
+ SkTScopedComPtr<IDWriteFontFace> dwFontFace;
+ HRB(dwFace->fDWriteFont->CreateFontFace(&dwFaceFontFace));
+ HRB(dwFont->CreateFontFace(&dwFontFace));
+ if (are_same(dwFaceFontFace.get(), dwFontFace.get())) {
+ return true;
+ }
+
+ UINT32 dwFaceNumFiles;
+ UINT32 dwNumFiles;
+ HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, NULL));
+ HRB(dwFontFace->GetFiles(&dwNumFiles, NULL));
+ if (dwFaceNumFiles != dwNumFiles) {
+ return false;
+ }
+
+ SkTScopedComPtr<IDWriteFontFile> dwFaceFontFile;
+ SkTScopedComPtr<IDWriteFontFile> dwFontFile;
+ HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, &dwFaceFontFile));
+ HRB(dwFontFace->GetFiles(&dwNumFiles, &dwFontFile));
+
+ //for (each file) { //we currently only admit fonts from one file.
+ SkTScopedComPtr<IDWriteFontFileLoader> dwFaceFontFileLoader;
+ SkTScopedComPtr<IDWriteFontFileLoader> dwFontFileLoader;
+ HRB(dwFaceFontFile->GetLoader(&dwFaceFontFileLoader));
+ HRB(dwFontFile->GetLoader(&dwFontFileLoader));
+ if (!are_same(dwFaceFontFileLoader.get(), dwFontFileLoader.get())) {
+ return false;
+ }
+ //}
+
+ const void* dwFaceFontRefKey;
+ UINT32 dwFaceFontRefKeySize;
+ const void* dwFontRefKey;
+ UINT32 dwFontRefKeySize;
+ HRB(dwFaceFontFile->GetReferenceKey(&dwFaceFontRefKey, &dwFaceFontRefKeySize));
+ HRB(dwFontFile->GetReferenceKey(&dwFontRefKey, &dwFontRefKeySize));
+ if (dwFaceFontRefKeySize != dwFontRefKeySize) {
+ return false;
+ }
+ if (0 != memcmp(dwFaceFontRefKey, dwFontRefKey, dwFontRefKeySize)) {
+ return false;
+ }
+
+ //TODO: better means than comparing name strings?
+ //NOTE: .tfc and fake bold/italic will end up here.
+ SkTScopedComPtr<IDWriteFontFamily> dwFaceFontFamily;
+ SkTScopedComPtr<IDWriteFontFamily> dwFontFamily;
+ HRB(dwFace->fDWriteFont->GetFontFamily(&dwFaceFontFamily));
+ HRB(dwFont->GetFontFamily(&dwFontFamily));
+
+ SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontFamilyNames;
+ SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontNames;
+ HRB(dwFaceFontFamily->GetFamilyNames(&dwFaceFontFamilyNames));
+ HRB(dwFace->fDWriteFont->GetFaceNames(&dwFaceFontNames));
+
+ SkTScopedComPtr<IDWriteLocalizedStrings> dwFontFamilyNames;
+ SkTScopedComPtr<IDWriteLocalizedStrings> dwFontNames;
+ HRB(dwFontFamily->GetFamilyNames(&dwFontFamilyNames));
+ HRB(dwFont->GetFaceNames(&dwFontNames));
+
+ UINT32 dwFaceFontFamilyNameLength;
+ UINT32 dwFaceFontNameLength;
+ HRB(dwFaceFontFamilyNames->GetStringLength(0, &dwFaceFontFamilyNameLength));
+ HRB(dwFaceFontNames->GetStringLength(0, &dwFaceFontNameLength));
+
+ UINT32 dwFontFamilyNameLength;
+ UINT32 dwFontNameLength;
+ HRB(dwFontFamilyNames->GetStringLength(0, &dwFontFamilyNameLength));
+ HRB(dwFontNames->GetStringLength(0, &dwFontNameLength));
+
+ if (dwFaceFontFamilyNameLength != dwFontFamilyNameLength ||
+ dwFaceFontNameLength != dwFontNameLength)
+ {
+ return false;
+ }
+
+ SkTDArray<wchar_t> dwFaceFontFamilyNameChar(new wchar_t[dwFaceFontFamilyNameLength+1], dwFaceFontFamilyNameLength+1);
+ SkTDArray<wchar_t> 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<wchar_t> dwFontFamilyNameChar(new wchar_t[dwFontFamilyNameLength+1], dwFontFamilyNameLength+1);
+ SkTDArray<wchar_t> 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,
+ IDWriteFontFileLoader* fontFileLoader = NULL,
+ IDWriteFontCollectionLoader* fontCollectionLoader = NULL) {
+ SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByDWriteFont, font);
+ if (face) {
+ face->ref();
+ } else {
+ 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<const DWriteFontTypeface*>(face)->fDWriteFont.get();
+ (*font)->AddRef();
+ }
+}
+static DWriteFontTypeface* GetDWriteFontByID(SkFontID fontID) {
+ return static_cast<DWriteFontTypeface*>(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<UINT32*>(&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;
+ mat.setAll(fRec.fPost2x2[0][0], fRec.fPost2x2[0][1], 0,
+ fRec.fPost2x2[1][0], fRec.fPost2x2[1][1], 0,
+ 0, 0, SkScalarToPersp(SK_Scalar1));
+ 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<IDWriteGlyphRunAnalysis> 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<uint8_t*>(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<bool APPLY_PREBLEND>
+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<uint8_t*>(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<APPLY_PREBLEND>((r + g + b) / 3, table8);
+ }
+ dst = (uint8_t*)((char*)dst + dstRB);
+ }
+}
+
+template<bool APPLY_PREBLEND>
+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<uint16_t*>(glyph.fImage);
+
+ for (U16CPU y = 0; y < glyph.fHeight; y++) {
+ for (U16CPU i = 0; i < width; i++) {
+ U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
+ U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
+ U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
+ dst[i] = SkPack888ToRGB16(r, g, b);
+ }
+ dst = (uint16_t*)((char*)dst + dstRB);
+ }
+}
+
+template<bool APPLY_PREBLEND>
+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<SkPMColor*>(glyph.fImage);
+
+ for (U16CPU y = 0; y < glyph.fHeight; y++) {
+ for (U16CPU i = 0; i < width; i++) {
+ U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
+ U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
+ U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
+ dst[i] = SkPackARGB32(0xFF, r, g, b);
+ }
+ dst = (SkPMColor*)((char*)dst + dstRB);
+ }
+}
+
+void SkScalerContext_Windows::generateImage(const SkGlyph& glyph,
+ SkMaskGamma::PreBlend* maskPreBlend) {
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ //Must be careful not to use these if maskPreBlend == NULL
+ const uint8_t* tableR = NULL;
+ const uint8_t* tableG = NULL;
+ const uint8_t* tableB = NULL;
+ if (maskPreBlend) {
+ tableR = maskPreBlend->fR;
+ tableG = maskPreBlend->fG;
+ tableB = maskPreBlend->fB;
+ }
+
+ 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 (maskPreBlend) {
+ rgb_to_a8<true>(src, glyph, tableG);
+ } else {
+ rgb_to_a8<false>(src, glyph, tableG);
+ }
+ } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
+ if (maskPreBlend) {
+ rgb_to_lcd16<true>(src, glyph, tableR, tableG, tableB);
+ } else {
+ rgb_to_lcd16<false>(src, glyph, tableR, tableG, tableB);
+ }
+ } else {
+ SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
+ if (maskPreBlend) {
+ rgb_to_lcd32<true>(src, glyph, tableR, tableG, tableB);
+ } else {
+ rgb_to_lcd32<true>(src, glyph, tableR, tableG, tableB);
+ }
+ }
+}
+
+void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ SkASSERT(&glyph && path);
+
+ path->reset();
+
+ SkTScopedComPtr<IDWriteGeometrySink> 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.");
+}
+
+void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
+ SkASSERT(!"SkFontHost::Serialize unimplemented");
+}
+
+SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
+ SkASSERT(!"SkFontHost::Deserialize unimplemented");
+ return NULL;
+}
+
+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;
+ }
+private:
+ StreamFontFileLoader(SkStream* stream) : fRefCount(1), fStream(stream) {
+ stream->ref();
+ }
+
+ ULONG fRefCount;
+ SkAutoTUnref<SkStream> fStream;
+};
+
+HRESULT StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
+ if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
+ *ppvObject = this;
+ AddRef();
+ return S_OK;
+ } else {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG StreamFontFileLoader::AddRef() {
+ return InterlockedIncrement(&fRefCount);
+}
+
+ULONG StreamFontFileLoader::Release() {
+ ULONG newCount = InterlockedDecrement(&fRefCount);
+ if (0 == newCount) {
+ delete this;
+ }
+ return newCount;
+}
+
+HRESULT StreamFontFileLoader::CreateStreamFromKey(
+ void const* fontFileReferenceKey,
+ UINT32 fontFileReferenceKeySize,
+ IDWriteFontFileStream** fontFileStream)
+{
+ SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
+ HR(SkDWriteFontFileStreamWrapper::Create(fStream, &stream));
+ *fontFileStream = stream.release();
+ return S_OK;
+}
+
+class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
+public:
+ // IUnknown methods
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef();
+ virtual ULONG STDMETHODCALLTYPE Release();
+
+ // IDWriteFontFileEnumerator methods
+ virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile);
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile);
+
+ static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
+ StreamFontFileEnumerator** streamFontFileEnumerator) {
+ *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
+ if (NULL == streamFontFileEnumerator) {
+ return E_OUTOFMEMORY;
+ }
+ return S_OK;
+ }
+private:
+ StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
+ ULONG fRefCount;
+
+ SkTScopedComPtr<IDWriteFactory> fFactory;
+ SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
+ SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
+ bool fHasNext;
+};
+
+StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
+ IDWriteFontFileLoader* fontFileLoader)
+ : fRefCount(1)
+ , fFactory(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<IDWriteFontFileLoader> fFontFileLoader;
+};
+
+HRESULT StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
+ if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
+ *ppvObject = this;
+ AddRef();
+ return S_OK;
+ } else {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG StreamFontCollectionLoader::AddRef() {
+ return InterlockedIncrement(&fRefCount);
+}
+
+ULONG StreamFontCollectionLoader::Release() {
+ ULONG newCount = InterlockedDecrement(&fRefCount);
+ if (0 == newCount) {
+ delete this;
+ }
+ return newCount;
+}
+
+HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey(
+ IDWriteFactory* factory,
+ void const* collectionKey,
+ UINT32 collectionKeySize,
+ IDWriteFontFileEnumerator** fontFileEnumerator)
+{
+ SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
+ HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
+ *fontFileEnumerator = enumerator.release();
+ return S_OK;
+}
+
+SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
+ IDWriteFactory* factory;
+ HRN(get_dwrite_factory(&factory));
+
+ SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
+ HRN(StreamFontFileLoader::Create(stream, &fontFileLoader));
+ HRN(factory->RegisterFontFileLoader(fontFileLoader.get()));
+
+ SkTScopedComPtr<StreamFontCollectionLoader> streamFontCollectionLoader;
+ HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &streamFontCollectionLoader));
+ HRN(factory->RegisterFontCollectionLoader(streamFontCollectionLoader.get()));
+
+ SkTScopedComPtr<IDWriteFontCollection> streamFontCollection;
+ HRN(factory->CreateCustomFontCollection(streamFontCollectionLoader.get(), NULL, 0,
+ &streamFontCollection));
+
+ SkTScopedComPtr<IDWriteFontFamily> fontFamily;
+ HRN(streamFontCollection->GetFontFamily(0, &fontFamily));
+
+ SkTScopedComPtr<IDWriteFont> font;
+ HRN(fontFamily->GetFont(0, &font));
+
+ SkTScopedComPtr<IDWriteFontFace> 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<IDWriteFontFile> 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<IDWriteFontFileLoader> fontFileLoader;
+ HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader.");
+
+ SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
+ HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize,
+ &fontFileStream),
+ "Could not create font file stream.");
+
+ return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
+}
+
+SkScalerContext* 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<IDWriteFontCollection> 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<wchar_t> 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<IDWriteFontFamily> fontFamily;
+ SkTScopedComPtr<IDWriteFontCollectionLoader> fontCollectionLoader;
+ SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
+ if (familyFace) {
+ const DWriteFontTypeface* face = static_cast<const DWriteFontTypeface*>(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<IDWriteFont> font;
+ hr = get_default_font(&font);
+ hr = font->GetFontFamily(&fontFamily);
+ }
+
+ SkTScopedComPtr<IDWriteFont> 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<IDWriteFontFace> fontFace;
+ hr = font->CreateFontFace(&fontFace);
+
+ return SkCreateTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get(),
+ fontFileLoader.get(), fontCollectionLoader.get());
+}
+
+SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
+ printf("SkFontHost::CreateTypefaceFromFile unimplemented");
+ return NULL;
+}
+
+void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
+ 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<IDWriteRenderingParams> 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<SkUnichar>* glyphToUnicode) {
+ HRESULT hr = S_OK;
+
+ //Do this like free type instead
+ UINT32 count = 0;
+ for (UINT32 c = 0; c < 0x10FFFF; ++c) {
+ UINT16 glyph;
+ hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
+ if (glyph > 0) {
+ ++count;
+ }
+ }
+
+ SkAutoTArray<UINT32> chars(count);
+ count = 0;
+ for (UINT32 c = 0; c < 0x10FFFF; ++c) {
+ UINT16 glyph;
+ hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
+ if (glyph > 0) {
+ chars[count] = c;
+ ++count;
+ }
+ }
+
+ SkAutoTArray<UINT16> glyph(count);
+ fontFace->GetGlyphIndices(chars.get(), count, glyph.get());
+
+ USHORT maxGlyph = 0;
+ for (USHORT j = 0; j < count; ++j) {
+ if (glyph[j] > maxGlyph) maxGlyph = glyph[j];
+ }
+
+ glyphToUnicode->setCount(maxGlyph+1);
+ for (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<typename T>
+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<const void **>(&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<IDWriteFontFace> 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<IDWriteLocalizedStrings> familyNames;
+ SkTScopedComPtr<IDWriteLocalizedStrings> 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<wchar_t> 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<char> 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<SkOTTableHead> headTable(typeface->fDWriteFontFace.get());
+ AutoDWriteTable<SkOTTablePostScript> postTable(typeface->fDWriteFontFace.get());
+ AutoDWriteTable<SkOTTableHorizontalHeader> hheaTable(typeface->fDWriteFontFace.get());
+ AutoDWriteTable<SkOTTableOS2> 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;
+ }
+ //Symbolic (uses more than base latin).
+ info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_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;
+}