SkRemotableFontMgr_win_dw.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. * Copyright 2014 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/utils/win/SkDWriteNTDDI_VERSION.h"
  8. #include "include/core/SkTypes.h"
  9. #if defined(SK_BUILD_FOR_WIN)
  10. #include "include/core/SkStream.h"
  11. #include "include/core/SkString.h"
  12. #include "include/core/SkTypes.h"
  13. #include "include/ports/SkRemotableFontMgr.h"
  14. #include "include/private/SkMutex.h"
  15. #include "include/private/SkTArray.h"
  16. #include "src/ports/SkTypeface_win_dw.h"
  17. #include "src/utils/SkUTF.h"
  18. #include "src/utils/win/SkDWrite.h"
  19. #include "src/utils/win/SkDWriteFontFileStream.h"
  20. #include "src/utils/win/SkHRESULT.h"
  21. #include "src/utils/win/SkTScopedComPtr.h"
  22. #include <dwrite.h>
  23. class SK_API SkRemotableFontMgr_DirectWrite : public SkRemotableFontMgr {
  24. private:
  25. struct DataId {
  26. IUnknown* fLoader; // In COM only IUnknown pointers may be safely used for identity.
  27. void* fKey;
  28. UINT32 fKeySize;
  29. DataId() { }
  30. DataId(DataId&& that) : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize) {
  31. that.fLoader = nullptr;
  32. that.fKey = nullptr;
  33. SkDEBUGCODE(that.fKeySize = 0xFFFFFFFF;)
  34. }
  35. ~DataId() {
  36. if (fLoader) {
  37. fLoader->Release();
  38. }
  39. sk_free(fKey);
  40. }
  41. };
  42. mutable SkTArray<DataId> fDataIdCache;
  43. mutable SkMutex fDataIdCacheMutex;
  44. int FindOrAdd(IDWriteFontFileLoader* fontFileLoader,
  45. const void* refKey, UINT32 refKeySize) const
  46. {
  47. SkTScopedComPtr<IUnknown> fontFileLoaderId;
  48. HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId),
  49. "Failed to re-convert to IDWriteFontFileLoader.",
  50. SkFontIdentity::kInvalidDataId);
  51. SkAutoMutexExclusive ama(fDataIdCacheMutex);
  52. int count = fDataIdCache.count();
  53. int i;
  54. for (i = 0; i < count; ++i) {
  55. const DataId& current = fDataIdCache[i];
  56. if (fontFileLoaderId.get() == current.fLoader &&
  57. refKeySize == current.fKeySize &&
  58. 0 == memcmp(refKey, current.fKey, refKeySize))
  59. {
  60. return i;
  61. }
  62. }
  63. DataId& added = fDataIdCache.push_back();
  64. added.fLoader = fontFileLoaderId.release(); // Ref is passed.
  65. added.fKey = sk_malloc_throw(refKeySize);
  66. memcpy(added.fKey, refKey, refKeySize);
  67. added.fKeySize = refKeySize;
  68. return i;
  69. }
  70. public:
  71. /** localeNameLength must include the null terminator. */
  72. SkRemotableFontMgr_DirectWrite(IDWriteFontCollection* fontCollection,
  73. WCHAR* localeName, int localeNameLength)
  74. : fFontCollection(SkRefComPtr(fontCollection))
  75. , fLocaleName(localeNameLength)
  76. {
  77. memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
  78. }
  79. HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const {
  80. SkTScopedComPtr<IDWriteFontFace> fontFace;
  81. HRM(font->CreateFontFace(&fontFace), "Could not create font face.");
  82. UINT32 numFiles;
  83. HR(fontFace->GetFiles(&numFiles, nullptr));
  84. if (numFiles > 1) {
  85. return E_FAIL;
  86. }
  87. // data id
  88. SkTScopedComPtr<IDWriteFontFile> fontFile;
  89. HR(fontFace->GetFiles(&numFiles, &fontFile));
  90. SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
  91. HR(fontFile->GetLoader(&fontFileLoader));
  92. const void* refKey;
  93. UINT32 refKeySize;
  94. HR(fontFile->GetReferenceKey(&refKey, &refKeySize));
  95. fontId->fDataId = FindOrAdd(fontFileLoader.get(), refKey, refKeySize);
  96. // index
  97. fontId->fTtcIndex = fontFace->GetIndex();
  98. // style
  99. fontId->fFontStyle = get_style(font);
  100. return S_OK;
  101. }
  102. SkRemotableFontIdentitySet* getIndex(int familyIndex) const override {
  103. SkTScopedComPtr<IDWriteFontFamily> fontFamily;
  104. HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
  105. "Could not get requested family.");
  106. int count = fontFamily->GetFontCount();
  107. SkFontIdentity* fontIds;
  108. sk_sp<SkRemotableFontIdentitySet> fontIdSet(
  109. new SkRemotableFontIdentitySet(count, &fontIds));
  110. for (int fontIndex = 0; fontIndex < count; ++fontIndex) {
  111. SkTScopedComPtr<IDWriteFont> font;
  112. HRNM(fontFamily->GetFont(fontIndex, &font), "Could not get font.");
  113. HRN(FontToIdentity(font.get(), &fontIds[fontIndex]));
  114. }
  115. return fontIdSet.release();
  116. }
  117. virtual SkFontIdentity matchIndexStyle(int familyIndex,
  118. const SkFontStyle& pattern) const override
  119. {
  120. SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
  121. SkTScopedComPtr<IDWriteFontFamily> fontFamily;
  122. HR_GENERAL(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
  123. "Could not get requested family.",
  124. identity);
  125. const DWriteStyle dwStyle(pattern);
  126. SkTScopedComPtr<IDWriteFont> font;
  127. HR_GENERAL(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth,
  128. dwStyle.fSlant, &font),
  129. "Could not match font in family.",
  130. identity);
  131. HR_GENERAL(FontToIdentity(font.get(), &identity), nullptr, identity);
  132. return identity;
  133. }
  134. static HRESULT getDefaultFontFamilyName(SkSMallocWCHAR* name) {
  135. NONCLIENTMETRICSW metrics;
  136. metrics.cbSize = sizeof(metrics);
  137. if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
  138. sizeof(metrics),
  139. &metrics,
  140. 0)) {
  141. return E_UNEXPECTED;
  142. }
  143. size_t len = wcsnlen_s(metrics.lfMessageFont.lfFaceName, LF_FACESIZE) + 1;
  144. if (0 != wcsncpy_s(name->reset(len), len, metrics.lfMessageFont.lfFaceName, _TRUNCATE)) {
  145. return E_UNEXPECTED;
  146. }
  147. return S_OK;
  148. }
  149. SkRemotableFontIdentitySet* matchName(const char familyName[]) const override {
  150. SkSMallocWCHAR dwFamilyName;
  151. if (nullptr == familyName) {
  152. HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName),
  153. nullptr, SkRemotableFontIdentitySet::NewEmpty());
  154. } else {
  155. HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName),
  156. nullptr, SkRemotableFontIdentitySet::NewEmpty());
  157. }
  158. UINT32 index;
  159. BOOL exists;
  160. HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
  161. "Failed while finding family by name.",
  162. SkRemotableFontIdentitySet::NewEmpty());
  163. if (!exists) {
  164. return SkRemotableFontIdentitySet::NewEmpty();
  165. }
  166. return this->getIndex(index);
  167. }
  168. virtual SkFontIdentity matchNameStyle(const char familyName[],
  169. const SkFontStyle& style) const override
  170. {
  171. SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
  172. SkSMallocWCHAR dwFamilyName;
  173. if (nullptr == familyName) {
  174. HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), nullptr, identity);
  175. } else {
  176. HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), nullptr, identity);
  177. }
  178. UINT32 index;
  179. BOOL exists;
  180. HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
  181. "Failed while finding family by name.",
  182. identity);
  183. if (!exists) {
  184. return identity;
  185. }
  186. return this->matchIndexStyle(index, style);
  187. }
  188. class FontFallbackRenderer : public IDWriteTextRenderer {
  189. public:
  190. FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite* outer, UINT32 character)
  191. : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character) {
  192. fIdentity.fDataId = SkFontIdentity::kInvalidDataId;
  193. }
  194. virtual ~FontFallbackRenderer() { }
  195. // IDWriteTextRenderer methods
  196. virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(
  197. void* clientDrawingContext,
  198. FLOAT baselineOriginX,
  199. FLOAT baselineOriginY,
  200. DWRITE_MEASURING_MODE measuringMode,
  201. DWRITE_GLYPH_RUN const* glyphRun,
  202. DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
  203. IUnknown* clientDrawingEffect) override
  204. {
  205. SkTScopedComPtr<IDWriteFont> font;
  206. HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
  207. "Could not get font from font face.");
  208. // It is possible that the font passed does not actually have the requested character,
  209. // due to no font being found and getting the fallback font.
  210. // Check that the font actually contains the requested character.
  211. BOOL exists;
  212. HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
  213. if (exists) {
  214. HR(fOuter->FontToIdentity(font.get(), &fIdentity));
  215. }
  216. return S_OK;
  217. }
  218. virtual HRESULT STDMETHODCALLTYPE DrawUnderline(
  219. void* clientDrawingContext,
  220. FLOAT baselineOriginX,
  221. FLOAT baselineOriginY,
  222. DWRITE_UNDERLINE const* underline,
  223. IUnknown* clientDrawingEffect) override
  224. { return E_NOTIMPL; }
  225. virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(
  226. void* clientDrawingContext,
  227. FLOAT baselineOriginX,
  228. FLOAT baselineOriginY,
  229. DWRITE_STRIKETHROUGH const* strikethrough,
  230. IUnknown* clientDrawingEffect) override
  231. { return E_NOTIMPL; }
  232. virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(
  233. void* clientDrawingContext,
  234. FLOAT originX,
  235. FLOAT originY,
  236. IDWriteInlineObject* inlineObject,
  237. BOOL isSideways,
  238. BOOL isRightToLeft,
  239. IUnknown* clientDrawingEffect) override
  240. { return E_NOTIMPL; }
  241. // IDWritePixelSnapping methods
  242. virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(
  243. void* clientDrawingContext,
  244. BOOL* isDisabled) override
  245. {
  246. *isDisabled = FALSE;
  247. return S_OK;
  248. }
  249. virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(
  250. void* clientDrawingContext,
  251. DWRITE_MATRIX* transform) override
  252. {
  253. const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
  254. *transform = ident;
  255. return S_OK;
  256. }
  257. virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(
  258. void* clientDrawingContext,
  259. FLOAT* pixelsPerDip) override
  260. {
  261. *pixelsPerDip = 1.0f;
  262. return S_OK;
  263. }
  264. // IUnknown methods
  265. ULONG STDMETHODCALLTYPE AddRef() override {
  266. return InterlockedIncrement(&fRefCount);
  267. }
  268. ULONG STDMETHODCALLTYPE Release() override {
  269. ULONG newCount = InterlockedDecrement(&fRefCount);
  270. if (0 == newCount) {
  271. delete this;
  272. }
  273. return newCount;
  274. }
  275. virtual HRESULT STDMETHODCALLTYPE QueryInterface(
  276. IID const& riid, void** ppvObject) override
  277. {
  278. if (__uuidof(IUnknown) == riid ||
  279. __uuidof(IDWritePixelSnapping) == riid ||
  280. __uuidof(IDWriteTextRenderer) == riid)
  281. {
  282. *ppvObject = this;
  283. this->AddRef();
  284. return S_OK;
  285. }
  286. *ppvObject = nullptr;
  287. return E_FAIL;
  288. }
  289. const SkFontIdentity FallbackIdentity() { return fIdentity; }
  290. protected:
  291. ULONG fRefCount;
  292. sk_sp<const SkRemotableFontMgr_DirectWrite> fOuter;
  293. UINT32 fCharacter;
  294. SkFontIdentity fIdentity;
  295. };
  296. virtual SkFontIdentity matchNameStyleCharacter(const char familyName[],
  297. const SkFontStyle& pattern,
  298. const char* bcp47[], int bcp47Count,
  299. SkUnichar character) const override
  300. {
  301. SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
  302. IDWriteFactory* dwFactory = sk_get_dwrite_factory();
  303. if (nullptr == dwFactory) {
  304. return identity;
  305. }
  306. // TODO: use IDWriteFactory2::GetSystemFontFallback when available.
  307. const DWriteStyle dwStyle(pattern);
  308. SkSMallocWCHAR dwFamilyName;
  309. if (nullptr == familyName) {
  310. HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), nullptr, identity);
  311. } else {
  312. HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), nullptr, identity);
  313. }
  314. const SkSMallocWCHAR* dwBcp47;
  315. SkSMallocWCHAR dwBcp47Local;
  316. if (bcp47Count < 1) {
  317. dwBcp47 = &fLocaleName;
  318. } else {
  319. //TODO: support fallback stack.
  320. HR_GENERAL(sk_cstring_to_wchar(bcp47[bcp47Count-1], &dwBcp47Local), nullptr, identity);
  321. dwBcp47 = &dwBcp47Local;
  322. }
  323. SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
  324. HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName,
  325. fFontCollection.get(),
  326. dwStyle.fWeight,
  327. dwStyle.fSlant,
  328. dwStyle.fWidth,
  329. 72.0f,
  330. *dwBcp47,
  331. &fallbackFormat),
  332. "Could not create text format.",
  333. identity);
  334. WCHAR str[16];
  335. UINT32 strLen = static_cast<UINT32>(
  336. SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str)));
  337. SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
  338. HR_GENERAL(dwFactory->CreateTextLayout(str, strLen, fallbackFormat.get(),
  339. 200.0f, 200.0f,
  340. &fallbackLayout),
  341. "Could not create text layout.",
  342. identity);
  343. SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
  344. new FontFallbackRenderer(this, character));
  345. HR_GENERAL(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f),
  346. "Could not draw layout with renderer.",
  347. identity);
  348. return fontFallbackRenderer->FallbackIdentity();
  349. }
  350. SkStreamAsset* getData(int dataId) const override {
  351. SkAutoMutexExclusive ama(fDataIdCacheMutex);
  352. if (dataId >= fDataIdCache.count()) {
  353. return nullptr;
  354. }
  355. const DataId& id = fDataIdCache[dataId];
  356. SkTScopedComPtr<IDWriteFontFileLoader> loader;
  357. HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFileLoader failed");
  358. SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
  359. HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream),
  360. "Could not create font file stream.");
  361. return new SkDWriteFontFileStream(fontFileStream.get());
  362. }
  363. private:
  364. SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
  365. SkSMallocWCHAR fLocaleName;
  366. typedef SkRemotableFontMgr INHERITED;
  367. };
  368. SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() {
  369. IDWriteFactory* factory = sk_get_dwrite_factory();
  370. if (nullptr == factory) {
  371. return nullptr;
  372. }
  373. SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
  374. HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
  375. "Could not get system font collection.");
  376. WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
  377. WCHAR* localeName = nullptr;
  378. int localeNameLen = 0;
  379. // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
  380. SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr;
  381. HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
  382. if (nullptr == getUserDefaultLocaleNameProc) {
  383. SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
  384. } else {
  385. localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
  386. if (localeNameLen) {
  387. localeName = localeNameStorage;
  388. };
  389. }
  390. return new SkRemotableFontMgr_DirectWrite(sysFontCollection.get(), localeName, localeNameLen);
  391. }
  392. #endif//defined(SK_BUILD_FOR_WIN)