gfxGDIFontList.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/DebugOnly.h"
  6. #include <algorithm>
  7. #include "mozilla/Logging.h"
  8. #include "mozilla/Sprintf.h"
  9. #include "gfxGDIFontList.h"
  10. #include "gfxWindowsPlatform.h"
  11. #include "gfxUserFontSet.h"
  12. #include "gfxFontUtils.h"
  13. #include "gfxGDIFont.h"
  14. #include "nsServiceManagerUtils.h"
  15. #include "nsTArray.h"
  16. #include "nsUnicharUtils.h"
  17. #include "nsDirectoryServiceUtils.h"
  18. #include "nsDirectoryServiceDefs.h"
  19. #include "nsAppDirectoryServiceDefs.h"
  20. #include "nsISimpleEnumerator.h"
  21. #include "nsIWindowsRegKey.h"
  22. #include "gfxFontConstants.h"
  23. #include "GeckoProfiler.h"
  24. #include "mozilla/MemoryReporting.h"
  25. #include "mozilla/Telemetry.h"
  26. #include "mozilla/WindowsVersion.h"
  27. #include <usp10.h>
  28. using namespace mozilla;
  29. #define ROUND(x) floor((x) + 0.5)
  30. #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
  31. LogLevel::Debug, args)
  32. #define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
  33. gfxPlatform::GetLog(eGfxLog_fontlist), \
  34. LogLevel::Debug)
  35. #define LOG_CMAPDATA_ENABLED() MOZ_LOG_TEST( \
  36. gfxPlatform::GetLog(eGfxLog_cmapdata), \
  37. LogLevel::Debug)
  38. static __inline void
  39. BuildKeyNameFromFontName(nsAString &aName)
  40. {
  41. if (aName.Length() >= LF_FACESIZE)
  42. aName.Truncate(LF_FACESIZE - 1);
  43. ToLowerCase(aName);
  44. }
  45. // Implementation of gfxPlatformFontList for Win32 GDI,
  46. // using GDI font enumeration APIs to get the list of fonts
  47. class WinUserFontData : public gfxUserFontData {
  48. public:
  49. WinUserFontData(HANDLE aFontRef)
  50. : mFontRef(aFontRef)
  51. { }
  52. virtual ~WinUserFontData()
  53. {
  54. DebugOnly<BOOL> success;
  55. success = RemoveFontMemResourceEx(mFontRef);
  56. #if DEBUG
  57. if (!success) {
  58. char buf[256];
  59. SprintfLiteral(buf, "error deleting font handle (%p) - RemoveFontMemResourceEx failed", mFontRef);
  60. NS_ASSERTION(success, buf);
  61. }
  62. #endif
  63. }
  64. HANDLE mFontRef;
  65. };
  66. BYTE
  67. FontTypeToOutPrecision(uint8_t fontType)
  68. {
  69. BYTE ret;
  70. switch (fontType) {
  71. case GFX_FONT_TYPE_TT_OPENTYPE:
  72. case GFX_FONT_TYPE_TRUETYPE:
  73. ret = OUT_TT_ONLY_PRECIS;
  74. break;
  75. case GFX_FONT_TYPE_PS_OPENTYPE:
  76. ret = OUT_PS_ONLY_PRECIS;
  77. break;
  78. case GFX_FONT_TYPE_TYPE1:
  79. ret = OUT_OUTLINE_PRECIS;
  80. break;
  81. case GFX_FONT_TYPE_RASTER:
  82. ret = OUT_RASTER_PRECIS;
  83. break;
  84. case GFX_FONT_TYPE_DEVICE:
  85. ret = OUT_DEVICE_PRECIS;
  86. break;
  87. default:
  88. ret = OUT_DEFAULT_PRECIS;
  89. }
  90. return ret;
  91. }
  92. /***************************************************************
  93. *
  94. * GDIFontEntry
  95. *
  96. */
  97. GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
  98. gfxWindowsFontType aFontType,
  99. uint8_t aStyle, uint16_t aWeight,
  100. int16_t aStretch,
  101. gfxUserFontData *aUserFontData,
  102. bool aFamilyHasItalicFace)
  103. : gfxFontEntry(aFaceName),
  104. mWindowsFamily(0), mWindowsPitch(0),
  105. mFontType(aFontType),
  106. mForceGDI(false),
  107. mFamilyHasItalicFace(aFamilyHasItalicFace),
  108. mCharset(), mUnicodeRanges()
  109. {
  110. mUserFontData.reset(aUserFontData);
  111. mStyle = aStyle;
  112. mWeight = aWeight;
  113. mStretch = aStretch;
  114. if (IsType1())
  115. mForceGDI = true;
  116. mIsDataUserFont = aUserFontData != nullptr;
  117. InitLogFont(aFaceName, aFontType);
  118. }
  119. nsresult
  120. GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
  121. {
  122. PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
  123. // attempt this once, if errors occur leave a blank cmap
  124. if (mCharacterMap) {
  125. return NS_OK;
  126. }
  127. // skip non-SFNT fonts completely
  128. if (mFontType != GFX_FONT_TYPE_PS_OPENTYPE &&
  129. mFontType != GFX_FONT_TYPE_TT_OPENTYPE &&
  130. mFontType != GFX_FONT_TYPE_TRUETYPE)
  131. {
  132. mCharacterMap = new gfxCharacterMap();
  133. mCharacterMap->mBuildOnTheFly = true;
  134. return NS_ERROR_FAILURE;
  135. }
  136. RefPtr<gfxCharacterMap> charmap;
  137. nsresult rv;
  138. bool unicodeFont = false, symbolFont = false;
  139. if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
  140. mUVSOffset,
  141. symbolFont))) {
  142. mSymbolFont = symbolFont;
  143. rv = NS_OK;
  144. } else {
  145. uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
  146. charmap = new gfxCharacterMap();
  147. AutoTArray<uint8_t, 16384> cmap;
  148. rv = CopyFontTable(kCMAP, cmap);
  149. if (NS_SUCCEEDED(rv)) {
  150. rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
  151. *charmap, mUVSOffset,
  152. unicodeFont, symbolFont);
  153. }
  154. mSymbolFont = symbolFont;
  155. }
  156. mHasCmapTable = NS_SUCCEEDED(rv);
  157. if (mHasCmapTable) {
  158. gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
  159. mCharacterMap = pfl->FindCharMap(charmap);
  160. } else {
  161. // if error occurred, initialize to null cmap
  162. mCharacterMap = new gfxCharacterMap();
  163. // For fonts where we failed to read the character map,
  164. // we can take a slow path to look up glyphs character by character
  165. mCharacterMap->mBuildOnTheFly = true;
  166. }
  167. LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
  168. NS_ConvertUTF16toUTF8(mName).get(),
  169. charmap->SizeOfIncludingThis(moz_malloc_size_of),
  170. charmap->mHash, mCharacterMap == charmap ? " new" : ""));
  171. if (LOG_CMAPDATA_ENABLED()) {
  172. char prefix[256];
  173. SprintfLiteral(prefix, "(cmapdata) name: %.220s",
  174. NS_ConvertUTF16toUTF8(mName).get());
  175. charmap->Dump(prefix, eGfxLog_cmapdata);
  176. }
  177. return rv;
  178. }
  179. bool
  180. GDIFontEntry::IsSymbolFont()
  181. {
  182. // initialize cmap first
  183. HasCmapTable();
  184. return mSymbolFont;
  185. }
  186. gfxFont *
  187. GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold)
  188. {
  189. return new gfxGDIFont(this, aFontStyle, aNeedsBold);
  190. }
  191. nsresult
  192. GDIFontEntry::CopyFontTable(uint32_t aTableTag, nsTArray<uint8_t>& aBuffer)
  193. {
  194. if (!IsTrueType()) {
  195. return NS_ERROR_FAILURE;
  196. }
  197. AutoDC dc;
  198. AutoSelectFont font(dc.GetDC(), &mLogFont);
  199. if (font.IsValid()) {
  200. uint32_t tableSize =
  201. ::GetFontData(dc.GetDC(),
  202. NativeEndian::swapToBigEndian(aTableTag),
  203. 0, nullptr, 0);
  204. if (tableSize != GDI_ERROR) {
  205. if (aBuffer.SetLength(tableSize, fallible)) {
  206. ::GetFontData(dc.GetDC(),
  207. NativeEndian::swapToBigEndian(aTableTag), 0,
  208. aBuffer.Elements(), tableSize);
  209. return NS_OK;
  210. }
  211. return NS_ERROR_OUT_OF_MEMORY;
  212. }
  213. }
  214. return NS_ERROR_FAILURE;
  215. }
  216. void
  217. GDIFontEntry::FillLogFont(LOGFONTW *aLogFont,
  218. uint16_t aWeight, gfxFloat aSize)
  219. {
  220. memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));
  221. aLogFont->lfHeight = (LONG)-ROUND(aSize);
  222. if (aLogFont->lfHeight == 0) {
  223. aLogFont->lfHeight = -1;
  224. }
  225. // If a non-zero weight is passed in, use this to override the original
  226. // weight in the entry's logfont. This is used to control synthetic bolding
  227. // for installed families with no bold face, and for downloaded fonts
  228. // (but NOT for local user fonts, because it could cause a different,
  229. // glyph-incompatible face to be used)
  230. if (aWeight) {
  231. aLogFont->lfWeight = aWeight;
  232. }
  233. // for non-local() user fonts, we never want to apply italics here;
  234. // if the face is described as italic, we should use it as-is,
  235. // and if it's not, but then the element is styled italic, we'll use
  236. // a cairo transform to create fake italic (oblique)
  237. if (mIsDataUserFont) {
  238. aLogFont->lfItalic = 0;
  239. }
  240. }
  241. #define MISSING_GLYPH 0x1F // glyph index returned for missing characters
  242. // on WinXP with .fon fonts, but not Type1 (.pfb)
  243. bool
  244. GDIFontEntry::TestCharacterMap(uint32_t aCh)
  245. {
  246. if (!mCharacterMap) {
  247. ReadCMAP();
  248. NS_ASSERTION(mCharacterMap, "failed to initialize a character map");
  249. }
  250. if (mCharacterMap->mBuildOnTheFly) {
  251. if (aCh > 0xFFFF)
  252. return false;
  253. // previous code was using the group style
  254. gfxFontStyle fakeStyle;
  255. if (!IsUpright()) {
  256. fakeStyle.style = NS_FONT_STYLE_ITALIC;
  257. }
  258. fakeStyle.weight = mWeight * 100;
  259. RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false);
  260. if (!tempFont || !tempFont->Valid())
  261. return false;
  262. gfxGDIFont *font = static_cast<gfxGDIFont*>(tempFont.get());
  263. HDC dc = GetDC((HWND)nullptr);
  264. SetGraphicsMode(dc, GM_ADVANCED);
  265. HFONT hfont = font->GetHFONT();
  266. HFONT oldFont = (HFONT)SelectObject(dc, hfont);
  267. wchar_t str[1] = { (wchar_t)aCh };
  268. WORD glyph[1];
  269. bool hasGlyph = false;
  270. // Bug 573038 - in some cases GetGlyphIndicesW returns 0xFFFF for a
  271. // missing glyph or 0x1F in other cases to indicate the "invalid"
  272. // glyph. Map both cases to "not found"
  273. if (IsType1() || mForceGDI) {
  274. // Type1 fonts and uniscribe APIs don't get along.
  275. // ScriptGetCMap will return E_HANDLE
  276. DWORD ret = GetGlyphIndicesW(dc, str, 1,
  277. glyph, GGI_MARK_NONEXISTING_GLYPHS);
  278. if (ret != GDI_ERROR
  279. && glyph[0] != 0xFFFF
  280. && (IsType1() || glyph[0] != MISSING_GLYPH))
  281. {
  282. hasGlyph = true;
  283. }
  284. } else {
  285. // ScriptGetCMap works better than GetGlyphIndicesW
  286. // for things like bitmap/vector fonts
  287. SCRIPT_CACHE sc = nullptr;
  288. HRESULT rv = ScriptGetCMap(dc, &sc, str, 1, 0, glyph);
  289. if (rv == S_OK)
  290. hasGlyph = true;
  291. }
  292. SelectObject(dc, oldFont);
  293. ReleaseDC(nullptr, dc);
  294. if (hasGlyph) {
  295. mCharacterMap->set(aCh);
  296. return true;
  297. }
  298. } else {
  299. // font had a cmap so simply check that
  300. return mCharacterMap->test(aCh);
  301. }
  302. return false;
  303. }
  304. void
  305. GDIFontEntry::InitLogFont(const nsAString& aName,
  306. gfxWindowsFontType aFontType)
  307. {
  308. #define CLIP_TURNOFF_FONTASSOCIATION 0x40
  309. mLogFont.lfHeight = -1;
  310. // Fill in logFont structure
  311. mLogFont.lfWidth = 0;
  312. mLogFont.lfEscapement = 0;
  313. mLogFont.lfOrientation = 0;
  314. mLogFont.lfUnderline = FALSE;
  315. mLogFont.lfStrikeOut = FALSE;
  316. mLogFont.lfCharSet = DEFAULT_CHARSET;
  317. mLogFont.lfOutPrecision = FontTypeToOutPrecision(aFontType);
  318. mLogFont.lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION;
  319. mLogFont.lfQuality = DEFAULT_QUALITY;
  320. mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  321. // always force lfItalic if we want it. Font selection code will
  322. // do its best to give us an italic font entry, but if no face exists
  323. // it may give us a regular one based on weight. Windows should
  324. // do fake italic for us in that case.
  325. mLogFont.lfItalic = !IsUpright();
  326. mLogFont.lfWeight = mWeight;
  327. int len = std::min<int>(aName.Length(), LF_FACESIZE - 1);
  328. memcpy(&mLogFont.lfFaceName, aName.BeginReading(), len * sizeof(char16_t));
  329. mLogFont.lfFaceName[len] = '\0';
  330. }
  331. GDIFontEntry*
  332. GDIFontEntry::CreateFontEntry(const nsAString& aName,
  333. gfxWindowsFontType aFontType,
  334. uint8_t aStyle,
  335. uint16_t aWeight, int16_t aStretch,
  336. gfxUserFontData* aUserFontData,
  337. bool aFamilyHasItalicFace)
  338. {
  339. // jtdfix - need to set charset, unicode ranges, pitch/family
  340. GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aStyle,
  341. aWeight, aStretch, aUserFontData,
  342. aFamilyHasItalicFace);
  343. return fe;
  344. }
  345. void
  346. GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
  347. FontListSizes* aSizes) const
  348. {
  349. aSizes->mFontListSize += aMallocSizeOf(this);
  350. AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  351. }
  352. /***************************************************************
  353. *
  354. * GDIFontFamily
  355. *
  356. */
  357. int CALLBACK
  358. GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
  359. const NEWTEXTMETRICEXW *nmetrics,
  360. DWORD fontType, LPARAM data)
  361. {
  362. const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
  363. LOGFONTW logFont = lpelfe->elfLogFont;
  364. GDIFontFamily *ff = reinterpret_cast<GDIFontFamily*>(data);
  365. // Some fonts claim to support things > 900, but we don't so clamp the sizes
  366. logFont.lfWeight = clamped(logFont.lfWeight, LONG(100), LONG(900));
  367. gfxWindowsFontType feType = GDIFontEntry::DetermineFontType(metrics, fontType);
  368. GDIFontEntry *fe = nullptr;
  369. for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
  370. fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
  371. if (feType > fe->mFontType) {
  372. // if the new type is better than the old one, remove the old entries
  373. ff->mAvailableFonts.RemoveElementAt(i);
  374. --i;
  375. } else if (feType < fe->mFontType) {
  376. // otherwise if the new type is worse, skip it
  377. return 1;
  378. }
  379. }
  380. for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
  381. fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
  382. // check if we already know about this face
  383. if (fe->mWeight == logFont.lfWeight &&
  384. fe->IsItalic() == (logFont.lfItalic == 0xFF)) {
  385. // update the charset bit here since this could be different
  386. fe->mCharset.set(metrics.tmCharSet);
  387. return 1;
  388. }
  389. }
  390. // We can't set the hasItalicFace flag correctly here,
  391. // because we might not have seen the family's italic face(s) yet.
  392. // So we'll set that flag for all members after loading all the faces.
  393. uint8_t italicStyle = (logFont.lfItalic == 0xFF ?
  394. NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL);
  395. fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName),
  396. feType, italicStyle,
  397. (uint16_t) (logFont.lfWeight), 0,
  398. nullptr, false);
  399. if (!fe)
  400. return 1;
  401. ff->AddFontEntry(fe);
  402. // mark the charset bit
  403. fe->mCharset.set(metrics.tmCharSet);
  404. fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
  405. fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
  406. if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
  407. nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
  408. nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 &&
  409. nmetrics->ntmFontSig.fsUsb[3] != 0x00000000) {
  410. // set the unicode ranges
  411. uint32_t x = 0;
  412. for (uint32_t i = 0; i < 4; ++i) {
  413. DWORD range = nmetrics->ntmFontSig.fsUsb[i];
  414. for (uint32_t k = 0; k < 32; ++k) {
  415. fe->mUnicodeRanges.set(x++, (range & (1 << k)) != 0);
  416. }
  417. }
  418. }
  419. if (LOG_FONTLIST_ENABLED()) {
  420. LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
  421. " with style: %s weight: %d stretch: %d",
  422. NS_ConvertUTF16toUTF8(fe->Name()).get(),
  423. NS_ConvertUTF16toUTF8(ff->Name()).get(),
  424. (logFont.lfItalic == 0xff) ? "italic" : "normal",
  425. logFont.lfWeight, fe->Stretch()));
  426. }
  427. return 1;
  428. }
  429. void
  430. GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
  431. {
  432. if (mHasStyles)
  433. return;
  434. mHasStyles = true;
  435. HDC hdc = GetDC(nullptr);
  436. SetGraphicsMode(hdc, GM_ADVANCED);
  437. LOGFONTW logFont;
  438. memset(&logFont, 0, sizeof(LOGFONTW));
  439. logFont.lfCharSet = DEFAULT_CHARSET;
  440. logFont.lfPitchAndFamily = 0;
  441. uint32_t l = std::min<uint32_t>(mName.Length(), LF_FACESIZE - 1);
  442. memcpy(logFont.lfFaceName, mName.get(), l * sizeof(char16_t));
  443. EnumFontFamiliesExW(hdc, &logFont,
  444. (FONTENUMPROCW)GDIFontFamily::FamilyAddStylesProc,
  445. (LPARAM)this, 0);
  446. if (LOG_FONTLIST_ENABLED() && mAvailableFonts.Length() == 0) {
  447. LOG_FONTLIST(("(fontlist) no styles available in family \"%s\"",
  448. NS_ConvertUTF16toUTF8(mName).get()));
  449. }
  450. ReleaseDC(nullptr, hdc);
  451. if (mIsBadUnderlineFamily) {
  452. SetBadUnderlineFonts();
  453. }
  454. // check for existence of italic face(s); if present, set the
  455. // FamilyHasItalic flag on all faces so that we'll know *not*
  456. // to use GDI's fake-italic effect with them
  457. size_t count = mAvailableFonts.Length();
  458. for (size_t i = 0; i < count; ++i) {
  459. if (mAvailableFonts[i]->IsItalic()) {
  460. for (uint32_t j = 0; j < count; ++j) {
  461. static_cast<GDIFontEntry*>(mAvailableFonts[j].get())->
  462. mFamilyHasItalicFace = true;
  463. }
  464. break;
  465. }
  466. }
  467. }
  468. /***************************************************************
  469. *
  470. * gfxGDIFontList
  471. *
  472. */
  473. gfxGDIFontList::gfxGDIFontList()
  474. : mFontSubstitutes(32)
  475. {
  476. #ifdef MOZ_BUNDLED_FONTS
  477. ActivateBundledFonts();
  478. #endif
  479. }
  480. static void
  481. RemoveCharsetFromFontSubstitute(nsAString &aName)
  482. {
  483. int32_t comma = aName.FindChar(char16_t(','));
  484. if (comma >= 0)
  485. aName.Truncate(comma);
  486. }
  487. #define MAX_VALUE_NAME 512
  488. #define MAX_VALUE_DATA 512
  489. nsresult
  490. gfxGDIFontList::GetFontSubstitutes()
  491. {
  492. HKEY hKey;
  493. DWORD i, rv, lenAlias, lenActual, valueType;
  494. WCHAR aliasName[MAX_VALUE_NAME];
  495. WCHAR actualName[MAX_VALUE_DATA];
  496. if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  497. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
  498. 0, KEY_READ, &hKey) != ERROR_SUCCESS)
  499. {
  500. return NS_ERROR_FAILURE;
  501. }
  502. for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
  503. aliasName[0] = 0;
  504. lenAlias = ArrayLength(aliasName);
  505. actualName[0] = 0;
  506. lenActual = sizeof(actualName);
  507. rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType,
  508. (LPBYTE)actualName, &lenActual);
  509. if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
  510. continue;
  511. }
  512. if (aliasName[0] == WCHAR('@')) {
  513. continue;
  514. }
  515. nsAutoString substituteName((char16_t*) aliasName);
  516. nsAutoString actualFontName((char16_t*) actualName);
  517. RemoveCharsetFromFontSubstitute(substituteName);
  518. BuildKeyNameFromFontName(substituteName);
  519. RemoveCharsetFromFontSubstitute(actualFontName);
  520. BuildKeyNameFromFontName(actualFontName);
  521. gfxFontFamily *ff;
  522. if (!actualFontName.IsEmpty() &&
  523. (ff = mFontFamilies.GetWeak(actualFontName))) {
  524. mFontSubstitutes.Put(substituteName, ff);
  525. } else {
  526. mNonExistingFonts.AppendElement(substituteName);
  527. }
  528. }
  529. // "Courier" on a default Windows install is an ugly bitmap font.
  530. // If there is no substitution for Courier in the registry
  531. // substitute "Courier" with "Courier New".
  532. nsAutoString substituteName;
  533. substituteName.AssignLiteral("Courier");
  534. BuildKeyNameFromFontName(substituteName);
  535. if (!mFontSubstitutes.GetWeak(substituteName)) {
  536. gfxFontFamily *ff;
  537. nsAutoString actualFontName;
  538. actualFontName.AssignLiteral("Courier New");
  539. BuildKeyNameFromFontName(actualFontName);
  540. ff = mFontFamilies.GetWeak(actualFontName);
  541. if (ff) {
  542. mFontSubstitutes.Put(substituteName, ff);
  543. }
  544. }
  545. return NS_OK;
  546. }
  547. nsresult
  548. gfxGDIFontList::InitFontListForPlatform()
  549. {
  550. mFontSubstitutes.Clear();
  551. mNonExistingFonts.Clear();
  552. // iterate over available families
  553. LOGFONTW logfont;
  554. memset(&logfont, 0, sizeof(logfont));
  555. logfont.lfCharSet = DEFAULT_CHARSET;
  556. AutoDC hdc;
  557. int result = EnumFontFamiliesExW(hdc.GetDC(), &logfont,
  558. (FONTENUMPROCW)&EnumFontFamExProc,
  559. 0, 0);
  560. GetFontSubstitutes();
  561. GetPrefsAndStartLoader();
  562. return NS_OK;
  563. }
  564. int CALLBACK
  565. gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
  566. NEWTEXTMETRICEXW *lpntme,
  567. DWORD fontType,
  568. LPARAM lParam)
  569. {
  570. const LOGFONTW& lf = lpelfe->elfLogFont;
  571. if (lf.lfFaceName[0] == '@') {
  572. return 1;
  573. }
  574. nsAutoString name(lf.lfFaceName);
  575. BuildKeyNameFromFontName(name);
  576. gfxGDIFontList *fontList = PlatformFontList();
  577. if (!fontList->mFontFamilies.GetWeak(name)) {
  578. nsDependentString faceName(lf.lfFaceName);
  579. RefPtr<gfxFontFamily> family = new GDIFontFamily(faceName);
  580. fontList->mFontFamilies.Put(name, family);
  581. // if locale is such that CJK font names are the default coming from
  582. // GDI, then if a family name is non-ASCII immediately read in other
  583. // family names. This assures that MS Gothic, MS Mincho are all found
  584. // before lookups begin.
  585. if (!IsASCII(faceName)) {
  586. family->ReadOtherFamilyNames(gfxPlatformFontList::PlatformFontList());
  587. }
  588. if (fontList->mBadUnderlineFamilyNames.Contains(name))
  589. family->SetBadUnderlineFamily();
  590. }
  591. return 1;
  592. }
  593. gfxFontEntry*
  594. gfxGDIFontList::LookupLocalFont(const nsAString& aFontName,
  595. uint16_t aWeight,
  596. int16_t aStretch,
  597. uint8_t aStyle)
  598. {
  599. gfxFontEntry *lookup;
  600. lookup = LookupInFaceNameLists(aFontName);
  601. if (!lookup) {
  602. return nullptr;
  603. }
  604. bool isCFF = false; // jtdfix -- need to determine this
  605. // use the face name from the lookup font entry, which will be the localized
  606. // face name which GDI mapping tables use (e.g. with the system locale set to
  607. // Dutch, a fullname of 'Arial Bold' will find a font entry with the face name
  608. // 'Arial Vet' which can be used as a key in GDI font lookups).
  609. GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(lookup->Name(),
  610. gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
  611. lookup->mStyle, lookup->mWeight, aStretch, nullptr,
  612. static_cast<GDIFontEntry*>(lookup)->mFamilyHasItalicFace);
  613. if (!fe)
  614. return nullptr;
  615. fe->mIsLocalUserFont = true;
  616. // make the new font entry match the userfont entry style characteristics
  617. fe->mWeight = (aWeight == 0 ? 400 : aWeight);
  618. fe->mStyle = aStyle;
  619. return fe;
  620. }
  621. // If aFontData contains only a MS/Symbol cmap subtable, not MS/Unicode,
  622. // we modify the subtable header to mark it as Unicode instead, because
  623. // otherwise GDI will refuse to load the font.
  624. // NOTE that this function does not bounds-check every access to the font data.
  625. // This is OK because we only use it on data that has already been validated
  626. // by OTS, and therefore we will not hit out-of-bounds accesses here.
  627. static bool
  628. FixupSymbolEncodedFont(uint8_t* aFontData, uint32_t aLength)
  629. {
  630. struct CmapHeader {
  631. AutoSwap_PRUint16 version;
  632. AutoSwap_PRUint16 numTables;
  633. };
  634. struct CmapEncodingRecord {
  635. AutoSwap_PRUint16 platformID;
  636. AutoSwap_PRUint16 encodingID;
  637. AutoSwap_PRUint32 offset;
  638. };
  639. const uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
  640. const TableDirEntry* dir =
  641. gfxFontUtils::FindTableDirEntry(aFontData, kCMAP);
  642. if (dir && uint32_t(dir->length) >= sizeof(CmapHeader)) {
  643. CmapHeader *cmap =
  644. reinterpret_cast<CmapHeader*>(aFontData + uint32_t(dir->offset));
  645. CmapEncodingRecord *encRec =
  646. reinterpret_cast<CmapEncodingRecord*>(cmap + 1);
  647. int32_t symbolSubtable = -1;
  648. for (uint32_t i = 0; i < (uint16_t)cmap->numTables; ++i) {
  649. if (uint16_t(encRec[i].platformID) !=
  650. gfxFontUtils::PLATFORM_ID_MICROSOFT) {
  651. continue; // only interested in MS platform
  652. }
  653. if (uint16_t(encRec[i].encodingID) ==
  654. gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP) {
  655. // We've got a Microsoft/Unicode table, so don't interfere.
  656. symbolSubtable = -1;
  657. break;
  658. }
  659. if (uint16_t(encRec[i].encodingID) ==
  660. gfxFontUtils::ENCODING_ID_MICROSOFT_SYMBOL) {
  661. // Found a symbol subtable; remember it for possible fixup,
  662. // but if we subsequently find a Microsoft/Unicode subtable,
  663. // we'll cancel this.
  664. symbolSubtable = i;
  665. }
  666. }
  667. if (symbolSubtable != -1) {
  668. // We found a windows/symbol cmap table, and no windows/unicode one;
  669. // change the encoding ID so that AddFontMemResourceEx will accept it
  670. encRec[symbolSubtable].encodingID =
  671. gfxFontUtils::ENCODING_ID_MICROSOFT_UNICODEBMP;
  672. return true;
  673. }
  674. }
  675. return false;
  676. }
  677. gfxFontEntry*
  678. gfxGDIFontList::MakePlatformFont(const nsAString& aFontName,
  679. uint16_t aWeight,
  680. int16_t aStretch,
  681. uint8_t aStyle,
  682. const uint8_t* aFontData,
  683. uint32_t aLength)
  684. {
  685. // MakePlatformFont is responsible for deleting the font data with free
  686. // so we set up a stack object to ensure it is freed even if we take an
  687. // early exit
  688. struct FontDataDeleter {
  689. FontDataDeleter(const uint8_t* aFontData)
  690. : mFontData(aFontData) { }
  691. ~FontDataDeleter() { free((void*)mFontData); }
  692. const uint8_t *mFontData;
  693. };
  694. FontDataDeleter autoDelete(aFontData);
  695. bool isCFF = gfxFontUtils::IsCffFont(aFontData);
  696. nsresult rv;
  697. HANDLE fontRef = nullptr;
  698. nsAutoString uniqueName;
  699. rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
  700. if (NS_FAILED(rv))
  701. return nullptr;
  702. FallibleTArray<uint8_t> newFontData;
  703. rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
  704. if (NS_FAILED(rv))
  705. return nullptr;
  706. DWORD numFonts = 0;
  707. uint8_t *fontData = reinterpret_cast<uint8_t*> (newFontData.Elements());
  708. uint32_t fontLength = newFontData.Length();
  709. NS_ASSERTION(fontData, "null font data after renaming");
  710. // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
  711. // "A font that is added by AddFontMemResourceEx is always private
  712. // to the process that made the call and is not enumerable."
  713. fontRef = AddFontMemResourceEx(fontData, fontLength,
  714. 0 /* reserved */, &numFonts);
  715. if (!fontRef) {
  716. if (FixupSymbolEncodedFont(fontData, fontLength)) {
  717. fontRef = AddFontMemResourceEx(fontData, fontLength, 0, &numFonts);
  718. }
  719. }
  720. if (!fontRef) {
  721. return nullptr;
  722. }
  723. // only load fonts with a single face contained in the data
  724. // AddFontMemResourceEx generates an additional face name for
  725. // vertical text if the font supports vertical writing but since
  726. // the font is referenced via the name this can be ignored
  727. if (fontRef && numFonts > 2) {
  728. RemoveFontMemResourceEx(fontRef);
  729. return nullptr;
  730. }
  731. // make a new font entry using the unique name
  732. WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
  733. uint16_t w = (aWeight == 0 ? 400 : aWeight);
  734. GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName,
  735. gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
  736. aStyle, w, aStretch, winUserFontData, false);
  737. if (fe) {
  738. fe->mIsDataUserFont = true;
  739. }
  740. return fe;
  741. }
  742. bool
  743. gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily,
  744. nsTArray<gfxFontFamily*>* aOutput,
  745. gfxFontStyle* aStyle,
  746. gfxFloat aDevToCssSize)
  747. {
  748. nsAutoString keyName(aFamily);
  749. BuildKeyNameFromFontName(keyName);
  750. gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
  751. if (ff) {
  752. aOutput->AppendElement(ff);
  753. return true;
  754. }
  755. if (mNonExistingFonts.Contains(keyName)) {
  756. return false;
  757. }
  758. return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aStyle,
  759. aDevToCssSize);
  760. }
  761. gfxFontFamily*
  762. gfxGDIFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
  763. {
  764. gfxFontFamily *ff = nullptr;
  765. // this really shouldn't fail to find a font....
  766. NONCLIENTMETRICSW ncm;
  767. ncm.cbSize = sizeof(ncm);
  768. BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
  769. sizeof(ncm), &ncm, 0);
  770. if (status) {
  771. ff = FindFamily(nsDependentString(ncm.lfMessageFont.lfFaceName));
  772. if (ff) {
  773. return ff;
  774. }
  775. }
  776. // ...but just in case, try another (long-deprecated) approach as well
  777. HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
  778. LOGFONTW logFont;
  779. if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
  780. ff = FindFamily(nsDependentString(logFont.lfFaceName));
  781. }
  782. return ff;
  783. }
  784. void
  785. gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
  786. FontListSizes* aSizes) const
  787. {
  788. gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  789. aSizes->mFontListSize +=
  790. SizeOfFontFamilyTableExcludingThis(mFontSubstitutes, aMallocSizeOf);
  791. aSizes->mFontListSize +=
  792. mNonExistingFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
  793. for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
  794. aSizes->mFontListSize +=
  795. mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  796. }
  797. }
  798. void
  799. gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
  800. FontListSizes* aSizes) const
  801. {
  802. aSizes->mFontListSize += aMallocSizeOf(this);
  803. AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  804. }
  805. // used to load system-wide font info on off-main thread
  806. class GDIFontInfo : public FontInfoData {
  807. public:
  808. GDIFontInfo(bool aLoadOtherNames,
  809. bool aLoadFaceNames,
  810. bool aLoadCmaps) :
  811. FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
  812. {}
  813. virtual ~GDIFontInfo() {}
  814. virtual void Load() {
  815. mHdc = GetDC(nullptr);
  816. SetGraphicsMode(mHdc, GM_ADVANCED);
  817. FontInfoData::Load();
  818. ReleaseDC(nullptr, mHdc);
  819. }
  820. // loads font data for all members of a given family
  821. virtual void LoadFontFamilyData(const nsAString& aFamilyName);
  822. // callback for GDI EnumFontFamiliesExW call
  823. static int CALLBACK EnumerateFontsForFamily(const ENUMLOGFONTEXW *lpelfe,
  824. const NEWTEXTMETRICEXW *nmetrics,
  825. DWORD fontType, LPARAM data);
  826. HDC mHdc;
  827. };
  828. struct EnumerateFontsForFamilyData {
  829. EnumerateFontsForFamilyData(const nsAString& aFamilyName,
  830. GDIFontInfo& aFontInfo)
  831. : mFamilyName(aFamilyName), mFontInfo(aFontInfo)
  832. {}
  833. nsString mFamilyName;
  834. nsTArray<nsString> mOtherFamilyNames;
  835. GDIFontInfo& mFontInfo;
  836. nsString mPreviousFontName;
  837. };
  838. int CALLBACK GDIFontInfo::EnumerateFontsForFamily(
  839. const ENUMLOGFONTEXW *lpelfe,
  840. const NEWTEXTMETRICEXW *nmetrics,
  841. DWORD fontType, LPARAM data)
  842. {
  843. EnumerateFontsForFamilyData *famData =
  844. reinterpret_cast<EnumerateFontsForFamilyData*>(data);
  845. HDC hdc = famData->mFontInfo.mHdc;
  846. LOGFONTW logFont = lpelfe->elfLogFont;
  847. const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
  848. AutoSelectFont font(hdc, &logFont);
  849. if (!font.IsValid()) {
  850. return 1;
  851. }
  852. FontFaceData fontData;
  853. nsDependentString fontName(lpelfe->elfFullName);
  854. // callback called for each style-charset so return if style already seen
  855. if (fontName.Equals(famData->mPreviousFontName)) {
  856. return 1;
  857. }
  858. famData->mPreviousFontName = fontName;
  859. famData->mFontInfo.mLoadStats.fonts++;
  860. // read name table info
  861. bool nameDataLoaded = false;
  862. if (famData->mFontInfo.mLoadFaceNames || famData->mFontInfo.mLoadOtherNames) {
  863. uint32_t kNAME =
  864. NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e'));
  865. uint32_t nameSize;
  866. AutoTArray<uint8_t, 1024> nameData;
  867. nameSize = ::GetFontData(hdc, kNAME, 0, nullptr, 0);
  868. if (nameSize != GDI_ERROR &&
  869. nameSize > 0 &&
  870. nameData.SetLength(nameSize, fallible)) {
  871. ::GetFontData(hdc, kNAME, 0, nameData.Elements(), nameSize);
  872. // face names
  873. if (famData->mFontInfo.mLoadFaceNames) {
  874. gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize,
  875. gfxFontUtils::NAME_ID_FULL,
  876. fontData.mFullName);
  877. gfxFontUtils::ReadCanonicalName((const char*)(nameData.Elements()), nameSize,
  878. gfxFontUtils::NAME_ID_POSTSCRIPT,
  879. fontData.mPostscriptName);
  880. nameDataLoaded = true;
  881. famData->mFontInfo.mLoadStats.facenames++;
  882. }
  883. // other family names
  884. if (famData->mFontInfo.mLoadOtherNames) {
  885. gfxFontFamily::ReadOtherFamilyNamesForFace(famData->mFamilyName,
  886. (const char*)(nameData.Elements()),
  887. nameSize,
  888. famData->mOtherFamilyNames,
  889. false);
  890. }
  891. }
  892. }
  893. // read cmap
  894. bool cmapLoaded = false;
  895. gfxWindowsFontType feType =
  896. GDIFontEntry::DetermineFontType(metrics, fontType);
  897. if (famData->mFontInfo.mLoadCmaps &&
  898. (feType == GFX_FONT_TYPE_PS_OPENTYPE ||
  899. feType == GFX_FONT_TYPE_TT_OPENTYPE ||
  900. feType == GFX_FONT_TYPE_TRUETYPE))
  901. {
  902. uint32_t kCMAP =
  903. NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p'));
  904. uint32_t cmapSize;
  905. AutoTArray<uint8_t, 1024> cmapData;
  906. cmapSize = ::GetFontData(hdc, kCMAP, 0, nullptr, 0);
  907. if (cmapSize != GDI_ERROR &&
  908. cmapSize > 0 &&
  909. cmapData.SetLength(cmapSize, fallible)) {
  910. ::GetFontData(hdc, kCMAP, 0, cmapData.Elements(), cmapSize);
  911. bool cmapLoaded = false;
  912. bool unicodeFont = false, symbolFont = false;
  913. RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
  914. uint32_t offset;
  915. if (NS_SUCCEEDED(gfxFontUtils::ReadCMAP(cmapData.Elements(),
  916. cmapSize, *charmap,
  917. offset, unicodeFont,
  918. symbolFont))) {
  919. fontData.mCharacterMap = charmap;
  920. fontData.mUVSOffset = offset;
  921. fontData.mSymbolFont = symbolFont;
  922. cmapLoaded = true;
  923. famData->mFontInfo.mLoadStats.cmaps++;
  924. }
  925. }
  926. }
  927. if (cmapLoaded || nameDataLoaded) {
  928. famData->mFontInfo.mFontFaceData.Put(fontName, fontData);
  929. }
  930. return famData->mFontInfo.mCanceled ? 0 : 1;
  931. }
  932. void
  933. GDIFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
  934. {
  935. // iterate over the family
  936. LOGFONTW logFont;
  937. memset(&logFont, 0, sizeof(LOGFONTW));
  938. logFont.lfCharSet = DEFAULT_CHARSET;
  939. logFont.lfPitchAndFamily = 0;
  940. uint32_t l = std::min<uint32_t>(aFamilyName.Length(), LF_FACESIZE - 1);
  941. memcpy(logFont.lfFaceName, aFamilyName.BeginReading(), l * sizeof(char16_t));
  942. EnumerateFontsForFamilyData data(aFamilyName, *this);
  943. EnumFontFamiliesExW(mHdc, &logFont,
  944. (FONTENUMPROCW)GDIFontInfo::EnumerateFontsForFamily,
  945. (LPARAM)(&data), 0);
  946. // if found other names, insert them
  947. if (data.mOtherFamilyNames.Length() != 0) {
  948. mOtherFamilyNames.Put(aFamilyName, data.mOtherFamilyNames);
  949. mLoadStats.othernames += data.mOtherFamilyNames.Length();
  950. }
  951. }
  952. already_AddRefed<FontInfoData>
  953. gfxGDIFontList::CreateFontInfoData()
  954. {
  955. bool loadCmaps = !UsesSystemFallback() ||
  956. gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
  957. RefPtr<GDIFontInfo> fi =
  958. new GDIFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps);
  959. return fi.forget();
  960. }
  961. #ifdef MOZ_BUNDLED_FONTS
  962. void
  963. gfxGDIFontList::ActivateBundledFonts()
  964. {
  965. nsCOMPtr<nsIFile> localDir;
  966. nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir));
  967. if (NS_FAILED(rv)) {
  968. return;
  969. }
  970. if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) {
  971. return;
  972. }
  973. bool isDir;
  974. if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) {
  975. return;
  976. }
  977. nsCOMPtr<nsISimpleEnumerator> e;
  978. rv = localDir->GetDirectoryEntries(getter_AddRefs(e));
  979. if (NS_FAILED(rv)) {
  980. return;
  981. }
  982. bool hasMore;
  983. while (NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore) {
  984. nsCOMPtr<nsISupports> entry;
  985. if (NS_FAILED(e->GetNext(getter_AddRefs(entry)))) {
  986. break;
  987. }
  988. nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
  989. if (!file) {
  990. continue;
  991. }
  992. nsAutoString path;
  993. if (NS_FAILED(file->GetPath(path))) {
  994. continue;
  995. }
  996. AddFontResourceExW(path.get(), FR_PRIVATE, nullptr);
  997. }
  998. }
  999. #endif