gfx/skia/trunk/src/ports/SkFontHost_win_dw.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 * Copyright 2011 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8 #include "SkTypes.h"
michael@0 9 #undef GetGlyphIndices
michael@0 10
michael@0 11 #include "SkAdvancedTypefaceMetrics.h"
michael@0 12 #include "SkColorFilter.h"
michael@0 13 #include "SkDWriteFontFileStream.h"
michael@0 14 #include "SkDWriteGeometrySink.h"
michael@0 15 #include "SkDescriptor.h"
michael@0 16 #include "SkEndian.h"
michael@0 17 #include "SkFontDescriptor.h"
michael@0 18 #include "SkFontHost.h"
michael@0 19 #include "SkFontMgr.h"
michael@0 20 #include "SkFontStream.h"
michael@0 21 #include "SkGlyph.h"
michael@0 22 #include "SkHRESULT.h"
michael@0 23 #include "SkMaskGamma.h"
michael@0 24 #include "SkOnce.h"
michael@0 25 #include "SkOTTable_head.h"
michael@0 26 #include "SkOTTable_hhea.h"
michael@0 27 #include "SkOTTable_OS_2.h"
michael@0 28 #include "SkOTTable_post.h"
michael@0 29 #include "SkPath.h"
michael@0 30 #include "SkStream.h"
michael@0 31 #include "SkString.h"
michael@0 32 #include "SkTScopedComPtr.h"
michael@0 33 #include "SkThread.h"
michael@0 34 #include "SkTypeface_win.h"
michael@0 35 #include "SkTypefaceCache.h"
michael@0 36 #include "SkUtils.h"
michael@0 37
michael@0 38 #include <dwrite.h>
michael@0 39
michael@0 40 static bool isLCD(const SkScalerContext::Rec& rec) {
michael@0 41 return SkMask::kLCD16_Format == rec.fMaskFormat ||
michael@0 42 SkMask::kLCD32_Format == rec.fMaskFormat;
michael@0 43 }
michael@0 44
michael@0 45 /** Prefer to use this type to prevent template proliferation. */
michael@0 46 typedef SkAutoSTMalloc<16, WCHAR> SkSMallocWCHAR;
michael@0 47
michael@0 48 /** Converts a utf8 string to a WCHAR string. */
michael@0 49 static HRESULT cstring_to_wchar(const char* skname, SkSMallocWCHAR* name) {
michael@0 50 int wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, NULL, 0);
michael@0 51 if (0 == wlen) {
michael@0 52 HRM(HRESULT_FROM_WIN32(GetLastError()),
michael@0 53 "Could not get length for wchar to utf-8 conversion.");
michael@0 54 }
michael@0 55 name->reset(wlen);
michael@0 56 wlen = MultiByteToWideChar(CP_UTF8, 0, skname, -1, name->get(), wlen);
michael@0 57 if (0 == wlen) {
michael@0 58 HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert wchar to utf-8.");
michael@0 59 }
michael@0 60 return S_OK;
michael@0 61 }
michael@0 62
michael@0 63 /** Converts a WCHAR string to a utf8 string. */
michael@0 64 static HRESULT wchar_to_skstring(WCHAR* name, SkString* skname) {
michael@0 65 int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);
michael@0 66 if (0 == len) {
michael@0 67 HRM(HRESULT_FROM_WIN32(GetLastError()),
michael@0 68 "Could not get length for utf-8 to wchar conversion.");
michael@0 69 }
michael@0 70 skname->resize(len - 1);
michael@0 71
michael@0 72 // TODO: remove after https://code.google.com/p/skia/issues/detail?id=1989 is fixed.
michael@0 73 // If we resize to 0 then the skname points to gEmptyRec (the unique empty SkString::Rec).
michael@0 74 // gEmptyRec is static const and on Windows this means the value is in a read only page.
michael@0 75 // Writing to it in the following call to WideCharToMultiByte will cause an access violation.
michael@0 76 if (1 == len) {
michael@0 77 return S_OK;
michael@0 78 }
michael@0 79
michael@0 80 len = WideCharToMultiByte(CP_UTF8, 0, name, -1, skname->writable_str(), len, NULL, NULL);
michael@0 81 if (0 == len) {
michael@0 82 HRM(HRESULT_FROM_WIN32(GetLastError()), "Could not convert utf-8 to wchar.");
michael@0 83 }
michael@0 84 return S_OK;
michael@0 85 }
michael@0 86
michael@0 87 ///////////////////////////////////////////////////////////////////////////////
michael@0 88
michael@0 89 static void create_dwrite_factory(IDWriteFactory** factory) {
michael@0 90 typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
michael@0 91 DWriteCreateFactoryProc dWriteCreateFactoryProc = reinterpret_cast<DWriteCreateFactoryProc>(
michael@0 92 GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory"));
michael@0 93
michael@0 94 if (!dWriteCreateFactoryProc) {
michael@0 95 HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
michael@0 96 if (!IS_ERROR(hr)) {
michael@0 97 hr = ERROR_PROC_NOT_FOUND;
michael@0 98 }
michael@0 99 HRVM(hr, "Could not get DWriteCreateFactory proc.");
michael@0 100 }
michael@0 101
michael@0 102 HRVM(dWriteCreateFactoryProc(DWRITE_FACTORY_TYPE_SHARED,
michael@0 103 __uuidof(IDWriteFactory),
michael@0 104 reinterpret_cast<IUnknown**>(factory)),
michael@0 105 "Could not create DirectWrite factory.");
michael@0 106 }
michael@0 107
michael@0 108 static IDWriteFactory* get_dwrite_factory() {
michael@0 109 static IDWriteFactory* gDWriteFactory = NULL;
michael@0 110 SK_DECLARE_STATIC_ONCE(once);
michael@0 111 SkOnce(&once, create_dwrite_factory, &gDWriteFactory);
michael@0 112
michael@0 113 return gDWriteFactory;
michael@0 114 }
michael@0 115
michael@0 116 ///////////////////////////////////////////////////////////////////////////////
michael@0 117
michael@0 118 class StreamFontFileLoader;
michael@0 119
michael@0 120 class SkFontMgr_DirectWrite : public SkFontMgr {
michael@0 121 public:
michael@0 122 /** localeNameLength must include the null terminator. */
michael@0 123 SkFontMgr_DirectWrite(IDWriteFontCollection* fontCollection,
michael@0 124 WCHAR* localeName, int localeNameLength)
michael@0 125 : fFontCollection(SkRefComPtr(fontCollection))
michael@0 126 , fLocaleName(localeNameLength)
michael@0 127 {
michael@0 128 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
michael@0 129 }
michael@0 130
michael@0 131 SkTypeface* createTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
michael@0 132 IDWriteFont* font,
michael@0 133 IDWriteFontFamily* fontFamily,
michael@0 134 StreamFontFileLoader* = NULL,
michael@0 135 IDWriteFontCollectionLoader* = NULL) const;
michael@0 136
michael@0 137 protected:
michael@0 138 virtual int onCountFamilies() const SK_OVERRIDE;
michael@0 139 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE;
michael@0 140 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE;
michael@0 141 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE;
michael@0 142 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
michael@0 143 const SkFontStyle& fontstyle) const SK_OVERRIDE;
michael@0 144 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
michael@0 145 const SkFontStyle& fontstyle) const SK_OVERRIDE;
michael@0 146 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE;
michael@0 147 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE;
michael@0 148 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE;
michael@0 149 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
michael@0 150 unsigned styleBits) const SK_OVERRIDE;
michael@0 151
michael@0 152 private:
michael@0 153 HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
michael@0 154 HRESULT getDefaultFontFamily(IDWriteFontFamily** fontFamily) const;
michael@0 155
michael@0 156 void Add(SkTypeface* face, SkTypeface::Style requestedStyle, bool strong) const {
michael@0 157 SkAutoMutexAcquire ama(fTFCacheMutex);
michael@0 158 fTFCache.add(face, requestedStyle, strong);
michael@0 159 }
michael@0 160
michael@0 161 SkTypeface* FindByProcAndRef(SkTypefaceCache::FindProc proc, void* ctx) const {
michael@0 162 SkAutoMutexAcquire ama(fTFCacheMutex);
michael@0 163 SkTypeface* typeface = fTFCache.findByProcAndRef(proc, ctx);
michael@0 164 return typeface;
michael@0 165 }
michael@0 166
michael@0 167 SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
michael@0 168 SkSMallocWCHAR fLocaleName;
michael@0 169 mutable SkMutex fTFCacheMutex;
michael@0 170 mutable SkTypefaceCache fTFCache;
michael@0 171
michael@0 172 friend class SkFontStyleSet_DirectWrite;
michael@0 173 };
michael@0 174
michael@0 175 class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
michael@0 176 public:
michael@0 177 SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr,
michael@0 178 IDWriteFontFamily* fontFamily)
michael@0 179 : fFontMgr(SkRef(fontMgr))
michael@0 180 , fFontFamily(SkRefComPtr(fontFamily))
michael@0 181 { }
michael@0 182
michael@0 183 virtual int count() SK_OVERRIDE;
michael@0 184 virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE;
michael@0 185 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE;
michael@0 186 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE;
michael@0 187
michael@0 188 private:
michael@0 189 SkAutoTUnref<const SkFontMgr_DirectWrite> fFontMgr;
michael@0 190 SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
michael@0 191 };
michael@0 192
michael@0 193 ///////////////////////////////////////////////////////////////////////////////
michael@0 194
michael@0 195 class DWriteOffscreen {
michael@0 196 public:
michael@0 197 DWriteOffscreen() : fWidth(0), fHeight(0) {
michael@0 198 }
michael@0 199
michael@0 200 void init(IDWriteFontFace* fontFace, const DWRITE_MATRIX& xform, FLOAT fontSize) {
michael@0 201 fFontFace = fontFace;
michael@0 202 fFontSize = fontSize;
michael@0 203 fXform = xform;
michael@0 204 }
michael@0 205
michael@0 206 const void* draw(const SkGlyph&, bool isBW);
michael@0 207
michael@0 208 private:
michael@0 209 uint16_t fWidth;
michael@0 210 uint16_t fHeight;
michael@0 211 IDWriteFontFace* fFontFace;
michael@0 212 FLOAT fFontSize;
michael@0 213 DWRITE_MATRIX fXform;
michael@0 214 SkTDArray<uint8_t> fBits;
michael@0 215 };
michael@0 216
michael@0 217 const void* DWriteOffscreen::draw(const SkGlyph& glyph, bool isBW) {
michael@0 218 IDWriteFactory* factory = get_dwrite_factory();
michael@0 219 SkASSERT(factory != NULL);
michael@0 220
michael@0 221 if (fWidth < glyph.fWidth || fHeight < glyph.fHeight) {
michael@0 222 fWidth = SkMax32(fWidth, glyph.fWidth);
michael@0 223 fHeight = SkMax32(fHeight, glyph.fHeight);
michael@0 224
michael@0 225 if (isBW) {
michael@0 226 fBits.setCount(fWidth * fHeight);
michael@0 227 } else {
michael@0 228 fBits.setCount(fWidth * fHeight * 3);
michael@0 229 }
michael@0 230 }
michael@0 231
michael@0 232 // erase
michael@0 233 memset(fBits.begin(), 0, fBits.count());
michael@0 234
michael@0 235 fXform.dx = SkFixedToFloat(glyph.getSubXFixed());
michael@0 236 fXform.dy = SkFixedToFloat(glyph.getSubYFixed());
michael@0 237
michael@0 238 FLOAT advance = 0.0f;
michael@0 239
michael@0 240 UINT16 index = glyph.getGlyphID();
michael@0 241
michael@0 242 DWRITE_GLYPH_OFFSET offset;
michael@0 243 offset.advanceOffset = 0.0f;
michael@0 244 offset.ascenderOffset = 0.0f;
michael@0 245
michael@0 246 DWRITE_GLYPH_RUN run;
michael@0 247 run.glyphCount = 1;
michael@0 248 run.glyphAdvances = &advance;
michael@0 249 run.fontFace = fFontFace;
michael@0 250 run.fontEmSize = fFontSize;
michael@0 251 run.bidiLevel = 0;
michael@0 252 run.glyphIndices = &index;
michael@0 253 run.isSideways = FALSE;
michael@0 254 run.glyphOffsets = &offset;
michael@0 255
michael@0 256 DWRITE_RENDERING_MODE renderingMode;
michael@0 257 DWRITE_TEXTURE_TYPE textureType;
michael@0 258 if (isBW) {
michael@0 259 renderingMode = DWRITE_RENDERING_MODE_ALIASED;
michael@0 260 textureType = DWRITE_TEXTURE_ALIASED_1x1;
michael@0 261 } else {
michael@0 262 renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
michael@0 263 textureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
michael@0 264 }
michael@0 265 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
michael@0 266 HRNM(factory->CreateGlyphRunAnalysis(&run,
michael@0 267 1.0f, // pixelsPerDip,
michael@0 268 &fXform,
michael@0 269 renderingMode,
michael@0 270 DWRITE_MEASURING_MODE_NATURAL,
michael@0 271 0.0f, // baselineOriginX,
michael@0 272 0.0f, // baselineOriginY,
michael@0 273 &glyphRunAnalysis),
michael@0 274 "Could not create glyph run analysis.");
michael@0 275
michael@0 276 //NOTE: this assumes that the glyph has already been measured
michael@0 277 //with an exact same glyph run analysis.
michael@0 278 RECT bbox;
michael@0 279 bbox.left = glyph.fLeft;
michael@0 280 bbox.top = glyph.fTop;
michael@0 281 bbox.right = glyph.fLeft + glyph.fWidth;
michael@0 282 bbox.bottom = glyph.fTop + glyph.fHeight;
michael@0 283 HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
michael@0 284 &bbox,
michael@0 285 fBits.begin(),
michael@0 286 fBits.count()),
michael@0 287 "Could not draw mask.");
michael@0 288 return fBits.begin();
michael@0 289 }
michael@0 290
michael@0 291 ///////////////////////////////////////////////////////////////////////////////
michael@0 292
michael@0 293 class StreamFontFileLoader : public IDWriteFontFileLoader {
michael@0 294 public:
michael@0 295 // IUnknown methods
michael@0 296 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
michael@0 297 virtual ULONG STDMETHODCALLTYPE AddRef();
michael@0 298 virtual ULONG STDMETHODCALLTYPE Release();
michael@0 299
michael@0 300 // IDWriteFontFileLoader methods
michael@0 301 virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
michael@0 302 void const* fontFileReferenceKey,
michael@0 303 UINT32 fontFileReferenceKeySize,
michael@0 304 IDWriteFontFileStream** fontFileStream);
michael@0 305
michael@0 306 static HRESULT Create(SkStream* stream, StreamFontFileLoader** streamFontFileLoader) {
michael@0 307 *streamFontFileLoader = new StreamFontFileLoader(stream);
michael@0 308 if (NULL == streamFontFileLoader) {
michael@0 309 return E_OUTOFMEMORY;
michael@0 310 }
michael@0 311 return S_OK;
michael@0 312 }
michael@0 313
michael@0 314 SkAutoTUnref<SkStream> fStream;
michael@0 315
michael@0 316 private:
michael@0 317 StreamFontFileLoader(SkStream* stream) : fRefCount(1), fStream(SkRef(stream)) { }
michael@0 318
michael@0 319 ULONG fRefCount;
michael@0 320 };
michael@0 321
michael@0 322 HRESULT StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
michael@0 323 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
michael@0 324 *ppvObject = this;
michael@0 325 AddRef();
michael@0 326 return S_OK;
michael@0 327 } else {
michael@0 328 *ppvObject = NULL;
michael@0 329 return E_NOINTERFACE;
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 ULONG StreamFontFileLoader::AddRef() {
michael@0 334 return InterlockedIncrement(&fRefCount);
michael@0 335 }
michael@0 336
michael@0 337 ULONG StreamFontFileLoader::Release() {
michael@0 338 ULONG newCount = InterlockedDecrement(&fRefCount);
michael@0 339 if (0 == newCount) {
michael@0 340 delete this;
michael@0 341 }
michael@0 342 return newCount;
michael@0 343 }
michael@0 344
michael@0 345 HRESULT StreamFontFileLoader::CreateStreamFromKey(
michael@0 346 void const* fontFileReferenceKey,
michael@0 347 UINT32 fontFileReferenceKeySize,
michael@0 348 IDWriteFontFileStream** fontFileStream)
michael@0 349 {
michael@0 350 SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
michael@0 351 HR(SkDWriteFontFileStreamWrapper::Create(fStream, &stream));
michael@0 352 *fontFileStream = stream.release();
michael@0 353 return S_OK;
michael@0 354 }
michael@0 355
michael@0 356 class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
michael@0 357 public:
michael@0 358 // IUnknown methods
michael@0 359 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
michael@0 360 virtual ULONG STDMETHODCALLTYPE AddRef();
michael@0 361 virtual ULONG STDMETHODCALLTYPE Release();
michael@0 362
michael@0 363 // IDWriteFontFileEnumerator methods
michael@0 364 virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* hasCurrentFile);
michael@0 365 virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile** fontFile);
michael@0 366
michael@0 367 static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
michael@0 368 StreamFontFileEnumerator** streamFontFileEnumerator) {
michael@0 369 *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
michael@0 370 if (NULL == streamFontFileEnumerator) {
michael@0 371 return E_OUTOFMEMORY;
michael@0 372 }
michael@0 373 return S_OK;
michael@0 374 }
michael@0 375 private:
michael@0 376 StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
michael@0 377 ULONG fRefCount;
michael@0 378
michael@0 379 SkTScopedComPtr<IDWriteFactory> fFactory;
michael@0 380 SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
michael@0 381 SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
michael@0 382 bool fHasNext;
michael@0 383 };
michael@0 384
michael@0 385 StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
michael@0 386 IDWriteFontFileLoader* fontFileLoader)
michael@0 387 : fRefCount(1)
michael@0 388 , fFactory(SkRefComPtr(factory))
michael@0 389 , fCurrentFile()
michael@0 390 , fFontFileLoader(SkRefComPtr(fontFileLoader))
michael@0 391 , fHasNext(true)
michael@0 392 { }
michael@0 393
michael@0 394 HRESULT StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
michael@0 395 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) {
michael@0 396 *ppvObject = this;
michael@0 397 AddRef();
michael@0 398 return S_OK;
michael@0 399 } else {
michael@0 400 *ppvObject = NULL;
michael@0 401 return E_NOINTERFACE;
michael@0 402 }
michael@0 403 }
michael@0 404
michael@0 405 ULONG StreamFontFileEnumerator::AddRef() {
michael@0 406 return InterlockedIncrement(&fRefCount);
michael@0 407 }
michael@0 408
michael@0 409 ULONG StreamFontFileEnumerator::Release() {
michael@0 410 ULONG newCount = InterlockedDecrement(&fRefCount);
michael@0 411 if (0 == newCount) {
michael@0 412 delete this;
michael@0 413 }
michael@0 414 return newCount;
michael@0 415 }
michael@0 416
michael@0 417 HRESULT StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
michael@0 418 *hasCurrentFile = FALSE;
michael@0 419
michael@0 420 if (!fHasNext) {
michael@0 421 return S_OK;
michael@0 422 }
michael@0 423 fHasNext = false;
michael@0 424
michael@0 425 UINT32 dummy = 0;
michael@0 426 HR(fFactory->CreateCustomFontFileReference(
michael@0 427 &dummy, //cannot be NULL
michael@0 428 sizeof(dummy), //even if this is 0
michael@0 429 fFontFileLoader.get(),
michael@0 430 &fCurrentFile));
michael@0 431
michael@0 432 *hasCurrentFile = TRUE;
michael@0 433 return S_OK;
michael@0 434 }
michael@0 435
michael@0 436 HRESULT StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) {
michael@0 437 if (fCurrentFile.get() == NULL) {
michael@0 438 *fontFile = NULL;
michael@0 439 return E_FAIL;
michael@0 440 }
michael@0 441
michael@0 442 *fontFile = SkRefComPtr(fCurrentFile.get());
michael@0 443 return S_OK;
michael@0 444 }
michael@0 445
michael@0 446 class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
michael@0 447 public:
michael@0 448 // IUnknown methods
michael@0 449 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
michael@0 450 virtual ULONG STDMETHODCALLTYPE AddRef();
michael@0 451 virtual ULONG STDMETHODCALLTYPE Release();
michael@0 452
michael@0 453 // IDWriteFontCollectionLoader methods
michael@0 454 virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
michael@0 455 IDWriteFactory* factory,
michael@0 456 void const* collectionKey,
michael@0 457 UINT32 collectionKeySize,
michael@0 458 IDWriteFontFileEnumerator** fontFileEnumerator);
michael@0 459
michael@0 460 static HRESULT Create(IDWriteFontFileLoader* fontFileLoader,
michael@0 461 StreamFontCollectionLoader** streamFontCollectionLoader) {
michael@0 462 *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader);
michael@0 463 if (NULL == streamFontCollectionLoader) {
michael@0 464 return E_OUTOFMEMORY;
michael@0 465 }
michael@0 466 return S_OK;
michael@0 467 }
michael@0 468 private:
michael@0 469 StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader)
michael@0 470 : fRefCount(1)
michael@0 471 , fFontFileLoader(SkRefComPtr(fontFileLoader))
michael@0 472 { }
michael@0 473
michael@0 474 ULONG fRefCount;
michael@0 475 SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
michael@0 476 };
michael@0 477
michael@0 478 HRESULT StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
michael@0 479 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
michael@0 480 *ppvObject = this;
michael@0 481 AddRef();
michael@0 482 return S_OK;
michael@0 483 } else {
michael@0 484 *ppvObject = NULL;
michael@0 485 return E_NOINTERFACE;
michael@0 486 }
michael@0 487 }
michael@0 488
michael@0 489 ULONG StreamFontCollectionLoader::AddRef() {
michael@0 490 return InterlockedIncrement(&fRefCount);
michael@0 491 }
michael@0 492
michael@0 493 ULONG StreamFontCollectionLoader::Release() {
michael@0 494 ULONG newCount = InterlockedDecrement(&fRefCount);
michael@0 495 if (0 == newCount) {
michael@0 496 delete this;
michael@0 497 }
michael@0 498 return newCount;
michael@0 499 }
michael@0 500
michael@0 501 HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey(
michael@0 502 IDWriteFactory* factory,
michael@0 503 void const* collectionKey,
michael@0 504 UINT32 collectionKeySize,
michael@0 505 IDWriteFontFileEnumerator** fontFileEnumerator)
michael@0 506 {
michael@0 507 SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
michael@0 508 HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
michael@0 509 *fontFileEnumerator = enumerator.release();
michael@0 510 return S_OK;
michael@0 511 }
michael@0 512
michael@0 513 ///////////////////////////////////////////////////////////////////////////////
michael@0 514
michael@0 515 static SkTypeface::Style get_style(IDWriteFont* font) {
michael@0 516 int style = SkTypeface::kNormal;
michael@0 517 DWRITE_FONT_WEIGHT weight = font->GetWeight();
michael@0 518 if (DWRITE_FONT_WEIGHT_DEMI_BOLD <= weight) {
michael@0 519 style |= SkTypeface::kBold;
michael@0 520 }
michael@0 521 DWRITE_FONT_STYLE angle = font->GetStyle();
michael@0 522 if (DWRITE_FONT_STYLE_OBLIQUE == angle || DWRITE_FONT_STYLE_ITALIC == angle) {
michael@0 523 style |= SkTypeface::kItalic;
michael@0 524 }
michael@0 525 return static_cast<SkTypeface::Style>(style);
michael@0 526 }
michael@0 527
michael@0 528 class DWriteFontTypeface : public SkTypeface {
michael@0 529 private:
michael@0 530 DWriteFontTypeface(SkTypeface::Style style, SkFontID fontID,
michael@0 531 IDWriteFontFace* fontFace,
michael@0 532 IDWriteFont* font,
michael@0 533 IDWriteFontFamily* fontFamily,
michael@0 534 StreamFontFileLoader* fontFileLoader = NULL,
michael@0 535 IDWriteFontCollectionLoader* fontCollectionLoader = NULL)
michael@0 536 : SkTypeface(style, fontID, false)
michael@0 537 , fDWriteFontCollectionLoader(SkSafeRefComPtr(fontCollectionLoader))
michael@0 538 , fDWriteFontFileLoader(SkSafeRefComPtr(fontFileLoader))
michael@0 539 , fDWriteFontFamily(SkRefComPtr(fontFamily))
michael@0 540 , fDWriteFont(SkRefComPtr(font))
michael@0 541 , fDWriteFontFace(SkRefComPtr(fontFace))
michael@0 542 { }
michael@0 543
michael@0 544 public:
michael@0 545 SkTScopedComPtr<IDWriteFontCollectionLoader> fDWriteFontCollectionLoader;
michael@0 546 SkTScopedComPtr<StreamFontFileLoader> fDWriteFontFileLoader;
michael@0 547 SkTScopedComPtr<IDWriteFontFamily> fDWriteFontFamily;
michael@0 548 SkTScopedComPtr<IDWriteFont> fDWriteFont;
michael@0 549 SkTScopedComPtr<IDWriteFontFace> fDWriteFontFace;
michael@0 550
michael@0 551 static DWriteFontTypeface* Create(IDWriteFontFace* fontFace,
michael@0 552 IDWriteFont* font,
michael@0 553 IDWriteFontFamily* fontFamily,
michael@0 554 StreamFontFileLoader* fontFileLoader = NULL,
michael@0 555 IDWriteFontCollectionLoader* fontCollectionLoader = NULL) {
michael@0 556 SkTypeface::Style style = get_style(font);
michael@0 557 SkFontID fontID = SkTypefaceCache::NewFontID();
michael@0 558 return SkNEW_ARGS(DWriteFontTypeface, (style, fontID,
michael@0 559 fontFace, font, fontFamily,
michael@0 560 fontFileLoader, fontCollectionLoader));
michael@0 561 }
michael@0 562
michael@0 563 ~DWriteFontTypeface() {
michael@0 564 if (fDWriteFontCollectionLoader.get() == NULL) return;
michael@0 565
michael@0 566 IDWriteFactory* factory = get_dwrite_factory();
michael@0 567 SkASSERT(factory != NULL);
michael@0 568 HRV(factory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get()));
michael@0 569 HRV(factory->UnregisterFontFileLoader(fDWriteFontFileLoader.get()));
michael@0 570 }
michael@0 571
michael@0 572 protected:
michael@0 573 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
michael@0 574 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
michael@0 575 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
michael@0 576 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
michael@0 577 SkAdvancedTypefaceMetrics::PerGlyphInfo,
michael@0 578 const uint32_t*, uint32_t) const SK_OVERRIDE;
michael@0 579 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
michael@0 580 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
michael@0 581 uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
michael@0 582 virtual int onCountGlyphs() const SK_OVERRIDE;
michael@0 583 virtual int onGetUPEM() const SK_OVERRIDE;
michael@0 584 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
michael@0 585 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
michael@0 586 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
michael@0 587 size_t length, void* data) const SK_OVERRIDE;
michael@0 588 };
michael@0 589
michael@0 590 class SkScalerContext_DW : public SkScalerContext {
michael@0 591 public:
michael@0 592 SkScalerContext_DW(DWriteFontTypeface*, const SkDescriptor* desc);
michael@0 593 virtual ~SkScalerContext_DW();
michael@0 594
michael@0 595 protected:
michael@0 596 virtual unsigned generateGlyphCount() SK_OVERRIDE;
michael@0 597 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
michael@0 598 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
michael@0 599 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
michael@0 600 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
michael@0 601 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
michael@0 602 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
michael@0 603 SkPaint::FontMetrics* mY) SK_OVERRIDE;
michael@0 604
michael@0 605 private:
michael@0 606 DWriteOffscreen fOffscreen;
michael@0 607 DWRITE_MATRIX fXform;
michael@0 608 SkAutoTUnref<DWriteFontTypeface> fTypeface;
michael@0 609 int fGlyphCount;
michael@0 610 };
michael@0 611
michael@0 612 static bool are_same(IUnknown* a, IUnknown* b) {
michael@0 613 SkTScopedComPtr<IUnknown> iunkA;
michael@0 614 if (FAILED(a->QueryInterface(&iunkA))) {
michael@0 615 return false;
michael@0 616 }
michael@0 617
michael@0 618 SkTScopedComPtr<IUnknown> iunkB;
michael@0 619 if (FAILED(b->QueryInterface(&iunkB))) {
michael@0 620 return false;
michael@0 621 }
michael@0 622
michael@0 623 return iunkA.get() == iunkB.get();
michael@0 624 }
michael@0 625 static bool FindByDWriteFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
michael@0 626 //Check to see if the two fonts are identical.
michael@0 627 DWriteFontTypeface* dwFace = reinterpret_cast<DWriteFontTypeface*>(face);
michael@0 628 IDWriteFont* dwFont = reinterpret_cast<IDWriteFont*>(ctx);
michael@0 629 if (are_same(dwFace->fDWriteFont.get(), dwFont)) {
michael@0 630 return true;
michael@0 631 }
michael@0 632
michael@0 633 //Check if the two fonts share the same loader and have the same key.
michael@0 634 SkTScopedComPtr<IDWriteFontFace> dwFaceFontFace;
michael@0 635 SkTScopedComPtr<IDWriteFontFace> dwFontFace;
michael@0 636 HRB(dwFace->fDWriteFont->CreateFontFace(&dwFaceFontFace));
michael@0 637 HRB(dwFont->CreateFontFace(&dwFontFace));
michael@0 638 if (are_same(dwFaceFontFace.get(), dwFontFace.get())) {
michael@0 639 return true;
michael@0 640 }
michael@0 641
michael@0 642 UINT32 dwFaceNumFiles;
michael@0 643 UINT32 dwNumFiles;
michael@0 644 HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, NULL));
michael@0 645 HRB(dwFontFace->GetFiles(&dwNumFiles, NULL));
michael@0 646 if (dwFaceNumFiles != dwNumFiles) {
michael@0 647 return false;
michael@0 648 }
michael@0 649
michael@0 650 SkTScopedComPtr<IDWriteFontFile> dwFaceFontFile;
michael@0 651 SkTScopedComPtr<IDWriteFontFile> dwFontFile;
michael@0 652 HRB(dwFaceFontFace->GetFiles(&dwFaceNumFiles, &dwFaceFontFile));
michael@0 653 HRB(dwFontFace->GetFiles(&dwNumFiles, &dwFontFile));
michael@0 654
michael@0 655 //for (each file) { //we currently only admit fonts from one file.
michael@0 656 SkTScopedComPtr<IDWriteFontFileLoader> dwFaceFontFileLoader;
michael@0 657 SkTScopedComPtr<IDWriteFontFileLoader> dwFontFileLoader;
michael@0 658 HRB(dwFaceFontFile->GetLoader(&dwFaceFontFileLoader));
michael@0 659 HRB(dwFontFile->GetLoader(&dwFontFileLoader));
michael@0 660 if (!are_same(dwFaceFontFileLoader.get(), dwFontFileLoader.get())) {
michael@0 661 return false;
michael@0 662 }
michael@0 663 //}
michael@0 664
michael@0 665 const void* dwFaceFontRefKey;
michael@0 666 UINT32 dwFaceFontRefKeySize;
michael@0 667 const void* dwFontRefKey;
michael@0 668 UINT32 dwFontRefKeySize;
michael@0 669 HRB(dwFaceFontFile->GetReferenceKey(&dwFaceFontRefKey, &dwFaceFontRefKeySize));
michael@0 670 HRB(dwFontFile->GetReferenceKey(&dwFontRefKey, &dwFontRefKeySize));
michael@0 671 if (dwFaceFontRefKeySize != dwFontRefKeySize) {
michael@0 672 return false;
michael@0 673 }
michael@0 674 if (0 != memcmp(dwFaceFontRefKey, dwFontRefKey, dwFontRefKeySize)) {
michael@0 675 return false;
michael@0 676 }
michael@0 677
michael@0 678 //TODO: better means than comparing name strings?
michael@0 679 //NOTE: .tfc and fake bold/italic will end up here.
michael@0 680 SkTScopedComPtr<IDWriteFontFamily> dwFaceFontFamily;
michael@0 681 SkTScopedComPtr<IDWriteFontFamily> dwFontFamily;
michael@0 682 HRB(dwFace->fDWriteFont->GetFontFamily(&dwFaceFontFamily));
michael@0 683 HRB(dwFont->GetFontFamily(&dwFontFamily));
michael@0 684
michael@0 685 SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontFamilyNames;
michael@0 686 SkTScopedComPtr<IDWriteLocalizedStrings> dwFaceFontNames;
michael@0 687 HRB(dwFaceFontFamily->GetFamilyNames(&dwFaceFontFamilyNames));
michael@0 688 HRB(dwFace->fDWriteFont->GetFaceNames(&dwFaceFontNames));
michael@0 689
michael@0 690 SkTScopedComPtr<IDWriteLocalizedStrings> dwFontFamilyNames;
michael@0 691 SkTScopedComPtr<IDWriteLocalizedStrings> dwFontNames;
michael@0 692 HRB(dwFontFamily->GetFamilyNames(&dwFontFamilyNames));
michael@0 693 HRB(dwFont->GetFaceNames(&dwFontNames));
michael@0 694
michael@0 695 UINT32 dwFaceFontFamilyNameLength;
michael@0 696 UINT32 dwFaceFontNameLength;
michael@0 697 HRB(dwFaceFontFamilyNames->GetStringLength(0, &dwFaceFontFamilyNameLength));
michael@0 698 HRB(dwFaceFontNames->GetStringLength(0, &dwFaceFontNameLength));
michael@0 699
michael@0 700 UINT32 dwFontFamilyNameLength;
michael@0 701 UINT32 dwFontNameLength;
michael@0 702 HRB(dwFontFamilyNames->GetStringLength(0, &dwFontFamilyNameLength));
michael@0 703 HRB(dwFontNames->GetStringLength(0, &dwFontNameLength));
michael@0 704
michael@0 705 if (dwFaceFontFamilyNameLength != dwFontFamilyNameLength ||
michael@0 706 dwFaceFontNameLength != dwFontNameLength)
michael@0 707 {
michael@0 708 return false;
michael@0 709 }
michael@0 710
michael@0 711 SkSMallocWCHAR dwFaceFontFamilyNameChar(dwFaceFontFamilyNameLength+1);
michael@0 712 SkSMallocWCHAR dwFaceFontNameChar(dwFaceFontNameLength+1);
michael@0 713 HRB(dwFaceFontFamilyNames->GetString(0, dwFaceFontFamilyNameChar.get(), dwFaceFontFamilyNameLength+1));
michael@0 714 HRB(dwFaceFontNames->GetString(0, dwFaceFontNameChar.get(), dwFaceFontNameLength+1));
michael@0 715
michael@0 716 SkSMallocWCHAR dwFontFamilyNameChar(dwFontFamilyNameLength+1);
michael@0 717 SkSMallocWCHAR dwFontNameChar(dwFontNameLength+1);
michael@0 718 HRB(dwFontFamilyNames->GetString(0, dwFontFamilyNameChar.get(), dwFontFamilyNameLength+1));
michael@0 719 HRB(dwFontNames->GetString(0, dwFontNameChar.get(), dwFontNameLength+1));
michael@0 720
michael@0 721 return wcscmp(dwFaceFontFamilyNameChar.get(), dwFontFamilyNameChar.get()) == 0 &&
michael@0 722 wcscmp(dwFaceFontNameChar.get(), dwFontNameChar.get()) == 0;
michael@0 723 }
michael@0 724
michael@0 725 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface,
michael@0 726 const SkDescriptor* desc)
michael@0 727 : SkScalerContext(typeface, desc)
michael@0 728 , fTypeface(SkRef(typeface))
michael@0 729 , fGlyphCount(-1) {
michael@0 730
michael@0 731 fXform.m11 = SkScalarToFloat(fRec.fPost2x2[0][0]);
michael@0 732 fXform.m12 = SkScalarToFloat(fRec.fPost2x2[1][0]);
michael@0 733 fXform.m21 = SkScalarToFloat(fRec.fPost2x2[0][1]);
michael@0 734 fXform.m22 = SkScalarToFloat(fRec.fPost2x2[1][1]);
michael@0 735 fXform.dx = 0;
michael@0 736 fXform.dy = 0;
michael@0 737
michael@0 738 fOffscreen.init(fTypeface->fDWriteFontFace.get(), fXform, SkScalarToFloat(fRec.fTextSize));
michael@0 739 }
michael@0 740
michael@0 741 SkScalerContext_DW::~SkScalerContext_DW() {
michael@0 742 }
michael@0 743
michael@0 744 unsigned SkScalerContext_DW::generateGlyphCount() {
michael@0 745 if (fGlyphCount < 0) {
michael@0 746 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount();
michael@0 747 }
michael@0 748 return fGlyphCount;
michael@0 749 }
michael@0 750
michael@0 751 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) {
michael@0 752 uint16_t index = 0;
michael@0 753 fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni), 1, &index);
michael@0 754 return index;
michael@0 755 }
michael@0 756
michael@0 757 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
michael@0 758 //Delta is the difference between the right/left side bearing metric
michael@0 759 //and where the right/left side bearing ends up after hinting.
michael@0 760 //DirectWrite does not provide this information.
michael@0 761 glyph->fRsbDelta = 0;
michael@0 762 glyph->fLsbDelta = 0;
michael@0 763
michael@0 764 glyph->fAdvanceX = 0;
michael@0 765 glyph->fAdvanceY = 0;
michael@0 766
michael@0 767 uint16_t glyphId = glyph->getGlyphID();
michael@0 768 DWRITE_GLYPH_METRICS gm;
michael@0 769 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
michael@0 770 "Could not get design metrics.");
michael@0 771
michael@0 772 DWRITE_FONT_METRICS dwfm;
michael@0 773 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
michael@0 774
michael@0 775 SkScalar advanceX = SkScalarMulDiv(fRec.fTextSize,
michael@0 776 SkIntToScalar(gm.advanceWidth),
michael@0 777 SkIntToScalar(dwfm.designUnitsPerEm));
michael@0 778
michael@0 779 if (!(fRec.fFlags & kSubpixelPositioning_Flag)) {
michael@0 780 advanceX = SkScalarRoundToScalar(advanceX);
michael@0 781 }
michael@0 782
michael@0 783 SkVector vecs[1] = { { advanceX, 0 } };
michael@0 784 SkMatrix mat;
michael@0 785 fRec.getMatrixFrom2x2(&mat);
michael@0 786 mat.mapVectors(vecs, SK_ARRAY_COUNT(vecs));
michael@0 787
michael@0 788 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX);
michael@0 789 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
michael@0 790 }
michael@0 791
michael@0 792 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
michael@0 793 glyph->fWidth = 0;
michael@0 794
michael@0 795 this->generateAdvance(glyph);
michael@0 796
michael@0 797 //Measure raster size.
michael@0 798 fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
michael@0 799 fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
michael@0 800
michael@0 801 FLOAT advance = 0;
michael@0 802
michael@0 803 UINT16 glyphId = glyph->getGlyphID();
michael@0 804
michael@0 805 DWRITE_GLYPH_OFFSET offset;
michael@0 806 offset.advanceOffset = 0.0f;
michael@0 807 offset.ascenderOffset = 0.0f;
michael@0 808
michael@0 809 DWRITE_GLYPH_RUN run;
michael@0 810 run.glyphCount = 1;
michael@0 811 run.glyphAdvances = &advance;
michael@0 812 run.fontFace = fTypeface->fDWriteFontFace.get();
michael@0 813 run.fontEmSize = SkScalarToFloat(fRec.fTextSize);
michael@0 814 run.bidiLevel = 0;
michael@0 815 run.glyphIndices = &glyphId;
michael@0 816 run.isSideways = FALSE;
michael@0 817 run.glyphOffsets = &offset;
michael@0 818
michael@0 819 IDWriteFactory* factory = get_dwrite_factory();
michael@0 820 SkASSERT(factory != NULL);
michael@0 821
michael@0 822 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
michael@0 823 DWRITE_RENDERING_MODE renderingMode;
michael@0 824 DWRITE_TEXTURE_TYPE textureType;
michael@0 825 if (isBW) {
michael@0 826 renderingMode = DWRITE_RENDERING_MODE_ALIASED;
michael@0 827 textureType = DWRITE_TEXTURE_ALIASED_1x1;
michael@0 828 } else {
michael@0 829 renderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
michael@0 830 textureType = DWRITE_TEXTURE_CLEARTYPE_3x1;
michael@0 831 }
michael@0 832
michael@0 833 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
michael@0 834 HRVM(factory->CreateGlyphRunAnalysis(&run,
michael@0 835 1.0f, // pixelsPerDip,
michael@0 836 &fXform,
michael@0 837 renderingMode,
michael@0 838 DWRITE_MEASURING_MODE_NATURAL,
michael@0 839 0.0f, // baselineOriginX,
michael@0 840 0.0f, // baselineOriginY,
michael@0 841 &glyphRunAnalysis),
michael@0 842 "Could not create glyph run analysis.");
michael@0 843
michael@0 844 RECT bbox;
michael@0 845 HRVM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, &bbox),
michael@0 846 "Could not get texture bounds.");
michael@0 847
michael@0 848 glyph->fWidth = SkToU16(bbox.right - bbox.left);
michael@0 849 glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
michael@0 850 glyph->fLeft = SkToS16(bbox.left);
michael@0 851 glyph->fTop = SkToS16(bbox.top);
michael@0 852 }
michael@0 853
michael@0 854 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
michael@0 855 SkPaint::FontMetrics* my) {
michael@0 856 if (!(mx || my))
michael@0 857 return;
michael@0 858
michael@0 859 if (mx) {
michael@0 860 sk_bzero(mx, sizeof(*mx));
michael@0 861 }
michael@0 862 if (my) {
michael@0 863 sk_bzero(my, sizeof(*my));
michael@0 864 }
michael@0 865
michael@0 866 DWRITE_FONT_METRICS dwfm;
michael@0 867 fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
michael@0 868
michael@0 869 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm);
michael@0 870 if (mx) {
michael@0 871 mx->fTop = -fRec.fTextSize * SkIntToScalar(dwfm.ascent) / upem;
michael@0 872 mx->fAscent = mx->fTop;
michael@0 873 mx->fDescent = fRec.fTextSize * SkIntToScalar(dwfm.descent) / upem;
michael@0 874 mx->fBottom = mx->fDescent;
michael@0 875 mx->fLeading = fRec.fTextSize * SkIntToScalar(dwfm.lineGap) / upem;
michael@0 876 mx->fXHeight = fRec.fTextSize * SkIntToScalar(dwfm.xHeight) / upem;
michael@0 877 mx->fUnderlineThickness = fRec.fTextSize * SkIntToScalar(dwfm.underlinePosition) / upem;
michael@0 878 mx->fUnderlinePosition = -(fRec.fTextSize * SkIntToScalar(dwfm.underlineThickness) / upem);
michael@0 879
michael@0 880 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
michael@0 881 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
michael@0 882 }
michael@0 883
michael@0 884 if (my) {
michael@0 885 my->fTop = -fRec.fTextSize * SkIntToScalar(dwfm.ascent) / upem;
michael@0 886 my->fAscent = my->fTop;
michael@0 887 my->fDescent = fRec.fTextSize * SkIntToScalar(dwfm.descent) / upem;
michael@0 888 my->fBottom = my->fDescent;
michael@0 889 my->fLeading = fRec.fTextSize * SkIntToScalar(dwfm.lineGap) / upem;
michael@0 890 my->fXHeight = fRec.fTextSize * SkIntToScalar(dwfm.xHeight) / upem;
michael@0 891 my->fUnderlineThickness = fRec.fTextSize * SkIntToScalar(dwfm.underlinePosition) / upem;
michael@0 892 my->fUnderlinePosition = -(fRec.fTextSize * SkIntToScalar(dwfm.underlineThickness) / upem);
michael@0 893
michael@0 894 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
michael@0 895 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
michael@0 896 }
michael@0 897 }
michael@0 898
michael@0 899 ///////////////////////////////////////////////////////////////////////////////
michael@0 900
michael@0 901 #include "SkColorPriv.h"
michael@0 902
michael@0 903 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph) {
michael@0 904 const int width = glyph.fWidth;
michael@0 905 const size_t dstRB = (width + 7) >> 3;
michael@0 906 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
michael@0 907
michael@0 908 int byteCount = width >> 3;
michael@0 909 int bitCount = width & 7;
michael@0 910
michael@0 911 for (int y = 0; y < glyph.fHeight; ++y) {
michael@0 912 if (byteCount > 0) {
michael@0 913 for (int i = 0; i < byteCount; ++i) {
michael@0 914 unsigned byte = 0;
michael@0 915 byte |= src[0] & (1 << 7);
michael@0 916 byte |= src[1] & (1 << 6);
michael@0 917 byte |= src[2] & (1 << 5);
michael@0 918 byte |= src[3] & (1 << 4);
michael@0 919 byte |= src[4] & (1 << 3);
michael@0 920 byte |= src[5] & (1 << 2);
michael@0 921 byte |= src[6] & (1 << 1);
michael@0 922 byte |= src[7] & (1 << 0);
michael@0 923 dst[i] = byte;
michael@0 924 src += 8;
michael@0 925 }
michael@0 926 }
michael@0 927 if (bitCount > 0) {
michael@0 928 unsigned byte = 0;
michael@0 929 unsigned mask = 0x80;
michael@0 930 for (int i = 0; i < bitCount; i++) {
michael@0 931 byte |= (src[i]) & mask;
michael@0 932 mask >>= 1;
michael@0 933 }
michael@0 934 dst[byteCount] = byte;
michael@0 935 }
michael@0 936 src += bitCount;
michael@0 937 dst += dstRB;
michael@0 938 }
michael@0 939 }
michael@0 940
michael@0 941 template<bool APPLY_PREBLEND>
michael@0 942 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
michael@0 943 const size_t dstRB = glyph.rowBytes();
michael@0 944 const U16CPU width = glyph.fWidth;
michael@0 945 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
michael@0 946
michael@0 947 for (U16CPU y = 0; y < glyph.fHeight; y++) {
michael@0 948 for (U16CPU i = 0; i < width; i++) {
michael@0 949 U8CPU r = *(src++);
michael@0 950 U8CPU g = *(src++);
michael@0 951 U8CPU b = *(src++);
michael@0 952 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
michael@0 953 }
michael@0 954 dst = (uint8_t*)((char*)dst + dstRB);
michael@0 955 }
michael@0 956 }
michael@0 957
michael@0 958 template<bool APPLY_PREBLEND>
michael@0 959 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
michael@0 960 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
michael@0 961 const size_t dstRB = glyph.rowBytes();
michael@0 962 const U16CPU width = glyph.fWidth;
michael@0 963 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage);
michael@0 964
michael@0 965 for (U16CPU y = 0; y < glyph.fHeight; y++) {
michael@0 966 for (U16CPU i = 0; i < width; i++) {
michael@0 967 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
michael@0 968 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
michael@0 969 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
michael@0 970 dst[i] = SkPack888ToRGB16(r, g, b);
michael@0 971 }
michael@0 972 dst = (uint16_t*)((char*)dst + dstRB);
michael@0 973 }
michael@0 974 }
michael@0 975
michael@0 976 template<bool APPLY_PREBLEND>
michael@0 977 static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
michael@0 978 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
michael@0 979 const size_t dstRB = glyph.rowBytes();
michael@0 980 const U16CPU width = glyph.fWidth;
michael@0 981 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage);
michael@0 982
michael@0 983 for (U16CPU y = 0; y < glyph.fHeight; y++) {
michael@0 984 for (U16CPU i = 0; i < width; i++) {
michael@0 985 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR);
michael@0 986 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG);
michael@0 987 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB);
michael@0 988 dst[i] = SkPackARGB32(0xFF, r, g, b);
michael@0 989 }
michael@0 990 dst = (SkPMColor*)((char*)dst + dstRB);
michael@0 991 }
michael@0 992 }
michael@0 993
michael@0 994 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
michael@0 995 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
michael@0 996 const bool isAA = !isLCD(fRec);
michael@0 997
michael@0 998 //Create the mask.
michael@0 999 const void* bits = fOffscreen.draw(glyph, isBW);
michael@0 1000 if (!bits) {
michael@0 1001 sk_bzero(glyph.fImage, glyph.computeImageSize());
michael@0 1002 return;
michael@0 1003 }
michael@0 1004
michael@0 1005 //Copy the mask into the glyph.
michael@0 1006 const uint8_t* src = (const uint8_t*)bits;
michael@0 1007 if (isBW) {
michael@0 1008 bilevel_to_bw(src, glyph);
michael@0 1009 } else if (isAA) {
michael@0 1010 if (fPreBlend.isApplicable()) {
michael@0 1011 rgb_to_a8<true>(src, glyph, fPreBlend.fG);
michael@0 1012 } else {
michael@0 1013 rgb_to_a8<false>(src, glyph, fPreBlend.fG);
michael@0 1014 }
michael@0 1015 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
michael@0 1016 if (fPreBlend.isApplicable()) {
michael@0 1017 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
michael@0 1018 } else {
michael@0 1019 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
michael@0 1020 }
michael@0 1021 } else {
michael@0 1022 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
michael@0 1023 if (fPreBlend.isApplicable()) {
michael@0 1024 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
michael@0 1025 } else {
michael@0 1026 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
michael@0 1027 }
michael@0 1028 }
michael@0 1029 }
michael@0 1030
michael@0 1031 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
michael@0 1032 SkASSERT(&glyph && path);
michael@0 1033
michael@0 1034 path->reset();
michael@0 1035
michael@0 1036 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath;
michael@0 1037 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
michael@0 1038 "Could not create geometry to path converter.");
michael@0 1039 uint16_t glyphId = glyph.getGlyphID();
michael@0 1040 //TODO: convert to<->from DIUs? This would make a difference if hinting.
michael@0 1041 //It may not be needed, it appears that DirectWrite only hints at em size.
michael@0 1042 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fRec.fTextSize),
michael@0 1043 &glyphId,
michael@0 1044 NULL, //advances
michael@0 1045 NULL, //offsets
michael@0 1046 1, //num glyphs
michael@0 1047 FALSE, //sideways
michael@0 1048 FALSE, //rtl
michael@0 1049 geometryToPath.get()),
michael@0 1050 "Could not create glyph outline.");
michael@0 1051
michael@0 1052 SkMatrix mat;
michael@0 1053 fRec.getMatrixFrom2x2(&mat);
michael@0 1054 path->transform(mat);
michael@0 1055 }
michael@0 1056
michael@0 1057 void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
michael@0 1058 bool* isLocalStream) const {
michael@0 1059 // Get the family name.
michael@0 1060 SkTScopedComPtr<IDWriteLocalizedStrings> dwFamilyNames;
michael@0 1061 HRV(fDWriteFontFamily->GetFamilyNames(&dwFamilyNames));
michael@0 1062
michael@0 1063 UINT32 dwFamilyNamesLength;
michael@0 1064 HRV(dwFamilyNames->GetStringLength(0, &dwFamilyNamesLength));
michael@0 1065
michael@0 1066 SkSMallocWCHAR dwFamilyNameChar(dwFamilyNamesLength+1);
michael@0 1067 HRV(dwFamilyNames->GetString(0, dwFamilyNameChar.get(), dwFamilyNamesLength+1));
michael@0 1068
michael@0 1069 SkString utf8FamilyName;
michael@0 1070 HRV(wchar_to_skstring(dwFamilyNameChar.get(), &utf8FamilyName));
michael@0 1071
michael@0 1072 desc->setFamilyName(utf8FamilyName.c_str());
michael@0 1073 *isLocalStream = SkToBool(fDWriteFontFileLoader.get());
michael@0 1074 }
michael@0 1075
michael@0 1076 static SkUnichar next_utf8(const void** chars) {
michael@0 1077 return SkUTF8_NextUnichar((const char**)chars);
michael@0 1078 }
michael@0 1079
michael@0 1080 static SkUnichar next_utf16(const void** chars) {
michael@0 1081 return SkUTF16_NextUnichar((const uint16_t**)chars);
michael@0 1082 }
michael@0 1083
michael@0 1084 static SkUnichar next_utf32(const void** chars) {
michael@0 1085 const SkUnichar** uniChars = (const SkUnichar**)chars;
michael@0 1086 SkUnichar uni = **uniChars;
michael@0 1087 *uniChars += 1;
michael@0 1088 return uni;
michael@0 1089 }
michael@0 1090
michael@0 1091 typedef SkUnichar (*EncodingProc)(const void**);
michael@0 1092
michael@0 1093 static EncodingProc find_encoding_proc(SkTypeface::Encoding enc) {
michael@0 1094 static const EncodingProc gProcs[] = {
michael@0 1095 next_utf8, next_utf16, next_utf32
michael@0 1096 };
michael@0 1097 SkASSERT((size_t)enc < SK_ARRAY_COUNT(gProcs));
michael@0 1098 return gProcs[enc];
michael@0 1099 }
michael@0 1100
michael@0 1101 int DWriteFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
michael@0 1102 uint16_t glyphs[], int glyphCount) const
michael@0 1103 {
michael@0 1104 if (NULL == glyphs) {
michael@0 1105 EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
michael@0 1106 for (int i = 0; i < glyphCount; ++i) {
michael@0 1107 const SkUnichar c = next_ucs4_proc(&chars);
michael@0 1108 BOOL exists;
michael@0 1109 fDWriteFont->HasCharacter(c, &exists);
michael@0 1110 if (!exists) {
michael@0 1111 return i;
michael@0 1112 }
michael@0 1113 }
michael@0 1114 return glyphCount;
michael@0 1115 }
michael@0 1116
michael@0 1117 switch (encoding) {
michael@0 1118 case SkTypeface::kUTF8_Encoding:
michael@0 1119 case SkTypeface::kUTF16_Encoding: {
michael@0 1120 static const int scratchCount = 256;
michael@0 1121 UINT32 scratch[scratchCount];
michael@0 1122 EncodingProc next_ucs4_proc = find_encoding_proc(encoding);
michael@0 1123 for (int baseGlyph = 0; baseGlyph < glyphCount; baseGlyph += scratchCount) {
michael@0 1124 int glyphsLeft = glyphCount - baseGlyph;
michael@0 1125 int limit = SkTMin(glyphsLeft, scratchCount);
michael@0 1126 for (int i = 0; i < limit; ++i) {
michael@0 1127 scratch[i] = next_ucs4_proc(&chars);
michael@0 1128 }
michael@0 1129 fDWriteFontFace->GetGlyphIndices(scratch, limit, &glyphs[baseGlyph]);
michael@0 1130 }
michael@0 1131 break;
michael@0 1132 }
michael@0 1133 case SkTypeface::kUTF32_Encoding: {
michael@0 1134 const UINT32* utf32 = reinterpret_cast<const UINT32*>(chars);
michael@0 1135 fDWriteFontFace->GetGlyphIndices(utf32, glyphCount, glyphs);
michael@0 1136 break;
michael@0 1137 }
michael@0 1138 default:
michael@0 1139 SK_CRASH();
michael@0 1140 }
michael@0 1141
michael@0 1142 for (int i = 0; i < glyphCount; ++i) {
michael@0 1143 if (0 == glyphs[i]) {
michael@0 1144 return i;
michael@0 1145 }
michael@0 1146 }
michael@0 1147 return glyphCount;
michael@0 1148 }
michael@0 1149
michael@0 1150 int DWriteFontTypeface::onCountGlyphs() const {
michael@0 1151 return fDWriteFontFace->GetGlyphCount();
michael@0 1152 }
michael@0 1153
michael@0 1154 int DWriteFontTypeface::onGetUPEM() const {
michael@0 1155 DWRITE_FONT_METRICS metrics;
michael@0 1156 fDWriteFontFace->GetMetrics(&metrics);
michael@0 1157 return metrics.designUnitsPerEm;
michael@0 1158 }
michael@0 1159
michael@0 1160 class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings {
michael@0 1161 public:
michael@0 1162 /** Takes ownership of the IDWriteLocalizedStrings. */
michael@0 1163 explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings)
michael@0 1164 : fIndex(0), fStrings(strings)
michael@0 1165 { }
michael@0 1166
michael@0 1167 virtual bool next(SkTypeface::LocalizedString* localizedString) SK_OVERRIDE {
michael@0 1168 if (fIndex >= fStrings->GetCount()) {
michael@0 1169 return false;
michael@0 1170 }
michael@0 1171
michael@0 1172 // String
michael@0 1173 UINT32 stringLength;
michael@0 1174 HRBM(fStrings->GetStringLength(fIndex, &stringLength), "Could not get string length.");
michael@0 1175 stringLength += 1;
michael@0 1176
michael@0 1177 SkSMallocWCHAR wString(stringLength);
michael@0 1178 HRBM(fStrings->GetString(fIndex, wString.get(), stringLength), "Could not get string.");
michael@0 1179
michael@0 1180 HRB(wchar_to_skstring(wString.get(), &localizedString->fString));
michael@0 1181
michael@0 1182 // Locale
michael@0 1183 UINT32 localeLength;
michael@0 1184 HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLength), "Could not get locale length.");
michael@0 1185 localeLength += 1;
michael@0 1186
michael@0 1187 SkSMallocWCHAR wLocale(localeLength);
michael@0 1188 HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLength), "Could not get locale.");
michael@0 1189
michael@0 1190 HRB(wchar_to_skstring(wLocale.get(), &localizedString->fLanguage));
michael@0 1191
michael@0 1192 ++fIndex;
michael@0 1193 return true;
michael@0 1194 }
michael@0 1195
michael@0 1196 private:
michael@0 1197 UINT32 fIndex;
michael@0 1198 SkTScopedComPtr<IDWriteLocalizedStrings> fStrings;
michael@0 1199 };
michael@0 1200
michael@0 1201 SkTypeface::LocalizedStrings* DWriteFontTypeface::onCreateFamilyNameIterator() const {
michael@0 1202 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
michael@0 1203 HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names.");
michael@0 1204
michael@0 1205 return new LocalizedStrings_IDWriteLocalizedStrings(familyNames.release());
michael@0 1206 }
michael@0 1207
michael@0 1208 int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
michael@0 1209 DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType();
michael@0 1210 if (type != DWRITE_FONT_FACE_TYPE_CFF &&
michael@0 1211 type != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
michael@0 1212 type != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
michael@0 1213 {
michael@0 1214 return 0;
michael@0 1215 }
michael@0 1216
michael@0 1217 int ttcIndex;
michael@0 1218 SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
michael@0 1219 return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
michael@0 1220 }
michael@0 1221
michael@0 1222 class AutoDWriteTable {
michael@0 1223 public:
michael@0 1224 AutoDWriteTable(IDWriteFontFace* fontFace, UINT32 beTag) : fFontFace(fontFace), fExists(FALSE) {
michael@0 1225 // Any errors are ignored, user must check fExists anyway.
michael@0 1226 fontFace->TryGetFontTable(beTag,
michael@0 1227 reinterpret_cast<const void **>(&fData), &fSize, &fLock, &fExists);
michael@0 1228 }
michael@0 1229 ~AutoDWriteTable() {
michael@0 1230 if (fExists) {
michael@0 1231 fFontFace->ReleaseFontTable(fLock);
michael@0 1232 }
michael@0 1233 }
michael@0 1234
michael@0 1235 const uint8_t* fData;
michael@0 1236 UINT32 fSize;
michael@0 1237 BOOL fExists;
michael@0 1238 private:
michael@0 1239 // Borrowed reference, the user must ensure the fontFace stays alive.
michael@0 1240 IDWriteFontFace* fFontFace;
michael@0 1241 void* fLock;
michael@0 1242 };
michael@0 1243
michael@0 1244 size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
michael@0 1245 size_t length, void* data) const
michael@0 1246 {
michael@0 1247 AutoDWriteTable table(fDWriteFontFace.get(), SkEndian_SwapBE32(tag));
michael@0 1248 if (!table.fExists) {
michael@0 1249 return 0;
michael@0 1250 }
michael@0 1251
michael@0 1252 if (offset > table.fSize) {
michael@0 1253 return 0;
michael@0 1254 }
michael@0 1255 size_t size = SkTMin(length, table.fSize - offset);
michael@0 1256 if (NULL != data) {
michael@0 1257 memcpy(data, table.fData + offset, size);
michael@0 1258 }
michael@0 1259
michael@0 1260 return size;
michael@0 1261 }
michael@0 1262
michael@0 1263 template <typename T> class SkAutoIDWriteUnregister {
michael@0 1264 public:
michael@0 1265 SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
michael@0 1266 : fFactory(factory), fUnregister(unregister)
michael@0 1267 { }
michael@0 1268
michael@0 1269 ~SkAutoIDWriteUnregister() {
michael@0 1270 if (fUnregister) {
michael@0 1271 unregister(fFactory, fUnregister);
michael@0 1272 }
michael@0 1273 }
michael@0 1274
michael@0 1275 T* detatch() {
michael@0 1276 T* old = fUnregister;
michael@0 1277 fUnregister = NULL;
michael@0 1278 return old;
michael@0 1279 }
michael@0 1280
michael@0 1281 private:
michael@0 1282 HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) {
michael@0 1283 return factory->UnregisterFontFileLoader(unregister);
michael@0 1284 }
michael@0 1285
michael@0 1286 HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) {
michael@0 1287 return factory->UnregisterFontCollectionLoader(unregister);
michael@0 1288 }
michael@0 1289
michael@0 1290 IDWriteFactory* fFactory;
michael@0 1291 T* fUnregister;
michael@0 1292 };
michael@0 1293
michael@0 1294 static SkTypeface* create_from_stream(SkStream* stream, int ttcIndex) {
michael@0 1295 IDWriteFactory* factory = get_dwrite_factory();
michael@0 1296 if (NULL == factory) {
michael@0 1297 return NULL;
michael@0 1298 }
michael@0 1299
michael@0 1300 SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
michael@0 1301 HRN(StreamFontFileLoader::Create(stream, &fontFileLoader));
michael@0 1302 HRN(factory->RegisterFontFileLoader(fontFileLoader.get()));
michael@0 1303 SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader(
michael@0 1304 factory, fontFileLoader.get());
michael@0 1305
michael@0 1306 SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader;
michael@0 1307 HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader));
michael@0 1308 HRN(factory->RegisterFontCollectionLoader(fontCollectionLoader.get()));
michael@0 1309 SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader(
michael@0 1310 factory, fontCollectionLoader.get());
michael@0 1311
michael@0 1312 SkTScopedComPtr<IDWriteFontCollection> fontCollection;
michael@0 1313 HRN(factory->CreateCustomFontCollection(fontCollectionLoader.get(), NULL, 0, &fontCollection));
michael@0 1314
michael@0 1315 // Find the first non-simulated font which has the given ttc index.
michael@0 1316 UINT32 familyCount = fontCollection->GetFontFamilyCount();
michael@0 1317 for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
michael@0 1318 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
michael@0 1319 HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily));
michael@0 1320
michael@0 1321 UINT32 fontCount = fontFamily->GetFontCount();
michael@0 1322 for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
michael@0 1323 SkTScopedComPtr<IDWriteFont> font;
michael@0 1324 HRN(fontFamily->GetFont(fontIndex, &font));
michael@0 1325 if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
michael@0 1326 continue;
michael@0 1327 }
michael@0 1328
michael@0 1329 SkTScopedComPtr<IDWriteFontFace> fontFace;
michael@0 1330 HRN(font->CreateFontFace(&fontFace));
michael@0 1331
michael@0 1332 UINT32 faceIndex = fontFace->GetIndex();
michael@0 1333 if (faceIndex == ttcIndex) {
michael@0 1334 return DWriteFontTypeface::Create(fontFace.get(), font.get(), fontFamily.get(),
michael@0 1335 autoUnregisterFontFileLoader.detatch(),
michael@0 1336 autoUnregisterFontCollectionLoader.detatch());
michael@0 1337 }
michael@0 1338 }
michael@0 1339 }
michael@0 1340
michael@0 1341 return NULL;
michael@0 1342 }
michael@0 1343
michael@0 1344 SkStream* DWriteFontTypeface::onOpenStream(int* ttcIndex) const {
michael@0 1345 *ttcIndex = fDWriteFontFace->GetIndex();
michael@0 1346
michael@0 1347 UINT32 numFiles;
michael@0 1348 HRNM(fDWriteFontFace->GetFiles(&numFiles, NULL),
michael@0 1349 "Could not get number of font files.");
michael@0 1350 if (numFiles != 1) {
michael@0 1351 return NULL;
michael@0 1352 }
michael@0 1353
michael@0 1354 SkTScopedComPtr<IDWriteFontFile> fontFile;
michael@0 1355 HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files.");
michael@0 1356
michael@0 1357 const void* fontFileKey;
michael@0 1358 UINT32 fontFileKeySize;
michael@0 1359 HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize),
michael@0 1360 "Could not get font file reference key.");
michael@0 1361
michael@0 1362 SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
michael@0 1363 HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader.");
michael@0 1364
michael@0 1365 SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
michael@0 1366 HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize,
michael@0 1367 &fontFileStream),
michael@0 1368 "Could not create font file stream.");
michael@0 1369
michael@0 1370 return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
michael@0 1371 }
michael@0 1372
michael@0 1373 SkScalerContext* DWriteFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
michael@0 1374 return SkNEW_ARGS(SkScalerContext_DW, (const_cast<DWriteFontTypeface*>(this), desc));
michael@0 1375 }
michael@0 1376
michael@0 1377 void DWriteFontTypeface::onFilterRec(SkScalerContext::Rec* rec) const {
michael@0 1378 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
michael@0 1379 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
michael@0 1380 {
michael@0 1381 rec->fMaskFormat = SkMask::kA8_Format;
michael@0 1382 }
michael@0 1383
michael@0 1384 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
michael@0 1385 SkScalerContext::kForceAutohinting_Flag |
michael@0 1386 SkScalerContext::kEmbeddedBitmapText_Flag |
michael@0 1387 SkScalerContext::kEmbolden_Flag |
michael@0 1388 SkScalerContext::kLCD_BGROrder_Flag |
michael@0 1389 SkScalerContext::kLCD_Vertical_Flag;
michael@0 1390 rec->fFlags &= ~flagsWeDontSupport;
michael@0 1391
michael@0 1392 SkPaint::Hinting h = rec->getHinting();
michael@0 1393 // DirectWrite does not provide for hinting hints.
michael@0 1394 h = SkPaint::kSlight_Hinting;
michael@0 1395 rec->setHinting(h);
michael@0 1396
michael@0 1397 #if SK_FONT_HOST_USE_SYSTEM_SETTINGS
michael@0 1398 IDWriteFactory* factory = get_dwrite_factory();
michael@0 1399 if (factory != NULL) {
michael@0 1400 SkTScopedComPtr<IDWriteRenderingParams> defaultRenderingParams;
michael@0 1401 if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) {
michael@0 1402 float gamma = defaultRenderingParams->GetGamma();
michael@0 1403 rec->setDeviceGamma(gamma);
michael@0 1404 rec->setPaintGamma(gamma);
michael@0 1405
michael@0 1406 rec->setContrast(defaultRenderingParams->GetEnhancedContrast());
michael@0 1407 }
michael@0 1408 }
michael@0 1409 #endif
michael@0 1410 }
michael@0 1411
michael@0 1412 ///////////////////////////////////////////////////////////////////////////////
michael@0 1413 //PDF Support
michael@0 1414
michael@0 1415 using namespace skia_advanced_typeface_metrics_utils;
michael@0 1416
michael@0 1417 // Construct Glyph to Unicode table.
michael@0 1418 // Unicode code points that require conjugate pairs in utf16 are not
michael@0 1419 // supported.
michael@0 1420 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
michael@0 1421 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
michael@0 1422 // of calling GetFontUnicodeRange().
michael@0 1423 // TODO(bungeman): This never does what anyone wants.
michael@0 1424 // What is really wanted is the text to glyphs mapping
michael@0 1425 static void populate_glyph_to_unicode(IDWriteFontFace* fontFace,
michael@0 1426 const unsigned glyphCount,
michael@0 1427 SkTDArray<SkUnichar>* glyphToUnicode) {
michael@0 1428 HRESULT hr = S_OK;
michael@0 1429
michael@0 1430 //Do this like free type instead
michael@0 1431 UINT32 count = 0;
michael@0 1432 for (UINT32 c = 0; c < 0x10FFFF; ++c) {
michael@0 1433 UINT16 glyph;
michael@0 1434 hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
michael@0 1435 if (glyph > 0) {
michael@0 1436 ++count;
michael@0 1437 }
michael@0 1438 }
michael@0 1439
michael@0 1440 SkAutoTArray<UINT32> chars(count);
michael@0 1441 count = 0;
michael@0 1442 for (UINT32 c = 0; c < 0x10FFFF; ++c) {
michael@0 1443 UINT16 glyph;
michael@0 1444 hr = fontFace->GetGlyphIndices(&c, 1, &glyph);
michael@0 1445 if (glyph > 0) {
michael@0 1446 chars[count] = c;
michael@0 1447 ++count;
michael@0 1448 }
michael@0 1449 }
michael@0 1450
michael@0 1451 SkAutoTArray<UINT16> glyph(count);
michael@0 1452 fontFace->GetGlyphIndices(chars.get(), count, glyph.get());
michael@0 1453
michael@0 1454 USHORT maxGlyph = 0;
michael@0 1455 for (USHORT j = 0; j < count; ++j) {
michael@0 1456 if (glyph[j] > maxGlyph) maxGlyph = glyph[j];
michael@0 1457 }
michael@0 1458
michael@0 1459 glyphToUnicode->setCount(maxGlyph+1);
michael@0 1460 for (USHORT j = 0; j < maxGlyph+1u; ++j) {
michael@0 1461 (*glyphToUnicode)[j] = 0;
michael@0 1462 }
michael@0 1463
michael@0 1464 //'invert'
michael@0 1465 for (USHORT j = 0; j < count; ++j) {
michael@0 1466 if (glyph[j] < glyphCount && (*glyphToUnicode)[glyph[j]] == 0) {
michael@0 1467 (*glyphToUnicode)[glyph[j]] = chars[j];
michael@0 1468 }
michael@0 1469 }
michael@0 1470 }
michael@0 1471
michael@0 1472 static bool getWidthAdvance(IDWriteFontFace* fontFace, int gId, int16_t* advance) {
michael@0 1473 SkASSERT(advance);
michael@0 1474
michael@0 1475 UINT16 glyphId = gId;
michael@0 1476 DWRITE_GLYPH_METRICS gm;
michael@0 1477 HRESULT hr = fontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm);
michael@0 1478
michael@0 1479 if (FAILED(hr)) {
michael@0 1480 *advance = 0;
michael@0 1481 return false;
michael@0 1482 }
michael@0 1483
michael@0 1484 *advance = gm.advanceWidth;
michael@0 1485 return true;
michael@0 1486 }
michael@0 1487
michael@0 1488 template<typename T> class AutoTDWriteTable : public AutoDWriteTable {
michael@0 1489 public:
michael@0 1490 static const UINT32 tag = DWRITE_MAKE_OPENTYPE_TAG(T::TAG0, T::TAG1, T::TAG2, T::TAG3);
michael@0 1491 AutoTDWriteTable(IDWriteFontFace* fontFace) : AutoDWriteTable(fontFace, tag) { }
michael@0 1492
michael@0 1493 const T* operator->() const { return reinterpret_cast<const T*>(fData); }
michael@0 1494 };
michael@0 1495
michael@0 1496 SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics(
michael@0 1497 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
michael@0 1498 const uint32_t* glyphIDs,
michael@0 1499 uint32_t glyphIDsCount) const {
michael@0 1500
michael@0 1501 SkAdvancedTypefaceMetrics* info = NULL;
michael@0 1502
michael@0 1503 HRESULT hr = S_OK;
michael@0 1504
michael@0 1505 const unsigned glyphCount = fDWriteFontFace->GetGlyphCount();
michael@0 1506
michael@0 1507 DWRITE_FONT_METRICS dwfm;
michael@0 1508 fDWriteFontFace->GetMetrics(&dwfm);
michael@0 1509
michael@0 1510 info = new SkAdvancedTypefaceMetrics;
michael@0 1511 info->fEmSize = dwfm.designUnitsPerEm;
michael@0 1512 info->fMultiMaster = false;
michael@0 1513 info->fLastGlyphID = SkToU16(glyphCount - 1);
michael@0 1514 info->fStyle = 0;
michael@0 1515
michael@0 1516
michael@0 1517 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
michael@0 1518 SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
michael@0 1519 hr = fDWriteFontFamily->GetFamilyNames(&familyNames);
michael@0 1520 hr = fDWriteFont->GetFaceNames(&faceNames);
michael@0 1521
michael@0 1522 UINT32 familyNameLength;
michael@0 1523 hr = familyNames->GetStringLength(0, &familyNameLength);
michael@0 1524
michael@0 1525 UINT32 faceNameLength;
michael@0 1526 hr = faceNames->GetStringLength(0, &faceNameLength);
michael@0 1527
michael@0 1528 UINT32 size = familyNameLength+1+faceNameLength+1;
michael@0 1529 SkSMallocWCHAR wFamilyName(size);
michael@0 1530 hr = familyNames->GetString(0, wFamilyName.get(), size);
michael@0 1531 wFamilyName[familyNameLength] = L' ';
michael@0 1532 hr = faceNames->GetString(0, &wFamilyName[familyNameLength+1], size - faceNameLength + 1);
michael@0 1533
michael@0 1534 hr = wchar_to_skstring(wFamilyName.get(), &info->fFontName);
michael@0 1535
michael@0 1536 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
michael@0 1537 populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode));
michael@0 1538 }
michael@0 1539
michael@0 1540 DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
michael@0 1541 if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE ||
michael@0 1542 fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
michael@0 1543 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
michael@0 1544 } else {
michael@0 1545 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
michael@0 1546 info->fItalicAngle = 0;
michael@0 1547 info->fAscent = dwfm.ascent;;
michael@0 1548 info->fDescent = dwfm.descent;
michael@0 1549 info->fStemV = 0;
michael@0 1550 info->fCapHeight = dwfm.capHeight;
michael@0 1551 info->fBBox = SkIRect::MakeEmpty();
michael@0 1552 return info;
michael@0 1553 }
michael@0 1554
michael@0 1555 AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
michael@0 1556 AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
michael@0 1557 AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
michael@0 1558 AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
michael@0 1559 if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
michael@0 1560 info->fItalicAngle = 0;
michael@0 1561 info->fAscent = dwfm.ascent;;
michael@0 1562 info->fDescent = dwfm.descent;
michael@0 1563 info->fStemV = 0;
michael@0 1564 info->fCapHeight = dwfm.capHeight;
michael@0 1565 info->fBBox = SkIRect::MakeEmpty();
michael@0 1566 return info;
michael@0 1567 }
michael@0 1568
michael@0 1569 //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
michael@0 1570 //but have full width, latin half-width, and half-width kana.
michael@0 1571 bool fixedWidth = (postTable->isFixedPitch &&
michael@0 1572 (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
michael@0 1573 //Monospace
michael@0 1574 if (fixedWidth) {
michael@0 1575 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
michael@0 1576 }
michael@0 1577 //Italic
michael@0 1578 if (os2Table->version.v0.fsSelection.field.Italic) {
michael@0 1579 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
michael@0 1580 }
michael@0 1581 //Script
michael@0 1582 if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType.value) {
michael@0 1583 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
michael@0 1584 //Serif
michael@0 1585 } else if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType.value &&
michael@0 1586 SkPanose::Data::TextAndDisplay::SerifStyle::Triangle <= os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value &&
michael@0 1587 SkPanose::Data::TextAndDisplay::SerifStyle::NoFit != os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value) {
michael@0 1588 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
michael@0 1589 }
michael@0 1590
michael@0 1591 info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;
michael@0 1592
michael@0 1593 info->fAscent = SkToS16(dwfm.ascent);
michael@0 1594 info->fDescent = SkToS16(dwfm.descent);
michael@0 1595 info->fCapHeight = SkToS16(dwfm.capHeight);
michael@0 1596
michael@0 1597 info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
michael@0 1598 (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
michael@0 1599 (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
michael@0 1600 (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));
michael@0 1601
michael@0 1602 //TODO: is this even desired? It seems PDF only wants this value for Type1
michael@0 1603 //fonts, and we only get here for TrueType fonts.
michael@0 1604 info->fStemV = 0;
michael@0 1605 /*
michael@0 1606 // Figure out a good guess for StemV - Min width of i, I, !, 1.
michael@0 1607 // This probably isn't very good with an italic font.
michael@0 1608 int16_t min_width = SHRT_MAX;
michael@0 1609 info->fStemV = 0;
michael@0 1610 char stem_chars[] = {'i', 'I', '!', '1'};
michael@0 1611 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
michael@0 1612 ABC abcWidths;
michael@0 1613 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
michael@0 1614 int16_t width = abcWidths.abcB;
michael@0 1615 if (width > 0 && width < min_width) {
michael@0 1616 min_width = width;
michael@0 1617 info->fStemV = min_width;
michael@0 1618 }
michael@0 1619 }
michael@0 1620 }
michael@0 1621 */
michael@0 1622
michael@0 1623 // If Restricted, the font may not be embedded in a document.
michael@0 1624 // If not Restricted, the font can be embedded.
michael@0 1625 // If PreviewPrint, the embedding is read-only.
michael@0 1626 if (os2Table->version.v0.fsType.field.Restricted) {
michael@0 1627 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
michael@0 1628 } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
michael@0 1629 if (fixedWidth) {
michael@0 1630 appendRange(&info->fGlyphWidths, 0);
michael@0 1631 int16_t advance;
michael@0 1632 getWidthAdvance(fDWriteFontFace.get(), 1, &advance);
michael@0 1633 info->fGlyphWidths->fAdvance.append(1, &advance);
michael@0 1634 finishRange(info->fGlyphWidths.get(), 0,
michael@0 1635 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
michael@0 1636 } else {
michael@0 1637 info->fGlyphWidths.reset(
michael@0 1638 getAdvanceData(fDWriteFontFace.get(),
michael@0 1639 glyphCount,
michael@0 1640 glyphIDs,
michael@0 1641 glyphIDsCount,
michael@0 1642 getWidthAdvance));
michael@0 1643 }
michael@0 1644 }
michael@0 1645
michael@0 1646 return info;
michael@0 1647 }
michael@0 1648
michael@0 1649 ///////////////////////////////////////////////////////////////////////////////
michael@0 1650
michael@0 1651 static void get_locale_string(IDWriteLocalizedStrings* names, const WCHAR* preferedLocale,
michael@0 1652 SkString* skname) {
michael@0 1653 UINT32 nameIndex = 0;
michael@0 1654 if (preferedLocale) {
michael@0 1655 // Ignore any errors and continue with index 0 if there is a problem.
michael@0 1656 BOOL nameExists;
michael@0 1657 names->FindLocaleName(preferedLocale, &nameIndex, &nameExists);
michael@0 1658 if (!nameExists) {
michael@0 1659 nameIndex = 0;
michael@0 1660 }
michael@0 1661 }
michael@0 1662
michael@0 1663 UINT32 nameLength;
michael@0 1664 HRVM(names->GetStringLength(nameIndex, &nameLength), "Could not get name length.");
michael@0 1665 nameLength += 1;
michael@0 1666
michael@0 1667 SkSMallocWCHAR name(nameLength);
michael@0 1668 HRVM(names->GetString(nameIndex, name.get(), nameLength), "Could not get string.");
michael@0 1669
michael@0 1670 HRV(wchar_to_skstring(name.get(), skname));
michael@0 1671 }
michael@0 1672
michael@0 1673 SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont(
michael@0 1674 IDWriteFontFace* fontFace,
michael@0 1675 IDWriteFont* font,
michael@0 1676 IDWriteFontFamily* fontFamily,
michael@0 1677 StreamFontFileLoader* fontFileLoader,
michael@0 1678 IDWriteFontCollectionLoader* fontCollectionLoader) const {
michael@0 1679 SkTypeface* face = FindByProcAndRef(FindByDWriteFont, font);
michael@0 1680 if (NULL == face) {
michael@0 1681 face = DWriteFontTypeface::Create(fontFace, font, fontFamily,
michael@0 1682 fontFileLoader, fontCollectionLoader);
michael@0 1683 if (face) {
michael@0 1684 Add(face, get_style(font), fontCollectionLoader != NULL);
michael@0 1685 }
michael@0 1686 }
michael@0 1687 return face;
michael@0 1688 }
michael@0 1689
michael@0 1690 int SkFontMgr_DirectWrite::onCountFamilies() const {
michael@0 1691 return fFontCollection->GetFontFamilyCount();
michael@0 1692 }
michael@0 1693
michael@0 1694 void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
michael@0 1695 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
michael@0 1696 HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
michael@0 1697
michael@0 1698 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
michael@0 1699 HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
michael@0 1700
michael@0 1701 get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
michael@0 1702 }
michael@0 1703
michael@0 1704 SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
michael@0 1705 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
michael@0 1706 HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
michael@0 1707
michael@0 1708 return SkNEW_ARGS(SkFontStyleSet_DirectWrite, (this, fontFamily.get()));
michael@0 1709 }
michael@0 1710
michael@0 1711 SkFontStyleSet* SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
michael@0 1712 SkSMallocWCHAR dwFamilyName;
michael@0 1713 HRN(cstring_to_wchar(familyName, &dwFamilyName));
michael@0 1714
michael@0 1715 UINT32 index;
michael@0 1716 BOOL exists;
michael@0 1717 HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
michael@0 1718 "Failed while finding family by name.");
michael@0 1719 if (!exists) {
michael@0 1720 return NULL;
michael@0 1721 }
michael@0 1722
michael@0 1723 return this->onCreateStyleSet(index);
michael@0 1724 }
michael@0 1725
michael@0 1726 SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
michael@0 1727 const SkFontStyle& fontstyle) const {
michael@0 1728 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
michael@0 1729 return sset->matchStyle(fontstyle);
michael@0 1730 }
michael@0 1731
michael@0 1732 SkTypeface* SkFontMgr_DirectWrite::onMatchFaceStyle(const SkTypeface* familyMember,
michael@0 1733 const SkFontStyle& fontstyle) const {
michael@0 1734 SkString familyName;
michael@0 1735 SkFontStyleSet_DirectWrite sset(
michael@0 1736 this, ((DWriteFontTypeface*)familyMember)->fDWriteFontFamily.get()
michael@0 1737 );
michael@0 1738 return sset.matchStyle(fontstyle);
michael@0 1739 }
michael@0 1740
michael@0 1741 SkTypeface* SkFontMgr_DirectWrite::onCreateFromStream(SkStream* stream, int ttcIndex) const {
michael@0 1742 return create_from_stream(stream, ttcIndex);
michael@0 1743 }
michael@0 1744
michael@0 1745 SkTypeface* SkFontMgr_DirectWrite::onCreateFromData(SkData* data, int ttcIndex) const {
michael@0 1746 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
michael@0 1747 return this->createFromStream(stream, ttcIndex);
michael@0 1748 }
michael@0 1749
michael@0 1750 SkTypeface* SkFontMgr_DirectWrite::onCreateFromFile(const char path[], int ttcIndex) const {
michael@0 1751 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
michael@0 1752 return this->createFromStream(stream, ttcIndex);
michael@0 1753 }
michael@0 1754
michael@0 1755 HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
michael@0 1756 IDWriteFontFamily** fontFamily) const {
michael@0 1757 UINT32 index;
michael@0 1758 BOOL exists;
michael@0 1759 HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
michael@0 1760
michael@0 1761 if (exists) {
michael@0 1762 HR(fFontCollection->GetFontFamily(index, fontFamily));
michael@0 1763 return S_OK;
michael@0 1764 }
michael@0 1765 return S_FALSE;
michael@0 1766 }
michael@0 1767
michael@0 1768 HRESULT SkFontMgr_DirectWrite::getDefaultFontFamily(IDWriteFontFamily** fontFamily) const {
michael@0 1769 NONCLIENTMETRICSW metrics;
michael@0 1770 metrics.cbSize = sizeof(metrics);
michael@0 1771 if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
michael@0 1772 sizeof(metrics),
michael@0 1773 &metrics,
michael@0 1774 0)) {
michael@0 1775 return E_UNEXPECTED;
michael@0 1776 }
michael@0 1777 HRM(this->getByFamilyName(metrics.lfMessageFont.lfFaceName, fontFamily),
michael@0 1778 "Could not create DWrite font family from LOGFONT.");
michael@0 1779
michael@0 1780 return S_OK;
michael@0 1781 }
michael@0 1782
michael@0 1783 SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[],
michael@0 1784 unsigned styleBits) const {
michael@0 1785 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
michael@0 1786 if (familyName) {
michael@0 1787 SkSMallocWCHAR wideFamilyName;
michael@0 1788 if (SUCCEEDED(cstring_to_wchar(familyName, &wideFamilyName))) {
michael@0 1789 this->getByFamilyName(wideFamilyName, &fontFamily);
michael@0 1790 }
michael@0 1791 }
michael@0 1792
michael@0 1793 if (NULL == fontFamily.get()) {
michael@0 1794 // No family with given name, try default.
michael@0 1795 HRNM(this->getDefaultFontFamily(&fontFamily), "Could not get default font family.");
michael@0 1796 }
michael@0 1797
michael@0 1798 SkTScopedComPtr<IDWriteFont> font;
michael@0 1799 DWRITE_FONT_WEIGHT weight = (styleBits & SkTypeface::kBold)
michael@0 1800 ? DWRITE_FONT_WEIGHT_BOLD
michael@0 1801 : DWRITE_FONT_WEIGHT_NORMAL;
michael@0 1802 DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL;
michael@0 1803 DWRITE_FONT_STYLE italic = (styleBits & SkTypeface::kItalic)
michael@0 1804 ? DWRITE_FONT_STYLE_ITALIC
michael@0 1805 : DWRITE_FONT_STYLE_NORMAL;
michael@0 1806 HRNM(fontFamily->GetFirstMatchingFont(weight, stretch, italic, &font),
michael@0 1807 "Could not get matching font.");
michael@0 1808
michael@0 1809 SkTScopedComPtr<IDWriteFontFace> fontFace;
michael@0 1810 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
michael@0 1811
michael@0 1812 return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
michael@0 1813 }
michael@0 1814
michael@0 1815 ///////////////////////////////////////////////////////////////////////////////
michael@0 1816
michael@0 1817 int SkFontStyleSet_DirectWrite::count() {
michael@0 1818 return fFontFamily->GetFontCount();
michael@0 1819 }
michael@0 1820
michael@0 1821 SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) {
michael@0 1822 SkTScopedComPtr<IDWriteFont> font;
michael@0 1823 HRNM(fFontFamily->GetFont(index, &font), "Could not get font.");
michael@0 1824
michael@0 1825 SkTScopedComPtr<IDWriteFontFace> fontFace;
michael@0 1826 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
michael@0 1827
michael@0 1828 return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
michael@0 1829 }
michael@0 1830
michael@0 1831 void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
michael@0 1832 SkTScopedComPtr<IDWriteFont> font;
michael@0 1833 HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
michael@0 1834
michael@0 1835 SkFontStyle::Slant slant;
michael@0 1836 switch (font->GetStyle()) {
michael@0 1837 case DWRITE_FONT_STYLE_NORMAL:
michael@0 1838 slant = SkFontStyle::kUpright_Slant;
michael@0 1839 break;
michael@0 1840 case DWRITE_FONT_STYLE_OBLIQUE:
michael@0 1841 case DWRITE_FONT_STYLE_ITALIC:
michael@0 1842 slant = SkFontStyle::kItalic_Slant;
michael@0 1843 break;
michael@0 1844 default:
michael@0 1845 SkASSERT(false);
michael@0 1846 }
michael@0 1847
michael@0 1848 int weight = font->GetWeight();
michael@0 1849 int width = font->GetStretch();
michael@0 1850
michael@0 1851 *fs = SkFontStyle(weight, width, slant);
michael@0 1852
michael@0 1853 SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
michael@0 1854 if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
michael@0 1855 get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
michael@0 1856 }
michael@0 1857 }
michael@0 1858
michael@0 1859 SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
michael@0 1860 DWRITE_FONT_STYLE slant;
michael@0 1861 switch (pattern.slant()) {
michael@0 1862 case SkFontStyle::kUpright_Slant:
michael@0 1863 slant = DWRITE_FONT_STYLE_NORMAL;
michael@0 1864 break;
michael@0 1865 case SkFontStyle::kItalic_Slant:
michael@0 1866 slant = DWRITE_FONT_STYLE_ITALIC;
michael@0 1867 break;
michael@0 1868 default:
michael@0 1869 SkASSERT(false);
michael@0 1870 }
michael@0 1871
michael@0 1872 DWRITE_FONT_WEIGHT weight = (DWRITE_FONT_WEIGHT)pattern.weight();
michael@0 1873 DWRITE_FONT_STRETCH width = (DWRITE_FONT_STRETCH)pattern.width();
michael@0 1874
michael@0 1875 SkTScopedComPtr<IDWriteFont> font;
michael@0 1876 // TODO: perhaps use GetMatchingFonts and get the least simulated?
michael@0 1877 HRNM(fFontFamily->GetFirstMatchingFont(weight, width, slant, &font),
michael@0 1878 "Could not match font in family.");
michael@0 1879
michael@0 1880 SkTScopedComPtr<IDWriteFontFace> fontFace;
michael@0 1881 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
michael@0 1882
michael@0 1883 return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(),
michael@0 1884 fFontFamily.get());
michael@0 1885 }
michael@0 1886
michael@0 1887 ///////////////////////////////////////////////////////////////////////////////
michael@0 1888
michael@0 1889 typedef decltype(GetUserDefaultLocaleName)* GetUserDefaultLocaleNameProc;
michael@0 1890 static HRESULT GetGetUserDefaultLocaleNameProc(GetUserDefaultLocaleNameProc* proc) {
michael@0 1891 *proc = reinterpret_cast<GetUserDefaultLocaleNameProc>(
michael@0 1892 GetProcAddress(LoadLibraryW(L"Kernel32.dll"), "GetUserDefaultLocaleName")
michael@0 1893 );
michael@0 1894 if (!*proc) {
michael@0 1895 HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
michael@0 1896 if (!IS_ERROR(hr)) {
michael@0 1897 hr = ERROR_PROC_NOT_FOUND;
michael@0 1898 }
michael@0 1899 return hr;
michael@0 1900 }
michael@0 1901 return S_OK;
michael@0 1902 }
michael@0 1903
michael@0 1904 SkFontMgr* SkFontMgr_New_DirectWrite() {
michael@0 1905 IDWriteFactory* factory = get_dwrite_factory();
michael@0 1906 if (NULL == factory) {
michael@0 1907 return NULL;
michael@0 1908 }
michael@0 1909
michael@0 1910 SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
michael@0 1911 HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
michael@0 1912 "Could not get system font collection.");
michael@0 1913
michael@0 1914 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
michael@0 1915 WCHAR* localeName = NULL;
michael@0 1916 int localeNameLen = 0;
michael@0 1917
michael@0 1918 // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
michael@0 1919 GetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL;
michael@0 1920 HRESULT hr = GetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
michael@0 1921 if (NULL == getUserDefaultLocaleNameProc) {
michael@0 1922 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
michael@0 1923 } else {
michael@0 1924 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
michael@0 1925 if (localeNameLen) {
michael@0 1926 localeName = localeNameStorage;
michael@0 1927 };
michael@0 1928 }
michael@0 1929
michael@0 1930 return SkNEW_ARGS(SkFontMgr_DirectWrite, (sysFontCollection.get(), localeName, localeNameLen));
michael@0 1931 }

mercurial