const nsTArray< nsCountedRef<FcPattern> >&
gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName)
{
    FontsByFcStrEntry *entry = mFontsByFamily.GetEntry(aFamilyName);

    if (!entry)
        return mEmptyPatternArray;

    return entry->GetFonts();
}
nsresult
gfxFontconfigUtils::UpdateFontListInternal(bool aForce)
{
    if (!aForce) {
        // This checks periodically according to fontconfig's configured
        // <rescan> interval.
        FcInitBringUptoDate();
    } else if (!FcConfigUptoDate(nullptr)) { // check now with aForce
        mLastConfig = nullptr;
        FcInitReinitialize();
    }

    // FcInitReinitialize() (used by FcInitBringUptoDate) creates a new config
    // before destroying the old config, so the only way that we'd miss an
    // update is if fontconfig did more than one update and the memory for the
    // most recent config happened to be at the same location as the original
    // config.
    FcConfig *currentConfig = FcConfigGetCurrent();
    if (currentConfig == mLastConfig)
        return NS_OK;

#ifdef MOZ_BUNDLED_FONTS
    ActivateBundledFonts();
#endif

    // These FcFontSets are owned by fontconfig
    FcFontSet *fontSets[] = {
        FcConfigGetFonts(currentConfig, FcSetSystem)
#ifdef MOZ_BUNDLED_FONTS
        , FcConfigGetFonts(currentConfig, FcSetApplication)
#endif
    };

    mFontsByFamily.Clear();
    mFontsByFullname.Clear();
    mLangSupportTable.Clear();

    // Record the existing font families
    for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) {
        FcFontSet *fontSet = fontSets[fs];
        if (!fontSet) { // the application set might not exist
            continue;
        }
        for (int f = 0; f < fontSet->nfont; ++f) {
            FcPattern *font = fontSet->fonts[f];

            FcChar8 *family;
            for (int v = 0;
                    FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch;
                    ++v) {
                FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family);
                if (entry) {
                    bool added = entry->AddFont(font);

                    if (!entry->mKey) {
                        // The reference to the font pattern keeps the pointer to
                        // string for the key valid.  If adding the font failed
                        // then the entry must be removed.
                        if (added) {
                            entry->mKey = family;
                        } else {
                            mFontsByFamily.RawRemoveEntry(entry);
                        }
                    }
                }
            }
        }
    }

    mLastConfig = currentConfig;
    return NS_OK;
}
nsresult
gfxFontconfigUtils::UpdateFontListInternal(bool aForce)
{
    if (!aForce) {
        // This checks periodically according to fontconfig's configured
        // <rescan> interval.
        FcInitBringUptoDate();
    } else if (!FcConfigUptoDate(NULL)) { // check now with aForce
        mLastConfig = NULL;
        FcInitReinitialize();
    }

    // FcInitReinitialize() (used by FcInitBringUptoDate) creates a new config
    // before destroying the old config, so the only way that we'd miss an
    // update is if fontconfig did more than one update and the memory for the
    // most recent config happened to be at the same location as the original
    // config.
    FcConfig *currentConfig = FcConfigGetCurrent();
    if (currentConfig == mLastConfig)
        return NS_OK;

    // This FcFontSet is owned by fontconfig
    FcFontSet *fontSet = FcConfigGetFonts(currentConfig, FcSetSystem);

    mFontsByFamily.Clear();
    mFontsByFullname.Clear();
    mLangSupportTable.Clear();
    mAliasForMultiFonts.Clear();

    // Record the existing font families
    for (int f = 0; f < fontSet->nfont; ++f) {
        FcPattern *font = fontSet->fonts[f];

        FcChar8 *family;
        for (int v = 0;
             FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch;
             ++v) {
            FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family);
            if (entry) {
                bool added = entry->AddFont(font);

                if (!entry->mKey) {
                    // The reference to the font pattern keeps the pointer to
                    // string for the key valid.  If adding the font failed
                    // then the entry must be removed.
                    if (added) {
                        entry->mKey = family;
                    } else {
                        mFontsByFamily.RawRemoveEntry(entry);
                    }
                }
            }
        }
    }

    // XXX we don't support all alias names.
    // Because if we don't check whether the given font name is alias name,
    // fontconfig converts the non existing font to sans-serif.
    // This is not good if the web page specifies font-family
    // that has Windows font name in the first.
    NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
    nsAdoptingCString list = Preferences::GetCString("font.alias-list");

    if (!list.IsEmpty()) {
        const char kComma = ',';
        const char *p, *p_end;
        list.BeginReading(p);
        list.EndReading(p_end);
        while (p < p_end) {
            while (nsCRT::IsAsciiSpace(*p)) {
                if (++p == p_end)
                    break;
            }
            if (p == p_end)
                break;
            const char *start = p;
            while (++p != p_end && *p != kComma)
                /* nothing */ ;
            nsAutoCString name(Substring(start, p));
            name.CompressWhitespace(false, true);
            mAliasForMultiFonts.AppendElement(name);
            p++;
        }
    }

    mLastConfig = currentConfig;
    return NS_OK;
}