gfx/thebes/gfxDWriteFontList.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxDWriteFontList.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1743 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "mozilla/ArrayUtils.h"
    1.10 +#include "mozilla/MemoryReporting.h"
    1.11 +
    1.12 +#ifdef MOZ_LOGGING
    1.13 +#define FORCE_PR_LOG /* Allow logging in the release build */
    1.14 +#endif /* MOZ_LOGGING */
    1.15 +
    1.16 +#include "gfxDWriteFontList.h"
    1.17 +#include "gfxDWriteFonts.h"
    1.18 +#include "nsUnicharUtils.h"
    1.19 +#include "nsILocaleService.h"
    1.20 +#include "nsServiceManagerUtils.h"
    1.21 +#include "nsCharSeparatedTokenizer.h"
    1.22 +#include "mozilla/Preferences.h"
    1.23 +#include "mozilla/Telemetry.h"
    1.24 +
    1.25 +#include "gfxGDIFontList.h"
    1.26 +
    1.27 +#include "nsIWindowsRegKey.h"
    1.28 +
    1.29 +#include "harfbuzz/hb.h"
    1.30 +
    1.31 +using namespace mozilla;
    1.32 +
    1.33 +#define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
    1.34 +                               PR_LOG_DEBUG, args)
    1.35 +#define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
    1.36 +                                   gfxPlatform::GetLog(eGfxLog_fontlist), \
    1.37 +                                   PR_LOG_DEBUG)
    1.38 +
    1.39 +#define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
    1.40 +                               PR_LOG_DEBUG, args)
    1.41 +#define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
    1.42 +                                   gfxPlatform::GetLog(eGfxLog_fontinit), \
    1.43 +                                   PR_LOG_DEBUG)
    1.44 +
    1.45 +#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
    1.46 +                                   gfxPlatform::GetLog(eGfxLog_cmapdata), \
    1.47 +                                   PR_LOG_DEBUG)
    1.48 +
    1.49 +static __inline void
    1.50 +BuildKeyNameFromFontName(nsAString &aName)
    1.51 +{
    1.52 +    if (aName.Length() >= LF_FACESIZE)
    1.53 +        aName.Truncate(LF_FACESIZE - 1);
    1.54 +    ToLowerCase(aName);
    1.55 +}
    1.56 +
    1.57 +////////////////////////////////////////////////////////////////////////////////
    1.58 +// gfxDWriteFontFamily
    1.59 +
    1.60 +gfxDWriteFontFamily::~gfxDWriteFontFamily()
    1.61 +{
    1.62 +}
    1.63 +
    1.64 +static HRESULT
    1.65 +GetDirectWriteFontName(IDWriteFont *aFont, nsAString& aFontName)
    1.66 +{
    1.67 +    HRESULT hr;
    1.68 +
    1.69 +    nsRefPtr<IDWriteLocalizedStrings> names;
    1.70 +    hr = aFont->GetFaceNames(getter_AddRefs(names));
    1.71 +    if (FAILED(hr)) {
    1.72 +        return hr;
    1.73 +    }
    1.74 +
    1.75 +    BOOL exists;
    1.76 +    nsAutoTArray<wchar_t,32> faceName;
    1.77 +    UINT32 englishIdx = 0;
    1.78 +    hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
    1.79 +    if (FAILED(hr)) {
    1.80 +        return hr;
    1.81 +    }
    1.82 +
    1.83 +    if (!exists) {
    1.84 +        // No english found, use whatever is first in the list.
    1.85 +        englishIdx = 0;
    1.86 +    }
    1.87 +    UINT32 length;
    1.88 +    hr = names->GetStringLength(englishIdx, &length);
    1.89 +    if (FAILED(hr)) {
    1.90 +        return hr;
    1.91 +    }
    1.92 +    faceName.SetLength(length + 1);
    1.93 +    hr = names->GetString(englishIdx, faceName.Elements(), length + 1);
    1.94 +    if (FAILED(hr)) {
    1.95 +        return hr;
    1.96 +    }
    1.97 +
    1.98 +    aFontName.Assign(faceName.Elements());
    1.99 +    return S_OK;
   1.100 +}
   1.101 +
   1.102 +// These strings are only defined in Win SDK 8+, so use #ifdef for now
   1.103 +#if MOZ_WINSDK_TARGETVER > 0x08000000
   1.104 +#define FULLNAME_ID   DWRITE_INFORMATIONAL_STRING_FULL_NAME
   1.105 +#define PSNAME_ID     DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME
   1.106 +#else
   1.107 +#define FULLNAME_ID   DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 1)
   1.108 +#define PSNAME_ID     DWRITE_INFORMATIONAL_STRING_ID(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT + 2)
   1.109 +#endif
   1.110 +
   1.111 +// for use in reading postscript or fullname
   1.112 +static HRESULT
   1.113 +GetDirectWriteFaceName(IDWriteFont *aFont,
   1.114 +                       DWRITE_INFORMATIONAL_STRING_ID aWhichName,
   1.115 +                       nsAString& aFontName)
   1.116 +{
   1.117 +    HRESULT hr;
   1.118 +
   1.119 +    BOOL exists;
   1.120 +    nsRefPtr<IDWriteLocalizedStrings> infostrings;
   1.121 +    hr = aFont->GetInformationalStrings(aWhichName, getter_AddRefs(infostrings), &exists);
   1.122 +    if (FAILED(hr) || !exists) {
   1.123 +        return E_FAIL;
   1.124 +    }
   1.125 +
   1.126 +    nsAutoTArray<wchar_t,32> faceName;
   1.127 +    UINT32 englishIdx = 0;
   1.128 +    hr = infostrings->FindLocaleName(L"en-us", &englishIdx, &exists);
   1.129 +    if (FAILED(hr)) {
   1.130 +        return hr;
   1.131 +    }
   1.132 +
   1.133 +    if (!exists) {
   1.134 +        // No english found, use whatever is first in the list.
   1.135 +        englishIdx = 0;
   1.136 +    }
   1.137 +    UINT32 length;
   1.138 +    hr = infostrings->GetStringLength(englishIdx, &length);
   1.139 +    if (FAILED(hr)) {
   1.140 +        return hr;
   1.141 +    }
   1.142 +    faceName.SetLength(length + 1);
   1.143 +    hr = infostrings->GetString(englishIdx, faceName.Elements(), length + 1);
   1.144 +    if (FAILED(hr)) {
   1.145 +        return hr;
   1.146 +    }
   1.147 +
   1.148 +    aFontName.Assign(faceName.Elements());
   1.149 +    return S_OK;
   1.150 +}
   1.151 +
   1.152 +void
   1.153 +gfxDWriteFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
   1.154 +{
   1.155 +    HRESULT hr;
   1.156 +    if (mHasStyles) {
   1.157 +        return;
   1.158 +    }
   1.159 +    mHasStyles = true;
   1.160 +
   1.161 +    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
   1.162 +
   1.163 +    bool skipFaceNames = mFaceNamesInitialized ||
   1.164 +                         !fp->NeedFullnamePostscriptNames();
   1.165 +    bool fontInfoShouldHaveFaceNames = !mFaceNamesInitialized &&
   1.166 +                                       fp->NeedFullnamePostscriptNames() &&
   1.167 +                                       aFontInfoData;
   1.168 +
   1.169 +    for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) {
   1.170 +        nsRefPtr<IDWriteFont> font;
   1.171 +        hr = mDWFamily->GetFont(i, getter_AddRefs(font));
   1.172 +        if (FAILED(hr)) {
   1.173 +            // This should never happen.
   1.174 +            NS_WARNING("Failed to get existing font from family.");
   1.175 +            continue;
   1.176 +        }
   1.177 +
   1.178 +        if (font->GetSimulations() & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
   1.179 +            // We don't want these.
   1.180 +            continue;
   1.181 +        }
   1.182 +
   1.183 +        // name
   1.184 +        nsString fullID(mName);
   1.185 +        nsAutoString faceName;
   1.186 +        hr = GetDirectWriteFontName(font, faceName);
   1.187 +        if (FAILED(hr)) {
   1.188 +            continue;
   1.189 +        }
   1.190 +        fullID.Append(NS_LITERAL_STRING(" "));
   1.191 +        fullID.Append(faceName);
   1.192 +
   1.193 +        gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font);
   1.194 +        fe->SetForceGDIClassic(mForceGDIClassic);
   1.195 +        AddFontEntry(fe);
   1.196 +
   1.197 +        // postscript/fullname if needed
   1.198 +        nsAutoString psname, fullname;
   1.199 +        if (fontInfoShouldHaveFaceNames) {
   1.200 +            aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
   1.201 +            if (!fullname.IsEmpty()) {
   1.202 +                fp->AddFullname(fe, fullname);
   1.203 +            }
   1.204 +            if (!psname.IsEmpty()) {
   1.205 +                fp->AddPostscriptName(fe, psname);
   1.206 +            }
   1.207 +        } else if (!skipFaceNames) {
   1.208 +            hr = GetDirectWriteFaceName(font, PSNAME_ID, psname);
   1.209 +            if (FAILED(hr)) {
   1.210 +                skipFaceNames = true;
   1.211 +            } else if (psname.Length() > 0) {
   1.212 +                fp->AddPostscriptName(fe, psname);
   1.213 +            }
   1.214 +
   1.215 +            hr = GetDirectWriteFaceName(font, FULLNAME_ID, fullname);
   1.216 +            if (FAILED(hr)) {
   1.217 +                skipFaceNames = true;
   1.218 +            } else if (fullname.Length() > 0) {
   1.219 +                fp->AddFullname(fe, fullname);
   1.220 +            }
   1.221 +        }
   1.222 +
   1.223 +#ifdef PR_LOGGING
   1.224 +        if (LOG_FONTLIST_ENABLED()) {
   1.225 +            LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
   1.226 +                 " with style: %s weight: %d stretch: %d psname: %s fullname: %s",
   1.227 +                 NS_ConvertUTF16toUTF8(fe->Name()).get(),
   1.228 +                 NS_ConvertUTF16toUTF8(Name()).get(),
   1.229 +                 (fe->IsItalic()) ? "italic" : "normal",
   1.230 +                 fe->Weight(), fe->Stretch(),
   1.231 +                 NS_ConvertUTF16toUTF8(psname).get(),
   1.232 +                 NS_ConvertUTF16toUTF8(fullname).get()));
   1.233 +        }
   1.234 +#endif
   1.235 +    }
   1.236 +
   1.237 +    // assume that if no error, all postscript/fullnames were initialized
   1.238 +    if (!skipFaceNames) {
   1.239 +        mFaceNamesInitialized = true;
   1.240 +    }
   1.241 +
   1.242 +    if (!mAvailableFonts.Length()) {
   1.243 +        NS_WARNING("Family with no font faces in it.");
   1.244 +    }
   1.245 +
   1.246 +    if (mIsBadUnderlineFamily) {
   1.247 +        SetBadUnderlineFonts();
   1.248 +    }
   1.249 +}
   1.250 +
   1.251 +void
   1.252 +gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
   1.253 +                                   bool aNeedFullnamePostscriptNames)
   1.254 +{
   1.255 +    // if all needed names have already been read, skip
   1.256 +    if (mOtherFamilyNamesInitialized &&
   1.257 +        (mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
   1.258 +        return;
   1.259 +    }
   1.260 +
   1.261 +    // DirectWrite version of this will try to read
   1.262 +    // postscript/fullnames via DirectWrite API
   1.263 +    FindStyleVariations();
   1.264 +
   1.265 +    // fallback to looking up via name table
   1.266 +    if (!mOtherFamilyNamesInitialized || !mFaceNamesInitialized) {
   1.267 +        gfxFontFamily::ReadFaceNames(aPlatformFontList,
   1.268 +                                     aNeedFullnamePostscriptNames);
   1.269 +    }
   1.270 +}
   1.271 +
   1.272 +void
   1.273 +gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName)
   1.274 +{
   1.275 +    aLocalizedName.AssignLiteral("Unknown Font");
   1.276 +    HRESULT hr;
   1.277 +    nsresult rv;
   1.278 +    nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID,
   1.279 +                                                  &rv);
   1.280 +    nsCOMPtr<nsILocale> locale;
   1.281 +    rv = ls->GetApplicationLocale(getter_AddRefs(locale));
   1.282 +    nsString localeName;
   1.283 +    if (NS_SUCCEEDED(rv)) {
   1.284 +        rv = locale->GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), 
   1.285 +                                 localeName);
   1.286 +    }
   1.287 +    if (NS_FAILED(rv)) {
   1.288 +        localeName.AssignLiteral("en-us");
   1.289 +    }
   1.290 +
   1.291 +    nsRefPtr<IDWriteLocalizedStrings> names;
   1.292 +
   1.293 +    hr = mDWFamily->GetFamilyNames(getter_AddRefs(names));
   1.294 +    if (FAILED(hr)) {
   1.295 +        return;
   1.296 +    }
   1.297 +    UINT32 idx = 0;
   1.298 +    BOOL exists;
   1.299 +    hr = names->FindLocaleName(localeName.get(),
   1.300 +                               &idx,
   1.301 +                               &exists);
   1.302 +    if (FAILED(hr)) {
   1.303 +        return;
   1.304 +    }
   1.305 +    if (!exists) {
   1.306 +        // Use english is localized is not found.
   1.307 +        hr = names->FindLocaleName(L"en-us", &idx, &exists);
   1.308 +        if (FAILED(hr)) {
   1.309 +            return;
   1.310 +        }
   1.311 +        if (!exists) {
   1.312 +            // Use 0 index if english is not found.
   1.313 +            idx = 0;
   1.314 +        }
   1.315 +    }
   1.316 +    AutoFallibleTArray<WCHAR, 32> famName;
   1.317 +    UINT32 length;
   1.318 +    
   1.319 +    hr = names->GetStringLength(idx, &length);
   1.320 +    if (FAILED(hr)) {
   1.321 +        return;
   1.322 +    }
   1.323 +    
   1.324 +    if (!famName.SetLength(length + 1)) {
   1.325 +        // Eeep - running out of memory. Unlikely to end well.
   1.326 +        return;
   1.327 +    }
   1.328 +
   1.329 +    hr = names->GetString(idx, famName.Elements(), length + 1);
   1.330 +    if (FAILED(hr)) {
   1.331 +        return;
   1.332 +    }
   1.333 +
   1.334 +    aLocalizedName = nsDependentString(famName.Elements());
   1.335 +}
   1.336 +
   1.337 +void
   1.338 +gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
   1.339 +                                            FontListSizes* aSizes) const
   1.340 +{
   1.341 +    gfxFontFamily::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   1.342 +    // TODO:
   1.343 +    // This doesn't currently account for |mDWFamily|
   1.344 +}
   1.345 +
   1.346 +void
   1.347 +gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   1.348 +                                            FontListSizes* aSizes) const
   1.349 +{
   1.350 +    aSizes->mFontListSize += aMallocSizeOf(this);
   1.351 +    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   1.352 +}
   1.353 +
   1.354 +////////////////////////////////////////////////////////////////////////////////
   1.355 +// gfxDWriteFontEntry
   1.356 +
   1.357 +gfxDWriteFontEntry::~gfxDWriteFontEntry()
   1.358 +{
   1.359 +}
   1.360 +
   1.361 +bool
   1.362 +gfxDWriteFontEntry::IsSymbolFont()
   1.363 +{
   1.364 +    if (mFont) {
   1.365 +        return mFont->IsSymbolFont();
   1.366 +    } else {
   1.367 +        return false;
   1.368 +    }
   1.369 +}
   1.370 +
   1.371 +static bool
   1.372 +UsingArabicOrHebrewScriptSystemLocale()
   1.373 +{
   1.374 +    LANGID langid = PRIMARYLANGID(::GetSystemDefaultLangID());
   1.375 +    switch (langid) {
   1.376 +    case LANG_ARABIC:
   1.377 +    case LANG_DARI:
   1.378 +    case LANG_PASHTO:
   1.379 +    case LANG_PERSIAN:
   1.380 +    case LANG_SINDHI:
   1.381 +    case LANG_UIGHUR:
   1.382 +    case LANG_URDU:
   1.383 +    case LANG_HEBREW:
   1.384 +        return true;
   1.385 +    default:
   1.386 +        return false;
   1.387 +    }
   1.388 +}
   1.389 +
   1.390 +nsresult
   1.391 +gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag,
   1.392 +                                  FallibleTArray<uint8_t> &aBuffer)
   1.393 +{
   1.394 +    gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList();
   1.395 +
   1.396 +    // Don't use GDI table loading for symbol fonts or for
   1.397 +    // italic fonts in Arabic-script system locales because of
   1.398 +    // potential cmap discrepancies, see bug 629386.
   1.399 +    // Ditto for Hebrew, bug 837498.
   1.400 +    if (mFont && pFontList->UseGDIFontTableAccess() &&
   1.401 +        !(mItalic && UsingArabicOrHebrewScriptSystemLocale()) &&
   1.402 +        !mFont->IsSymbolFont())
   1.403 +    {
   1.404 +        LOGFONTW logfont = { 0 };
   1.405 +        if (!InitLogFont(mFont, &logfont))
   1.406 +            return NS_ERROR_FAILURE;
   1.407 +
   1.408 +        AutoDC dc;
   1.409 +        AutoSelectFont font(dc.GetDC(), &logfont);
   1.410 +        if (font.IsValid()) {
   1.411 +            uint32_t tableSize =
   1.412 +                ::GetFontData(dc.GetDC(),
   1.413 +                              NativeEndian::swapToBigEndian(aTableTag), 0,
   1.414 +                              nullptr, 0);
   1.415 +            if (tableSize != GDI_ERROR) {
   1.416 +                if (aBuffer.SetLength(tableSize)) {
   1.417 +                    ::GetFontData(dc.GetDC(),
   1.418 +                                  NativeEndian::swapToBigEndian(aTableTag), 0,
   1.419 +                                  aBuffer.Elements(), aBuffer.Length());
   1.420 +                    return NS_OK;
   1.421 +                }
   1.422 +                return NS_ERROR_OUT_OF_MEMORY;
   1.423 +            }
   1.424 +        }
   1.425 +        return NS_ERROR_FAILURE;
   1.426 +    }
   1.427 +
   1.428 +    nsRefPtr<IDWriteFontFace> fontFace;
   1.429 +    nsresult rv = CreateFontFace(getter_AddRefs(fontFace));
   1.430 +    if (NS_FAILED(rv)) {
   1.431 +        return rv;
   1.432 +    }
   1.433 +
   1.434 +    uint8_t *tableData;
   1.435 +    uint32_t len;
   1.436 +    void *tableContext = nullptr;
   1.437 +    BOOL exists;
   1.438 +    HRESULT hr =
   1.439 +        fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
   1.440 +                                  (const void**)&tableData, &len,
   1.441 +                                  &tableContext, &exists);
   1.442 +    if (FAILED(hr) || !exists) {
   1.443 +        return NS_ERROR_FAILURE;
   1.444 +    }
   1.445 +
   1.446 +    if (aBuffer.SetLength(len)) {
   1.447 +        memcpy(aBuffer.Elements(), tableData, len);
   1.448 +        rv = NS_OK;
   1.449 +    } else {
   1.450 +        rv = NS_ERROR_OUT_OF_MEMORY;
   1.451 +    }
   1.452 +
   1.453 +    if (tableContext) {
   1.454 +        fontFace->ReleaseFontTable(&tableContext);
   1.455 +    }
   1.456 +
   1.457 +    return rv;
   1.458 +}
   1.459 +
   1.460 +// Access to font tables packaged in hb_blob_t form
   1.461 +
   1.462 +// object attached to the Harfbuzz blob, used to release
   1.463 +// the table when the blob is destroyed
   1.464 +class FontTableRec {
   1.465 +public:
   1.466 +    FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
   1.467 +        : mFontFace(aFontFace), mContext(aContext)
   1.468 +    { }
   1.469 +
   1.470 +    ~FontTableRec() {
   1.471 +        mFontFace->ReleaseFontTable(mContext);
   1.472 +    }
   1.473 +
   1.474 +private:
   1.475 +    nsRefPtr<IDWriteFontFace> mFontFace;
   1.476 +    void            *mContext;
   1.477 +};
   1.478 +
   1.479 +static void
   1.480 +DestroyBlobFunc(void* aUserData)
   1.481 +{
   1.482 +    FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
   1.483 +    delete ftr;
   1.484 +}
   1.485 +
   1.486 +hb_blob_t *
   1.487 +gfxDWriteFontEntry::GetFontTable(uint32_t aTag)
   1.488 +{
   1.489 +    // try to avoid potentially expensive DWrite call if we haven't actually
   1.490 +    // created the font face yet, by using the gfxFontEntry method that will
   1.491 +    // use CopyFontTable and then cache the data
   1.492 +    if (!mFontFace) {
   1.493 +        return gfxFontEntry::GetFontTable(aTag);
   1.494 +    }
   1.495 +
   1.496 +    const void *data;
   1.497 +    UINT32      size;
   1.498 +    void       *context;
   1.499 +    BOOL        exists;
   1.500 +    HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
   1.501 +                                            &data, &size, &context, &exists);
   1.502 +    if (SUCCEEDED(hr) && exists) {
   1.503 +        FontTableRec *ftr = new FontTableRec(mFontFace, context);
   1.504 +        return hb_blob_create(static_cast<const char*>(data), size,
   1.505 +                              HB_MEMORY_MODE_READONLY,
   1.506 +                              ftr, DestroyBlobFunc);
   1.507 +    }
   1.508 +
   1.509 +    return nullptr;
   1.510 +}
   1.511 +
   1.512 +nsresult
   1.513 +gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
   1.514 +{
   1.515 +    // attempt this once, if errors occur leave a blank cmap
   1.516 +    if (mCharacterMap) {
   1.517 +        return NS_OK;
   1.518 +    }
   1.519 +
   1.520 +    nsRefPtr<gfxCharacterMap> charmap;
   1.521 +    nsresult rv;
   1.522 +    bool symbolFont;
   1.523 +
   1.524 +    if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
   1.525 +                                                        mUVSOffset,
   1.526 +                                                        symbolFont))) {
   1.527 +        rv = NS_OK;
   1.528 +    } else {
   1.529 +        uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
   1.530 +        charmap = new gfxCharacterMap();
   1.531 +        AutoTable cmapTable(this, kCMAP);
   1.532 +
   1.533 +        if (cmapTable) {
   1.534 +            bool unicodeFont = false, symbolFont = false; // currently ignored
   1.535 +            uint32_t cmapLen;
   1.536 +            const uint8_t* cmapData =
   1.537 +                reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
   1.538 +                                                                  &cmapLen));
   1.539 +            rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
   1.540 +                                        *charmap, mUVSOffset,
   1.541 +                                        unicodeFont, symbolFont);
   1.542 +        } else {
   1.543 +            rv = NS_ERROR_NOT_AVAILABLE;
   1.544 +        }
   1.545 +    }
   1.546 +
   1.547 +    mHasCmapTable = NS_SUCCEEDED(rv);
   1.548 +    if (mHasCmapTable) {
   1.549 +        // Bug 969504: exclude U+25B6 from Segoe UI family, because it's used
   1.550 +        // by sites to represent a "Play" icon, but the glyph in Segoe UI Light
   1.551 +        // and Semibold on Windows 7 is too thin. (Ditto for leftward U+25C0.)
   1.552 +        // Fallback to Segoe UI Symbol is preferred.
   1.553 +        if (FamilyName().EqualsLiteral("Segoe UI")) {
   1.554 +            charmap->clear(0x25b6);
   1.555 +            charmap->clear(0x25c0);
   1.556 +        }
   1.557 +        gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
   1.558 +        mCharacterMap = pfl->FindCharMap(charmap);
   1.559 +    } else {
   1.560 +        // if error occurred, initialize to null cmap
   1.561 +        mCharacterMap = new gfxCharacterMap();
   1.562 +    }
   1.563 +
   1.564 +#ifdef PR_LOGGING
   1.565 +    LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
   1.566 +                  NS_ConvertUTF16toUTF8(mName).get(),
   1.567 +                  charmap->SizeOfIncludingThis(moz_malloc_size_of),
   1.568 +                  charmap->mHash, mCharacterMap == charmap ? " new" : ""));
   1.569 +    if (LOG_CMAPDATA_ENABLED()) {
   1.570 +        char prefix[256];
   1.571 +        sprintf(prefix, "(cmapdata) name: %.220s",
   1.572 +                NS_ConvertUTF16toUTF8(mName).get());
   1.573 +        charmap->Dump(prefix, eGfxLog_cmapdata);
   1.574 +    }
   1.575 +#endif
   1.576 +
   1.577 +    return rv;
   1.578 +}
   1.579 +
   1.580 +gfxFont *
   1.581 +gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle,
   1.582 +                                       bool aNeedsBold)
   1.583 +{
   1.584 +    return new gfxDWriteFont(this, aFontStyle, aNeedsBold);
   1.585 +}
   1.586 +
   1.587 +nsresult
   1.588 +gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
   1.589 +                                   DWRITE_FONT_SIMULATIONS aSimulations)
   1.590 +{
   1.591 +    // initialize mFontFace if this hasn't been done before
   1.592 +    if (!mFontFace) {
   1.593 +        HRESULT hr;
   1.594 +        if (mFont) {
   1.595 +            hr = mFont->CreateFontFace(getter_AddRefs(mFontFace));
   1.596 +        } else if (mFontFile) {
   1.597 +            IDWriteFontFile *fontFile = mFontFile.get();
   1.598 +            hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   1.599 +                CreateFontFace(mFaceType,
   1.600 +                               1,
   1.601 +                               &fontFile,
   1.602 +                               0,
   1.603 +                               DWRITE_FONT_SIMULATIONS_NONE,
   1.604 +                               getter_AddRefs(mFontFace));
   1.605 +        } else {
   1.606 +            NS_NOTREACHED("invalid font entry");
   1.607 +            return NS_ERROR_FAILURE;
   1.608 +        }
   1.609 +        if (FAILED(hr)) {
   1.610 +            return NS_ERROR_FAILURE;
   1.611 +        }
   1.612 +    }
   1.613 +
   1.614 +    // check whether we need to add a DWrite simulated style
   1.615 +    if ((aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
   1.616 +        !(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
   1.617 +        // if so, we need to return not mFontFace itself but a version that
   1.618 +        // has the Bold simulation - unfortunately, DWrite doesn't provide
   1.619 +        // a simple API for this
   1.620 +        UINT32 numberOfFiles = 0;
   1.621 +        if (FAILED(mFontFace->GetFiles(&numberOfFiles, nullptr))) {
   1.622 +            return NS_ERROR_FAILURE;
   1.623 +        }
   1.624 +        nsAutoTArray<IDWriteFontFile*,1> files;
   1.625 +        files.AppendElements(numberOfFiles);
   1.626 +        if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) {
   1.627 +            return NS_ERROR_FAILURE;
   1.628 +        }
   1.629 +        HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   1.630 +            CreateFontFace(mFontFace->GetType(),
   1.631 +                           numberOfFiles,
   1.632 +                           files.Elements(),
   1.633 +                           mFontFace->GetIndex(),
   1.634 +                           aSimulations,
   1.635 +                           aFontFace);
   1.636 +        for (UINT32 i = 0; i < numberOfFiles; ++i) {
   1.637 +            files[i]->Release();
   1.638 +        }
   1.639 +        return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
   1.640 +    }
   1.641 +
   1.642 +    // no simulation: we can just add a reference to mFontFace and return that
   1.643 +    *aFontFace = mFontFace;
   1.644 +    (*aFontFace)->AddRef();
   1.645 +    return NS_OK;
   1.646 +}
   1.647 +
   1.648 +bool
   1.649 +gfxDWriteFontEntry::InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont)
   1.650 +{
   1.651 +    HRESULT hr;
   1.652 +
   1.653 +    BOOL isInSystemCollection;
   1.654 +    IDWriteGdiInterop *gdi = 
   1.655 +        gfxDWriteFontList::PlatformFontList()->GetGDIInterop();
   1.656 +    hr = gdi->ConvertFontToLOGFONT(aFont, aLogFont, &isInSystemCollection);
   1.657 +    return (FAILED(hr) ? false : true);
   1.658 +}
   1.659 +
   1.660 +bool
   1.661 +gfxDWriteFontEntry::IsCJKFont()
   1.662 +{
   1.663 +    if (mIsCJK != UNINITIALIZED_VALUE) {
   1.664 +        return mIsCJK;
   1.665 +    }
   1.666 +
   1.667 +    mIsCJK = false;
   1.668 +
   1.669 +    const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
   1.670 +    AutoFallibleTArray<uint8_t,128> buffer;
   1.671 +    if (CopyFontTable(kOS2Tag, buffer) != NS_OK) {
   1.672 +        return mIsCJK;
   1.673 +    }
   1.674 +
   1.675 +    // ulCodePageRange bit definitions for the CJK codepages,
   1.676 +    // from http://www.microsoft.com/typography/otspec/os2.htm#cpr
   1.677 +    const uint32_t CJK_CODEPAGE_BITS =
   1.678 +        (1 << 17) | // codepage 932 - JIS/Japan
   1.679 +        (1 << 18) | // codepage 936 - Chinese (simplified)
   1.680 +        (1 << 19) | // codepage 949 - Korean Wansung
   1.681 +        (1 << 20) | // codepage 950 - Chinese (traditional)
   1.682 +        (1 << 21);  // codepage 1361 - Korean Johab
   1.683 +
   1.684 +    if (buffer.Length() >= offsetof(OS2Table, sxHeight)) {
   1.685 +        const OS2Table* os2 =
   1.686 +            reinterpret_cast<const OS2Table*>(buffer.Elements());
   1.687 +        if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) {
   1.688 +            mIsCJK = true;
   1.689 +        }
   1.690 +    }
   1.691 +
   1.692 +    return mIsCJK;
   1.693 +}
   1.694 +
   1.695 +void
   1.696 +gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
   1.697 +                                           FontListSizes* aSizes) const
   1.698 +{
   1.699 +    gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   1.700 +    // TODO:
   1.701 +    // This doesn't currently account for the |mFont| and |mFontFile| members
   1.702 +}
   1.703 +
   1.704 +void
   1.705 +gfxDWriteFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
   1.706 +                                           FontListSizes* aSizes) const
   1.707 +{
   1.708 +    aSizes->mFontListSize += aMallocSizeOf(this);
   1.709 +    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   1.710 +}
   1.711 +
   1.712 +////////////////////////////////////////////////////////////////////////////////
   1.713 +// gfxDWriteFontList
   1.714 +
   1.715 +gfxDWriteFontList::gfxDWriteFontList()
   1.716 +    : mInitialized(false), mForceGDIClassicMaxFontSize(0.0)
   1.717 +{
   1.718 +}
   1.719 +
   1.720 +// bug 602792 - CJK systems default to large CJK fonts which cause excessive
   1.721 +//   I/O strain during cold startup due to dwrite caching bugs.  Default to
   1.722 +//   Arial to avoid this.
   1.723 +
   1.724 +gfxFontFamily *
   1.725 +gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle)
   1.726 +{
   1.727 +    nsAutoString resolvedName;
   1.728 +
   1.729 +    // try Arial first
   1.730 +    if (ResolveFontName(NS_LITERAL_STRING("Arial"), resolvedName)) {
   1.731 +        return FindFamily(resolvedName);
   1.732 +    }
   1.733 +
   1.734 +    // otherwise, use local default
   1.735 +    NONCLIENTMETRICSW ncm;
   1.736 +    ncm.cbSize = sizeof(ncm);
   1.737 +    BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 
   1.738 +                                          sizeof(ncm), &ncm, 0);
   1.739 +    if (status) {
   1.740 +        if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName),
   1.741 +                            resolvedName)) {
   1.742 +            return FindFamily(resolvedName);
   1.743 +        }
   1.744 +    }
   1.745 +
   1.746 +    return nullptr;
   1.747 +}
   1.748 +
   1.749 +gfxFontEntry *
   1.750 +gfxDWriteFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
   1.751 +                                   const nsAString& aFullname)
   1.752 +{
   1.753 +    gfxFontEntry *lookup;
   1.754 +
   1.755 +    lookup = LookupInFaceNameLists(aFullname);
   1.756 +    if (!lookup) {
   1.757 +        return nullptr;
   1.758 +    }
   1.759 +
   1.760 +    gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
   1.761 +    gfxDWriteFontEntry *fe =
   1.762 +        new gfxDWriteFontEntry(lookup->Name(),
   1.763 +                               dwriteLookup->mFont,
   1.764 +                               aProxyEntry->Weight(),
   1.765 +                               aProxyEntry->Stretch(),
   1.766 +                               aProxyEntry->IsItalic());
   1.767 +    fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic());
   1.768 +    return fe;
   1.769 +}
   1.770 +
   1.771 +gfxFontEntry *
   1.772 +gfxDWriteFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
   1.773 +                                    const uint8_t *aFontData,
   1.774 +                                    uint32_t aLength)
   1.775 +{
   1.776 +    nsresult rv;
   1.777 +    nsAutoString uniqueName;
   1.778 +    rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
   1.779 +    if (NS_FAILED(rv)) {
   1.780 +        NS_Free((void*)aFontData);
   1.781 +        return nullptr;
   1.782 +    }
   1.783 +
   1.784 +    FallibleTArray<uint8_t> newFontData;
   1.785 +
   1.786 +    rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
   1.787 +    NS_Free((void*)aFontData);
   1.788 +
   1.789 +    if (NS_FAILED(rv)) {
   1.790 +        return nullptr;
   1.791 +    }
   1.792 +    
   1.793 +    nsRefPtr<IDWriteFontFile> fontFile;
   1.794 +    HRESULT hr;
   1.795 +
   1.796 +    /**
   1.797 +     * We pass in a pointer to a structure containing a pointer to the array
   1.798 +     * containing the font data and a unique identifier. DWrite will
   1.799 +     * internally copy what is at that pointer, and pass that to
   1.800 +     * CreateStreamFromKey. The array will be empty when the function 
   1.801 +     * succesfully returns since it swaps out the data.
   1.802 +     */
   1.803 +    ffReferenceKey key;
   1.804 +    key.mArray = &newFontData;
   1.805 +    nsCOMPtr<nsIUUIDGenerator> uuidgen =
   1.806 +      do_GetService("@mozilla.org/uuid-generator;1");
   1.807 +    if (!uuidgen) {
   1.808 +        return nullptr;
   1.809 +    }
   1.810 +
   1.811 +    rv = uuidgen->GenerateUUIDInPlace(&key.mGUID);
   1.812 +
   1.813 +    if (NS_FAILED(rv)) {
   1.814 +        return nullptr;
   1.815 +    }
   1.816 +
   1.817 +    hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   1.818 +        CreateCustomFontFileReference(&key,
   1.819 +                                      sizeof(key),
   1.820 +                                      gfxDWriteFontFileLoader::Instance(),
   1.821 +                                      getter_AddRefs(fontFile));
   1.822 +
   1.823 +    if (FAILED(hr)) {
   1.824 +        NS_WARNING("Failed to create custom font file reference.");
   1.825 +        return nullptr;
   1.826 +    }
   1.827 +
   1.828 +    BOOL isSupported;
   1.829 +    DWRITE_FONT_FILE_TYPE fileType;
   1.830 +    UINT32 numFaces;
   1.831 +
   1.832 +    gfxDWriteFontEntry *entry = 
   1.833 +        new gfxDWriteFontEntry(uniqueName, 
   1.834 +                               fontFile,
   1.835 +                               aProxyEntry->Weight(),
   1.836 +                               aProxyEntry->Stretch(),
   1.837 +                               aProxyEntry->IsItalic());
   1.838 +
   1.839 +    fontFile->Analyze(&isSupported, &fileType, &entry->mFaceType, &numFaces);
   1.840 +    if (!isSupported || numFaces > 1) {
   1.841 +        // We don't know how to deal with 0 faces either.
   1.842 +        delete entry;
   1.843 +        return nullptr;
   1.844 +    }
   1.845 +
   1.846 +    return entry;
   1.847 +}
   1.848 +
   1.849 +#ifdef DEBUG_DWRITE_STARTUP
   1.850 +
   1.851 +#define LOGREGISTRY(msg) LogRegistryEvent(msg)
   1.852 +
   1.853 +// for use when monitoring process
   1.854 +static void LogRegistryEvent(const wchar_t *msg)
   1.855 +{
   1.856 +    HKEY dummyKey;
   1.857 +    HRESULT hr;
   1.858 +    wchar_t buf[512];
   1.859 +
   1.860 +    wsprintfW(buf, L" log %s", msg);
   1.861 +    hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
   1.862 +    if (SUCCEEDED(hr)) {
   1.863 +        RegCloseKey(dummyKey);
   1.864 +    }
   1.865 +}
   1.866 +#else
   1.867 +
   1.868 +#define LOGREGISTRY(msg)
   1.869 +
   1.870 +#endif
   1.871 +
   1.872 +nsresult
   1.873 +gfxDWriteFontList::InitFontList()
   1.874 +{
   1.875 +    LOGREGISTRY(L"InitFontList start");
   1.876 +
   1.877 +    mInitialized = false;
   1.878 +
   1.879 +    LARGE_INTEGER frequency;        // ticks per second
   1.880 +    LARGE_INTEGER t1, t2, t3;           // ticks
   1.881 +    double elapsedTime, upTime;
   1.882 +    char nowTime[256], nowDate[256];
   1.883 +
   1.884 +    if (LOG_FONTINIT_ENABLED()) {    
   1.885 +        GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, 
   1.886 +                      nullptr, nullptr, nowTime, 256);
   1.887 +        GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256);
   1.888 +    }
   1.889 +    upTime = (double) GetTickCount();
   1.890 +    QueryPerformanceFrequency(&frequency);
   1.891 +    QueryPerformanceCounter(&t1);
   1.892 +
   1.893 +    HRESULT hr;
   1.894 +    gfxFontCache *fc = gfxFontCache::GetCache();
   1.895 +    if (fc) {
   1.896 +        fc->AgeAllGenerations();
   1.897 +    }
   1.898 +
   1.899 +    mGDIFontTableAccess = Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading", false);
   1.900 +
   1.901 +    gfxPlatformFontList::InitFontList();
   1.902 +
   1.903 +    mFontSubstitutes.Clear();
   1.904 +    mNonExistingFonts.Clear();
   1.905 +
   1.906 +    QueryPerformanceCounter(&t2);
   1.907 +
   1.908 +    hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   1.909 +        GetGdiInterop(getter_AddRefs(mGDIInterop));
   1.910 +    if (FAILED(hr)) {
   1.911 +        return NS_ERROR_FAILURE;
   1.912 +    }
   1.913 +
   1.914 +    LOGREGISTRY(L"InitFontList end");
   1.915 +
   1.916 +    QueryPerformanceCounter(&t3);
   1.917 +
   1.918 +    if (LOG_FONTINIT_ENABLED()) {
   1.919 +        // determine dwrite version
   1.920 +        nsAutoString dwriteVers;
   1.921 +        gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers);
   1.922 +        LOG_FONTINIT(("InitFontList\n"));
   1.923 +        LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime));
   1.924 +        LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000));
   1.925 +        LOG_FONTINIT(("dwrite version: %s\n", 
   1.926 +                      NS_ConvertUTF16toUTF8(dwriteVers).get()));
   1.927 +    }
   1.928 +
   1.929 +    elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
   1.930 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_TOTAL, elapsedTime);
   1.931 +    LOG_FONTINIT(("Total time in InitFontList:    %9.3f ms\n", elapsedTime));
   1.932 +    elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
   1.933 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_INIT, elapsedTime);
   1.934 +    LOG_FONTINIT((" --- gfxPlatformFontList init: %9.3f ms\n", elapsedTime));
   1.935 +    elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
   1.936 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_INITFONTLIST_GDI, elapsedTime);
   1.937 +    LOG_FONTINIT((" --- GdiInterop object:        %9.3f ms\n", elapsedTime));
   1.938 +
   1.939 +    return NS_OK;
   1.940 +}
   1.941 +
   1.942 +nsresult
   1.943 +gfxDWriteFontList::DelayedInitFontList()
   1.944 +{
   1.945 +    LOGREGISTRY(L"DelayedInitFontList start");
   1.946 +
   1.947 +    LARGE_INTEGER frequency;        // ticks per second
   1.948 +    LARGE_INTEGER t1, t2, t3;           // ticks
   1.949 +    double elapsedTime, upTime;
   1.950 +    char nowTime[256], nowDate[256];
   1.951 +
   1.952 +    if (LOG_FONTINIT_ENABLED()) {    
   1.953 +        GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, 
   1.954 +                      nullptr, nullptr, nowTime, 256);
   1.955 +        GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256);
   1.956 +    }
   1.957 +
   1.958 +    upTime = (double) GetTickCount();
   1.959 +    QueryPerformanceFrequency(&frequency);
   1.960 +    QueryPerformanceCounter(&t1);
   1.961 +
   1.962 +    HRESULT hr;
   1.963 +
   1.964 +    LOGREGISTRY(L"calling GetSystemFontCollection");
   1.965 +    nsRefPtr<IDWriteFontCollection> systemFonts;
   1.966 +    hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
   1.967 +        GetSystemFontCollection(getter_AddRefs(systemFonts));
   1.968 +    NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
   1.969 +    LOGREGISTRY(L"GetSystemFontCollection done");
   1.970 +
   1.971 +    if (FAILED(hr)) {
   1.972 +        return NS_ERROR_FAILURE;
   1.973 +    }
   1.974 +
   1.975 +    QueryPerformanceCounter(&t2);
   1.976 +
   1.977 +    for (UINT32 i = 0; i < systemFonts->GetFontFamilyCount(); i++) {
   1.978 +        nsRefPtr<IDWriteFontFamily> family;
   1.979 +        systemFonts->GetFontFamily(i, getter_AddRefs(family));
   1.980 +
   1.981 +        nsRefPtr<IDWriteLocalizedStrings> names;
   1.982 +        hr = family->GetFamilyNames(getter_AddRefs(names));
   1.983 +        if (FAILED(hr)) {
   1.984 +            continue;
   1.985 +        }
   1.986 +
   1.987 +        UINT32 englishIdx = 0;
   1.988 +
   1.989 +        BOOL exists;
   1.990 +        hr = names->FindLocaleName(L"en-us", &englishIdx, &exists);
   1.991 +        if (FAILED(hr)) {
   1.992 +            continue;
   1.993 +        }
   1.994 +        if (!exists) {
   1.995 +            // Use 0 index if english is not found.
   1.996 +            englishIdx = 0;
   1.997 +        }
   1.998 +
   1.999 +        AutoFallibleTArray<WCHAR, 32> enName;
  1.1000 +        UINT32 length;
  1.1001 +        
  1.1002 +        hr = names->GetStringLength(englishIdx, &length);
  1.1003 +        if (FAILED(hr)) {
  1.1004 +            continue;
  1.1005 +        }
  1.1006 +        
  1.1007 +        if (!enName.SetLength(length + 1)) {
  1.1008 +            // Eeep - running out of memory. Unlikely to end well.
  1.1009 +            continue;
  1.1010 +        }
  1.1011 +
  1.1012 +        hr = names->GetString(englishIdx, enName.Elements(), length + 1);
  1.1013 +        if (FAILED(hr)) {
  1.1014 +            continue;
  1.1015 +        }
  1.1016 +
  1.1017 +        nsAutoString name(enName.Elements());
  1.1018 +        BuildKeyNameFromFontName(name);
  1.1019 +
  1.1020 +        nsRefPtr<gfxFontFamily> fam;
  1.1021 +
  1.1022 +        if (mFontFamilies.GetWeak(name)) {
  1.1023 +            continue;
  1.1024 +        }
  1.1025 +        
  1.1026 +        nsDependentString familyName(enName.Elements());
  1.1027 +
  1.1028 +        fam = new gfxDWriteFontFamily(familyName, family);
  1.1029 +        if (!fam) {
  1.1030 +            continue;
  1.1031 +        }
  1.1032 +
  1.1033 +        if (mBadUnderlineFamilyNames.Contains(name)) {
  1.1034 +            fam->SetBadUnderlineFamily();
  1.1035 +        }
  1.1036 +        mFontFamilies.Put(name, fam);
  1.1037 +
  1.1038 +        // now add other family name localizations, if present
  1.1039 +        uint32_t nameCount = names->GetCount();
  1.1040 +        uint32_t nameIndex;
  1.1041 +
  1.1042 +        for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
  1.1043 +            UINT32 nameLen;
  1.1044 +            AutoFallibleTArray<WCHAR, 32> localizedName;
  1.1045 +
  1.1046 +            // only add other names
  1.1047 +            if (nameIndex == englishIdx) {
  1.1048 +                continue;
  1.1049 +            }
  1.1050 +            
  1.1051 +            hr = names->GetStringLength(nameIndex, &nameLen);
  1.1052 +            if (FAILED(hr)) {
  1.1053 +                continue;
  1.1054 +            }
  1.1055 +
  1.1056 +            if (!localizedName.SetLength(nameLen + 1)) {
  1.1057 +                continue;
  1.1058 +            }
  1.1059 +
  1.1060 +            hr = names->GetString(nameIndex, localizedName.Elements(), 
  1.1061 +                                  nameLen + 1);
  1.1062 +            if (FAILED(hr)) {
  1.1063 +                continue;
  1.1064 +            }
  1.1065 +
  1.1066 +            nsDependentString locName(localizedName.Elements());
  1.1067 +
  1.1068 +            if (!familyName.Equals(locName)) {
  1.1069 +                AddOtherFamilyName(fam, locName);
  1.1070 +            }
  1.1071 +
  1.1072 +        }
  1.1073 +
  1.1074 +        // at this point, all family names have been read in
  1.1075 +        fam->SetOtherFamilyNamesInitialized();
  1.1076 +    }
  1.1077 +
  1.1078 +    mOtherFamilyNamesInitialized = true;
  1.1079 +    GetFontSubstitutes();
  1.1080 +
  1.1081 +    // bug 642093 - DirectWrite does not support old bitmap (.fon)
  1.1082 +    // font files, but a few of these such as "Courier" and "MS Sans Serif"
  1.1083 +    // are frequently specified in shoddy CSS, without appropriate fallbacks.
  1.1084 +    // By mapping these to TrueType equivalents, we provide better consistency
  1.1085 +    // with both pre-DW systems and with IE9, which appears to do the same.
  1.1086 +    GetDirectWriteSubstitutes();
  1.1087 +
  1.1088 +    // bug 551313 - DirectWrite creates a Gill Sans family out of 
  1.1089 +    // poorly named members of the Gill Sans MT family containing
  1.1090 +    // only Ultra Bold weights.  This causes big problems for pages
  1.1091 +    // using Gill Sans which is usually only available on OSX
  1.1092 +
  1.1093 +    nsAutoString nameGillSans(L"Gill Sans");
  1.1094 +    nsAutoString nameGillSansMT(L"Gill Sans MT");
  1.1095 +    BuildKeyNameFromFontName(nameGillSans);
  1.1096 +    BuildKeyNameFromFontName(nameGillSansMT);
  1.1097 +
  1.1098 +    gfxFontFamily *gillSansFamily = mFontFamilies.GetWeak(nameGillSans);
  1.1099 +    gfxFontFamily *gillSansMTFamily = mFontFamilies.GetWeak(nameGillSansMT);
  1.1100 +
  1.1101 +    if (gillSansFamily && gillSansMTFamily) {
  1.1102 +        gillSansFamily->FindStyleVariations();
  1.1103 +        nsTArray<nsRefPtr<gfxFontEntry> >& faces = gillSansFamily->GetFontList();
  1.1104 +        uint32_t i;
  1.1105 +
  1.1106 +        bool allUltraBold = true;
  1.1107 +        for (i = 0; i < faces.Length(); i++) {
  1.1108 +            // does the face have 'Ultra Bold' in the name?
  1.1109 +            if (faces[i]->Name().Find(NS_LITERAL_STRING("Ultra Bold")) == -1) {
  1.1110 +                allUltraBold = false;
  1.1111 +                break;
  1.1112 +            }
  1.1113 +        }
  1.1114 +
  1.1115 +        // if all the Gill Sans faces are Ultra Bold ==> move faces
  1.1116 +        // for Gill Sans into Gill Sans MT family
  1.1117 +        if (allUltraBold) {
  1.1118 +
  1.1119 +            // add faces to Gill Sans MT
  1.1120 +            for (i = 0; i < faces.Length(); i++) {
  1.1121 +                gillSansMTFamily->AddFontEntry(faces[i]);
  1.1122 +
  1.1123 +#ifdef PR_LOGGING
  1.1124 +                if (LOG_FONTLIST_ENABLED()) {
  1.1125 +                    gfxFontEntry *fe = faces[i];
  1.1126 +                    LOG_FONTLIST(("(fontlist) moved (%s) to family (%s)"
  1.1127 +                         " with style: %s weight: %d stretch: %d",
  1.1128 +                         NS_ConvertUTF16toUTF8(fe->Name()).get(),
  1.1129 +                         NS_ConvertUTF16toUTF8(gillSansMTFamily->Name()).get(),
  1.1130 +                         (fe->IsItalic()) ? "italic" : "normal",
  1.1131 +                         fe->Weight(), fe->Stretch()));
  1.1132 +                }
  1.1133 +#endif
  1.1134 +            }
  1.1135 +
  1.1136 +            // remove Gills Sans
  1.1137 +            mFontFamilies.Remove(nameGillSans);
  1.1138 +        }
  1.1139 +    }
  1.1140 +
  1.1141 +    nsAdoptingCString classicFamilies =
  1.1142 +        Preferences::GetCString("gfx.font_rendering.cleartype_params.force_gdi_classic_for_families");
  1.1143 +    if (classicFamilies) {
  1.1144 +        nsCCharSeparatedTokenizer tokenizer(classicFamilies, ',');
  1.1145 +        while (tokenizer.hasMoreTokens()) {
  1.1146 +            NS_ConvertUTF8toUTF16 name(tokenizer.nextToken());
  1.1147 +            BuildKeyNameFromFontName(name);
  1.1148 +            gfxFontFamily *family = mFontFamilies.GetWeak(name);
  1.1149 +            if (family) {
  1.1150 +                static_cast<gfxDWriteFontFamily*>(family)->SetForceGDIClassic(true);
  1.1151 +            }
  1.1152 +        }
  1.1153 +    }
  1.1154 +    mForceGDIClassicMaxFontSize =
  1.1155 +        Preferences::GetInt("gfx.font_rendering.cleartype_params.force_gdi_classic_max_size",
  1.1156 +                            mForceGDIClassicMaxFontSize);
  1.1157 +
  1.1158 +    GetPrefsAndStartLoader();
  1.1159 +
  1.1160 +    LOGREGISTRY(L"DelayedInitFontList end");
  1.1161 +
  1.1162 +    QueryPerformanceCounter(&t3);
  1.1163 +
  1.1164 +    if (LOG_FONTINIT_ENABLED()) {
  1.1165 +        // determine dwrite version
  1.1166 +        nsAutoString dwriteVers;
  1.1167 +        gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers);
  1.1168 +        LOG_FONTINIT(("DelayedInitFontList\n"));
  1.1169 +        LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime));
  1.1170 +        LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000));
  1.1171 +        LOG_FONTINIT(("dwrite version: %s\n", 
  1.1172 +                      NS_ConvertUTF16toUTF8(dwriteVers).get()));
  1.1173 +    }
  1.1174 +
  1.1175 +    elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
  1.1176 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_TOTAL, elapsedTime);
  1.1177 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COUNT,
  1.1178 +                          systemFonts->GetFontFamilyCount());
  1.1179 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_GDI_TABLE, mGDIFontTableAccess);
  1.1180 +    LOG_FONTINIT((
  1.1181 +       "Total time in DelayedInitFontList:    %9.3f ms (families: %d, %s)\n",
  1.1182 +       elapsedTime, systemFonts->GetFontFamilyCount(),
  1.1183 +       (mGDIFontTableAccess ? "gdi table access" : "dwrite table access")));
  1.1184 +
  1.1185 +    elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
  1.1186 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COLLECT, elapsedTime);
  1.1187 +    LOG_FONTINIT((" --- GetSystemFontCollection:  %9.3f ms\n", elapsedTime));
  1.1188 +
  1.1189 +    elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
  1.1190 +    Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_ITERATE, elapsedTime);
  1.1191 +    LOG_FONTINIT((" --- iterate over families:    %9.3f ms\n", elapsedTime));
  1.1192 +
  1.1193 +    return NS_OK;
  1.1194 +}
  1.1195 +
  1.1196 +static void
  1.1197 +RemoveCharsetFromFontSubstitute(nsAString &aName)
  1.1198 +{
  1.1199 +    int32_t comma = aName.FindChar(char16_t(','));
  1.1200 +    if (comma >= 0)
  1.1201 +        aName.Truncate(comma);
  1.1202 +}
  1.1203 +
  1.1204 +#define MAX_VALUE_NAME 512
  1.1205 +#define MAX_VALUE_DATA 512
  1.1206 +
  1.1207 +nsresult
  1.1208 +gfxDWriteFontList::GetFontSubstitutes()
  1.1209 +{
  1.1210 +    HKEY hKey;
  1.1211 +    DWORD i, rv, lenAlias, lenActual, valueType;
  1.1212 +    WCHAR aliasName[MAX_VALUE_NAME];
  1.1213 +    WCHAR actualName[MAX_VALUE_DATA];
  1.1214 +
  1.1215 +    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, 
  1.1216 +          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
  1.1217 +          0, KEY_READ, &hKey) != ERROR_SUCCESS)
  1.1218 +    {
  1.1219 +        return NS_ERROR_FAILURE;
  1.1220 +    }
  1.1221 +
  1.1222 +    for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
  1.1223 +        aliasName[0] = 0;
  1.1224 +        lenAlias = ArrayLength(aliasName);
  1.1225 +        actualName[0] = 0;
  1.1226 +        lenActual = sizeof(actualName);
  1.1227 +        rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType,
  1.1228 +                (LPBYTE)actualName, &lenActual);
  1.1229 +
  1.1230 +        if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
  1.1231 +            continue;
  1.1232 +        }
  1.1233 +
  1.1234 +        if (aliasName[0] == WCHAR('@')) {
  1.1235 +            continue;
  1.1236 +        }
  1.1237 +
  1.1238 +        nsAutoString substituteName((char16_t*) aliasName);
  1.1239 +        nsAutoString actualFontName((char16_t*) actualName);
  1.1240 +        RemoveCharsetFromFontSubstitute(substituteName);
  1.1241 +        BuildKeyNameFromFontName(substituteName);
  1.1242 +        RemoveCharsetFromFontSubstitute(actualFontName);
  1.1243 +        BuildKeyNameFromFontName(actualFontName);
  1.1244 +        gfxFontFamily *ff;
  1.1245 +        if (!actualFontName.IsEmpty() && 
  1.1246 +            (ff = mFontFamilies.GetWeak(actualFontName))) {
  1.1247 +            mFontSubstitutes.Put(substituteName, ff);
  1.1248 +        } else {
  1.1249 +            mNonExistingFonts.AppendElement(substituteName);
  1.1250 +        }
  1.1251 +    }
  1.1252 +    return NS_OK;
  1.1253 +}
  1.1254 +
  1.1255 +struct FontSubstitution {
  1.1256 +    const WCHAR* aliasName;
  1.1257 +    const WCHAR* actualName;
  1.1258 +};
  1.1259 +
  1.1260 +static const FontSubstitution sDirectWriteSubs[] = {
  1.1261 +    { L"MS Sans Serif", L"Microsoft Sans Serif" },
  1.1262 +    { L"MS Serif", L"Times New Roman" },
  1.1263 +    { L"Courier", L"Courier New" },
  1.1264 +    { L"Small Fonts", L"Arial" },
  1.1265 +    { L"Roman", L"Times New Roman" },
  1.1266 +    { L"Script", L"Mistral" }
  1.1267 +};
  1.1268 +
  1.1269 +void
  1.1270 +gfxDWriteFontList::GetDirectWriteSubstitutes()
  1.1271 +{
  1.1272 +    for (uint32_t i = 0; i < ArrayLength(sDirectWriteSubs); ++i) {
  1.1273 +        const FontSubstitution& sub(sDirectWriteSubs[i]);
  1.1274 +        nsAutoString substituteName((char16_t*)sub.aliasName);
  1.1275 +        BuildKeyNameFromFontName(substituteName);
  1.1276 +        if (nullptr != mFontFamilies.GetWeak(substituteName)) {
  1.1277 +            // don't do the substitution if user actually has a usable font
  1.1278 +            // with this name installed
  1.1279 +            continue;
  1.1280 +        }
  1.1281 +        nsAutoString actualFontName((char16_t*)sub.actualName);
  1.1282 +        BuildKeyNameFromFontName(actualFontName);
  1.1283 +        gfxFontFamily *ff;
  1.1284 +        if (nullptr != (ff = mFontFamilies.GetWeak(actualFontName))) {
  1.1285 +            mFontSubstitutes.Put(substituteName, ff);
  1.1286 +        } else {
  1.1287 +            mNonExistingFonts.AppendElement(substituteName);
  1.1288 +        }
  1.1289 +    }
  1.1290 +}
  1.1291 +
  1.1292 +bool
  1.1293 +gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName,
  1.1294 +                                         nsAString& aFamilyName)
  1.1295 +{
  1.1296 +    gfxFontFamily *family = FindFamily(aFontName);
  1.1297 +    if (family) {
  1.1298 +        family->LocalizedName(aFamilyName);
  1.1299 +        return true;
  1.1300 +    }
  1.1301 +
  1.1302 +    return false;
  1.1303 +}
  1.1304 +
  1.1305 +gfxFontFamily* gfxDWriteFontList::FindFamily(const nsAString& aFamily)
  1.1306 +{
  1.1307 +    if (!mInitialized) {
  1.1308 +        mInitialized = true;
  1.1309 +        DelayedInitFontList();
  1.1310 +    }
  1.1311 +
  1.1312 +    return gfxPlatformFontList::FindFamily(aFamily);
  1.1313 +}
  1.1314 +
  1.1315 +void
  1.1316 +gfxDWriteFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
  1.1317 +{
  1.1318 +    if (!mInitialized) {
  1.1319 +        mInitialized = true;
  1.1320 +        DelayedInitFontList();
  1.1321 +    }
  1.1322 +
  1.1323 +    return gfxPlatformFontList::GetFontFamilyList(aFamilyArray);
  1.1324 +}
  1.1325 +
  1.1326 +bool 
  1.1327 +gfxDWriteFontList::ResolveFontName(const nsAString& aFontName,
  1.1328 +                                   nsAString& aResolvedFontName)
  1.1329 +{
  1.1330 +    if (!mInitialized) {
  1.1331 +        mInitialized = true;
  1.1332 +        DelayedInitFontList();
  1.1333 +    }
  1.1334 +
  1.1335 +    nsAutoString keyName(aFontName);
  1.1336 +    BuildKeyNameFromFontName(keyName);
  1.1337 +
  1.1338 +    gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
  1.1339 +    if (ff) {
  1.1340 +        aResolvedFontName = ff->Name();
  1.1341 +        return true;
  1.1342 +    }
  1.1343 +
  1.1344 +    if (mNonExistingFonts.Contains(keyName)) {
  1.1345 +        return false;
  1.1346 +    }
  1.1347 +
  1.1348 +    return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
  1.1349 +}
  1.1350 +
  1.1351 +void
  1.1352 +gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
  1.1353 +                                          FontListSizes* aSizes) const
  1.1354 +{
  1.1355 +    gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  1.1356 +
  1.1357 +    aSizes->mFontListSize +=
  1.1358 +        mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
  1.1359 +                                             aMallocSizeOf);
  1.1360 +
  1.1361 +    aSizes->mFontListSize +=
  1.1362 +        mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf);
  1.1363 +    for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
  1.1364 +        aSizes->mFontListSize +=
  1.1365 +            mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  1.1366 +    }
  1.1367 +}
  1.1368 +
  1.1369 +void
  1.1370 +gfxDWriteFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
  1.1371 +                                          FontListSizes* aSizes) const
  1.1372 +{
  1.1373 +    aSizes->mFontListSize += aMallocSizeOf(this);
  1.1374 +    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
  1.1375 +}
  1.1376 +
  1.1377 +static HRESULT GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
  1.1378 +{
  1.1379 +    HRESULT hr;
  1.1380 +    nsRefPtr<IDWriteFontFamily> family;
  1.1381 +
  1.1382 +    // clean out previous value
  1.1383 +    aFamilyName.Truncate();
  1.1384 +
  1.1385 +    hr = aFont->GetFontFamily(getter_AddRefs(family));
  1.1386 +    if (FAILED(hr)) {
  1.1387 +        return hr;
  1.1388 +    }
  1.1389 +
  1.1390 +    nsRefPtr<IDWriteLocalizedStrings> familyNames;
  1.1391 +
  1.1392 +    hr = family->GetFamilyNames(getter_AddRefs(familyNames));
  1.1393 +    if (FAILED(hr)) {
  1.1394 +        return hr;
  1.1395 +    }
  1.1396 +
  1.1397 +    UINT32 index = 0;
  1.1398 +    BOOL exists = false;
  1.1399 +
  1.1400 +    hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
  1.1401 +    if (FAILED(hr)) {
  1.1402 +        return hr;
  1.1403 +    }
  1.1404 +
  1.1405 +    // If the specified locale doesn't exist, select the first on the list.
  1.1406 +    if (!exists) {
  1.1407 +        index = 0;
  1.1408 +    }
  1.1409 +
  1.1410 +    AutoFallibleTArray<WCHAR, 32> name;
  1.1411 +    UINT32 length;
  1.1412 +
  1.1413 +    hr = familyNames->GetStringLength(index, &length);
  1.1414 +    if (FAILED(hr)) {
  1.1415 +        return hr;
  1.1416 +    }
  1.1417 +
  1.1418 +    if (!name.SetLength(length + 1)) {
  1.1419 +        return E_FAIL;
  1.1420 +    }
  1.1421 +    hr = familyNames->GetString(index, name.Elements(), length + 1);
  1.1422 +    if (FAILED(hr)) {
  1.1423 +        return hr;
  1.1424 +    }
  1.1425 +
  1.1426 +    aFamilyName.Assign(name.Elements());
  1.1427 +    return S_OK;
  1.1428 +}
  1.1429 +
  1.1430 +// bug 705594 - the method below doesn't actually do any "drawing", it's only
  1.1431 +// used to invoke the DirectWrite layout engine to determine the fallback font
  1.1432 +// for a given character.
  1.1433 +
  1.1434 +IFACEMETHODIMP FontFallbackRenderer::DrawGlyphRun(
  1.1435 +    void* clientDrawingContext,
  1.1436 +    FLOAT baselineOriginX,
  1.1437 +    FLOAT baselineOriginY,
  1.1438 +    DWRITE_MEASURING_MODE measuringMode,
  1.1439 +    DWRITE_GLYPH_RUN const* glyphRun,
  1.1440 +    DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
  1.1441 +    IUnknown* clientDrawingEffect
  1.1442 +    )
  1.1443 +{
  1.1444 +    if (!mSystemFonts) {
  1.1445 +        return E_FAIL;
  1.1446 +    }
  1.1447 +
  1.1448 +    HRESULT hr = S_OK;
  1.1449 +
  1.1450 +    nsRefPtr<IDWriteFont> font;
  1.1451 +    hr = mSystemFonts->GetFontFromFontFace(glyphRun->fontFace,
  1.1452 +                                           getter_AddRefs(font));
  1.1453 +    if (FAILED(hr)) {
  1.1454 +        return hr;
  1.1455 +    }
  1.1456 +
  1.1457 +    // copy the family name
  1.1458 +    hr = GetFamilyName(font, mFamilyName);
  1.1459 +    if (FAILED(hr)) {
  1.1460 +        return hr;
  1.1461 +    }
  1.1462 +
  1.1463 +    // Arial is used as the default fallback font
  1.1464 +    // so if it matches ==> no font found
  1.1465 +    if (mFamilyName.EqualsLiteral("Arial")) {
  1.1466 +        mFamilyName.Truncate();
  1.1467 +        return E_FAIL;
  1.1468 +    }
  1.1469 +    return hr;
  1.1470 +}
  1.1471 +
  1.1472 +gfxFontEntry*
  1.1473 +gfxDWriteFontList::GlobalFontFallback(const uint32_t aCh,
  1.1474 +                                      int32_t aRunScript,
  1.1475 +                                      const gfxFontStyle* aMatchStyle,
  1.1476 +                                      uint32_t& aCmapCount,
  1.1477 +                                      gfxFontFamily** aMatchedFamily)
  1.1478 +{
  1.1479 +    bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
  1.1480 +
  1.1481 +    if (useCmaps) {
  1.1482 +        return gfxPlatformFontList::GlobalFontFallback(aCh,
  1.1483 +                                                       aRunScript,
  1.1484 +                                                       aMatchStyle,
  1.1485 +                                                       aCmapCount,
  1.1486 +                                                       aMatchedFamily);
  1.1487 +    }
  1.1488 +
  1.1489 +    HRESULT hr;
  1.1490 +
  1.1491 +    nsRefPtr<IDWriteFactory> dwFactory =
  1.1492 +        gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
  1.1493 +    if (!dwFactory) {
  1.1494 +        return nullptr;
  1.1495 +    }
  1.1496 +
  1.1497 +    // initialize fallback renderer
  1.1498 +    if (!mFallbackRenderer) {
  1.1499 +        mFallbackRenderer = new FontFallbackRenderer(dwFactory);
  1.1500 +    }
  1.1501 +
  1.1502 +    // initialize text format
  1.1503 +    if (!mFallbackFormat) {
  1.1504 +        hr = dwFactory->CreateTextFormat(L"Arial", nullptr,
  1.1505 +                                         DWRITE_FONT_WEIGHT_REGULAR,
  1.1506 +                                         DWRITE_FONT_STYLE_NORMAL,
  1.1507 +                                         DWRITE_FONT_STRETCH_NORMAL,
  1.1508 +                                         72.0f, L"en-us",
  1.1509 +                                         getter_AddRefs(mFallbackFormat));
  1.1510 +        if (FAILED(hr)) {
  1.1511 +            return nullptr;
  1.1512 +        }
  1.1513 +    }
  1.1514 +
  1.1515 +    // set up string with fallback character
  1.1516 +    wchar_t str[16];
  1.1517 +    uint32_t strLen;
  1.1518 +
  1.1519 +    if (IS_IN_BMP(aCh)) {
  1.1520 +        str[0] = static_cast<wchar_t> (aCh);
  1.1521 +        str[1] = 0;
  1.1522 +        strLen = 1;
  1.1523 +    } else {
  1.1524 +        str[0] = static_cast<wchar_t> (H_SURROGATE(aCh));
  1.1525 +        str[1] = static_cast<wchar_t> (L_SURROGATE(aCh));
  1.1526 +        str[2] = 0;
  1.1527 +        strLen = 2;
  1.1528 +    }
  1.1529 +
  1.1530 +    // set up layout
  1.1531 +    nsRefPtr<IDWriteTextLayout> fallbackLayout;
  1.1532 +
  1.1533 +    hr = dwFactory->CreateTextLayout(str, strLen, mFallbackFormat,
  1.1534 +                                     200.0f, 200.0f,
  1.1535 +                                     getter_AddRefs(fallbackLayout));
  1.1536 +    if (FAILED(hr)) {
  1.1537 +        return nullptr;
  1.1538 +    }
  1.1539 +
  1.1540 +    // call the draw method to invoke the DirectWrite layout functions
  1.1541 +    // which determine the fallback font
  1.1542 +    hr = fallbackLayout->Draw(nullptr, mFallbackRenderer, 50.0f, 50.0f);
  1.1543 +    if (FAILED(hr)) {
  1.1544 +        return nullptr;
  1.1545 +    }
  1.1546 +
  1.1547 +    gfxFontFamily *family = FindFamily(mFallbackRenderer->FallbackFamilyName());
  1.1548 +    if (family) {
  1.1549 +        gfxFontEntry *fontEntry;
  1.1550 +        bool needsBold;  // ignored in the system fallback case
  1.1551 +        fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
  1.1552 +        if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
  1.1553 +            *aMatchedFamily = family;
  1.1554 +            return fontEntry;
  1.1555 +        }
  1.1556 +        Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
  1.1557 +    }
  1.1558 +
  1.1559 +    return nullptr;
  1.1560 +}
  1.1561 +
  1.1562 +// used to load system-wide font info on off-main thread
  1.1563 +class DirectWriteFontInfo : public FontInfoData {
  1.1564 +public:
  1.1565 +    DirectWriteFontInfo(bool aLoadOtherNames,
  1.1566 +                        bool aLoadFaceNames,
  1.1567 +                        bool aLoadCmaps) :
  1.1568 +        FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
  1.1569 +    {}
  1.1570 +
  1.1571 +    virtual ~DirectWriteFontInfo() {}
  1.1572 +
  1.1573 +    // loads font data for all members of a given family
  1.1574 +    virtual void LoadFontFamilyData(const nsAString& aFamilyName);
  1.1575 +
  1.1576 +    nsRefPtr<IDWriteFontCollection> mSystemFonts;
  1.1577 +};
  1.1578 +
  1.1579 +void
  1.1580 +DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
  1.1581 +{
  1.1582 +    // lookup the family
  1.1583 +    nsAutoTArray<wchar_t, 32> famName;
  1.1584 +
  1.1585 +    uint32_t len = aFamilyName.Length();
  1.1586 +    famName.SetLength(len + 1);
  1.1587 +    memcpy(famName.Elements(), aFamilyName.BeginReading(), len * sizeof(char16_t));
  1.1588 +    famName[len] = 0;
  1.1589 +
  1.1590 +    HRESULT hr;
  1.1591 +    BOOL exists = false;
  1.1592 +
  1.1593 +    uint32_t index;
  1.1594 +    hr = mSystemFonts->FindFamilyName(famName.Elements(), &index, &exists);
  1.1595 +    if (FAILED(hr) || !exists) {
  1.1596 +        return;
  1.1597 +    }
  1.1598 +
  1.1599 +    nsRefPtr<IDWriteFontFamily> family;
  1.1600 +    mSystemFonts->GetFontFamily(index, getter_AddRefs(family));
  1.1601 +    if (!family) {
  1.1602 +        return;
  1.1603 +    }
  1.1604 +
  1.1605 +    // later versions of DirectWrite support querying the fullname/psname
  1.1606 +    bool loadFaceNamesUsingDirectWrite = mLoadFaceNames;
  1.1607 +
  1.1608 +    for (uint32_t i = 0; i < family->GetFontCount(); i++) {
  1.1609 +        // get the font
  1.1610 +        nsRefPtr<IDWriteFont> dwFont;
  1.1611 +        hr = family->GetFont(i, getter_AddRefs(dwFont));
  1.1612 +        if (FAILED(hr)) {
  1.1613 +            // This should never happen.
  1.1614 +            NS_WARNING("Failed to get existing font from family.");
  1.1615 +            continue;
  1.1616 +        }
  1.1617 +
  1.1618 +        if (dwFont->GetSimulations() & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
  1.1619 +            // We don't want these.
  1.1620 +            continue;
  1.1621 +        }
  1.1622 +
  1.1623 +        mLoadStats.fonts++;
  1.1624 +
  1.1625 +        // get the name of the face
  1.1626 +        nsString fullID(aFamilyName);
  1.1627 +        nsAutoString fontName;
  1.1628 +        hr = GetDirectWriteFontName(dwFont, fontName);
  1.1629 +        if (FAILED(hr)) {
  1.1630 +            continue;
  1.1631 +        }
  1.1632 +        fullID.Append(NS_LITERAL_STRING(" "));
  1.1633 +        fullID.Append(fontName);
  1.1634 +
  1.1635 +        FontFaceData fontData;
  1.1636 +        bool haveData = true;
  1.1637 +        nsRefPtr<IDWriteFontFace> dwFontFace;
  1.1638 +
  1.1639 +        if (mLoadFaceNames) {
  1.1640 +            // try to load using DirectWrite first
  1.1641 +            if (loadFaceNamesUsingDirectWrite) {
  1.1642 +                hr = GetDirectWriteFaceName(dwFont, PSNAME_ID, fontData.mPostscriptName);
  1.1643 +                if (FAILED(hr)) {
  1.1644 +                    loadFaceNamesUsingDirectWrite = false;
  1.1645 +                }
  1.1646 +                hr = GetDirectWriteFaceName(dwFont, FULLNAME_ID, fontData.mFullName);
  1.1647 +                if (FAILED(hr)) {
  1.1648 +                    loadFaceNamesUsingDirectWrite = false;
  1.1649 +                }
  1.1650 +            }
  1.1651 +
  1.1652 +            // if DirectWrite read fails, load directly from name table
  1.1653 +            if (!loadFaceNamesUsingDirectWrite) {
  1.1654 +                hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace));
  1.1655 +                if (SUCCEEDED(hr)) {
  1.1656 +                    uint32_t kNAME =
  1.1657 +                        NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e'));
  1.1658 +                    const char *nameData;
  1.1659 +                    BOOL exists;
  1.1660 +                    void* ctx;
  1.1661 +                    uint32_t nameSize;
  1.1662 +
  1.1663 +                    hr = dwFontFace->TryGetFontTable(
  1.1664 +                             kNAME,
  1.1665 +                             (const void**)&nameData, &nameSize, &ctx, &exists);
  1.1666 +
  1.1667 +                    if (SUCCEEDED(hr) && nameData && nameSize > 0) {
  1.1668 +                        gfxFontUtils::ReadCanonicalName(nameData, nameSize,
  1.1669 +                            gfxFontUtils::NAME_ID_FULL,
  1.1670 +                            fontData.mFullName);
  1.1671 +                        gfxFontUtils::ReadCanonicalName(nameData, nameSize,
  1.1672 +                            gfxFontUtils::NAME_ID_POSTSCRIPT,
  1.1673 +                            fontData.mPostscriptName);
  1.1674 +                        dwFontFace->ReleaseFontTable(ctx);
  1.1675 +                    }
  1.1676 +                }
  1.1677 +            }
  1.1678 +
  1.1679 +            haveData = !fontData.mPostscriptName.IsEmpty() ||
  1.1680 +                       !fontData.mFullName.IsEmpty();
  1.1681 +            if (haveData) {
  1.1682 +                mLoadStats.facenames++;
  1.1683 +            }
  1.1684 +        }
  1.1685 +
  1.1686 +        // cmaps
  1.1687 +        if (mLoadCmaps) {
  1.1688 +            if (!dwFontFace) {
  1.1689 +                hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace));
  1.1690 +                if (!SUCCEEDED(hr)) {
  1.1691 +                    continue;
  1.1692 +                }
  1.1693 +            }
  1.1694 +
  1.1695 +            uint32_t kCMAP =
  1.1696 +                NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p'));
  1.1697 +            const uint8_t *cmapData;
  1.1698 +            BOOL exists;
  1.1699 +            void* ctx;
  1.1700 +            uint32_t cmapSize;
  1.1701 +
  1.1702 +            hr = dwFontFace->TryGetFontTable(kCMAP,
  1.1703 +                     (const void**)&cmapData, &cmapSize, &ctx, &exists);
  1.1704 +
  1.1705 +            if (SUCCEEDED(hr)) {
  1.1706 +                bool cmapLoaded = false;
  1.1707 +                bool unicodeFont = false, symbolFont = false;
  1.1708 +                nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
  1.1709 +                uint32_t offset;
  1.1710 +
  1.1711 +                if (cmapData &&
  1.1712 +                    cmapSize > 0 &&
  1.1713 +                    NS_SUCCEEDED(
  1.1714 +                        gfxFontUtils::ReadCMAP(cmapData, cmapSize, *charmap,
  1.1715 +                                               offset, unicodeFont, symbolFont))) {
  1.1716 +                    fontData.mCharacterMap = charmap;
  1.1717 +                    fontData.mUVSOffset = offset;
  1.1718 +                    fontData.mSymbolFont = symbolFont;
  1.1719 +                    cmapLoaded = true;
  1.1720 +                    mLoadStats.cmaps++;
  1.1721 +                }
  1.1722 +                dwFontFace->ReleaseFontTable(ctx);
  1.1723 +                haveData = haveData || cmapLoaded;
  1.1724 +           }
  1.1725 +        }
  1.1726 +
  1.1727 +        // if have data, load
  1.1728 +        if (haveData) {
  1.1729 +            mFontFaceData.Put(fullID, fontData);
  1.1730 +        }
  1.1731 +    }
  1.1732 +}
  1.1733 +
  1.1734 +already_AddRefed<FontInfoData>
  1.1735 +gfxDWriteFontList::CreateFontInfoData()
  1.1736 +{
  1.1737 +    bool loadCmaps = !UsesSystemFallback() ||
  1.1738 +        gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
  1.1739 +
  1.1740 +    nsRefPtr<DirectWriteFontInfo> fi =
  1.1741 +        new DirectWriteFontInfo(false, NeedFullnamePostscriptNames(), loadCmaps);
  1.1742 +    gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
  1.1743 +        GetSystemFontCollection(getter_AddRefs(fi->mSystemFonts));
  1.1744 +
  1.1745 +    return fi.forget();
  1.1746 +}

mercurial