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.

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

mercurial