blob: e024b465aab71a0f0986b283cfe45ecbb143f031 [file] [log] [blame]
bungeman@google.come8f05922012-08-16 16:13:40 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkTypes.h"
9#undef GetGlyphIndices
10
11#include "SkAdvancedTypefaceMetrics.h"
12#include "SkColorFilter.h"
bungeman@google.com72cf4fc2014-03-21 22:48:32 +000013#include "SkDWrite.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000014#include "SkDWriteFontFileStream.h"
15#include "SkDWriteGeometrySink.h"
16#include "SkDescriptor.h"
17#include "SkEndian.h"
bungeman@google.com94acfb52012-08-31 15:41:09 +000018#include "SkFontDescriptor.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000019#include "SkFontHost.h"
bungeman@google.combfc6cc42013-08-21 15:20:43 +000020#include "SkFontMgr.h"
bungeman@google.comb10b51f2013-08-01 20:18:41 +000021#include "SkFontStream.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000022#include "SkGlyph.h"
23#include "SkHRESULT.h"
24#include "SkMaskGamma.h"
bungeman@google.com058670b2014-05-01 20:39:14 +000025#include "SkMatrix22.h"
bungeman@google.com0ff457b2013-12-09 18:58:31 +000026#include "SkOnce.h"
bungeman@google.com058670b2014-05-01 20:39:14 +000027#include "SkOTTable_EBLC.h"
28#include "SkOTTable_EBSC.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000029#include "SkOTTable_head.h"
30#include "SkOTTable_hhea.h"
31#include "SkOTTable_OS_2.h"
32#include "SkOTTable_post.h"
33#include "SkPath.h"
34#include "SkStream.h"
35#include "SkString.h"
36#include "SkTScopedComPtr.h"
37#include "SkThread.h"
38#include "SkTypeface_win.h"
39#include "SkTypefaceCache.h"
40#include "SkUtils.h"
41
42#include <dwrite.h>
43
bungeman@google.come8f05922012-08-16 16:13:40 +000044static bool isLCD(const SkScalerContext::Rec& rec) {
45 return SkMask::kLCD16_Format == rec.fMaskFormat ||
46 SkMask::kLCD32_Format == rec.fMaskFormat;
47}
48
bungeman@google.com0ff457b2013-12-09 18:58:31 +000049///////////////////////////////////////////////////////////////////////////////
50
bungeman@google.combfc6cc42013-08-21 15:20:43 +000051class StreamFontFileLoader;
52
53class SkFontMgr_DirectWrite : public SkFontMgr {
54public:
55 /** localeNameLength must include the null terminator. */
bungeman@google.com6eddc772014-03-31 19:18:07 +000056 SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection,
bungeman@google.combfc6cc42013-08-21 15:20:43 +000057 WCHAR* localeName, int localeNameLength)
bungeman@google.com6eddc772014-03-31 19:18:07 +000058 : fFactory(SkRefComPtr(factory))
59 , fFontCollection(SkRefComPtr(fontCollection))
bungeman@google.combfc6cc42013-08-21 15:20:43 +000060 , fLocaleName(localeNameLength)
61 {
62 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
63 }
64
bungeman@google.com6eddc772014-03-31 19:18:07 +000065 /** Creates a typeface using a typeface cache. */
bungeman@google.combfc6cc42013-08-21 15:20:43 +000066 SkTypeface* createTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
67 IDWriteFont* font,
bungeman@google.com6eddc772014-03-31 19:18:07 +000068 IDWriteFontFamily* fontFamily) const;
bungeman@google.combfc6cc42013-08-21 15:20:43 +000069
70protected:
commit-bot@chromium.org967dee32014-02-04 22:35:01 +000071 virtual int onCountFamilies() const SK_OVERRIDE;
72 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE;
73 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE;
74 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE;
bungeman@google.combfc6cc42013-08-21 15:20:43 +000075 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
commit-bot@chromium.org967dee32014-02-04 22:35:01 +000076 const SkFontStyle& fontstyle) const SK_OVERRIDE;
bungeman@google.combfc6cc42013-08-21 15:20:43 +000077 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
commit-bot@chromium.org967dee32014-02-04 22:35:01 +000078 const SkFontStyle& fontstyle) const SK_OVERRIDE;
79 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE;
80 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE;
81 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE;
bungeman@google.combfc6cc42013-08-21 15:20:43 +000082 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
commit-bot@chromium.org967dee32014-02-04 22:35:01 +000083 unsigned styleBits) const SK_OVERRIDE;
bungeman@google.combfc6cc42013-08-21 15:20:43 +000084
85private:
commit-bot@chromium.org967dee32014-02-04 22:35:01 +000086 HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
87 HRESULT getDefaultFontFamily(IDWriteFontFamily** fontFamily) const;
bungeman@google.com8f53d582013-11-20 22:42:13 +000088
commit-bot@chromium.org967dee32014-02-04 22:35:01 +000089 void Add(SkTypeface* face, SkTypeface::Style requestedStyle, bool strong) const {
bungeman@google.com86dd7522013-10-04 17:00:35 +000090 SkAutoMutexAcquire ama(fTFCacheMutex);
91 fTFCache.add(face, requestedStyle, strong);
92 }
93
commit-bot@chromium.org967dee32014-02-04 22:35:01 +000094 SkTypeface* FindByProcAndRef(SkTypefaceCache::FindProc proc, void* ctx) const {
bungeman@google.com86dd7522013-10-04 17:00:35 +000095 SkAutoMutexAcquire ama(fTFCacheMutex);
96 SkTypeface* typeface = fTFCache.findByProcAndRef(proc, ctx);
97 return typeface;
98 }
99
bungeman@google.com6eddc772014-03-31 19:18:07 +0000100 SkTScopedComPtr<IDWriteFactory> fFactory;
bungeman@google.combfc6cc42013-08-21 15:20:43 +0000101 SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
102 SkSMallocWCHAR fLocaleName;
commit-bot@chromium.org967dee32014-02-04 22:35:01 +0000103 mutable SkMutex fTFCacheMutex;
104 mutable SkTypefaceCache fTFCache;
105
106 friend class SkFontStyleSet_DirectWrite;
bungeman@google.combfc6cc42013-08-21 15:20:43 +0000107};
108
109class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
110public:
commit-bot@chromium.org967dee32014-02-04 22:35:01 +0000111 SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr,
112 IDWriteFontFamily* fontFamily)
bungeman@google.combfc6cc42013-08-21 15:20:43 +0000113 : fFontMgr(SkRef(fontMgr))
114 , fFontFamily(SkRefComPtr(fontFamily))
115 { }
116
117 virtual int count() SK_OVERRIDE;
118 virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE;
119 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE;
120 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE;
121
122private:
commit-bot@chromium.org967dee32014-02-04 22:35:01 +0000123 SkAutoTUnref<const SkFontMgr_DirectWrite> fFontMgr;
bungeman@google.combfc6cc42013-08-21 15:20:43 +0000124 SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
125};
126
127///////////////////////////////////////////////////////////////////////////////
128
bungeman@google.com94acfb52012-08-31 15:41:09 +0000129class StreamFontFileLoader : public IDWriteFontFileLoader {
130public:
131 // IUnknown methods
132 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
133 virtual ULONG STDMETHODCALLTYPE AddRef();
134 virtual ULONG STDMETHODCALLTYPE Release();
135
136 // IDWriteFontFileLoader methods
137 virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
138 void const* fontFileReferenceKey,
139 UINT32 fontFileReferenceKeySize,
140 IDWriteFontFileStream** fontFileStream);
141
142 static HRESULT Create(SkStream* stream, StreamFontFileLoader** streamFontFileLoader) {
143 *streamFontFileLoader = new StreamFontFileLoader(stream);
144 if (NULL == streamFontFileLoader) {
145 return E_OUTOFMEMORY;
146 }
147 return S_OK;
148 }
149
150 SkAutoTUnref<SkStream> fStream;
151
152private:
bungeman@google.com4bbc5242013-05-02 14:01:36 +0000153 StreamFontFileLoader(SkStream* stream) : fRefCount(1), fStream(SkRef(stream)) { }
bungeman@google.com94acfb52012-08-31 15:41:09 +0000154
155 ULONG fRefCount;
156};
157
158HRESULT StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
159 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
160 *ppvObject = this;
161 AddRef();
162 return S_OK;
163 } else {
164 *ppvObject = NULL;
165 return E_NOINTERFACE;
166 }
167}
168
169ULONG StreamFontFileLoader::AddRef() {
170 return InterlockedIncrement(&fRefCount);
171}
172
173ULONG StreamFontFileLoader::Release() {
174 ULONG newCount = InterlockedDecrement(&fRefCount);
175 if (0 == newCount) {
176 delete this;
177 }
178 return newCount;
179}
180
181HRESULT StreamFontFileLoader::CreateStreamFromKey(
182 void const* fontFileReferenceKey,
183 UINT32 fontFileReferenceKeySize,
184 IDWriteFontFileStream** fontFileStream)
185{
186 SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
187 HR(SkDWriteFontFileStreamWrapper::Create(fStream, &stream));
188 *fontFileStream = stream.release();
189 return S_OK;
190}
191
192class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
193public:
194 // IUnknown methods
195 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
196 virtual ULONG STDMETHODCALLTYPE AddRef();
197 virtual ULONG STDMETHODCALLTYPE Release();
198
199 // IDWriteFontFileEnumerator methods
200 virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile);
201 virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile);
202
203 static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
204 StreamFontFileEnumerator** streamFontFileEnumerator) {
205 *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
206 if (NULL == streamFontFileEnumerator) {
207 return E_OUTOFMEMORY;
208 }
209 return S_OK;
210 }
211private:
212 StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
213 ULONG fRefCount;
214
215 SkTScopedComPtr<IDWriteFactory> fFactory;
216 SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
217 SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
218 bool fHasNext;
219};
220
221StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
222 IDWriteFontFileLoader* fontFileLoader)
223 : fRefCount(1)
bungeman@google.com4bbc5242013-05-02 14:01:36 +0000224 , fFactory(SkRefComPtr(factory))
bungeman@google.com94acfb52012-08-31 15:41:09 +0000225 , fCurrentFile()
bungeman@google.com4bbc5242013-05-02 14:01:36 +0000226 , fFontFileLoader(SkRefComPtr(fontFileLoader))
bungeman@google.com94acfb52012-08-31 15:41:09 +0000227 , fHasNext(true)
bungeman@google.com4bbc5242013-05-02 14:01:36 +0000228{ }
bungeman@google.com94acfb52012-08-31 15:41:09 +0000229
230HRESULT StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
231 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) {
232 *ppvObject = this;
233 AddRef();
234 return S_OK;
235 } else {
236 *ppvObject = NULL;
237 return E_NOINTERFACE;
238 }
239}
240
241ULONG StreamFontFileEnumerator::AddRef() {
242 return InterlockedIncrement(&fRefCount);
243}
244
245ULONG StreamFontFileEnumerator::Release() {
246 ULONG newCount = InterlockedDecrement(&fRefCount);
247 if (0 == newCount) {
248 delete this;
249 }
250 return newCount;
251}
252
253HRESULT StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
254 *hasCurrentFile = FALSE;
255
256 if (!fHasNext) {
257 return S_OK;
258 }
259 fHasNext = false;
260
261 UINT32 dummy = 0;
262 HR(fFactory->CreateCustomFontFileReference(
263 &dummy, //cannot be NULL
264 sizeof(dummy), //even if this is 0
265 fFontFileLoader.get(),
266 &fCurrentFile));
267
268 *hasCurrentFile = TRUE;
269 return S_OK;
270}
271
272HRESULT StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) {
273 if (fCurrentFile.get() == NULL) {
274 *fontFile = NULL;
275 return E_FAIL;
276 }
277
bungeman@google.com4bbc5242013-05-02 14:01:36 +0000278 *fontFile = SkRefComPtr(fCurrentFile.get());
bungeman@google.com94acfb52012-08-31 15:41:09 +0000279 return S_OK;
280}
281
282class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
283public:
284 // IUnknown methods
285 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
286 virtual ULONG STDMETHODCALLTYPE AddRef();
287 virtual ULONG STDMETHODCALLTYPE Release();
288
289 // IDWriteFontCollectionLoader methods
290 virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
291 IDWriteFactory* factory,
292 void const* collectionKey,
293 UINT32 collectionKeySize,
294 IDWriteFontFileEnumerator** fontFileEnumerator);
295
296 static HRESULT Create(IDWriteFontFileLoader* fontFileLoader,
297 StreamFontCollectionLoader** streamFontCollectionLoader) {
298 *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader);
299 if (NULL == streamFontCollectionLoader) {
300 return E_OUTOFMEMORY;
301 }
302 return S_OK;
303 }
304private:
305 StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader)
306 : fRefCount(1)
bungeman@google.com4bbc5242013-05-02 14:01:36 +0000307 , fFontFileLoader(SkRefComPtr(fontFileLoader))
308 { }
bungeman@google.com94acfb52012-08-31 15:41:09 +0000309
310 ULONG fRefCount;
311 SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
312};
313
314HRESULT StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
315 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
316 *ppvObject = this;
317 AddRef();
318 return S_OK;
319 } else {
320 *ppvObject = NULL;
321 return E_NOINTERFACE;
322 }
323}
324
325ULONG StreamFontCollectionLoader::AddRef() {
326 return InterlockedIncrement(&fRefCount);
327}
328
329ULONG StreamFontCollectionLoader::Release() {
330 ULONG newCount = InterlockedDecrement(&fRefCount);
331 if (0 == newCount) {
332 delete this;
333 }
334 return newCount;
335}
336
337HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey(
338 IDWriteFactory* factory,
339 void const* collectionKey,
340 UINT32 collectionKeySize,
341 IDWriteFontFileEnumerator** fontFileEnumerator)
342{
343 SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
344 HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
345 *fontFileEnumerator = enumerator.release();
346 return S_OK;
347}
348
349///////////////////////////////////////////////////////////////////////////////
350
bungeman@google.come8f05922012-08-16 16:13:40 +0000351static SkTypeface::Style get_style(IDWriteFont* font) {
352 int style = SkTypeface::kNormal;
353 DWRITE_FONT_WEIGHT weight = font->GetWeight();
354 if (DWRITE_FONT_WEIGHT_DEMI_BOLD <= weight) {
355 style |= SkTypeface::kBold;
356 }
357 DWRITE_FONT_STYLE angle = font->GetStyle();
358 if (DWRITE_FONT_STYLE_OBLIQUE == angle || DWRITE_FONT_STYLE_ITALIC == angle) {
359 style |= SkTypeface::kItalic;
360 }
361 return static_cast<SkTypeface::Style>(style);
362}
363
364class DWriteFontTypeface : public SkTypeface {
365private:
366 DWriteFontTypeface(SkTypeface::Style style, SkFontID fontID,
bungeman@google.com6eddc772014-03-31 19:18:07 +0000367 IDWriteFactory* factory,
bungeman@google.come8f05922012-08-16 16:13:40 +0000368 IDWriteFontFace* fontFace,
369 IDWriteFont* font,
370 IDWriteFontFamily* fontFamily,
bungeman@google.com94acfb52012-08-31 15:41:09 +0000371 StreamFontFileLoader* fontFileLoader = NULL,
bungeman@google.come8f05922012-08-16 16:13:40 +0000372 IDWriteFontCollectionLoader* fontCollectionLoader = NULL)
373 : SkTypeface(style, fontID, false)
bungeman@google.com6eddc772014-03-31 19:18:07 +0000374 , fFactory(SkRefComPtr(factory))
bungeman@google.com4bbc5242013-05-02 14:01:36 +0000375 , fDWriteFontCollectionLoader(SkSafeRefComPtr(fontCollectionLoader))
376 , fDWriteFontFileLoader(SkSafeRefComPtr(fontFileLoader))
377 , fDWriteFontFamily(SkRefComPtr(fontFamily))
378 , fDWriteFont(SkRefComPtr(font))
379 , fDWriteFontFace(SkRefComPtr(fontFace))
380 { }
bungeman@google.come8f05922012-08-16 16:13:40 +0000381
382public:
bungeman@google.com6eddc772014-03-31 19:18:07 +0000383 SkTScopedComPtr<IDWriteFactory> fFactory;
bungeman@google.come8f05922012-08-16 16:13:40 +0000384 SkTScopedComPtr<IDWriteFontCollectionLoader> fDWriteFontCollectionLoader;
bungeman@google.com94acfb52012-08-31 15:41:09 +0000385 SkTScopedComPtr<StreamFontFileLoader> fDWriteFontFileLoader;
bungeman@google.come8f05922012-08-16 16:13:40 +0000386 SkTScopedComPtr<IDWriteFontFamily> fDWriteFontFamily;
387 SkTScopedComPtr<IDWriteFont> fDWriteFont;
388 SkTScopedComPtr<IDWriteFontFace> fDWriteFontFace;
389
bungeman@google.com6eddc772014-03-31 19:18:07 +0000390 static DWriteFontTypeface* Create(IDWriteFactory* factory,
391 IDWriteFontFace* fontFace,
bungeman@google.come8f05922012-08-16 16:13:40 +0000392 IDWriteFont* font,
393 IDWriteFontFamily* fontFamily,
bungeman@google.com94acfb52012-08-31 15:41:09 +0000394 StreamFontFileLoader* fontFileLoader = NULL,
bungeman@google.come8f05922012-08-16 16:13:40 +0000395 IDWriteFontCollectionLoader* fontCollectionLoader = NULL) {
396 SkTypeface::Style style = get_style(font);
397 SkFontID fontID = SkTypefaceCache::NewFontID();
bungeman@google.com94acfb52012-08-31 15:41:09 +0000398 return SkNEW_ARGS(DWriteFontTypeface, (style, fontID,
bungeman@google.com6eddc772014-03-31 19:18:07 +0000399 factory, fontFace, font, fontFamily,
bungeman@google.come8f05922012-08-16 16:13:40 +0000400 fontFileLoader, fontCollectionLoader));
401 }
402
bungeman@google.com72cf4fc2014-03-21 22:48:32 +0000403protected:
404 virtual void weak_dispose() const SK_OVERRIDE {
bungeman@google.com6eddc772014-03-31 19:18:07 +0000405 if (fDWriteFontCollectionLoader.get()) {
406 HRV(fFactory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get()));
407 }
408 if (fDWriteFontFileLoader.get()) {
409 HRV(fFactory->UnregisterFontFileLoader(fDWriteFontFileLoader.get()));
410 }
bungeman@google.com72cf4fc2014-03-21 22:48:32 +0000411
412 //SkTypefaceCache::Remove(this);
413 INHERITED::weak_dispose();
bungeman@google.come8f05922012-08-16 16:13:40 +0000414 }
reed@google.com0da48612013-03-19 16:06:52 +0000415
reed@google.com177dc6e2013-03-21 20:55:10 +0000416 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
reed@google.com0da48612013-03-19 16:06:52 +0000417 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
418 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
reed@google.com2689f612013-03-20 20:01:47 +0000419 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
420 SkAdvancedTypefaceMetrics::PerGlyphInfo,
421 const uint32_t*, uint32_t) const SK_OVERRIDE;
reed@google.com5526ede2013-03-25 13:03:37 +0000422 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
bungeman@google.com3c996f82013-10-24 21:39:35 +0000423 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
424 uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000425 virtual int onCountGlyphs() const SK_OVERRIDE;
426 virtual int onGetUPEM() const SK_OVERRIDE;
bungeman@google.com839702b2013-08-07 17:09:22 +0000427 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
bungeman@google.comb10b51f2013-08-01 20:18:41 +0000428 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
429 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
430 size_t length, void* data) const SK_OVERRIDE;
bungeman@google.com72cf4fc2014-03-21 22:48:32 +0000431
432private:
433 typedef SkTypeface INHERITED;
bungeman@google.come8f05922012-08-16 16:13:40 +0000434};
435
reed@google.com30ddd612013-07-30 17:47:39 +0000436class SkScalerContext_DW : public SkScalerContext {
bungeman@google.come8f05922012-08-16 16:13:40 +0000437public:
reed@google.com30ddd612013-07-30 17:47:39 +0000438 SkScalerContext_DW(DWriteFontTypeface*, const SkDescriptor* desc);
439 virtual ~SkScalerContext_DW();
bungeman@google.come8f05922012-08-16 16:13:40 +0000440
441protected:
442 virtual unsigned generateGlyphCount() SK_OVERRIDE;
443 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
444 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
445 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
bungeman@google.coma76de722012-10-26 19:35:54 +0000446 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
bungeman@google.come8f05922012-08-16 16:13:40 +0000447 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
448 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
449 SkPaint::FontMetrics* mY) SK_OVERRIDE;
450
451private:
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000452 const void* drawDWMask(const SkGlyph& glyph);
453
454 SkTDArray<uint8_t> fBits;
bungeman@google.com058670b2014-05-01 20:39:14 +0000455 /** The total matrix without the text height scale. */
456 SkMatrix fSkXform;
457 /** The total matrix without the text height scale. */
bungeman@google.come8f05922012-08-16 16:13:40 +0000458 DWRITE_MATRIX fXform;
bungeman@google.com058670b2014-05-01 20:39:14 +0000459 /** The non-rotational part of total matrix without the text height scale.
460 * This is used to find the magnitude of gdi compatible advances.
461 */
462 DWRITE_MATRIX fGsA;
463 /** The inverse of the rotational part of the total matrix.
464 * This is used to find the direction of gdi compatible advances.
465 */
466 SkMatrix fG_inv;
467 /** The text size to render with. */
468 SkScalar fTextSizeRender;
469 /** The text size to measure with. */
470 SkScalar fTextSizeMeasure;
bungeman@google.come8f05922012-08-16 16:13:40 +0000471 SkAutoTUnref<DWriteFontTypeface> fTypeface;
472 int fGlyphCount;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000473 DWRITE_RENDERING_MODE fRenderingMode;
474 DWRITE_TEXTURE_TYPE fTextureType;
475 DWRITE_MEASURING_MODE fMeasuringMode;
bungeman@google.come8f05922012-08-16 16:13:40 +0000476};
477
bungeman@google.come8f05922012-08-16 16:13:40 +0000478static bool are_same(IUnknown* a, IUnknown* b) {
479 SkTScopedComPtr<IUnknown> iunkA;
480 if (FAILED(a->QueryInterface(&iunkA))) {
481 return false;
482 }
483
484 SkTScopedComPtr<IUnknown> iunkB;
485 if (FAILED(b->QueryInterface(&iunkB))) {
486 return false;
487 }
488
489 return iunkA.get() == iunkB.get();
490}
491static bool FindByDWriteFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
492 //Check to see if the two fonts are identical.
493 DWriteFontTypeface* dwFace = reinterpret_cast<DWriteFontTypeface*>(face);
494 IDWriteFont* dwFont = reinterpret_cast<IDWriteFont*>(ctx);
495 if (are_same(dwFace->fDWriteFont.get(), dwFont)) {
496 return true;
497 }
498
499 //Check if the two fonts share the same loader and have the same key.
500 SkTScopedComPtr<IDWriteFontFace> dwFaceFontFace;
501 SkTScopedComPtr<IDWriteFontFace> dwFontFace;
502 HRB(dwFace->fDWriteFont->CreateFontFace(&dwFaceFontFace));
503 HRB(dwFont->CreateFontFace(&dwFontFace));
504 if (are_same(dwFaceFontFace.get(), dwFontFace.get())) {
505 return true;
506 }
507
508 UINT32 dwFaceNumFiles;
509 UINT32 dwNumFiles;
510 HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, NULL));
511 HRB(dwFontFace->GetFiles(&dwNumFiles, NULL));
512 if (dwFaceNumFiles != dwNumFiles) {
513 return false;
514 }
515
516 SkTScopedComPtr<IDWriteFontFile> dwFaceFontFile;
517 SkTScopedComPtr<IDWriteFontFile> dwFontFile;
518 HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, &dwFaceFontFile));
519 HRB(dwFontFace->GetFiles(&dwNumFiles, &dwFontFile));
520
521 //for (each file) { //we currently only admit fonts from one file.
522 SkTScopedComPtr<IDWriteFontFileLoader> dwFaceFontFileLoader;
523 SkTScopedComPtr<IDWriteFontFileLoader> dwFontFileLoader;
524 HRB(dwFaceFontFile->GetLoader(&dwFaceFontFileLoader));
525 HRB(dwFontFile->GetLoader(&dwFontFileLoader));
526 if (!are_same(dwFaceFontFileLoader.get(), dwFontFileLoader.get())) {
527 return false;
528 }
529 //}
530
531 const void* dwFaceFontRefKey;
532 UINT32 dwFaceFontRefKeySize;
533 const void* dwFontRefKey;
534 UINT32 dwFontRefKeySize;
535 HRB(dwFaceFontFile->GetReferenceKey(&dwFaceFontRefKey, &dwFaceFontRefKeySize));
536 HRB(dwFontFile->GetReferenceKey(&dwFontRefKey, &dwFontRefKeySize));
537 if (dwFaceFontRefKeySize != dwFontRefKeySize) {
538 return false;
539 }
540 if (0 != memcmp(dwFaceFontRefKey, dwFontRefKey, dwFontRefKeySize)) {
541 return false;
542 }
543
544 //TODO: better means than comparing name strings?
545 //NOTE: .tfc and fake bold/italic will end up here.
546 SkTScopedComPtr<IDWriteFontFamily> dwFaceFontFamily;
547 SkTScopedComPtr<IDWriteFontFamily> dwFontFamily;
548 HRB(dwFace->fDWriteFont->GetFontFamily(&dwFaceFontFamily));
549 HRB(dwFont->GetFontFamily(&dwFontFamily));
550
551 SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontFamilyNames;
552 SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontNames;
553 HRB(dwFaceFontFamily->GetFamilyNames(&dwFaceFontFamilyNames));
554 HRB(dwFace->fDWriteFont->GetFaceNames(&dwFaceFontNames));
555
556 SkTScopedComPtr<IDWriteLocalizedStrings> dwFontFamilyNames;
557 SkTScopedComPtr<IDWriteLocalizedStrings> dwFontNames;
558 HRB(dwFontFamily->GetFamilyNames(&dwFontFamilyNames));
559 HRB(dwFont->GetFaceNames(&dwFontNames));
560
561 UINT32 dwFaceFontFamilyNameLength;
562 UINT32 dwFaceFontNameLength;
563 HRB(dwFaceFontFamilyNames->GetStringLength(0, &dwFaceFontFamilyNameLength));
564 HRB(dwFaceFontNames->GetStringLength(0, &dwFaceFontNameLength));
565
566 UINT32 dwFontFamilyNameLength;
567 UINT32 dwFontNameLength;
568 HRB(dwFontFamilyNames->GetStringLength(0, &dwFontFamilyNameLength));
569 HRB(dwFontNames->GetStringLength(0, &dwFontNameLength));
570
571 if (dwFaceFontFamilyNameLength != dwFontFamilyNameLength ||
572 dwFaceFontNameLength != dwFontNameLength)
573 {
574 return false;
575 }
576
bungeman@google.com71033442013-05-01 14:21:20 +0000577 SkSMallocWCHAR dwFaceFontFamilyNameChar(dwFaceFontFamilyNameLength+1);
578 SkSMallocWCHAR dwFaceFontNameChar(dwFaceFontNameLength+1);
579 HRB(dwFaceFontFamilyNames->GetString(0, dwFaceFontFamilyNameChar.get(), dwFaceFontFamilyNameLength+1));
580 HRB(dwFaceFontNames->GetString(0, dwFaceFontNameChar.get(), dwFaceFontNameLength+1));
bungeman@google.come8f05922012-08-16 16:13:40 +0000581
bungeman@google.com71033442013-05-01 14:21:20 +0000582 SkSMallocWCHAR dwFontFamilyNameChar(dwFontFamilyNameLength+1);
583 SkSMallocWCHAR dwFontNameChar(dwFontNameLength+1);
584 HRB(dwFontFamilyNames->GetString(0, dwFontFamilyNameChar.get(), dwFontFamilyNameLength+1));
585 HRB(dwFontNames->GetString(0, dwFontNameChar.get(), dwFontNameLength+1));
bungeman@google.come8f05922012-08-16 16:13:40 +0000586
bungeman@google.com71033442013-05-01 14:21:20 +0000587 return wcscmp(dwFaceFontFamilyNameChar.get(), dwFontFamilyNameChar.get()) == 0 &&
588 wcscmp(dwFaceFontNameChar.get(), dwFontNameChar.get()) == 0;
bungeman@google.come8f05922012-08-16 16:13:40 +0000589}
590
bungeman@google.com058670b2014-05-01 20:39:14 +0000591class AutoDWriteTable {
592public:
593 AutoDWriteTable(IDWriteFontFace* fontFace, UINT32 beTag) : fFontFace(fontFace), fExists(FALSE) {
594 // Any errors are ignored, user must check fExists anyway.
595 fontFace->TryGetFontTable(beTag,
596 reinterpret_cast<const void **>(&fData), &fSize, &fLock, &fExists);
597 }
598 ~AutoDWriteTable() {
599 if (fExists) {
600 fFontFace->ReleaseFontTable(fLock);
601 }
602 }
603
604 const uint8_t* fData;
605 UINT32 fSize;
606 BOOL fExists;
607private:
608 // Borrowed reference, the user must ensure the fontFace stays alive.
609 IDWriteFontFace* fFontFace;
610 void* fLock;
611};
612template<typename T> class AutoTDWriteTable : public AutoDWriteTable {
613public:
614 static const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3);
615 AutoTDWriteTable(IDWriteFontFace* fontFace) : AutoDWriteTable(fontFace, tag) { }
616
617 const T* get() const { return reinterpret_cast<const T*>(fData); }
618 const T* operator->() const { return reinterpret_cast<const T*>(fData); }
619};
620
621static bool hasBitmapStrike(DWriteFontTypeface* typeface, int size) {
622 {
623 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
624 if (!eblc.fExists) {
625 return false;
626 }
627 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) {
628 return false;
629 }
630 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) {
631 return false;
632 }
633
634 uint32_t numSizes = SkEndianSwap32(eblc->numSizes);
635 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) +
636 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable) * numSizes)
637 {
638 return false;
639 }
640
641 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable =
642 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>(eblc.get());
643 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
644 if (sizeTable->ppemX == size && sizeTable->ppemY == size) {
645 // TODO: determine if we should dig through IndexSubTableArray/IndexSubTable
646 // to determine the actual number of glyphs with bitmaps.
647
648 // TODO: Ensure that the bitmaps actually cover a significant portion of the strike.
649
650 //TODO: Endure that the bitmaps are bi-level.
651 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3) {
652 return true;
653 }
654 }
655 }
656 }
657
658 {
659 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteFontFace.get());
660 if (!ebsc.fExists) {
661 return false;
662 }
663 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) {
664 return false;
665 }
666 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) {
667 return false;
668 }
669
670 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes);
671 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) +
672 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable) * numSizes)
673 {
674 return false;
675 }
676
677 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable =
678 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>(ebsc.get());
679 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
680 if (scaleTable->ppemX == size && scaleTable->ppemY == size) {
681 // EBSC tables are normally only found in bitmap only fonts.
682 return true;
683 }
684 }
685 }
686
687 return false;
688}
689
690static bool bothZero(SkScalar a, SkScalar b) {
691 return 0 == a && 0 == b;
692}
693
694// returns false if there is any non-90-rotation or skew
695static bool isAxisAligned(const SkScalerContext::Rec& rec) {
696 return 0 == rec.fPreSkewX &&
697 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
698 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
699}
700
reed@google.com30ddd612013-07-30 17:47:39 +0000701SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
bungeman@google.com6eddc772014-03-31 19:18:07 +0000702 const SkDescriptor* desc)
reed@google.com0da48612013-03-19 16:06:52 +0000703 : SkScalerContext(typeface, desc)
704 , fTypeface(SkRef(typeface))
bungeman@google.come8f05922012-08-16 16:13:40 +0000705 , fGlyphCount(-1) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000706
bungeman@google.com058670b2014-05-01 20:39:14 +0000707 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC
708 // except when bi-level rendering is requested or there are embedded
709 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation).
710 //
711 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do
712 // this. As a result, determine the actual size of the text and then see if
713 // there are any embedded bi-level bitmaps of that size. If there are, then
714 // force bitmaps by requesting bi-level rendering.
715 //
716 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes
717 // square pixels and only uses ppemY. Therefore the transform must track any
718 // non-uniform x-scale.
719 //
720 // Also, rotated glyphs should have the same absolute advance widths as
721 // horizontal glyphs and the subpixel flag should not affect glyph shapes.
bungeman@google.come8f05922012-08-16 16:13:40 +0000722
bungeman@google.com058670b2014-05-01 20:39:14 +0000723 // A is the total matrix.
724 SkMatrix A;
725 fRec.getSingleMatrix(&A);
726
727 // h is where A maps the horizontal baseline.
728 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
729 A.mapPoints(&h, 1);
730
731 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
732 SkMatrix G;
733 SkComputeGivensRotation(h, &G);
734
735 // GA is the matrix A with rotation removed.
736 SkMatrix GA(G);
737 GA.preConcat(A);
738
739 // realTextSize is the actual device size we want (as opposed to the size the user requested).
740 // gdiTextSize is the size we request when GDI compatible.
741 // If the scale is negative, this means the matrix will do the flip anyway.
742 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
743 // Due to floating point math, the lower bits are suspect. Round carefully.
744 SkScalar roundedTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f;
745 SkScalar gdiTextSize = SkScalarFloorToScalar(roundedTextSize);
746 if (gdiTextSize == 0) {
747 gdiTextSize = SK_Scalar1;
748 }
749
750 bool hasBitmap = fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag &&
751 hasBitmapStrike(typeface, SkScalarTruncToInt(gdiTextSize));
752 bool axisAligned = isAxisAligned(fRec);
753 bool isBiLevel = SkMask::kBW_Format == fRec.fMaskFormat || (hasBitmap && axisAligned);
754
755 if (isBiLevel) {
756 fTextSizeRender = gdiTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000757 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED;
758 fTextureType = DWRITE_TEXTURE_ALIASED_1x1;
bungeman@google.com058670b2014-05-01 20:39:14 +0000759 fTextSizeMeasure = gdiTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000760 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
bungeman@google.com058670b2014-05-01 20:39:14 +0000761 } else if (hasBitmap) {
762 // If rotated but the horizontal text would have used a bitmap,
763 // render high quality rotated glyphs using the bitmap metrics.
764 fTextSizeRender = gdiTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000765 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
766 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
bungeman@google.com058670b2014-05-01 20:39:14 +0000767 fTextSizeMeasure = gdiTextSize;
768 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
769 } else {
770 fTextSizeRender = realTextSize;
771 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
772 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
773 fTextSizeMeasure = realTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000774 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
775 }
776
777 if (this->isSubpixel()) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000778 fTextSizeMeasure = realTextSize;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000779 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
780 }
bungeman@google.com058670b2014-05-01 20:39:14 +0000781
782 // Remove the realTextSize, as that is the text height scale currently in A.
783 SkScalar scale = SkScalarInvert(realTextSize);
784
785 // fSkXform is the total matrix A without the text height scale.
786 fSkXform = A;
787 fSkXform.preScale(scale, scale); //remove the text height scale.
788
789 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX());
790 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY());
791 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX());
792 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY());
793 fXform.dx = 0;
794 fXform.dy = 0;
795
796 // GsA is the non-rotational part of A without the text height scale.
797 SkMatrix GsA(GA);
798 GsA.preScale(scale, scale); //remove text height scale, G is rotational so reorders with scale.
799
800 fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX));
801 fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
802 fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX));
803 fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY));
bungeman@google.come4ae0bc2014-05-21 19:44:39 +0000804 fGsA.dx = 0;
805 fGsA.dy = 0;
bungeman@google.com058670b2014-05-01 20:39:14 +0000806
807 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
808 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
809 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
810 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
bungeman@google.come8f05922012-08-16 16:13:40 +0000811}
812
reed@google.com30ddd612013-07-30 17:47:39 +0000813SkScalerContext_DW::~SkScalerContext_DW() {
bungeman@google.come8f05922012-08-16 16:13:40 +0000814}
815
reed@google.com30ddd612013-07-30 17:47:39 +0000816unsigned SkScalerContext_DW::generateGlyphCount() {
bungeman@google.come8f05922012-08-16 16:13:40 +0000817 if (fGlyphCount < 0) {
818 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
819 }
820 return fGlyphCount;
821}
822
reed@google.com30ddd612013-07-30 17:47:39 +0000823uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000824 uint16_t index = 0;
825 fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
826 return index;
827}
828
reed@google.com30ddd612013-07-30 17:47:39 +0000829void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000830 //Delta is the difference between the right/left side bearing metric
831 //and where the right/left side bearing ends up after hinting.
832 //DirectWrite does not provide this information.
833 glyph->fRsbDelta = 0;
834 glyph->fLsbDelta = 0;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000835
bungeman@google.come8f05922012-08-16 16:13:40 +0000836 glyph->fAdvanceX = 0;
837 glyph->fAdvanceY = 0;
838
839 uint16_t glyphId = glyph->getGlyphID();
840 DWRITE_GLYPH_METRICS gm;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000841
842 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
843 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
844 {
845 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
bungeman@google.com058670b2014-05-01 20:39:14 +0000846 fTextSizeMeasure,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000847 1.0f, // pixelsPerDip
bungeman@google.com058670b2014-05-01 20:39:14 +0000848 &fGsA,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000849 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode,
850 &glyphId, 1,
851 &gm),
852 "Could not get gdi compatible glyph metrics.");
853 } else {
854 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
855 "Could not get design metrics.");
856 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000857
858 DWRITE_FONT_METRICS dwfm;
859 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
bungeman@google.com058670b2014-05-01 20:39:14 +0000860 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
bungeman@google.come8f05922012-08-16 16:13:40 +0000861 SkIntToScalar(gm.advanceWidth),
862 SkIntToScalar(dwfm.designUnitsPerEm));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000863
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000864 if (!this->isSubpixel()) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000865 advanceX = SkScalarRoundToScalar(advanceX);
866 }
867
868 SkVector vecs[1] = { { advanceX, 0 } };
bungeman@google.com058670b2014-05-01 20:39:14 +0000869 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
870 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
871 {
872 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
873 } else {
874 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
875 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000876
877 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
878 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
879}
880
reed@google.com30ddd612013-07-30 17:47:39 +0000881void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000882 glyph->fWidth = 0;
883
884 this->generateAdvance(glyph);
885
886 //Measure raster size.
887 fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
888 fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
889
890 FLOAT advance = 0;
891
892 UINT16 glyphId = glyph->getGlyphID();
893
894 DWRITE_GLYPH_OFFSET offset;
895 offset.advanceOffset = 0.0f;
896 offset.ascenderOffset = 0.0f;
897
898 DWRITE_GLYPH_RUN run;
899 run.glyphCount = 1;
900 run.glyphAdvances = &advance;
901 run.fontFace = fTypeface->fDWriteFontFace.get();
bungeman@google.com058670b2014-05-01 20:39:14 +0000902 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
bungeman@google.come8f05922012-08-16 16:13:40 +0000903 run.bidiLevel = 0;
904 run.glyphIndices = &glyphId;
905 run.isSideways = FALSE;
906 run.glyphOffsets = &offset;
907
bungeman@google.come8f05922012-08-16 16:13:40 +0000908 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
bungeman@google.com6eddc772014-03-31 19:18:07 +0000909 HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
910 &run,
911 1.0f, // pixelsPerDip,
912 &fXform,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000913 fRenderingMode,
914 fMeasuringMode,
bungeman@google.com6eddc772014-03-31 19:18:07 +0000915 0.0f, // baselineOriginX,
916 0.0f, // baselineOriginY,
917 &glyphRunAnalysis),
bungeman@google.come8f05922012-08-16 16:13:40 +0000918 "Could not create glyph run analysis.");
rmistry@google.comd6176b02012-08-23 18:14:13 +0000919
bungeman@google.come8f05922012-08-16 16:13:40 +0000920 RECT bbox;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000921 HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
bungeman@google.come8f05922012-08-16 16:13:40 +0000922 "Could not get texture bounds.");
923
924 glyph->fWidth = SkToU16(bbox.right - bbox.left);
925 glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
926 glyph->fLeft = SkToS16(bbox.left);
927 glyph->fTop = SkToS16(bbox.top);
928}
929
reed@google.com30ddd612013-07-30 17:47:39 +0000930void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000931 SkPaint::FontMetrics* my) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000932 if (!(mx || my))
933 return;
934
bungeman@google.come1b9bad2013-08-27 21:51:37 +0000935 if (mx) {
936 sk_bzero(mx, sizeof(*mx));
937 }
938 if (my) {
939 sk_bzero(my, sizeof(*my));
940 }
941
bungeman@google.come8f05922012-08-16 16:13:40 +0000942 DWRITE_FONT_METRICS dwfm;
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000943 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
944 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
945 {
946 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics(
bungeman@google.com058670b2014-05-01 20:39:14 +0000947 fTextSizeRender,
bungeman@google.comd715aaa2014-04-09 15:35:03 +0000948 1.0f, // pixelsPerDip
949 &fXform,
950 &dwfm);
951 } else {
952 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
953 }
bungeman@google.come8f05922012-08-16 16:13:40 +0000954
bungeman@google.come1b9bad2013-08-27 21:51:37 +0000955 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
bungeman@google.come8f05922012-08-16 16:13:40 +0000956 if (mx) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000957 mx->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
bungeman@google.com76875782013-08-28 03:16:02 +0000958 mx->fAscent = mx->fTop;
bungeman@google.com058670b2014-05-01 20:39:14 +0000959 mx->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
bungeman@google.com76875782013-08-28 03:16:02 +0000960 mx->fBottom = mx->fDescent;
bungeman@google.com058670b2014-05-01 20:39:14 +0000961 mx->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
962 mx->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
bungeman@google.com7584c292014-05-09 19:25:43 +0000963 mx->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
964 mx->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
commit-bot@chromium.org0bc406d2014-03-01 20:12:26 +0000965
966 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
967 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
bungeman@google.come8f05922012-08-16 16:13:40 +0000968 }
969
970 if (my) {
bungeman@google.com058670b2014-05-01 20:39:14 +0000971 my->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem;
bungeman@google.come8f05922012-08-16 16:13:40 +0000972 my->fAscent = my->fTop;
bungeman@google.com058670b2014-05-01 20:39:14 +0000973 my->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem;
bungeman@google.come8f05922012-08-16 16:13:40 +0000974 my->fBottom = my->fDescent;
bungeman@google.com058670b2014-05-01 20:39:14 +0000975 my->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem;
976 my->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem;
bungeman@google.com7584c292014-05-09 19:25:43 +0000977 my->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underlineThickness) / upem;
978 my->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlinePosition) / upem);
commit-bot@chromium.org0bc406d2014-03-01 20:12:26 +0000979
980 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
981 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
bungeman@google.come8f05922012-08-16 16:13:40 +0000982 }
983}
984
985///////////////////////////////////////////////////////////////////////////////
986
987#include "SkColorPriv.h"
988
989static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
990 const int width = glyph.fWidth;
991 const size_t dstRB = (width + 7) >> 3;
992 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
993
994 int byteCount = width >> 3;
995 int bitCount = width & 7;
996
997 for (int y = 0; y < glyph.fHeight; ++y) {
998 if (byteCount > 0) {
999 for (int i = 0; i < byteCount; ++i) {
1000 unsigned byte = 0;
1001 byte |= src[0] & (1 << 7);
1002 byte |= src[1] & (1 << 6);
1003 byte |= src[2] & (1 << 5);
1004 byte |= src[3] & (1 << 4);
1005 byte |= src[4] & (1 << 3);
1006 byte |= src[5] & (1 << 2);
1007 byte |= src[6] & (1 << 1);
1008 byte |= src[7] & (1 << 0);
1009 dst[i] = byte;
1010 src += 8;
1011 }
1012 }
1013 if (bitCount > 0) {
1014 unsigned byte = 0;
1015 unsigned mask = 0x80;
1016 for (int i = 0; i < bitCount; i++) {
1017 byte |= (src[i]) & mask;
1018 mask >>= 1;
1019 }
1020 dst[byteCount] = byte;
1021 }
1022 src += bitCount;
1023 dst += dstRB;
1024 }
1025}
1026
1027template<bool APPLY_PREBLEND>
1028static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
1029 const size_t dstRB = glyph.rowBytes();
1030 const U16CPU width = glyph.fWidth;
1031 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
1032
1033 for (U16CPU y = 0; y < glyph.fHeight; y++) {
1034 for (U16CPU i = 0; i < width; i++) {
1035 U8CPU r = *(src++);
1036 U8CPU g = *(src++);
1037 U8CPU b = *(src++);
1038 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
1039 }
1040 dst = (uint8_t*)((char*)dst + dstRB);
1041 }
1042}
1043
1044template<bool APPLY_PREBLEND>
1045static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
1046 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1047 const size_t dstRB = glyph.rowBytes();
1048 const U16CPU width = glyph.fWidth;
1049 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
1050
1051 for (U16CPU y = 0; y < glyph.fHeight; y++) {
1052 for (U16CPU i = 0; i < width; i++) {
1053 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
1054 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
1055 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
1056 dst[i] = SkPack888ToRGB16(r, g, b);
1057 }
1058 dst = (uint16_t*)((char*)dst + dstRB);
1059 }
1060}
1061
1062template<bool APPLY_PREBLEND>
1063static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
1064 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1065 const size_t dstRB = glyph.rowBytes();
1066 const U16CPU width = glyph.fWidth;
1067 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
1068
1069 for (U16CPU y = 0; y < glyph.fHeight; y++) {
1070 for (U16CPU i = 0; i < width; i++) {
1071 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
1072 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
1073 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
1074 dst[i] = SkPackARGB32(0xFF, r, g, b);
1075 }
1076 dst = (SkPMColor*)((char*)dst + dstRB);
1077 }
1078}
1079
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001080const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
1081 int sizeNeeded = glyph.fWidth * glyph.fHeight;
1082 if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
1083 sizeNeeded *= 3;
1084 }
1085 if (sizeNeeded > fBits.count()) {
1086 fBits.setCount(sizeNeeded);
1087 }
bungeman@google.come8f05922012-08-16 16:13:40 +00001088
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001089 // erase
1090 memset(fBits.begin(), 0, sizeNeeded);
1091
1092 fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
1093 fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
1094
1095 FLOAT advance = 0.0f;
1096
1097 UINT16 index = glyph.getGlyphID();
1098
1099 DWRITE_GLYPH_OFFSET offset;
1100 offset.advanceOffset = 0.0f;
1101 offset.ascenderOffset = 0.0f;
1102
1103 DWRITE_GLYPH_RUN run;
1104 run.glyphCount = 1;
1105 run.glyphAdvances = &advance;
1106 run.fontFace = fTypeface->fDWriteFontFace.get();
bungeman@google.com058670b2014-05-01 20:39:14 +00001107 run.fontEmSize = SkScalarToFloat(fTextSizeRender);
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001108 run.bidiLevel = 0;
1109 run.glyphIndices = &index;
1110 run.isSideways = FALSE;
1111 run.glyphOffsets = &offset;
1112
1113 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
1114 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
1115 1.0f, // pixelsPerDip,
1116 &fXform,
1117 fRenderingMode,
1118 fMeasuringMode,
1119 0.0f, // baselineOriginX,
1120 0.0f, // baselineOriginY,
1121 &glyphRunAnalysis),
1122 "Could not create glyph run analysis.");
1123
1124 //NOTE: this assumes that the glyph has already been measured
1125 //with an exact same glyph run analysis.
1126 RECT bbox;
1127 bbox.left = glyph.fLeft;
1128 bbox.top = glyph.fTop;
1129 bbox.right = glyph.fLeft + glyph.fWidth;
1130 bbox.bottom = glyph.fTop + glyph.fHeight;
1131 HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType,
1132 &bbox,
1133 fBits.begin(),
1134 sizeNeeded),
1135 "Could not draw mask.");
1136 return fBits.begin();
1137}
1138
1139void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
bungeman@google.come8f05922012-08-16 16:13:40 +00001140 //Create the mask.
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001141 const void* bits = this->drawDWMask(glyph);
bungeman@google.come8f05922012-08-16 16:13:40 +00001142 if (!bits) {
1143 sk_bzero(glyph.fImage, glyph.computeImageSize());
1144 return;
1145 }
1146
1147 //Copy the mask into the glyph.
bungeman@google.come8f05922012-08-16 16:13:40 +00001148 const uint8_t* src = (const uint8_t*)bits;
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001149 if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) {
bungeman@google.come8f05922012-08-16 16:13:40 +00001150 bilevel_to_bw(src, glyph);
bungeman@google.comd715aaa2014-04-09 15:35:03 +00001151 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
1152 } else if (!isLCD(fRec)) {
bungeman@google.coma76de722012-10-26 19:35:54 +00001153 if (fPreBlend.isApplicable()) {
1154 rgb_to_a8<true>(src, glyph, fPreBlend.fG);
bungeman@google.come8f05922012-08-16 16:13:40 +00001155 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001156 rgb_to_a8<false>(src, glyph, fPreBlend.fG);
bungeman@google.come8f05922012-08-16 16:13:40 +00001157 }
1158 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
bungeman@google.coma76de722012-10-26 19:35:54 +00001159 if (fPreBlend.isApplicable()) {
1160 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.come8f05922012-08-16 16:13:40 +00001161 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001162 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.come8f05922012-08-16 16:13:40 +00001163 }
1164 } else {
1165 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
bungeman@google.coma76de722012-10-26 19:35:54 +00001166 if (fPreBlend.isApplicable()) {
1167 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.come8f05922012-08-16 16:13:40 +00001168 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001169 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.come8f05922012-08-16 16:13:40 +00001170 }
1171 }
1172}
1173
reed@google.com30ddd612013-07-30 17:47:39 +00001174void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
bungeman@google.come8f05922012-08-16 16:13:40 +00001175 SkASSERT(&glyph && path);
1176
1177 path->reset();
1178
1179 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
1180 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
1181 "Could not create geometry to path converter.");
1182 uint16_t glyphId = glyph.getGlyphID();
1183 //TODO: convert to<->from DIUs? This would make a difference if hinting.
1184 //It may not be needed, it appears that DirectWrite only hints at em size.
bungeman@google.com058670b2014-05-01 20:39:14 +00001185 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
bungeman@google.come8f05922012-08-16 16:13:40 +00001186 &glyphId,
1187 NULL, //advances
1188 NULL, //offsets
1189 1, //num glyphs
1190 FALSE, //sideways
1191 FALSE, //rtl
1192 geometryToPath.get()),
1193 "Could not create glyph outline.");
bungeman@google.com091f51b2013-01-10 18:56:18 +00001194
bungeman@google.com058670b2014-05-01 20:39:14 +00001195 path->transform(fSkXform);
bungeman@google.come8f05922012-08-16 16:13:40 +00001196}
1197
reed@google.com5526ede2013-03-25 13:03:37 +00001198void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1199 bool* isLocalStream) const {
bungeman@google.com94acfb52012-08-31 15:41:09 +00001200 // Get the family name.
1201 SkTScopedComPtr<IDWriteLocalizedStrings> dwFamilyNames;
reed@google.com5526ede2013-03-25 13:03:37 +00001202 HRV(fDWriteFontFamily->GetFamilyNames(&dwFamilyNames));
bungeman@google.com94acfb52012-08-31 15:41:09 +00001203
1204 UINT32 dwFamilyNamesLength;
1205 HRV(dwFamilyNames->GetStringLength(0, &dwFamilyNamesLength));
1206
bungeman@google.com71033442013-05-01 14:21:20 +00001207 SkSMallocWCHAR dwFamilyNameChar(dwFamilyNamesLength+1);
1208 HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.get(), dwFamilyNamesLength+1));
bungeman@google.com94acfb52012-08-31 15:41:09 +00001209
bungeman@google.com71033442013-05-01 14:21:20 +00001210 SkString utf8FamilyName;
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001211 HRV(sk_wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName));
bungeman@google.com94acfb52012-08-31 15:41:09 +00001212
bungeman@google.com71033442013-05-01 14:21:20 +00001213 desc->setFamilyName(utf8FamilyName.c_str());
reed@google.com5526ede2013-03-25 13:03:37 +00001214 *isLocalStream = SkToBool(fDWriteFontFileLoader.get());
bungeman@google.come8f05922012-08-16 16:13:40 +00001215}
1216
bungeman@google.com3c996f82013-10-24 21:39:35 +00001217static SkUnichar next_utf8(const void** chars) {
1218 return SkUTF8_NextUnichar((const char**)chars);
1219}
1220
1221static SkUnichar next_utf16(const void** chars) {
1222 return SkUTF16_NextUnichar((const uint16_t**)chars);
1223}
1224
1225static SkUnichar next_utf32(const void** chars) {
1226 const SkUnichar** uniChars = (const SkUnichar**)chars;
1227 SkUnichar uni = **uniChars;
1228 *uniChars += 1;
1229 return uni;
1230}
1231
1232typedef SkUnichar (*EncodingProc)(const void**);
1233
1234static EncodingProc find_encoding_proc(SkTypeface::Encoding enc) {
1235 static const EncodingProc gProcs[] = {
1236 next_utf8, next_utf16, next_utf32
1237 };
1238 SkASSERT((size_t)enc < SK_ARRAY_COUNT(gProcs));
1239 return gProcs[enc];
1240}
1241
1242int DWriteFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
1243 uint16_t glyphs[], int glyphCount) const
1244{
1245 if (NULL == glyphs) {
1246 EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
1247 for (int i = 0; i < glyphCount; ++i) {
1248 const SkUnichar c = next_ucs4_proc(&chars);
1249 BOOL exists;
1250 fDWriteFont->HasCharacter(c, &exists);
1251 if (!exists) {
1252 return i;
1253 }
1254 }
1255 return glyphCount;
1256 }
1257
1258 switch (encoding) {
1259 case SkTypeface::kUTF8_Encoding:
1260 case SkTypeface::kUTF16_Encoding: {
1261 static const int scratchCount = 256;
1262 UINT32 scratch[scratchCount];
1263 EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
1264 for (int baseGlyph = 0; baseGlyph < glyphCount; baseGlyph += scratchCount) {
1265 int glyphsLeft = glyphCount - baseGlyph;
1266 int limit = SkTMin(glyphsLeft, scratchCount);
1267 for (int i = 0; i < limit; ++i) {
1268 scratch[i] = next_ucs4_proc(&chars);
1269 }
1270 fDWriteFontFace->GetGlyphIndices(scratch, limit, &glyphs[baseGlyph]);
1271 }
1272 break;
1273 }
bungeman@google.com172c3632013-10-24 21:50:12 +00001274 case SkTypeface::kUTF32_Encoding: {
bungeman@google.com3c996f82013-10-24 21:39:35 +00001275 const UINT32* utf32 = reinterpret_cast<const UINT32*>(chars);
1276 fDWriteFontFace->GetGlyphIndices(utf32, glyphCount, glyphs);
1277 break;
bungeman@google.com172c3632013-10-24 21:50:12 +00001278 }
bungeman@google.com3c996f82013-10-24 21:39:35 +00001279 default:
1280 SK_CRASH();
1281 }
1282
1283 for (int i = 0; i < glyphCount; ++i) {
1284 if (0 == glyphs[i]) {
1285 return i;
1286 }
1287 }
1288 return glyphCount;
1289}
1290
bungeman@google.com7bdd6142013-07-15 19:42:57 +00001291int DWriteFontTypeface::onCountGlyphs() const {
1292 return fDWriteFontFace->GetGlyphCount();
1293}
1294
1295int DWriteFontTypeface::onGetUPEM() const {
1296 DWRITE_FONT_METRICS metrics;
1297 fDWriteFontFace->GetMetrics(&metrics);
1298 return metrics.designUnitsPerEm;
1299}
1300
bungeman@google.coma9802692013-08-07 02:45:25 +00001301class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings {
1302public:
1303 /** Takes ownership of the IDWriteLocalizedStrings. */
1304 explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings)
1305 : fIndex(0), fStrings(strings)
1306 { }
1307
1308 virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE {
1309 if (fIndex >= fStrings->GetCount()) {
1310 return false;
1311 }
1312
1313 // String
1314 UINT32 stringLength;
1315 HRBM(fStrings->GetStringLength(fIndex, &stringLength), "Could not get string length.");
1316 stringLength += 1;
1317
1318 SkSMallocWCHAR wString(stringLength);
1319 HRBM(fStrings->GetString(fIndex, wString.get(), stringLength), "Could not get string.");
1320
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001321 HRB(sk_wchar_to_skstring(wString.get(), &localizedString->fString));
bungeman@google.coma9802692013-08-07 02:45:25 +00001322
1323 // Locale
1324 UINT32 localeLength;
1325 HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLength), "Could not get locale length.");
1326 localeLength += 1;
1327
1328 SkSMallocWCHAR wLocale(localeLength);
1329 HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLength), "Could not get locale.");
1330
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001331 HRB(sk_wchar_to_skstring(wLocale.get(), &localizedString->fLanguage));
bungeman@google.coma9802692013-08-07 02:45:25 +00001332
1333 ++fIndex;
1334 return true;
1335 }
1336
1337private:
1338 UINT32 fIndex;
1339 SkTScopedComPtr<IDWriteLocalizedStrings> fStrings;
1340};
1341
bungeman@google.com839702b2013-08-07 17:09:22 +00001342SkTypeface::LocalizedStrings* DWriteFontTypeface::onCreateFamilyNameIterator() const {
bungeman@google.coma9802692013-08-07 02:45:25 +00001343 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
1344 HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names.");
1345
1346 return new LocalizedStrings_IDWriteLocalizedStrings(familyNames.release());
1347}
1348
bungeman@google.comb10b51f2013-08-01 20:18:41 +00001349int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
1350 DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType();
1351 if (type != DWRITE_FONT_FACE_TYPE_CFF &&
1352 type != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
1353 type != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
1354 {
1355 return 0;
1356 }
1357
1358 int ttcIndex;
1359 SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
1360 return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
1361}
1362
bungeman@google.comb10b51f2013-08-01 20:18:41 +00001363size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
1364 size_t length, void* data) const
1365{
1366 AutoDWriteTable table(fDWriteFontFace.get(), SkEndian_SwapBE32(tag));
1367 if (!table.fExists) {
1368 return 0;
1369 }
1370
1371 if (offset > table.fSize) {
1372 return 0;
1373 }
1374 size_t size = SkTMin(length, table.fSize - offset);
1375 if (NULL != data) {
1376 memcpy(data, table.fData + offset, size);
1377 }
1378
1379 return size;
1380}
1381
bungeman@google.com4bbc5242013-05-02 14:01:36 +00001382template <typename T> class SkAutoIDWriteUnregister {
1383public:
1384 SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
1385 : fFactory(factory), fUnregister(unregister)
1386 { }
1387
1388 ~SkAutoIDWriteUnregister() {
1389 if (fUnregister) {
1390 unregister(fFactory, fUnregister);
1391 }
1392 }
1393
1394 T* detatch() {
1395 T* old = fUnregister;
1396 fUnregister = NULL;
1397 return old;
1398 }
1399
1400private:
1401 HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) {
1402 return factory->UnregisterFontFileLoader(unregister);
1403 }
1404
1405 HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) {
1406 return factory->UnregisterFontCollectionLoader(unregister);
1407 }
1408
1409 IDWriteFactory* fFactory;
1410 T* fUnregister;
1411};
1412
reed@google.com177dc6e2013-03-21 20:55:10 +00001413SkStream* DWriteFontTypeface::onOpenStream(int* ttcIndex) const {
bungeman@google.com4bbc5242013-05-02 14:01:36 +00001414 *ttcIndex = fDWriteFontFace->GetIndex();
bungeman@google.come8f05922012-08-16 16:13:40 +00001415
1416 UINT32 numFiles;
reed@google.com177dc6e2013-03-21 20:55:10 +00001417 HRNM(fDWriteFontFace->GetFiles(&numFiles, NULL),
bungeman@google.come8f05922012-08-16 16:13:40 +00001418 "Could not get number of font files.");
1419 if (numFiles != 1) {
1420 return NULL;
1421 }
1422
1423 SkTScopedComPtr<IDWriteFontFile> fontFile;
reed@google.com177dc6e2013-03-21 20:55:10 +00001424 HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files.");
bungeman@google.come8f05922012-08-16 16:13:40 +00001425
1426 const void* fontFileKey;
1427 UINT32 fontFileKeySize;
1428 HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize),
1429 "Could not get font file reference key.");
1430
1431 SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
1432 HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader.");
1433
1434 SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
1435 HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize,
1436 &fontFileStream),
1437 "Could not create font file stream.");
1438
1439 return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
1440}
1441
reed@google.com0da48612013-03-19 16:06:52 +00001442SkScalerContext* DWriteFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
reed@google.com30ddd612013-07-30 17:47:39 +00001443 return SkNEW_ARGS(SkScalerContext_DW, (const_cast<DWriteFontTypeface*>(this), desc));
bungeman@google.come8f05922012-08-16 16:13:40 +00001444}
1445
reed@google.com0da48612013-03-19 16:06:52 +00001446void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const {
commit-bot@chromium.orgc5fd4612013-05-06 22:23:08 +00001447 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
1448 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
1449 {
1450 rec->fMaskFormat = SkMask::kA8_Format;
1451 }
1452
bungeman@google.come8f05922012-08-16 16:13:40 +00001453 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
bungeman@google.comf6f56872014-01-23 19:01:36 +00001454 SkScalerContext::kForceAutohinting_Flag |
bungeman@google.come8f05922012-08-16 16:13:40 +00001455 SkScalerContext::kEmbolden_Flag |
1456 SkScalerContext::kLCD_BGROrder_Flag |
1457 SkScalerContext::kLCD_Vertical_Flag;
1458 rec->fFlags &= ~flagsWeDontSupport;
1459
1460 SkPaint::Hinting h = rec->getHinting();
1461 // DirectWrite does not provide for hinting hints.
1462 h = SkPaint::kSlight_Hinting;
1463 rec->setHinting(h);
1464
1465#if SK_FONT_HOST_USE_SYSTEM_SETTINGS
bungeman@google.com0ff457b2013-12-09 18:58:31 +00001466 IDWriteFactory* factory = get_dwrite_factory();
1467 if (factory != NULL) {
bungeman@google.come8f05922012-08-16 16:13:40 +00001468 SkTScopedComPtr<IDWriteRenderingParams> defaultRenderingParams;
1469 if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) {
1470 float gamma = defaultRenderingParams->GetGamma();
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +00001471 rec->setDeviceGamma(gamma);
1472 rec->setPaintGamma(gamma);
rmistry@google.comd6176b02012-08-23 18:14:13 +00001473
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +00001474 rec->setContrast(defaultRenderingParams->GetEnhancedContrast());
bungeman@google.come8f05922012-08-16 16:13:40 +00001475 }
1476 }
1477#endif
1478}
1479
1480///////////////////////////////////////////////////////////////////////////////
1481//PDF Support
1482
1483using namespace skia_advanced_typeface_metrics_utils;
1484
1485// Construct Glyph to Unicode table.
1486// Unicode code points that require conjugate pairs in utf16 are not
1487// supported.
1488// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
1489// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
1490// of calling GetFontUnicodeRange().
1491// TODO(bungeman): This never does what anyone wants.
1492// What is really wanted is the text to glyphs mapping
1493static void populate_glyph_to_unicode(IDWriteFontFace* fontFace,
1494 const unsigned glyphCount,
1495 SkTDArray<SkUnichar>* glyphToUnicode) {
1496 HRESULT hr = S_OK;
1497
1498 //Do this like free type instead
1499 UINT32 count = 0;
1500 for (UINT32 c = 0; c < 0x10FFFF; ++c) {
1501 UINT16 glyph;
1502 hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
1503 if (glyph > 0) {
1504 ++count;
1505 }
1506 }
1507
1508 SkAutoTArray<UINT32> chars(count);
1509 count = 0;
1510 for (UINT32 c = 0; c < 0x10FFFF; ++c) {
1511 UINT16 glyph;
1512 hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
1513 if (glyph > 0) {
1514 chars[count] = c;
1515 ++count;
1516 }
1517 }
1518
1519 SkAutoTArray<UINT16> glyph(count);
1520 fontFace->GetGlyphIndices(chars.get(), count, glyph.get());
1521
1522 USHORT maxGlyph = 0;
1523 for (USHORT j = 0; j < count; ++j) {
1524 if (glyph[j] > maxGlyph) maxGlyph = glyph[j];
1525 }
1526
1527 glyphToUnicode->setCount(maxGlyph+1);
robertphillips@google.comadacc702013-10-14 21:53:24 +00001528 for (USHORT j = 0; j < maxGlyph+1u; ++j) {
bungeman@google.come8f05922012-08-16 16:13:40 +00001529 (*glyphToUnicode)[j] = 0;
1530 }
1531
1532 //'invert'
1533 for (USHORT j = 0; j < count; ++j) {
1534 if (glyph[j] < glyphCount && (*glyphToUnicode)[glyph[j]] == 0) {
1535 (*glyphToUnicode)[glyph[j]] = chars[j];
1536 }
1537 }
1538}
1539
1540static bool getWidthAdvance(IDWriteFontFace* fontFace, int gId, int16_t* advance) {
1541 SkASSERT(advance);
1542
1543 UINT16 glyphId = gId;
1544 DWRITE_GLYPH_METRICS gm;
1545 HRESULT hr = fontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm);
1546
1547 if (FAILED(hr)) {
1548 *advance = 0;
1549 return false;
1550 }
1551
1552 *advance = gm.advanceWidth;
1553 return true;
1554}
1555
reed@google.com2689f612013-03-20 20:01:47 +00001556SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics(
bungeman@google.come8f05922012-08-16 16:13:40 +00001557 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1558 const uint32_t* glyphIDs,
reed@google.com2689f612013-03-20 20:01:47 +00001559 uint32_t glyphIDsCount) const {
bungeman@google.come8f05922012-08-16 16:13:40 +00001560
1561 SkAdvancedTypefaceMetrics* info = NULL;
1562
1563 HRESULT hr = S_OK;
1564
reed@google.com2689f612013-03-20 20:01:47 +00001565 const unsigned glyphCount = fDWriteFontFace->GetGlyphCount();
bungeman@google.come8f05922012-08-16 16:13:40 +00001566
1567 DWRITE_FONT_METRICS dwfm;
reed@google.com2689f612013-03-20 20:01:47 +00001568 fDWriteFontFace->GetMetrics(&dwfm);
bungeman@google.come8f05922012-08-16 16:13:40 +00001569
1570 info = new SkAdvancedTypefaceMetrics;
1571 info->fEmSize = dwfm.designUnitsPerEm;
vandebo@chromium.org5f209e62013-12-10 17:22:41 +00001572 info->fMultiMaster = false;
bungeman@google.come8f05922012-08-16 16:13:40 +00001573 info->fLastGlyphID = SkToU16(glyphCount - 1);
1574 info->fStyle = 0;
vandebo@chromium.org5f209e62013-12-10 17:22:41 +00001575
bungeman@google.come8f05922012-08-16 16:13:40 +00001576
1577 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
1578 SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
reed@google.com2689f612013-03-20 20:01:47 +00001579 hr = fDWriteFontFamily->GetFamilyNames(&familyNames);
1580 hr = fDWriteFont->GetFaceNames(&faceNames);
bungeman@google.come8f05922012-08-16 16:13:40 +00001581
1582 UINT32 familyNameLength;
1583 hr = familyNames->GetStringLength(0, &familyNameLength);
1584
1585 UINT32 faceNameLength;
1586 hr = faceNames->GetStringLength(0, &faceNameLength);
1587
bungeman@google.com71033442013-05-01 14:21:20 +00001588 UINT32 size = familyNameLength+1+faceNameLength+1;
1589 SkSMallocWCHAR wFamilyName(size);
1590 hr = familyNames->GetString(0, wFamilyName.get(), size);
bungeman@google.come8f05922012-08-16 16:13:40 +00001591 wFamilyName[familyNameLength] = L' ';
1592 hr = faceNames->GetString(0, &wFamilyName[familyNameLength+1], size - faceNameLength + 1);
1593
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001594 hr = sk_wchar_to_skstring(wFamilyName.get(), &info->fFontName);
bungeman@google.come8f05922012-08-16 16:13:40 +00001595
1596 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
reed@google.com2689f612013-03-20 20:01:47 +00001597 populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode));
bungeman@google.come8f05922012-08-16 16:13:40 +00001598 }
1599
reed@google.com2689f612013-03-20 20:01:47 +00001600 DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
bungeman@google.come8f05922012-08-16 16:13:40 +00001601 if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE ||
1602 fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
1603 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1604 } else {
1605 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1606 info->fItalicAngle = 0;
1607 info->fAscent = dwfm.ascent;;
1608 info->fDescent = dwfm.descent;
1609 info->fStemV = 0;
1610 info->fCapHeight = dwfm.capHeight;
1611 info->fBBox = SkIRect::MakeEmpty();
1612 return info;
1613 }
1614
bungeman@google.comb10b51f2013-08-01 20:18:41 +00001615 AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
1616 AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
1617 AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
1618 AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
bungeman@google.come8f05922012-08-16 16:13:40 +00001619 if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
1620 info->fItalicAngle = 0;
1621 info->fAscent = dwfm.ascent;;
1622 info->fDescent = dwfm.descent;
1623 info->fStemV = 0;
1624 info->fCapHeight = dwfm.capHeight;
1625 info->fBBox = SkIRect::MakeEmpty();
1626 return info;
1627 }
1628
1629 //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
1630 //but have full width, latin half-width, and half-width kana.
1631 bool fixedWidth = (postTable->isFixedPitch &&
1632 (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
1633 //Monospace
1634 if (fixedWidth) {
1635 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1636 }
1637 //Italic
1638 if (os2Table->version.v0.fsSelection.field.Italic) {
1639 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1640 }
bungeman@google.come8f05922012-08-16 16:13:40 +00001641 //Script
1642 if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType.value) {
1643 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1644 //Serif
1645 } else if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType.value &&
1646 SkPanose::Data::TextAndDisplay::SerifStyle::Triangle <= os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value &&
1647 SkPanose::Data::TextAndDisplay::SerifStyle::NoFit != os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value) {
1648 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1649 }
1650
1651 info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;
1652
1653 info->fAscent = SkToS16(dwfm.ascent);
1654 info->fDescent = SkToS16(dwfm.descent);
1655 info->fCapHeight = SkToS16(dwfm.capHeight);
1656
1657 info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
1658 (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
1659 (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
1660 (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));
1661
1662 //TODO: is this even desired? It seems PDF only wants this value for Type1
1663 //fonts, and we only get here for TrueType fonts.
1664 info->fStemV = 0;
1665 /*
1666 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1667 // This probably isn't very good with an italic font.
1668 int16_t min_width = SHRT_MAX;
1669 info->fStemV = 0;
1670 char stem_chars[] = {'i', 'I', '!', '1'};
1671 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1672 ABC abcWidths;
1673 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1674 int16_t width = abcWidths.abcB;
1675 if (width > 0 && width < min_width) {
1676 min_width = width;
1677 info->fStemV = min_width;
1678 }
1679 }
1680 }
1681 */
rmistry@google.comd6176b02012-08-23 18:14:13 +00001682
vandebo@chromium.org5f209e62013-12-10 17:22:41 +00001683 // If Restricted, the font may not be embedded in a document.
1684 // If not Restricted, the font can be embedded.
1685 // If PreviewPrint, the embedding is read-only.
1686 if (os2Table->version.v0.fsType.field.Restricted) {
1687 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
1688 } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
bungeman@google.come8f05922012-08-16 16:13:40 +00001689 if (fixedWidth) {
1690 appendRange(&info->fGlyphWidths, 0);
1691 int16_t advance;
reed@google.com2689f612013-03-20 20:01:47 +00001692 getWidthAdvance(fDWriteFontFace.get(), 1, &advance);
bungeman@google.come8f05922012-08-16 16:13:40 +00001693 info->fGlyphWidths->fAdvance.append(1, &advance);
1694 finishRange(info->fGlyphWidths.get(), 0,
1695 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1696 } else {
1697 info->fGlyphWidths.reset(
reed@google.com2689f612013-03-20 20:01:47 +00001698 getAdvanceData(fDWriteFontFace.get(),
bungeman@google.come8f05922012-08-16 16:13:40 +00001699 glyphCount,
1700 glyphIDs,
1701 glyphIDsCount,
1702 getWidthAdvance));
1703 }
1704 }
1705
1706 return info;
1707}
reed@google.com070da5e2013-03-27 20:01:49 +00001708
1709///////////////////////////////////////////////////////////////////////////////
1710
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001711SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont(
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001712 IDWriteFontFace* fontFace,
1713 IDWriteFont* font,
bungeman@google.com6eddc772014-03-31 19:18:07 +00001714 IDWriteFontFamily* fontFamily) const {
bungeman@google.com86dd7522013-10-04 17:00:35 +00001715 SkTypeface* face = FindByProcAndRef(FindByDWriteFont, font);
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001716 if (NULL == face) {
bungeman@google.com6eddc772014-03-31 19:18:07 +00001717 face = DWriteFontTypeface::Create(fFactory.get(), fontFace, font, fontFamily);
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001718 if (face) {
bungeman@google.com6eddc772014-03-31 19:18:07 +00001719 Add(face, get_style(font), true);
bungeman@google.com71033442013-05-01 14:21:20 +00001720 }
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001721 }
1722 return face;
1723}
bungeman@google.com71033442013-05-01 14:21:20 +00001724
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001725int SkFontMgr_DirectWrite::onCountFamilies() const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001726 return fFontCollection->GetFontFamilyCount();
1727}
bungeman@google.com71033442013-05-01 14:21:20 +00001728
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001729void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001730 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
1731 HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
bungeman@google.com71033442013-05-01 14:21:20 +00001732
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001733 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
1734 HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
bungeman@google.com71033442013-05-01 14:21:20 +00001735
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001736 sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001737}
1738
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001739SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001740 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
1741 HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
1742
1743 return SkNEW_ARGS(SkFontStyleSet_DirectWrite, (this, fontFamily.get()));
1744}
1745
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001746SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001747 SkSMallocWCHAR dwFamilyName;
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001748 HRN(sk_cstring_to_wchar(familyName, &dwFamilyName));
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001749
1750 UINT32 index;
1751 BOOL exists;
1752 HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
1753 "Failed while finding family by name.");
1754 if (!exists) {
1755 return NULL;
bungeman@google.com71033442013-05-01 14:21:20 +00001756 }
1757
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001758 return this->onCreateStyleSet(index);
1759}
bungeman@google.com71033442013-05-01 14:21:20 +00001760
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001761SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001762 const SkFontStyle& fontstyle) const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001763 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
1764 return sset->matchStyle(fontstyle);
1765}
bungeman@google.com71033442013-05-01 14:21:20 +00001766
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001767SkTypeface* SkFontMgr_DirectWrite::onMatchFaceStyle(const SkTypeface* familyMember,
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001768 const SkFontStyle& fontstyle) const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001769 SkString familyName;
1770 SkFontStyleSet_DirectWrite sset(
1771 this, ((DWriteFontTypeface*)familyMember)->fDWriteFontFamily.get()
1772 );
1773 return sset.matchStyle(fontstyle);
1774}
bungeman@google.com71033442013-05-01 14:21:20 +00001775
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001776SkTypeface* SkFontMgr_DirectWrite::onCreateFromStream(SkStream* stream, int ttcIndex) const {
bungeman@google.com6eddc772014-03-31 19:18:07 +00001777 SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
1778 HRN(StreamFontFileLoader::Create(stream, &fontFileLoader));
1779 HRN(fFactory->RegisterFontFileLoader(fontFileLoader.get()));
1780 SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader(
1781 fFactory.get(), fontFileLoader.get());
1782
1783 SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader;
1784 HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader));
1785 HRN(fFactory->RegisterFontCollectionLoader(fontCollectionLoader.get()));
1786 SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader(
1787 fFactory.get(), fontCollectionLoader.get());
1788
1789 SkTScopedComPtr<IDWriteFontCollection> fontCollection;
1790 HRN(fFactory->CreateCustomFontCollection(fontCollectionLoader.get(), NULL, 0, &fontCollection));
1791
1792 // Find the first non-simulated font which has the given ttc index.
1793 UINT32 familyCount = fontCollection->GetFontFamilyCount();
1794 for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
1795 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
1796 HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily));
1797
1798 UINT32 fontCount = fontFamily->GetFontCount();
1799 for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
1800 SkTScopedComPtr<IDWriteFont> font;
1801 HRN(fontFamily->GetFont(fontIndex, &font));
1802 if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
1803 continue;
1804 }
1805
1806 SkTScopedComPtr<IDWriteFontFace> fontFace;
1807 HRN(font->CreateFontFace(&fontFace));
1808
1809 UINT32 faceIndex = fontFace->GetIndex();
1810 if (faceIndex == ttcIndex) {
1811 return DWriteFontTypeface::Create(fFactory.get(),
1812 fontFace.get(), font.get(), fontFamily.get(),
1813 autoUnregisterFontFileLoader.detatch(),
1814 autoUnregisterFontCollectionLoader.detatch());
1815 }
1816 }
1817 }
1818
1819 return NULL;
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001820}
bungeman@google.com71033442013-05-01 14:21:20 +00001821
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001822SkTypeface* SkFontMgr_DirectWrite::onCreateFromData(SkData* data, int ttcIndex) const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001823 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
1824 return this->createFromStream(stream, ttcIndex);
1825}
bungeman@google.com71033442013-05-01 14:21:20 +00001826
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001827SkTypeface* SkFontMgr_DirectWrite::onCreateFromFile(const char path[], int ttcIndex) const {
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001828 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
1829 return this->createFromStream(stream, ttcIndex);
1830}
bungeman@google.com71033442013-05-01 14:21:20 +00001831
bungeman@google.com8f53d582013-11-20 22:42:13 +00001832HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001833 IDWriteFontFamily** fontFamily) const {
bungeman@google.com8f53d582013-11-20 22:42:13 +00001834 UINT32 index;
1835 BOOL exists;
1836 HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
1837
1838 if (exists) {
1839 HR(fFontCollection->GetFontFamily(index, fontFamily));
bungeman@google.com8f53d582013-11-20 22:42:13 +00001840 }
bungeman@google.comc94a0282014-03-27 16:21:31 +00001841 return S_OK;
bungeman@google.com8f53d582013-11-20 22:42:13 +00001842}
1843
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001844HRESULT SkFontMgr_DirectWrite::getDefaultFontFamily(IDWriteFontFamily** fontFamily) const {
bungeman@google.com8f53d582013-11-20 22:42:13 +00001845 NONCLIENTMETRICSW metrics;
1846 metrics.cbSize = sizeof(metrics);
1847 if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
1848 sizeof(metrics),
1849 &metrics,
1850 0)) {
1851 return E_UNEXPECTED;
1852 }
1853 HRM(this->getByFamilyName(metrics.lfMessageFont.lfFaceName, fontFamily),
1854 "Could not create DWrite font family from LOGFONT.");
bungeman@google.com8f53d582013-11-20 22:42:13 +00001855 return S_OK;
1856}
1857
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001858SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[],
commit-bot@chromium.org967dee32014-02-04 22:35:01 +00001859 unsigned styleBits) const {
bungeman@google.comf7159bb2013-11-20 15:11:05 +00001860 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
1861 if (familyName) {
bungeman@google.com8f53d582013-11-20 22:42:13 +00001862 SkSMallocWCHAR wideFamilyName;
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001863 if (SUCCEEDED(sk_cstring_to_wchar(familyName, &wideFamilyName))) {
bungeman@google.com8f53d582013-11-20 22:42:13 +00001864 this->getByFamilyName(wideFamilyName, &fontFamily);
1865 }
bungeman@google.comf7159bb2013-11-20 15:11:05 +00001866 }
1867
1868 if (NULL == fontFamily.get()) {
bungeman@google.com8f53d582013-11-20 22:42:13 +00001869 // No family with given name, try default.
1870 HRNM(this->getDefaultFontFamily(&fontFamily), "Could not get default font family.");
bungeman@google.comf7159bb2013-11-20 15:11:05 +00001871 }
1872
bungeman@google.comc94a0282014-03-27 16:21:31 +00001873 if (NULL == fontFamily.get()) {
1874 // Could not obtain the default font.
1875 HRNM(fFontCollection->GetFontFamily(0, &fontFamily),
1876 "Could not get default-default font family.");
1877 }
1878
bungeman@google.comf7159bb2013-11-20 15:11:05 +00001879 SkTScopedComPtr<IDWriteFont> font;
1880 DWRITE_FONT_WEIGHT weight = (styleBits & SkTypeface::kBold)
1881 ? DWRITE_FONT_WEIGHT_BOLD
1882 : DWRITE_FONT_WEIGHT_NORMAL;
bungeman@google.com97a5d5d2014-01-08 20:32:07 +00001883 DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL;
bungeman@google.comf7159bb2013-11-20 15:11:05 +00001884 DWRITE_FONT_STYLE italic = (styleBits & SkTypeface::kItalic)
1885 ? DWRITE_FONT_STYLE_ITALIC
1886 : DWRITE_FONT_STYLE_NORMAL;
1887 HRNM(fontFamily->GetFirstMatchingFont(weight, stretch, italic, &font),
1888 "Could not get matching font.");
1889
1890 SkTScopedComPtr<IDWriteFontFace> fontFace;
1891 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1892
1893 return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001894}
bungeman@google.com71033442013-05-01 14:21:20 +00001895
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001896///////////////////////////////////////////////////////////////////////////////
bungeman@google.com71033442013-05-01 14:21:20 +00001897
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001898int SkFontStyleSet_DirectWrite::count() {
1899 return fFontFamily->GetFontCount();
1900}
bungeman@google.com71033442013-05-01 14:21:20 +00001901
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001902SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) {
1903 SkTScopedComPtr<IDWriteFont> font;
1904 HRNM(fFontFamily->GetFont(index, &font), "Could not get font.");
reed@google.com30ddd612013-07-30 17:47:39 +00001905
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001906 SkTScopedComPtr<IDWriteFontFace> fontFace;
1907 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1908
1909 return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
1910}
bungeman@google.com71033442013-05-01 14:21:20 +00001911
1912void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
1913 SkTScopedComPtr<IDWriteFont> font;
1914 HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
1915
bungeman@google.com1d1f2342014-03-17 14:04:50 +00001916 if (fs) {
1917 SkFontStyle::Slant slant;
1918 switch (font->GetStyle()) {
1919 case DWRITE_FONT_STYLE_NORMAL:
1920 slant = SkFontStyle::kUpright_Slant;
1921 break;
1922 case DWRITE_FONT_STYLE_OBLIQUE:
1923 case DWRITE_FONT_STYLE_ITALIC:
1924 slant = SkFontStyle::kItalic_Slant;
1925 break;
1926 default:
1927 SkASSERT(false);
1928 }
1929
1930 int weight = font->GetWeight();
1931 int width = font->GetStretch();
1932
1933 *fs = SkFontStyle(weight, width, slant);
bungeman@google.com71033442013-05-01 14:21:20 +00001934 }
1935
bungeman@google.com1d1f2342014-03-17 14:04:50 +00001936 if (styleName) {
1937 SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
1938 if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001939 sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
bungeman@google.com1d1f2342014-03-17 14:04:50 +00001940 }
bungeman@google.com71033442013-05-01 14:21:20 +00001941 }
1942}
1943
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001944SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
1945 DWRITE_FONT_STYLE slant;
1946 switch (pattern.slant()) {
1947 case SkFontStyle::kUpright_Slant:
1948 slant = DWRITE_FONT_STYLE_NORMAL;
1949 break;
1950 case SkFontStyle::kItalic_Slant:
1951 slant = DWRITE_FONT_STYLE_ITALIC;
1952 break;
1953 default:
1954 SkASSERT(false);
1955 }
1956
1957 DWRITE_FONT_WEIGHT weight = (DWRITE_FONT_WEIGHT)pattern.weight();
1958 DWRITE_FONT_STRETCH width = (DWRITE_FONT_STRETCH)pattern.width();
1959
1960 SkTScopedComPtr<IDWriteFont> font;
1961 // TODO: perhaps use GetMatchingFonts and get the least simulated?
1962 HRNM(fFontFamily->GetFirstMatchingFont(weight, width, slant, &font),
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001963 "Could not match font in family.");
bungeman@google.combfc6cc42013-08-21 15:20:43 +00001964
1965 SkTScopedComPtr<IDWriteFontFace> fontFace;
1966 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
1967
1968 return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(),
1969 fFontFamily.get());
1970}
1971
reed@google.com30ddd612013-07-30 17:47:39 +00001972///////////////////////////////////////////////////////////////////////////////
1973
bungeman@google.com6eddc772014-03-31 19:18:07 +00001974SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory) {
bungeman@google.com0ff457b2013-12-09 18:58:31 +00001975 if (NULL == factory) {
bungeman@google.com6eddc772014-03-31 19:18:07 +00001976 factory = sk_get_dwrite_factory();
1977 if (NULL == factory) {
1978 return NULL;
1979 }
bungeman@google.com0ff457b2013-12-09 18:58:31 +00001980 }
bungeman@google.com71033442013-05-01 14:21:20 +00001981
1982 SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
1983 HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
1984 "Could not get system font collection.");
1985
1986 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
1987 WCHAR* localeName = NULL;
bungeman@google.comaf9296e2013-08-21 14:53:59 +00001988 int localeNameLen = 0;
1989
1990 // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00001991 SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL;
1992 HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
bungeman@google.comaf9296e2013-08-21 14:53:59 +00001993 if (NULL == getUserDefaultLocaleNameProc) {
bungeman@google.com42a78292013-08-21 22:41:05 +00001994 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
bungeman@google.comaf9296e2013-08-21 14:53:59 +00001995 } else {
1996 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
1997 if (localeNameLen) {
1998 localeName = localeNameStorage;
1999 };
2000 }
bungeman@google.com71033442013-05-01 14:21:20 +00002001
bungeman@google.com6eddc772014-03-31 19:18:07 +00002002 return SkNEW_ARGS(SkFontMgr_DirectWrite, (factory, sysFontCollection.get(),
2003 localeName, localeNameLen));
reed@google.com070da5e2013-03-27 20:01:49 +00002004}
bungeman@google.com72cf4fc2014-03-21 22:48:32 +00002005
2006#include "SkFontMgr_indirect.h"
2007SkFontMgr* SkFontMgr_New_DirectWriteRenderer(SkRemotableFontMgr* proxy) {
2008 SkAutoTUnref<SkFontMgr> impl(SkFontMgr_New_DirectWrite());
2009 if (impl.get() == NULL) {
2010 return NULL;
2011 }
2012 return SkNEW_ARGS(SkFontMgr_Indirect, (impl.get(), proxy));
2013}