gfx/thebes/gfxGDIFontList.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial