gfx/thebes/gfxDWriteFontList.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/ArrayUtils.h"
     7 #include "mozilla/MemoryReporting.h"
     9 #ifdef MOZ_LOGGING
    10 #define FORCE_PR_LOG /* Allow logging in the release build */
    11 #endif /* MOZ_LOGGING */
    13 #include "gfxDWriteFontList.h"
    14 #include "gfxDWriteFonts.h"
    15 #include "nsUnicharUtils.h"
    16 #include "nsILocaleService.h"
    17 #include "nsServiceManagerUtils.h"
    18 #include "nsCharSeparatedTokenizer.h"
    19 #include "mozilla/Preferences.h"
    20 #include "mozilla/Telemetry.h"
    22 #include "gfxGDIFontList.h"
    24 #include "nsIWindowsRegKey.h"
    26 #include "harfbuzz/hb.h"
    28 using namespace mozilla;
    30 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
    31                                PR_LOG_DEBUG, args)
    32 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
    33                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
    34                                    PR_LOG_DEBUG)
    36 #define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
    37                                PR_LOG_DEBUG, args)
    38 #define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
    39                                    gfxPlatform::GetLog(eGfxLog_fontinit), \
    40                                    PR_LOG_DEBUG)
    42 #define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
    43                                    gfxPlatform::GetLog(eGfxLog_cmapdata), \
    44                                    PR_LOG_DEBUG)
    46 static __inline void
    47 BuildKeyNameFromFontName(nsAString &aName)
    48 {
    49     if (aName.Length() >= LF_FACESIZE)
    50         aName.Truncate(LF_FACESIZE - 1);
    51     ToLowerCase(aName);
    52 }
    54 ////////////////////////////////////////////////////////////////////////////////
    55 // gfxDWriteFontFamily
    57 gfxDWriteFontFamily::~gfxDWriteFontFamily()
    58 {
    59 }
    61 static HRESULT
    62 GetDirectWriteFontName(IDWriteFont *aFont, nsAString& aFontName)
    63 {
    64     HRESULT hr;
    66     nsRefPtr<IDWriteLocalizedStrings> names;
    67     hr = aFont->GetFaceNames(getter_AddRefs(names));
    68     if (FAILED(hr)) {
    69         return hr;
    70     }
    72     BOOL exists;
    73     nsAutoTArray<wchar_t,32> faceName;
    74     UINT32 englishIdx = 0;
    75     hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
    76     if (FAILED(hr)) {
    77         return hr;
    78     }
    80     if (!exists) {
    81         // No english found, use whatever is first in the list.
    82         englishIdx = 0;
    83     }
    84     UINT32 length;
    85     hr = names->GetStringLength(englishIdx, &length);
    86     if (FAILED(hr)) {
    87         return hr;
    88     }
    89     faceName.SetLength(length + 1);
    90     hr = names->GetString(englishIdx, faceName.Elements(), length + 1);
    91     if (FAILED(hr)) {
    92         return hr;
    93     }
    95     aFontName.Assign(faceName.Elements());
    96     return S_OK;
    97 }
    99 // These strings are only defined in Win SDK 8+, so use #ifdef for now
   100 #if MOZ_WINSDK_TARGETVER > 0x08000000
   101 #define FULLNAME_ID   DWRITE_INFORMATIONAL_STRING_FULL_NAME
   102 #define PSNAME_ID     DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME
   103 #else
   104 #define FULLNAME_ID   DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 1)
   105 #define PSNAME_ID     DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 2)
   106 #endif
   108 // for use in reading postscript or fullname
   109 static HRESULT
   110 GetDirectWriteFaceName(IDWriteFont *aFont,
   111                        DWRITE_INFORMATIONAL_STRING_ID aWhichName,
   112                        nsAString& aFontName)
   113 {
   114     HRESULT hr;
   116     BOOL exists;
   117     nsRefPtr<IDWriteLocalizedStrings> infostrings;
   118     hr = aFont->GetInformationalStrings(aWhichName, getter_AddRefs(infostrings), &exists);
   119     if (FAILED(hr) || !exists) {
   120         return E_FAIL;
   121     }
   123     nsAutoTArray<wchar_t,32> faceName;
   124     UINT32 englishIdx = 0;
   125     hr = infostrings->FindLocaleName(L"en-us", &englishIdx, &exists);
   126     if (FAILED(hr)) {
   127         return hr;
   128     }
   130     if (!exists) {
   131         // No english found, use whatever is first in the list.
   132         englishIdx = 0;
   133     }
   134     UINT32 length;
   135     hr = infostrings->GetStringLength(englishIdx, &length);
   136     if (FAILED(hr)) {
   137         return hr;
   138     }
   139     faceName.SetLength(length + 1);
   140     hr = infostrings->GetString(englishIdx, faceName.Elements(), length + 1);
   141     if (FAILED(hr)) {
   142         return hr;
   143     }
   145     aFontName.Assign(faceName.Elements());
   146     return S_OK;
   147 }
   149 void
   150 gfxDWriteFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
   151 {
   152     HRESULT hr;
   153     if (mHasStyles) {
   154         return;
   155     }
   156     mHasStyles = true;
   158     gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
   160     bool skipFaceNames = mFaceNamesInitialized ||
   161                          !fp->NeedFullnamePostscriptNames();
   162     bool fontInfoShouldHaveFaceNames = !mFaceNamesInitialized &&
   163                                        fp->NeedFullnamePostscriptNames() &&
   164                                        aFontInfoData;
   166     for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) {
   167         nsRefPtr<IDWriteFont> font;
   168         hr = mDWFamily->GetFont(i, getter_AddRefs(font));
   169         if (FAILED(hr)) {
   170             // This should never happen.
   171             NS_WARNING("Failed to get existing font from family.");
   172             continue;
   173         }
   175         if (font->GetSimulations() & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
   176             // We don't want these.
   177             continue;
   178         }
   180         // name
   181         nsString fullID(mName);
   182         nsAutoString faceName;
   183         hr = GetDirectWriteFontName(font, faceName);
   184         if (FAILED(hr)) {
   185             continue;
   186         }
   187         fullID.Append(NS_LITERAL_STRING(" "));
   188         fullID.Append(faceName);
   190         gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font);
   191         fe->SetForceGDIClassic(mForceGDIClassic);
   192         AddFontEntry(fe);
   194         // postscript/fullname if needed
   195         nsAutoString psname, fullname;
   196         if (fontInfoShouldHaveFaceNames) {
   197             aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
   198             if (!fullname.IsEmpty()) {
   199                 fp->AddFullname(fe, fullname);
   200             }
   201             if (!psname.IsEmpty()) {
   202                 fp->AddPostscriptName(fe, psname);
   203             }
   204         } else if (!skipFaceNames) {
   205             hr = GetDirectWriteFaceName(font, PSNAME_ID, psname);
   206             if (FAILED(hr)) {
   207                 skipFaceNames = true;
   208             } else if (psname.Length() > 0) {
   209                 fp->AddPostscriptName(fe, psname);
   210             }
   212             hr = GetDirectWriteFaceName(font, FULLNAME_ID, fullname);
   213             if (FAILED(hr)) {
   214                 skipFaceNames = true;
   215             } else if (fullname.Length() > 0) {
   216                 fp->AddFullname(fe, fullname);
   217             }
   218         }
   220 #ifdef PR_LOGGING
   221         if (LOG_FONTLIST_ENABLED()) {
   222             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
   223                  " with style: %s weight: %d stretch: %d psname: %s fullname: %s",
   224                  NS_ConvertUTF16toUTF8(fe->Name()).get(),
   225                  NS_ConvertUTF16toUTF8(Name()).get(),
   226                  (fe->IsItalic()) ? "italic" : "normal",
   227                  fe->Weight(), fe->Stretch(),
   228                  NS_ConvertUTF16toUTF8(psname).get(),
   229                  NS_ConvertUTF16toUTF8(fullname).get()));
   230         }
   231 #endif
   232     }
   234     // assume that if no error, all postscript/fullnames were initialized
   235     if (!skipFaceNames) {
   236         mFaceNamesInitialized = true;
   237     }
   239     if (!mAvailableFonts.Length()) {
   240         NS_WARNING("Family with no font faces in it.");
   241     }
   243     if (mIsBadUnderlineFamily) {
   244         SetBadUnderlineFonts();
   245     }
   246 }
   248 void
   249 gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
   250                                    bool aNeedFullnamePostscriptNames)
   251 {
   252     // if all needed names have already been read, skip
   253     if (mOtherFamilyNamesInitialized &&
   254         (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
   255         return;
   256     }
   258     // DirectWrite version of this will try to read
   259     // postscript/fullnames via DirectWrite API
   260     FindStyleVariations();
   262     // fallback to looking up via name table
   263     if (!mOtherFamilyNamesInitialized || !mFaceNamesInitialized) {
   264         gfxFontFamily::ReadFaceNames(aPlatformFontList,
   265                                      aNeedFullnamePostscriptNames);
   266     }
   267 }
   269 void
   270 gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName)
   271 {
   272     aLocalizedName.AssignLiteral("Unknown Font");
   273     HRESULT hr;
   274     nsresult rv;
   275     nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID,
   276                                                   &rv);
   277     nsCOMPtr<nsILocale> locale;
   278     rv = ls->GetApplicationLocale(getter_AddRefs(locale));
   279     nsString localeName;
   280     if (NS_SUCCEEDED(rv)) {
   281         rv = locale->GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), 
   282                                  localeName);
   283     }
   284     if (NS_FAILED(rv)) {
   285         localeName.AssignLiteral("en-us");
   286     }
   288     nsRefPtr<IDWriteLocalizedStrings> names;
   290     hr = mDWFamily->GetFamilyNames(getter_AddRefs(names));
   291     if (FAILED(hr)) {
   292         return;
   293     }
   294     UINT32 idx = 0;
   295     BOOL exists;
   296     hr = names->FindLocaleName(localeName.get(),
   297                                &idx,
   298                                &exists);
   299     if (FAILED(hr)) {
   300         return;
   301     }
   302     if (!exists) {
   303         // Use english is localized is not found.
   304         hr = names->FindLocaleName(L"en-us", &idx, &exists);
   305         if (FAILED(hr)) {
   306             return;
   307         }
   308         if (!exists) {
   309             // Use 0 index if english is not found.
   310             idx = 0;
   311         }
   312     }
   313     AutoFallibleTArray<WCHAR, 32> famName;
   314     UINT32 length;
   316     hr = names->GetStringLength(idx, &length);
   317     if (FAILED(hr)) {
   318         return;
   319     }
   321     if (!famName.SetLength(length + 1)) {
   322         // Eeep - running out of memory. Unlikely to end well.
   323         return;
   324     }
   326     hr = names->GetString(idx, famName.Elements(), length + 1);
   327     if (FAILED(hr)) {
   328         return;
   329     }
   331     aLocalizedName = nsDependentString(famName.Elements());
   332 }
   334 void
   335 gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
   336                                             FontListSizes* aSizes) const
   337 {
   338     gfxFontFamily::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   339     // TODO:
   340     // This doesn't currently account for |mDWFamily|
   341 }
   343 void
   344 gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   345                                             FontListSizes* aSizes) const
   346 {
   347     aSizes->mFontListSize += aMallocSizeOf(this);
   348     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   349 }
   351 ////////////////////////////////////////////////////////////////////////////////
   352 // gfxDWriteFontEntry
   354 gfxDWriteFontEntry::~gfxDWriteFontEntry()
   355 {
   356 }
   358 bool
   359 gfxDWriteFontEntry::IsSymbolFont()
   360 {
   361     if (mFont) {
   362         return mFont->IsSymbolFont();
   363     } else {
   364         return false;
   365     }
   366 }
   368 static bool
   369 UsingArabicOrHebrewScriptSystemLocale()
   370 {
   371     LANGID langid = PRIMARYLANGID(::GetSystemDefaultLangID());
   372     switch (langid) {
   373     case LANG_ARABIC:
   374     case LANG_DARI:
   375     case LANG_PASHTO:
   376     case LANG_PERSIAN:
   377     case LANG_SINDHI:
   378     case LANG_UIGHUR:
   379     case LANG_URDU:
   380     case LANG_HEBREW:
   381         return true;
   382     default:
   383         return false;
   384     }
   385 }
   387 nsresult
   388 gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag,
   389                                   FallibleTArray<uint8_t> &aBuffer)
   390 {
   391     gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList();
   393     // Don't use GDI table loading for symbol fonts or for
   394     // italic fonts in Arabic-script system locales because of
   395     // potential cmap discrepancies, see bug 629386.
   396     // Ditto for Hebrew, bug 837498.
   397     if (mFont && pFontList->UseGDIFontTableAccess() &&
   398         !(mItalic && UsingArabicOrHebrewScriptSystemLocale()) &&
   399         !mFont->IsSymbolFont())
   400     {
   401         LOGFONTW logfont = { 0 };
   402         if (!InitLogFont(mFont, &logfont))
   403             return NS_ERROR_FAILURE;
   405         AutoDC dc;
   406         AutoSelectFont font(dc.GetDC(), &logfont);
   407         if (font.IsValid()) {
   408             uint32_t tableSize =
   409                 ::GetFontData(dc.GetDC(),
   410                               NativeEndian::swapToBigEndian(aTableTag), 0,
   411                               nullptr, 0);
   412             if (tableSize != GDI_ERROR) {
   413                 if (aBuffer.SetLength(tableSize)) {
   414                     ::GetFontData(dc.GetDC(),
   415                                   NativeEndian::swapToBigEndian(aTableTag), 0,
   416                                   aBuffer.Elements(), aBuffer.Length());
   417                     return NS_OK;
   418                 }
   419                 return NS_ERROR_OUT_OF_MEMORY;
   420             }
   421         }
   422         return NS_ERROR_FAILURE;
   423     }
   425     nsRefPtr<IDWriteFontFace> fontFace;
   426     nsresult rv = CreateFontFace(getter_AddRefs(fontFace));
   427     if (NS_FAILED(rv)) {
   428         return rv;
   429     }
   431     uint8_t *tableData;
   432     uint32_t len;
   433     void *tableContext = nullptr;
   434     BOOL exists;
   435     HRESULT hr =
   436         fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
   437                                   (const void**)&tableData, &len,
   438                                   &tableContext, &exists);
   439     if (FAILED(hr) || !exists) {
   440         return NS_ERROR_FAILURE;
   441     }
   443     if (aBuffer.SetLength(len)) {
   444         memcpy(aBuffer.Elements(), tableData, len);
   445         rv = NS_OK;
   446     } else {
   447         rv = NS_ERROR_OUT_OF_MEMORY;
   448     }
   450     if (tableContext) {
   451         fontFace->ReleaseFontTable(&tableContext);
   452     }
   454     return rv;
   455 }
   457 // Access to font tables packaged in hb_blob_t form
   459 // object attached to the Harfbuzz blob, used to release
   460 // the table when the blob is destroyed
   461 class FontTableRec {
   462 public:
   463     FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
   464         : mFontFace(aFontFace), mContext(aContext)
   465     { }
   467     ~FontTableRec() {
   468         mFontFace->ReleaseFontTable(mContext);
   469     }
   471 private:
   472     nsRefPtr<IDWriteFontFace> mFontFace;
   473     void            *mContext;
   474 };
   476 static void
   477 DestroyBlobFunc(void* aUserData)
   478 {
   479     FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
   480     delete ftr;
   481 }
   483 hb_blob_t *
   484 gfxDWriteFontEntry::GetFontTable(uint32_t aTag)
   485 {
   486     // try to avoid potentially expensive DWrite call if we haven't actually
   487     // created the font face yet, by using the gfxFontEntry method that will
   488     // use CopyFontTable and then cache the data
   489     if (!mFontFace) {
   490         return gfxFontEntry::GetFontTable(aTag);
   491     }
   493     const void *data;
   494     UINT32      size;
   495     void       *context;
   496     BOOL        exists;
   497     HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
   498                                             &data, &size, &context, &exists);
   499     if (SUCCEEDED(hr) && exists) {
   500         FontTableRec *ftr = new FontTableRec(mFontFace, context);
   501         return hb_blob_create(static_cast<const char*>(data), size,
   502                               HB_MEMORY_MODE_READONLY,
   503                               ftr, DestroyBlobFunc);
   504     }
   506     return nullptr;
   507 }
   509 nsresult
   510 gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
   511 {
   512     // attempt this once, if errors occur leave a blank cmap
   513     if (mCharacterMap) {
   514         return NS_OK;
   515     }
   517     nsRefPtr<gfxCharacterMap> charmap;
   518     nsresult rv;
   519     bool symbolFont;
   521     if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
   522                                                         mUVSOffset,
   523                                                         symbolFont))) {
   524         rv = NS_OK;
   525     } else {
   526         uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
   527         charmap = new gfxCharacterMap();
   528         AutoTable cmapTable(this, kCMAP);
   530         if (cmapTable) {
   531             bool unicodeFont = false, symbolFont = false; // currently ignored
   532             uint32_t cmapLen;
   533             const uint8_t* cmapData =
   534                 reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
   535                                                                   &cmapLen));
   536             rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
   537                                         *charmap, mUVSOffset,
   538                                         unicodeFont, symbolFont);
   539         } else {
   540             rv = NS_ERROR_NOT_AVAILABLE;
   541         }
   542     }
   544     mHasCmapTable = NS_SUCCEEDED(rv);
   545     if (mHasCmapTable) {
   546         // Bug 969504: exclude U+25B6 from Segoe UI family, because it's used
   547         // by sites to represent a "Play" icon, but the glyph in Segoe UI Light
   548         // and Semibold on Windows 7 is too thin. (Ditto for leftward U+25C0.)
   549         // Fallback to Segoe UI Symbol is preferred.
   550         if (FamilyName().EqualsLiteral("Segoe UI")) {
   551             charmap->clear(0x25b6);
   552             charmap->clear(0x25c0);
   553         }
   554         gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
   555         mCharacterMap = pfl->FindCharMap(charmap);
   556     } else {
   557         // if error occurred, initialize to null cmap
   558         mCharacterMap = new gfxCharacterMap();
   559     }
   561 #ifdef PR_LOGGING
   562     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
   563                   NS_ConvertUTF16toUTF8(mName).get(),
   564                   charmap->SizeOfIncludingThis(moz_malloc_size_of),
   565                   charmap->mHash, mCharacterMap == charmap ? " new" : ""));
   566     if (LOG_CMAPDATA_ENABLED()) {
   567         char prefix[256];
   568         sprintf(prefix, "(cmapdata) name: %.220s",
   569                 NS_ConvertUTF16toUTF8(mName).get());
   570         charmap->Dump(prefix, eGfxLog_cmapdata);
   571     }
   572 #endif
   574     return rv;
   575 }
   577 gfxFont *
   578 gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle,
   579                                        bool aNeedsBold)
   580 {
   581     return new gfxDWriteFont(this, aFontStyle, aNeedsBold);
   582 }
   584 nsresult
   585 gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
   586                                    DWRITE_FONT_SIMULATIONS aSimulations)
   587 {
   588     // initialize mFontFace if this hasn't been done before
   589     if (!mFontFace) {
   590         HRESULT hr;
   591         if (mFont) {
   592             hr = mFont->CreateFontFace(getter_AddRefs(mFontFace));
   593         } else if (mFontFile) {
   594             IDWriteFontFile *fontFile = mFontFile.get();
   595             hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   596                 CreateFontFace(mFaceType,
   597                                1,
   598                                &fontFile,
   599                                0,
   600                                DWRITE_FONT_SIMULATIONS_NONE,
   601                                getter_AddRefs(mFontFace));
   602         } else {
   603             NS_NOTREACHED("invalid font entry");
   604             return NS_ERROR_FAILURE;
   605         }
   606         if (FAILED(hr)) {
   607             return NS_ERROR_FAILURE;
   608         }
   609     }
   611     // check whether we need to add a DWrite simulated style
   612     if ((aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
   613         !(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
   614         // if so, we need to return not mFontFace itself but a version that
   615         // has the Bold simulation - unfortunately, DWrite doesn't provide
   616         // a simple API for this
   617         UINT32 numberOfFiles = 0;
   618         if (FAILED(mFontFace->GetFiles(&numberOfFiles, nullptr))) {
   619             return NS_ERROR_FAILURE;
   620         }
   621         nsAutoTArray<IDWriteFontFile*,1> files;
   622         files.AppendElements(numberOfFiles);
   623         if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) {
   624             return NS_ERROR_FAILURE;
   625         }
   626         HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   627             CreateFontFace(mFontFace->GetType(),
   628                            numberOfFiles,
   629                            files.Elements(),
   630                            mFontFace->GetIndex(),
   631                            aSimulations,
   632                            aFontFace);
   633         for (UINT32 i = 0; i < numberOfFiles; ++i) {
   634             files[i]->Release();
   635         }
   636         return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
   637     }
   639     // no simulation: we can just add a reference to mFontFace and return that
   640     *aFontFace = mFontFace;
   641     (*aFontFace)->AddRef();
   642     return NS_OK;
   643 }
   645 bool
   646 gfxDWriteFontEntry::InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont)
   647 {
   648     HRESULT hr;
   650     BOOL isInSystemCollection;
   651     IDWriteGdiInterop *gdi = 
   652         gfxDWriteFontList::PlatformFontList()->GetGDIInterop();
   653     hr = gdi->ConvertFontToLOGFONT(aFont, aLogFont, &isInSystemCollection);
   654     return (FAILED(hr) ? false : true);
   655 }
   657 bool
   658 gfxDWriteFontEntry::IsCJKFont()
   659 {
   660     if (mIsCJK != UNINITIALIZED_VALUE) {
   661         return mIsCJK;
   662     }
   664     mIsCJK = false;
   666     const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
   667     AutoFallibleTArray<uint8_t,128> buffer;
   668     if (CopyFontTable(kOS2Tag, buffer) != NS_OK) {
   669         return mIsCJK;
   670     }
   672     // ulCodePageRange bit definitions for the CJK codepages,
   673     // from http://www.microsoft.com/typography/otspec/os2.htm#cpr
   674     const uint32_t CJK_CODEPAGE_BITS =
   675         (1 << 17) | // codepage 932 - JIS/Japan
   676         (1 << 18) | // codepage 936 - Chinese (simplified)
   677         (1 << 19) | // codepage 949 - Korean Wansung
   678         (1 << 20) | // codepage 950 - Chinese (traditional)
   679         (1 << 21);  // codepage 1361 - Korean Johab
   681     if (buffer.Length() >= offsetof(OS2Table, sxHeight)) {
   682         const OS2Table* os2 =
   683             reinterpret_cast<const OS2Table*>(buffer.Elements());
   684         if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) {
   685             mIsCJK = true;
   686         }
   687     }
   689     return mIsCJK;
   690 }
   692 void
   693 gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
   694                                            FontListSizes* aSizes) const
   695 {
   696     gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   697     // TODO:
   698     // This doesn't currently account for the |mFont| and |mFontFile| members
   699 }
   701 void
   702 gfxDWriteFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   703                                            FontListSizes* aSizes) const
   704 {
   705     aSizes->mFontListSize += aMallocSizeOf(this);
   706     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   707 }
   709 ////////////////////////////////////////////////////////////////////////////////
   710 // gfxDWriteFontList
   712 gfxDWriteFontList::gfxDWriteFontList()
   713     : mInitialized(false), mForceGDIClassicMaxFontSize(0.0)
   714 {
   715 }
   717 // bug 602792 - CJK systems default to large CJK fonts which cause excessive
   718 //   I/O strain during cold startup due to dwrite caching bugs.  Default to
   719 //   Arial to avoid this.
   721 gfxFontFamily *
   722 gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle)
   723 {
   724     nsAutoString resolvedName;
   726     // try Arial first
   727     if (ResolveFontName(NS_LITERAL_STRING("Arial"), resolvedName)) {
   728         return FindFamily(resolvedName);
   729     }
   731     // otherwise, use local default
   732     NONCLIENTMETRICSW ncm;
   733     ncm.cbSize = sizeof(ncm);
   734     BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
   735                                           sizeof(ncm), &ncm, 0);
   736     if (status) {
   737         if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName),
   738                             resolvedName)) {
   739             return FindFamily(resolvedName);
   740         }
   741     }
   743     return nullptr;
   744 }
   746 gfxFontEntry *
   747 gfxDWriteFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
   748                                    const nsAString& aFullname)
   749 {
   750     gfxFontEntry *lookup;
   752     lookup = LookupInFaceNameLists(aFullname);
   753     if (!lookup) {
   754         return nullptr;
   755     }
   757     gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
   758     gfxDWriteFontEntry *fe =
   759         new gfxDWriteFontEntry(lookup->Name(),
   760                                dwriteLookup->mFont,
   761                                aProxyEntry->Weight(),
   762                                aProxyEntry->Stretch(),
   763                                aProxyEntry->IsItalic());
   764     fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic());
   765     return fe;
   766 }
   768 gfxFontEntry *
   769 gfxDWriteFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
   770                                     const uint8_t *aFontData,
   771                                     uint32_t aLength)
   772 {
   773     nsresult rv;
   774     nsAutoString uniqueName;
   775     rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
   776     if (NS_FAILED(rv)) {
   777         NS_Free((void*)aFontData);
   778         return nullptr;
   779     }
   781     FallibleTArray<uint8_t> newFontData;
   783     rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
   784     NS_Free((void*)aFontData);
   786     if (NS_FAILED(rv)) {
   787         return nullptr;
   788     }
   790     nsRefPtr<IDWriteFontFile> fontFile;
   791     HRESULT hr;
   793     /**
   794      * We pass in a pointer to a structure containing a pointer to the array
   795      * containing the font data and a unique identifier. DWrite will
   796      * internally copy what is at that pointer, and pass that to
   797      * CreateStreamFromKey. The array will be empty when the function 
   798      * succesfully returns since it swaps out the data.
   799      */
   800     ffReferenceKey key;
   801     key.mArray = &newFontData;
   802     nsCOMPtr<nsIUUIDGenerator> uuidgen =
   803       do_GetService("@mozilla.org/uuid-generator;1");
   804     if (!uuidgen) {
   805         return nullptr;
   806     }
   808     rv = uuidgen->GenerateUUIDInPlace(&key.mGUID);
   810     if (NS_FAILED(rv)) {
   811         return nullptr;
   812     }
   814     hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   815         CreateCustomFontFileReference(&key,
   816                                       sizeof(key),
   817                                       gfxDWriteFontFileLoader::Instance(),
   818                                       getter_AddRefs(fontFile));
   820     if (FAILED(hr)) {
   821         NS_WARNING("Failed to create custom font file reference.");
   822         return nullptr;
   823     }
   825     BOOL isSupported;
   826     DWRITE_FONT_FILE_TYPE fileType;
   827     UINT32 numFaces;
   829     gfxDWriteFontEntry *entry = 
   830         new gfxDWriteFontEntry(uniqueName, 
   831                                fontFile,
   832                                aProxyEntry->Weight(),
   833                                aProxyEntry->Stretch(),
   834                                aProxyEntry->IsItalic());
   836     fontFile->Analyze(&isSupported, &fileType, &entry->mFaceType, &numFaces);
   837     if (!isSupported || numFaces > 1) {
   838         // We don't know how to deal with 0 faces either.
   839         delete entry;
   840         return nullptr;
   841     }
   843     return entry;
   844 }
   846 #ifdef DEBUG_DWRITE_STARTUP
   848 #define LOGREGISTRY(msg) LogRegistryEvent(msg)
   850 // for use when monitoring process
   851 static void LogRegistryEvent(const wchar_t *msg)
   852 {
   853     HKEY dummyKey;
   854     HRESULT hr;
   855     wchar_t buf[512];
   857     wsprintfW(buf, L" log %s", msg);
   858     hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
   859     if (SUCCEEDED(hr)) {
   860         RegCloseKey(dummyKey);
   861     }
   862 }
   863 #else
   865 #define LOGREGISTRY(msg)
   867 #endif
   869 nsresult
   870 gfxDWriteFontList::InitFontList()
   871 {
   872     LOGREGISTRY(L"InitFontList start");
   874     mInitialized = false;
   876     LARGE_INTEGER frequency;        // ticks per second
   877     LARGE_INTEGER t1, t2, t3;           // ticks
   878     double elapsedTime, upTime;
   879     char nowTime[256], nowDate[256];
   881     if (LOG_FONTINIT_ENABLED()) {    
   882         GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, 
   883                       nullptr, nullptr, nowTime, 256);
   884         GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256);
   885     }
   886     upTime = (double) GetTickCount();
   887     QueryPerformanceFrequency(&frequency);
   888     QueryPerformanceCounter(&t1);
   890     HRESULT hr;
   891     gfxFontCache *fc = gfxFontCache::GetCache();
   892     if (fc) {
   893         fc->AgeAllGenerations();
   894     }
   896     mGDIFontTableAccess = Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading", false);
   898     gfxPlatformFontList::InitFontList();
   900     mFontSubstitutes.Clear();
   901     mNonExistingFonts.Clear();
   903     QueryPerformanceCounter(&t2);
   905     hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   906         GetGdiInterop(getter_AddRefs(mGDIInterop));
   907     if (FAILED(hr)) {
   908         return NS_ERROR_FAILURE;
   909     }
   911     LOGREGISTRY(L"InitFontList end");
   913     QueryPerformanceCounter(&t3);
   915     if (LOG_FONTINIT_ENABLED()) {
   916         // determine dwrite version
   917         nsAutoString dwriteVers;
   918         gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers);
   919         LOG_FONTINIT(("InitFontList\n"));
   920         LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime));
   921         LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000));
   922         LOG_FONTINIT(("dwrite version: %s\n", 
   923                       NS_ConvertUTF16toUTF8(dwriteVers).get()));
   924     }
   926     elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
   927     Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_TOTAL, elapsedTime);
   928     LOG_FONTINIT(("Total time in InitFontList:    %9.3f ms\n", elapsedTime));
   929     elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
   930     Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_INIT, elapsedTime);
   931     LOG_FONTINIT((" --- gfxPlatformFontList init: %9.3f ms\n", elapsedTime));
   932     elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
   933     Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_GDI, elapsedTime);
   934     LOG_FONTINIT((" --- GdiInterop object:        %9.3f ms\n", elapsedTime));
   936     return NS_OK;
   937 }
   939 nsresult
   940 gfxDWriteFontList::DelayedInitFontList()
   941 {
   942     LOGREGISTRY(L"DelayedInitFontList start");
   944     LARGE_INTEGER frequency;        // ticks per second
   945     LARGE_INTEGER t1, t2, t3;           // ticks
   946     double elapsedTime, upTime;
   947     char nowTime[256], nowDate[256];
   949     if (LOG_FONTINIT_ENABLED()) {    
   950         GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, 
   951                       nullptr, nullptr, nowTime, 256);
   952         GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256);
   953     }
   955     upTime = (double) GetTickCount();
   956     QueryPerformanceFrequency(&frequency);
   957     QueryPerformanceCounter(&t1);
   959     HRESULT hr;
   961     LOGREGISTRY(L"calling GetSystemFontCollection");
   962     nsRefPtr<IDWriteFontCollection> systemFonts;
   963     hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   964         GetSystemFontCollection(getter_AddRefs(systemFonts));
   965     NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
   966     LOGREGISTRY(L"GetSystemFontCollection done");
   968     if (FAILED(hr)) {
   969         return NS_ERROR_FAILURE;
   970     }
   972     QueryPerformanceCounter(&t2);
   974     for (UINT32 i = 0; i < systemFonts->GetFontFamilyCount(); i++) {
   975         nsRefPtr<IDWriteFontFamily> family;
   976         systemFonts->GetFontFamily(i, getter_AddRefs(family));
   978         nsRefPtr<IDWriteLocalizedStrings> names;
   979         hr = family->GetFamilyNames(getter_AddRefs(names));
   980         if (FAILED(hr)) {
   981             continue;
   982         }
   984         UINT32 englishIdx = 0;
   986         BOOL exists;
   987         hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
   988         if (FAILED(hr)) {
   989             continue;
   990         }
   991         if (!exists) {
   992             // Use 0 index if english is not found.
   993             englishIdx = 0;
   994         }
   996         AutoFallibleTArray<WCHAR, 32> enName;
   997         UINT32 length;
   999         hr = names->GetStringLength(englishIdx, &length);
  1000         if (FAILED(hr)) {
  1001             continue;
  1004         if (!enName.SetLength(length + 1)) {
  1005             // Eeep - running out of memory. Unlikely to end well.
  1006             continue;
  1009         hr = names->GetString(englishIdx, enName.Elements(), length + 1);
  1010         if (FAILED(hr)) {
  1011             continue;
  1014         nsAutoString name(enName.Elements());
  1015         BuildKeyNameFromFontName(name);
  1017         nsRefPtr<gfxFontFamily> fam;
  1019         if (mFontFamilies.GetWeak(name)) {
  1020             continue;
  1023         nsDependentString familyName(enName.Elements());
  1025         fam = new gfxDWriteFontFamily(familyName, family);
  1026         if (!fam) {
  1027             continue;
  1030         if (mBadUnderlineFamilyNames.Contains(name)) {
  1031             fam->SetBadUnderlineFamily();
  1033         mFontFamilies.Put(name, fam);
  1035         // now add other family name localizations, if present
  1036         uint32_t nameCount = names->GetCount();
  1037         uint32_t nameIndex;
  1039         for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
  1040             UINT32 nameLen;
  1041             AutoFallibleTArray<WCHAR, 32> localizedName;
  1043             // only add other names
  1044             if (nameIndex == englishIdx) {
  1045                 continue;
  1048             hr = names->GetStringLength(nameIndex, &nameLen);
  1049             if (FAILED(hr)) {
  1050                 continue;
  1053             if (!localizedName.SetLength(nameLen + 1)) {
  1054                 continue;
  1057             hr = names->GetString(nameIndex, localizedName.Elements(), 
  1058                                   nameLen + 1);
  1059             if (FAILED(hr)) {
  1060                 continue;
  1063             nsDependentString locName(localizedName.Elements());
  1065             if (!familyName.Equals(locName)) {
  1066                 AddOtherFamilyName(fam, locName);
  1071         // at this point, all family names have been read in
  1072         fam->SetOtherFamilyNamesInitialized();
  1075     mOtherFamilyNamesInitialized = true;
  1076     GetFontSubstitutes();
  1078     // bug 642093 - DirectWrite does not support old bitmap (.fon)
  1079     // font files, but a few of these such as "Courier" and "MS Sans Serif"
  1080     // are frequently specified in shoddy CSS, without appropriate fallbacks.
  1081     // By mapping these to TrueType equivalents, we provide better consistency
  1082     // with both pre-DW systems and with IE9, which appears to do the same.
  1083     GetDirectWriteSubstitutes();
  1085     // bug 551313 - DirectWrite creates a Gill Sans family out of 
  1086     // poorly named members of the Gill Sans MT family containing
  1087     // only Ultra Bold weights.  This causes big problems for pages
  1088     // using Gill Sans which is usually only available on OSX
  1090     nsAutoString nameGillSans(L"Gill Sans");
  1091     nsAutoString nameGillSansMT(L"Gill Sans MT");
  1092     BuildKeyNameFromFontName(nameGillSans);
  1093     BuildKeyNameFromFontName(nameGillSansMT);
  1095     gfxFontFamily *gillSansFamily = mFontFamilies.GetWeak(nameGillSans);
  1096     gfxFontFamily *gillSansMTFamily = mFontFamilies.GetWeak(nameGillSansMT);
  1098     if (gillSansFamily && gillSansMTFamily) {
  1099         gillSansFamily->FindStyleVariations();
  1100         nsTArray<nsRefPtr<gfxFontEntry> >& faces = gillSansFamily->GetFontList();
  1101         uint32_t i;
  1103         bool allUltraBold = true;
  1104         for (i = 0; i < faces.Length(); i++) {
  1105             // does the face have 'Ultra Bold' in the name?
  1106             if (faces[i]->Name().Find(NS_LITERAL_STRING("Ultra Bold")) == -1) {
  1107                 allUltraBold = false;
  1108                 break;
  1112         // if all the Gill Sans faces are Ultra Bold ==> move faces
  1113         // for Gill Sans into Gill Sans MT family
  1114         if (allUltraBold) {
  1116             // add faces to Gill Sans MT
  1117             for (i = 0; i < faces.Length(); i++) {
  1118                 gillSansMTFamily->AddFontEntry(faces[i]);
  1120 #ifdef PR_LOGGING
  1121                 if (LOG_FONTLIST_ENABLED()) {
  1122                     gfxFontEntry *fe = faces[i];
  1123                     LOG_FONTLIST(("(fontlist) moved (%s) to family (%s)"
  1124                          " with style: %s weight: %d stretch: %d",
  1125                          NS_ConvertUTF16toUTF8(fe->Name()).get(),
  1126                          NS_ConvertUTF16toUTF8(gillSansMTFamily->Name()).get(),
  1127                          (fe->IsItalic()) ? "italic" : "normal",
  1128                          fe->Weight(), fe->Stretch()));
  1130 #endif
  1133             // remove Gills Sans
  1134             mFontFamilies.Remove(nameGillSans);
  1138     nsAdoptingCString classicFamilies =
  1139         Preferences::GetCString("gfx.font_rendering.cleartype_params.force_gdi_classic_for_families");
  1140     if (classicFamilies) {
  1141         nsCCharSeparatedTokenizer tokenizer(classicFamilies, ',');
  1142         while (tokenizer.hasMoreTokens()) {
  1143             NS_ConvertUTF8toUTF16 name(tokenizer.nextToken());
  1144             BuildKeyNameFromFontName(name);
  1145             gfxFontFamily *family = mFontFamilies.GetWeak(name);
  1146             if (family) {
  1147                 static_cast<gfxDWriteFontFamily*>(family)->SetForceGDIClassic(true);
  1151     mForceGDIClassicMaxFontSize =
  1152         Preferences::GetInt("gfx.font_rendering.cleartype_params.force_gdi_classic_max_size",
  1153                             mForceGDIClassicMaxFontSize);
  1155     GetPrefsAndStartLoader();
  1157     LOGREGISTRY(L"DelayedInitFontList end");
  1159     QueryPerformanceCounter(&t3);
  1161     if (LOG_FONTINIT_ENABLED()) {
  1162         // determine dwrite version
  1163         nsAutoString dwriteVers;
  1164         gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers);
  1165         LOG_FONTINIT(("DelayedInitFontList\n"));
  1166         LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime));
  1167         LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000));
  1168         LOG_FONTINIT(("dwrite version: %s\n", 
  1169                       NS_ConvertUTF16toUTF8(dwriteVers).get()));
  1172     elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
  1173     Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_TOTAL, elapsedTime);
  1174     Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COUNT,
  1175                           systemFonts->GetFontFamilyCount());
  1176     Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_GDI_TABLE, mGDIFontTableAccess);
  1177     LOG_FONTINIT((
  1178        "Total time in DelayedInitFontList:    %9.3f ms (families: %d, %s)\n",
  1179        elapsedTime, systemFonts->GetFontFamilyCount(),
  1180        (mGDIFontTableAccess ? "gdi table access" : "dwrite table access")));
  1182     elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
  1183     Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COLLECT, elapsedTime);
  1184     LOG_FONTINIT((" --- GetSystemFontCollection:  %9.3f ms\n", elapsedTime));
  1186     elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
  1187     Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_ITERATE, elapsedTime);
  1188     LOG_FONTINIT((" --- iterate over families:    %9.3f ms\n", elapsedTime));
  1190     return NS_OK;
  1193 static void
  1194 RemoveCharsetFromFontSubstitute(nsAString &aName)
  1196     int32_t comma = aName.FindChar(char16_t(','));
  1197     if (comma >= 0)
  1198         aName.Truncate(comma);
  1201 #define MAX_VALUE_NAME 512
  1202 #define MAX_VALUE_DATA 512
  1204 nsresult
  1205 gfxDWriteFontList::GetFontSubstitutes()
  1207     HKEY hKey;
  1208     DWORD i, rv, lenAlias, lenActual, valueType;
  1209     WCHAR aliasName[MAX_VALUE_NAME];
  1210     WCHAR actualName[MAX_VALUE_DATA];
  1212     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, 
  1213           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
  1214           0, KEY_READ, &hKey) != ERROR_SUCCESS)
  1216         return NS_ERROR_FAILURE;
  1219     for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
  1220         aliasName[0] = 0;
  1221         lenAlias = ArrayLength(aliasName);
  1222         actualName[0] = 0;
  1223         lenActual = sizeof(actualName);
  1224         rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType,
  1225                 (LPBYTE)actualName, &lenActual);
  1227         if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
  1228             continue;
  1231         if (aliasName[0] == WCHAR('@')) {
  1232             continue;
  1235         nsAutoString substituteName((char16_t*) aliasName);
  1236         nsAutoString actualFontName((char16_t*) actualName);
  1237         RemoveCharsetFromFontSubstitute(substituteName);
  1238         BuildKeyNameFromFontName(substituteName);
  1239         RemoveCharsetFromFontSubstitute(actualFontName);
  1240         BuildKeyNameFromFontName(actualFontName);
  1241         gfxFontFamily *ff;
  1242         if (!actualFontName.IsEmpty() && 
  1243             (ff = mFontFamilies.GetWeak(actualFontName))) {
  1244             mFontSubstitutes.Put(substituteName, ff);
  1245         } else {
  1246             mNonExistingFonts.AppendElement(substituteName);
  1249     return NS_OK;
  1252 struct FontSubstitution {
  1253     const WCHAR* aliasName;
  1254     const WCHAR* actualName;
  1255 };
  1257 static const FontSubstitution sDirectWriteSubs[] = {
  1258     { L"MS Sans Serif", L"Microsoft Sans Serif" },
  1259     { L"MS Serif", L"Times New Roman" },
  1260     { L"Courier", L"Courier New" },
  1261     { L"Small Fonts", L"Arial" },
  1262     { L"Roman", L"Times New Roman" },
  1263     { L"Script", L"Mistral" }
  1264 };
  1266 void
  1267 gfxDWriteFontList::GetDirectWriteSubstitutes()
  1269     for (uint32_t i = 0; i < ArrayLength(sDirectWriteSubs); ++i) {
  1270         const FontSubstitution& sub(sDirectWriteSubs[i]);
  1271         nsAutoString substituteName((char16_t*)sub.aliasName);
  1272         BuildKeyNameFromFontName(substituteName);
  1273         if (nullptr != mFontFamilies.GetWeak(substituteName)) {
  1274             // don't do the substitution if user actually has a usable font
  1275             // with this name installed
  1276             continue;
  1278         nsAutoString actualFontName((char16_t*)sub.actualName);
  1279         BuildKeyNameFromFontName(actualFontName);
  1280         gfxFontFamily *ff;
  1281         if (nullptr != (ff = mFontFamilies.GetWeak(actualFontName))) {
  1282             mFontSubstitutes.Put(substituteName, ff);
  1283         } else {
  1284             mNonExistingFonts.AppendElement(substituteName);
  1289 bool
  1290 gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName,
  1291                                          nsAString& aFamilyName)
  1293     gfxFontFamily *family = FindFamily(aFontName);
  1294     if (family) {
  1295         family->LocalizedName(aFamilyName);
  1296         return true;
  1299     return false;
  1302 gfxFontFamily* gfxDWriteFontList::FindFamily(const nsAString& aFamily)
  1304     if (!mInitialized) {
  1305         mInitialized = true;
  1306         DelayedInitFontList();
  1309     return gfxPlatformFontList::FindFamily(aFamily);
  1312 void
  1313 gfxDWriteFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
  1315     if (!mInitialized) {
  1316         mInitialized = true;
  1317         DelayedInitFontList();
  1320     return gfxPlatformFontList::GetFontFamilyList(aFamilyArray);
  1323 bool 
  1324 gfxDWriteFontList::ResolveFontName(const nsAString& aFontName,
  1325                                    nsAString& aResolvedFontName)
  1327     if (!mInitialized) {
  1328         mInitialized = true;
  1329         DelayedInitFontList();
  1332     nsAutoString keyName(aFontName);
  1333     BuildKeyNameFromFontName(keyName);
  1335     gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
  1336     if (ff) {
  1337         aResolvedFontName = ff->Name();
  1338         return true;
  1341     if (mNonExistingFonts.Contains(keyName)) {
  1342         return false;
  1345     return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
  1348 void
  1349 gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
  1350                                           FontListSizes* aSizes) const
  1352     gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  1354     aSizes->mFontListSize +=
  1355         mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
  1356                                              aMallocSizeOf);
  1358     aSizes->mFontListSize +=
  1359         mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf);
  1360     for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
  1361         aSizes->mFontListSize +=
  1362             mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  1366 void
  1367 gfxDWriteFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
  1368                                           FontListSizes* aSizes) const
  1370     aSizes->mFontListSize += aMallocSizeOf(this);
  1371     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  1374 static HRESULT GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
  1376     HRESULT hr;
  1377     nsRefPtr<IDWriteFontFamily> family;
  1379     // clean out previous value
  1380     aFamilyName.Truncate();
  1382     hr = aFont->GetFontFamily(getter_AddRefs(family));
  1383     if (FAILED(hr)) {
  1384         return hr;
  1387     nsRefPtr<IDWriteLocalizedStrings> familyNames;
  1389     hr = family->GetFamilyNames(getter_AddRefs(familyNames));
  1390     if (FAILED(hr)) {
  1391         return hr;
  1394     UINT32 index = 0;
  1395     BOOL exists = false;
  1397     hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
  1398     if (FAILED(hr)) {
  1399         return hr;
  1402     // If the specified locale doesn't exist, select the first on the list.
  1403     if (!exists) {
  1404         index = 0;
  1407     AutoFallibleTArray<WCHAR, 32> name;
  1408     UINT32 length;
  1410     hr = familyNames->GetStringLength(index, &length);
  1411     if (FAILED(hr)) {
  1412         return hr;
  1415     if (!name.SetLength(length + 1)) {
  1416         return E_FAIL;
  1418     hr = familyNames->GetString(index, name.Elements(), length + 1);
  1419     if (FAILED(hr)) {
  1420         return hr;
  1423     aFamilyName.Assign(name.Elements());
  1424     return S_OK;
  1427 // bug 705594 - the method below doesn't actually do any "drawing", it's only
  1428 // used to invoke the DirectWrite layout engine to determine the fallback font
  1429 // for a given character.
  1431 IFACEMETHODIMP FontFallbackRenderer::DrawGlyphRun(
  1432     void* clientDrawingContext,
  1433     FLOAT baselineOriginX,
  1434     FLOAT baselineOriginY,
  1435     DWRITE_MEASURING_MODE measuringMode,
  1436     DWRITE_GLYPH_RUN const* glyphRun,
  1437     DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
  1438     IUnknown* clientDrawingEffect
  1441     if (!mSystemFonts) {
  1442         return E_FAIL;
  1445     HRESULT hr = S_OK;
  1447     nsRefPtr<IDWriteFont> font;
  1448     hr = mSystemFonts->GetFontFromFontFace(glyphRun->fontFace,
  1449                                            getter_AddRefs(font));
  1450     if (FAILED(hr)) {
  1451         return hr;
  1454     // copy the family name
  1455     hr = GetFamilyName(font, mFamilyName);
  1456     if (FAILED(hr)) {
  1457         return hr;
  1460     // Arial is used as the default fallback font
  1461     // so if it matches ==> no font found
  1462     if (mFamilyName.EqualsLiteral("Arial")) {
  1463         mFamilyName.Truncate();
  1464         return E_FAIL;
  1466     return hr;
  1469 gfxFontEntry*
  1470 gfxDWriteFontList::GlobalFontFallback(const uint32_t aCh,
  1471                                       int32_t aRunScript,
  1472                                       const gfxFontStyle* aMatchStyle,
  1473                                       uint32_t& aCmapCount,
  1474                                       gfxFontFamily** aMatchedFamily)
  1476     bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
  1478     if (useCmaps) {
  1479         return gfxPlatformFontList::GlobalFontFallback(aCh,
  1480                                                        aRunScript,
  1481                                                        aMatchStyle,
  1482                                                        aCmapCount,
  1483                                                        aMatchedFamily);
  1486     HRESULT hr;
  1488     nsRefPtr<IDWriteFactory> dwFactory =
  1489         gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
  1490     if (!dwFactory) {
  1491         return nullptr;
  1494     // initialize fallback renderer
  1495     if (!mFallbackRenderer) {
  1496         mFallbackRenderer = new FontFallbackRenderer(dwFactory);
  1499     // initialize text format
  1500     if (!mFallbackFormat) {
  1501         hr = dwFactory->CreateTextFormat(L"Arial", nullptr,
  1502                                          DWRITE_FONT_WEIGHT_REGULAR,
  1503                                          DWRITE_FONT_STYLE_NORMAL,
  1504                                          DWRITE_FONT_STRETCH_NORMAL,
  1505                                          72.0f, L"en-us",
  1506                                          getter_AddRefs(mFallbackFormat));
  1507         if (FAILED(hr)) {
  1508             return nullptr;
  1512     // set up string with fallback character
  1513     wchar_t str[16];
  1514     uint32_t strLen;
  1516     if (IS_IN_BMP(aCh)) {
  1517         str[0] = static_cast<wchar_t> (aCh);
  1518         str[1] = 0;
  1519         strLen = 1;
  1520     } else {
  1521         str[0] = static_cast<wchar_t> (H_SURROGATE(aCh));
  1522         str[1] = static_cast<wchar_t> (L_SURROGATE(aCh));
  1523         str[2] = 0;
  1524         strLen = 2;
  1527     // set up layout
  1528     nsRefPtr<IDWriteTextLayout> fallbackLayout;
  1530     hr = dwFactory->CreateTextLayout(str, strLen, mFallbackFormat,
  1531                                      200.0f, 200.0f,
  1532                                      getter_AddRefs(fallbackLayout));
  1533     if (FAILED(hr)) {
  1534         return nullptr;
  1537     // call the draw method to invoke the DirectWrite layout functions
  1538     // which determine the fallback font
  1539     hr = fallbackLayout->Draw(nullptr, mFallbackRenderer, 50.0f, 50.0f);
  1540     if (FAILED(hr)) {
  1541         return nullptr;
  1544     gfxFontFamily *family = FindFamily(mFallbackRenderer->FallbackFamilyName());
  1545     if (family) {
  1546         gfxFontEntry *fontEntry;
  1547         bool needsBold;  // ignored in the system fallback case
  1548         fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
  1549         if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
  1550             *aMatchedFamily = family;
  1551             return fontEntry;
  1553         Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
  1556     return nullptr;
  1559 // used to load system-wide font info on off-main thread
  1560 class DirectWriteFontInfo : public FontInfoData {
  1561 public:
  1562     DirectWriteFontInfo(bool aLoadOtherNames,
  1563                         bool aLoadFaceNames,
  1564                         bool aLoadCmaps) :
  1565         FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
  1566     {}
  1568     virtual ~DirectWriteFontInfo() {}
  1570     // loads font data for all members of a given family
  1571     virtual void LoadFontFamilyData(const nsAString& aFamilyName);
  1573     nsRefPtr<IDWriteFontCollection> mSystemFonts;
  1574 };
  1576 void
  1577 DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
  1579     // lookup the family
  1580     nsAutoTArray<wchar_t, 32> famName;
  1582     uint32_t len = aFamilyName.Length();
  1583     famName.SetLength(len + 1);
  1584     memcpy(famName.Elements(), aFamilyName.BeginReading(), len * sizeof(char16_t));
  1585     famName[len] = 0;
  1587     HRESULT hr;
  1588     BOOL exists = false;
  1590     uint32_t index;
  1591     hr = mSystemFonts->FindFamilyName(famName.Elements(), &index, &exists);
  1592     if (FAILED(hr) || !exists) {
  1593         return;
  1596     nsRefPtr<IDWriteFontFamily> family;
  1597     mSystemFonts->GetFontFamily(index, getter_AddRefs(family));
  1598     if (!family) {
  1599         return;
  1602     // later versions of DirectWrite support querying the fullname/psname
  1603     bool loadFaceNamesUsingDirectWrite = mLoadFaceNames;
  1605     for (uint32_t i = 0; i < family->GetFontCount(); i++) {
  1606         // get the font
  1607         nsRefPtr<IDWriteFont> dwFont;
  1608         hr = family->GetFont(i, getter_AddRefs(dwFont));
  1609         if (FAILED(hr)) {
  1610             // This should never happen.
  1611             NS_WARNING("Failed to get existing font from family.");
  1612             continue;
  1615         if (dwFont->GetSimulations() & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
  1616             // We don't want these.
  1617             continue;
  1620         mLoadStats.fonts++;
  1622         // get the name of the face
  1623         nsString fullID(aFamilyName);
  1624         nsAutoString fontName;
  1625         hr = GetDirectWriteFontName(dwFont, fontName);
  1626         if (FAILED(hr)) {
  1627             continue;
  1629         fullID.Append(NS_LITERAL_STRING(" "));
  1630         fullID.Append(fontName);
  1632         FontFaceData fontData;
  1633         bool haveData = true;
  1634         nsRefPtr<IDWriteFontFace> dwFontFace;
  1636         if (mLoadFaceNames) {
  1637             // try to load using DirectWrite first
  1638             if (loadFaceNamesUsingDirectWrite) {
  1639                 hr = GetDirectWriteFaceName(dwFont, PSNAME_ID, fontData.mPostscriptName);
  1640                 if (FAILED(hr)) {
  1641                     loadFaceNamesUsingDirectWrite = false;
  1643                 hr = GetDirectWriteFaceName(dwFont, FULLNAME_ID, fontData.mFullName);
  1644                 if (FAILED(hr)) {
  1645                     loadFaceNamesUsingDirectWrite = false;
  1649             // if DirectWrite read fails, load directly from name table
  1650             if (!loadFaceNamesUsingDirectWrite) {
  1651                 hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace));
  1652                 if (SUCCEEDED(hr)) {
  1653                     uint32_t kNAME =
  1654                         NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e'));
  1655                     const char *nameData;
  1656                     BOOL exists;
  1657                     void* ctx;
  1658                     uint32_t nameSize;
  1660                     hr = dwFontFace->TryGetFontTable(
  1661                              kNAME,
  1662                              (const void**)&nameData, &nameSize, &ctx, &exists);
  1664                     if (SUCCEEDED(hr) && nameData && nameSize > 0) {
  1665                         gfxFontUtils::ReadCanonicalName(nameData, nameSize,
  1666                             gfxFontUtils::NAME_ID_FULL,
  1667                             fontData.mFullName);
  1668                         gfxFontUtils::ReadCanonicalName(nameData, nameSize,
  1669                             gfxFontUtils::NAME_ID_POSTSCRIPT,
  1670                             fontData.mPostscriptName);
  1671                         dwFontFace->ReleaseFontTable(ctx);
  1676             haveData = !fontData.mPostscriptName.IsEmpty() ||
  1677                        !fontData.mFullName.IsEmpty();
  1678             if (haveData) {
  1679                 mLoadStats.facenames++;
  1683         // cmaps
  1684         if (mLoadCmaps) {
  1685             if (!dwFontFace) {
  1686                 hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace));
  1687                 if (!SUCCEEDED(hr)) {
  1688                     continue;
  1692             uint32_t kCMAP =
  1693                 NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p'));
  1694             const uint8_t *cmapData;
  1695             BOOL exists;
  1696             void* ctx;
  1697             uint32_t cmapSize;
  1699             hr = dwFontFace->TryGetFontTable(kCMAP,
  1700                      (const void**)&cmapData, &cmapSize, &ctx, &exists);
  1702             if (SUCCEEDED(hr)) {
  1703                 bool cmapLoaded = false;
  1704                 bool unicodeFont = false, symbolFont = false;
  1705                 nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
  1706                 uint32_t offset;
  1708                 if (cmapData &&
  1709                     cmapSize > 0 &&
  1710                     NS_SUCCEEDED(
  1711                         gfxFontUtils::ReadCMAP(cmapData, cmapSize, *charmap,
  1712                                                offset, unicodeFont, symbolFont))) {
  1713                     fontData.mCharacterMap = charmap;
  1714                     fontData.mUVSOffset = offset;
  1715                     fontData.mSymbolFont = symbolFont;
  1716                     cmapLoaded = true;
  1717                     mLoadStats.cmaps++;
  1719                 dwFontFace->ReleaseFontTable(ctx);
  1720                 haveData = haveData || cmapLoaded;
  1724         // if have data, load
  1725         if (haveData) {
  1726             mFontFaceData.Put(fullID, fontData);
  1731 already_AddRefed<FontInfoData>
  1732 gfxDWriteFontList::CreateFontInfoData()
  1734     bool loadCmaps = !UsesSystemFallback() ||
  1735         gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
  1737     nsRefPtr<DirectWriteFontInfo> fi =
  1738         new DirectWriteFontInfo(false, NeedFullnamePostscriptNames(), loadCmaps);
  1739     gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
  1740         GetSystemFontCollection(getter_AddRefs(fi->mSystemFonts));
  1742     return fi.forget();

mercurial