Sat, 03 Jan 2015 20:18:00 +0100
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 | } |