gfx/thebes/gfxUserFontSet.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxUserFontSet.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1056 @@
     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 +#ifdef MOZ_LOGGING
    1.10 +#define FORCE_PR_LOG /* Allow logging in the release build */
    1.11 +#endif /* MOZ_LOGGING */
    1.12 +#include "prlog.h"
    1.13 +
    1.14 +#include "gfxUserFontSet.h"
    1.15 +#include "nsFont.h"
    1.16 +#include "gfxPlatform.h"
    1.17 +#include "nsUnicharUtils.h"
    1.18 +#include "nsNetUtil.h"
    1.19 +#include "nsICacheService.h"
    1.20 +#include "nsIProtocolHandler.h"
    1.21 +#include "nsIPrincipal.h"
    1.22 +#include "gfxFontConstants.h"
    1.23 +#include "mozilla/Services.h"
    1.24 +#include "mozilla/gfx/2D.h"
    1.25 +#include "gfxPlatformFontList.h"
    1.26 +
    1.27 +#include "opentype-sanitiser.h"
    1.28 +#include "ots-memory-stream.h"
    1.29 +
    1.30 +using namespace mozilla;
    1.31 +
    1.32 +#ifdef PR_LOGGING
    1.33 +PRLogModuleInfo *
    1.34 +gfxUserFontSet::GetUserFontsLog()
    1.35 +{
    1.36 +    static PRLogModuleInfo *sLog;
    1.37 +    if (!sLog)
    1.38 +        sLog = PR_NewLogModule("userfonts");
    1.39 +    return sLog;
    1.40 +}
    1.41 +#endif /* PR_LOGGING */
    1.42 +
    1.43 +#define LOG(args) PR_LOG(GetUserFontsLog(), PR_LOG_DEBUG, args)
    1.44 +#define LOG_ENABLED() PR_LOG_TEST(GetUserFontsLog(), PR_LOG_DEBUG)
    1.45 +
    1.46 +static uint64_t sFontSetGeneration = 0;
    1.47 +
    1.48 +// TODO: support for unicode ranges not yet implemented
    1.49 +
    1.50 +gfxProxyFontEntry::gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
    1.51 +             uint32_t aWeight,
    1.52 +             int32_t aStretch,
    1.53 +             uint32_t aItalicStyle,
    1.54 +             const nsTArray<gfxFontFeature>& aFeatureSettings,
    1.55 +             uint32_t aLanguageOverride,
    1.56 +             gfxSparseBitSet *aUnicodeRanges)
    1.57 +    : gfxFontEntry(NS_LITERAL_STRING("Proxy")),
    1.58 +      mLoadingState(NOT_LOADING),
    1.59 +      mUnsupportedFormat(false),
    1.60 +      mLoader(nullptr)
    1.61 +{
    1.62 +    mIsProxy = true;
    1.63 +    mSrcList = aFontFaceSrcList;
    1.64 +    mSrcIndex = 0;
    1.65 +    mWeight = aWeight;
    1.66 +    mStretch = aStretch;
    1.67 +    // XXX Currently, we don't distinguish 'italic' and 'oblique' styles;
    1.68 +    // we need to fix this. (Bug 543715)
    1.69 +    mItalic = (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
    1.70 +    mFeatureSettings.AppendElements(aFeatureSettings);
    1.71 +    mLanguageOverride = aLanguageOverride;
    1.72 +    mIsUserFont = true;
    1.73 +}
    1.74 +
    1.75 +gfxProxyFontEntry::~gfxProxyFontEntry()
    1.76 +{
    1.77 +}
    1.78 +
    1.79 +bool
    1.80 +gfxProxyFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
    1.81 +                           uint32_t aWeight,
    1.82 +                           int32_t aStretch,
    1.83 +                           uint32_t aItalicStyle,
    1.84 +                           const nsTArray<gfxFontFeature>& aFeatureSettings,
    1.85 +                           uint32_t aLanguageOverride,
    1.86 +                           gfxSparseBitSet *aUnicodeRanges)
    1.87 +{
    1.88 +    // XXX font entries don't distinguish italic from oblique (bug 543715)
    1.89 +    bool isItalic =
    1.90 +        (aItalicStyle & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) != 0;
    1.91 +
    1.92 +    return mWeight == aWeight &&
    1.93 +           mStretch == aStretch &&
    1.94 +           mItalic == isItalic &&
    1.95 +           mFeatureSettings == aFeatureSettings &&
    1.96 +           mLanguageOverride == aLanguageOverride &&
    1.97 +           mSrcList == aFontFaceSrcList;
    1.98 +           // XXX once we support unicode-range (bug 475891),
    1.99 +           // we'll need to compare that here as well
   1.100 +}
   1.101 +
   1.102 +gfxFont*
   1.103 +gfxProxyFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
   1.104 +{
   1.105 +    // cannot create an actual font for a proxy entry
   1.106 +    return nullptr;
   1.107 +}
   1.108 +
   1.109 +gfxUserFontSet::gfxUserFontSet()
   1.110 +    : mFontFamilies(5), mLocalRulesUsed(false)
   1.111 +{
   1.112 +    IncrementGeneration();
   1.113 +    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
   1.114 +    if (fp) {
   1.115 +        fp->AddUserFontSet(this);
   1.116 +    }
   1.117 +}
   1.118 +
   1.119 +gfxUserFontSet::~gfxUserFontSet()
   1.120 +{
   1.121 +    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
   1.122 +    if (fp) {
   1.123 +        fp->RemoveUserFontSet(this);
   1.124 +    }
   1.125 +}
   1.126 +
   1.127 +gfxFontEntry*
   1.128 +gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
   1.129 +                            const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
   1.130 +                            uint32_t aWeight,
   1.131 +                            int32_t aStretch,
   1.132 +                            uint32_t aItalicStyle,
   1.133 +                            const nsTArray<gfxFontFeature>& aFeatureSettings,
   1.134 +                            const nsString& aLanguageOverride,
   1.135 +                            gfxSparseBitSet *aUnicodeRanges)
   1.136 +{
   1.137 +    nsAutoString key(aFamilyName);
   1.138 +    ToLowerCase(key);
   1.139 +
   1.140 +    bool found;
   1.141 +
   1.142 +    if (aWeight == 0)
   1.143 +        aWeight = NS_FONT_WEIGHT_NORMAL;
   1.144 +
   1.145 +    // stretch, italic/oblique ==> zero implies normal
   1.146 +
   1.147 +    gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
   1.148 +    if (!family) {
   1.149 +        family = new gfxMixedFontFamily(aFamilyName);
   1.150 +        mFontFamilies.Put(key, family);
   1.151 +    }
   1.152 +
   1.153 +    uint32_t languageOverride =
   1.154 +        gfxFontStyle::ParseFontLanguageOverride(aLanguageOverride);
   1.155 +
   1.156 +    // If there's already a proxy in the family whose descriptors all match,
   1.157 +    // we can just move it to the end of the list instead of adding a new
   1.158 +    // face that will always "shadow" the old one.
   1.159 +    // Note that we can't do this for "real" (non-proxy) entries, even if the
   1.160 +    // style descriptors match, as they might have had a different source list,
   1.161 +    // but we no longer have the old source list available to check.
   1.162 +    nsTArray<nsRefPtr<gfxFontEntry> >& fontList = family->GetFontList();
   1.163 +    for (uint32_t i = 0, count = fontList.Length(); i < count; i++) {
   1.164 +        if (!fontList[i]->mIsProxy) {
   1.165 +            continue;
   1.166 +        }
   1.167 +
   1.168 +        gfxProxyFontEntry *existingProxyEntry =
   1.169 +            static_cast<gfxProxyFontEntry*>(fontList[i].get());
   1.170 +        if (!existingProxyEntry->Matches(aFontFaceSrcList,
   1.171 +                                         aWeight, aStretch, aItalicStyle,
   1.172 +                                         aFeatureSettings, languageOverride,
   1.173 +                                         aUnicodeRanges)) {
   1.174 +            continue;
   1.175 +        }
   1.176 +
   1.177 +        // We've found an entry that matches the new face exactly, so just add
   1.178 +        // it to the end of the list. gfxMixedFontFamily::AddFontEntry() will
   1.179 +        // automatically remove any earlier occurrence of the same proxy.
   1.180 +        family->AddFontEntry(existingProxyEntry);
   1.181 +        return existingProxyEntry;
   1.182 +    }
   1.183 +
   1.184 +    // construct a new face and add it into the family
   1.185 +    gfxProxyFontEntry *proxyEntry =
   1.186 +        new gfxProxyFontEntry(aFontFaceSrcList, aWeight, aStretch,
   1.187 +                              aItalicStyle,
   1.188 +                              aFeatureSettings,
   1.189 +                              languageOverride,
   1.190 +                              aUnicodeRanges);
   1.191 +    family->AddFontEntry(proxyEntry);
   1.192 +#ifdef PR_LOGGING
   1.193 +    if (LOG_ENABLED()) {
   1.194 +        LOG(("userfonts (%p) added (%s) with style: %s weight: %d stretch: %d",
   1.195 +             this, NS_ConvertUTF16toUTF8(aFamilyName).get(),
   1.196 +             (aItalicStyle & NS_FONT_STYLE_ITALIC ? "italic" :
   1.197 +                 (aItalicStyle & NS_FONT_STYLE_OBLIQUE ? "oblique" : "normal")),
   1.198 +             aWeight, aStretch));
   1.199 +    }
   1.200 +#endif
   1.201 +
   1.202 +    return proxyEntry;
   1.203 +}
   1.204 +
   1.205 +void
   1.206 +gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
   1.207 +                            gfxFontEntry     *aFontEntry)
   1.208 +{
   1.209 +    nsAutoString key(aFamilyName);
   1.210 +    ToLowerCase(key);
   1.211 +
   1.212 +    bool found;
   1.213 +
   1.214 +    gfxMixedFontFamily *family = mFontFamilies.GetWeak(key, &found);
   1.215 +    if (!family) {
   1.216 +        family = new gfxMixedFontFamily(aFamilyName);
   1.217 +        mFontFamilies.Put(key, family);
   1.218 +    }
   1.219 +
   1.220 +    family->AddFontEntry(aFontEntry);
   1.221 +}
   1.222 +
   1.223 +gfxFontEntry*
   1.224 +gfxUserFontSet::FindFontEntry(gfxFontFamily *aFamily,
   1.225 +                              const gfxFontStyle& aFontStyle,
   1.226 +                              bool& aNeedsBold,
   1.227 +                              bool& aWaitForUserFont)
   1.228 +{
   1.229 +    aWaitForUserFont = false;
   1.230 +    gfxMixedFontFamily *family = static_cast<gfxMixedFontFamily*>(aFamily);
   1.231 +
   1.232 +    gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold);
   1.233 +
   1.234 +    // if not a proxy, font has already been loaded
   1.235 +    if (!fe->mIsProxy) {
   1.236 +        return fe;
   1.237 +    }
   1.238 +
   1.239 +    gfxProxyFontEntry *proxyEntry = static_cast<gfxProxyFontEntry*> (fe);
   1.240 +
   1.241 +    // if currently loading, return null for now
   1.242 +    if (proxyEntry->mLoadingState > gfxProxyFontEntry::NOT_LOADING) {
   1.243 +        aWaitForUserFont =
   1.244 +            (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
   1.245 +        return nullptr;
   1.246 +    }
   1.247 +
   1.248 +    // hasn't been loaded yet, start the load process
   1.249 +    LoadStatus status;
   1.250 +
   1.251 +    // NOTE that if all sources in the entry fail, this will delete proxyEntry,
   1.252 +    // so we cannot use it again if status==STATUS_END_OF_LIST
   1.253 +    status = LoadNext(family, proxyEntry);
   1.254 +
   1.255 +    // if the load succeeded immediately, the font entry was replaced so
   1.256 +    // search again
   1.257 +    if (status == STATUS_LOADED) {
   1.258 +        return family->FindFontForStyle(aFontStyle, aNeedsBold);
   1.259 +    }
   1.260 +
   1.261 +    // check whether we should wait for load to complete before painting
   1.262 +    // a fallback font -- but not if all sources failed (bug 633500)
   1.263 +    aWaitForUserFont = (status != STATUS_END_OF_LIST) &&
   1.264 +        (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);
   1.265 +
   1.266 +    // if either loading or an error occurred, return null
   1.267 +    return nullptr;
   1.268 +}
   1.269 +
   1.270 +// Based on ots::ExpandingMemoryStream from ots-memory-stream.h,
   1.271 +// adapted to use Mozilla allocators and to allow the final
   1.272 +// memory buffer to be adopted by the client.
   1.273 +class ExpandingMemoryStream : public ots::OTSStream {
   1.274 +public:
   1.275 +    ExpandingMemoryStream(size_t initial, size_t limit)
   1.276 +        : mLength(initial), mLimit(limit), mOff(0) {
   1.277 +        mPtr = NS_Alloc(mLength);
   1.278 +    }
   1.279 +
   1.280 +    ~ExpandingMemoryStream() {
   1.281 +        NS_Free(mPtr);
   1.282 +    }
   1.283 +
   1.284 +    // return the buffer, and give up ownership of it
   1.285 +    // so the caller becomes responsible to call NS_Free
   1.286 +    // when finished with it
   1.287 +    void* forget() {
   1.288 +        void* p = mPtr;
   1.289 +        mPtr = nullptr;
   1.290 +        return p;
   1.291 +    }
   1.292 +
   1.293 +    bool WriteRaw(const void *data, size_t length) {
   1.294 +        if ((mOff + length > mLength) ||
   1.295 +            (mLength > std::numeric_limits<size_t>::max() - mOff)) {
   1.296 +            if (mLength == mLimit) {
   1.297 +                return false;
   1.298 +            }
   1.299 +            size_t newLength = (mLength + 1) * 2;
   1.300 +            if (newLength < mLength) {
   1.301 +                return false;
   1.302 +            }
   1.303 +            if (newLength > mLimit) {
   1.304 +                newLength = mLimit;
   1.305 +            }
   1.306 +            mPtr = NS_Realloc(mPtr, newLength);
   1.307 +            mLength = newLength;
   1.308 +            return WriteRaw(data, length);
   1.309 +        }
   1.310 +        std::memcpy(static_cast<char*>(mPtr) + mOff, data, length);
   1.311 +        mOff += length;
   1.312 +        return true;
   1.313 +    }
   1.314 +
   1.315 +    bool Seek(off_t position) {
   1.316 +        if (position < 0) {
   1.317 +            return false;
   1.318 +        }
   1.319 +        if (static_cast<size_t>(position) > mLength) {
   1.320 +            return false;
   1.321 +        }
   1.322 +        mOff = position;
   1.323 +        return true;
   1.324 +    }
   1.325 +
   1.326 +    off_t Tell() const {
   1.327 +        return mOff;
   1.328 +    }
   1.329 +
   1.330 +private:
   1.331 +    void*        mPtr;
   1.332 +    size_t       mLength;
   1.333 +    const size_t mLimit;
   1.334 +    off_t        mOff;
   1.335 +};
   1.336 +
   1.337 +static ots::TableAction
   1.338 +OTSTableAction(uint32_t aTag, void *aUserData)
   1.339 +{
   1.340 +    // preserve Graphite and SVG tables
   1.341 +    if (aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
   1.342 +        aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
   1.343 +        aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
   1.344 +        aTag == TRUETYPE_TAG('G', 'l', 'a', 't') ||
   1.345 +        aTag == TRUETYPE_TAG('F', 'e', 'a', 't') ||
   1.346 +        aTag == TRUETYPE_TAG('S', 'V', 'G', ' ')) {
   1.347 +        return ots::TABLE_ACTION_PASSTHRU;
   1.348 +    }
   1.349 +    return ots::TABLE_ACTION_DEFAULT;
   1.350 +}
   1.351 +
   1.352 +struct OTSCallbackUserData {
   1.353 +    gfxUserFontSet     *mFontSet;
   1.354 +    gfxMixedFontFamily *mFamily;
   1.355 +    gfxProxyFontEntry  *mProxy;
   1.356 +};
   1.357 +
   1.358 +/* static */ bool
   1.359 +gfxUserFontSet::OTSMessage(void *aUserData, const char *format, ...)
   1.360 +{
   1.361 +    va_list va;
   1.362 +    va_start(va, format);
   1.363 +
   1.364 +    // buf should be more than adequate for any message OTS generates,
   1.365 +    // so we don't worry about checking the result of vsnprintf()
   1.366 +    char buf[512];
   1.367 +    (void)vsnprintf(buf, sizeof(buf), format, va);
   1.368 +
   1.369 +    va_end(va);
   1.370 +
   1.371 +    OTSCallbackUserData *d = static_cast<OTSCallbackUserData*>(aUserData);
   1.372 +    d->mFontSet->LogMessage(d->mFamily, d->mProxy, buf);
   1.373 +
   1.374 +    return false;
   1.375 +}
   1.376 +
   1.377 +// Call the OTS library to sanitize an sfnt before attempting to use it.
   1.378 +// Returns a newly-allocated block, or nullptr in case of fatal errors.
   1.379 +const uint8_t*
   1.380 +gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
   1.381 +                                     gfxProxyFontEntry *aProxy,
   1.382 +                                     const uint8_t* aData, uint32_t aLength,
   1.383 +                                     uint32_t& aSaneLength, bool aIsCompressed)
   1.384 +{
   1.385 +    // limit output/expansion to 256MB
   1.386 +    ExpandingMemoryStream output(aIsCompressed ? aLength * 2 : aLength,
   1.387 +                                 1024 * 1024 * 256);
   1.388 +
   1.389 +    OTSCallbackUserData userData;
   1.390 +    userData.mFontSet = this;
   1.391 +    userData.mFamily = aFamily;
   1.392 +    userData.mProxy = aProxy;
   1.393 +
   1.394 +    ots::SetTableActionCallback(&OTSTableAction, nullptr);
   1.395 +    ots::SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData);
   1.396 +
   1.397 +    if (ots::Process(&output, aData, aLength)) {
   1.398 +        aSaneLength = output.Tell();
   1.399 +        return static_cast<uint8_t*>(output.forget());
   1.400 +    } else {
   1.401 +        aSaneLength = 0;
   1.402 +        return nullptr;
   1.403 +    }
   1.404 +}
   1.405 +
   1.406 +static void
   1.407 +StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
   1.408 +                  bool aPrivate, const nsAString& aOriginalName,
   1.409 +                  FallibleTArray<uint8_t>* aMetadata, uint32_t aMetaOrigLen)
   1.410 +{
   1.411 +    if (!aFontEntry->mUserFontData) {
   1.412 +        aFontEntry->mUserFontData = new gfxUserFontData;
   1.413 +    }
   1.414 +    gfxUserFontData* userFontData = aFontEntry->mUserFontData;
   1.415 +    userFontData->mSrcIndex = aProxy->mSrcIndex;
   1.416 +    const gfxFontFaceSrc& src = aProxy->mSrcList[aProxy->mSrcIndex];
   1.417 +    if (src.mIsLocal) {
   1.418 +        userFontData->mLocalName = src.mLocalName;
   1.419 +    } else {
   1.420 +        userFontData->mURI = src.mURI;
   1.421 +        userFontData->mPrincipal = aProxy->mPrincipal;
   1.422 +    }
   1.423 +    userFontData->mPrivate = aPrivate;
   1.424 +    userFontData->mFormat = src.mFormatFlags;
   1.425 +    userFontData->mRealName = aOriginalName;
   1.426 +    if (aMetadata) {
   1.427 +        userFontData->mMetadata.SwapElements(*aMetadata);
   1.428 +        userFontData->mMetaOrigLen = aMetaOrigLen;
   1.429 +    }
   1.430 +}
   1.431 +
   1.432 +struct WOFFHeader {
   1.433 +    AutoSwap_PRUint32 signature;
   1.434 +    AutoSwap_PRUint32 flavor;
   1.435 +    AutoSwap_PRUint32 length;
   1.436 +    AutoSwap_PRUint16 numTables;
   1.437 +    AutoSwap_PRUint16 reserved;
   1.438 +    AutoSwap_PRUint32 totalSfntSize;
   1.439 +    AutoSwap_PRUint16 majorVersion;
   1.440 +    AutoSwap_PRUint16 minorVersion;
   1.441 +    AutoSwap_PRUint32 metaOffset;
   1.442 +    AutoSwap_PRUint32 metaCompLen;
   1.443 +    AutoSwap_PRUint32 metaOrigLen;
   1.444 +    AutoSwap_PRUint32 privOffset;
   1.445 +    AutoSwap_PRUint32 privLen;
   1.446 +};
   1.447 +
   1.448 +void
   1.449 +gfxUserFontSet::CopyWOFFMetadata(const uint8_t* aFontData,
   1.450 +                                 uint32_t aLength,
   1.451 +                                 FallibleTArray<uint8_t>* aMetadata,
   1.452 +                                 uint32_t* aMetaOrigLen)
   1.453 +{
   1.454 +    // This function may be called with arbitrary, unvalidated "font" data
   1.455 +    // from @font-face, so it needs to be careful to bounds-check, etc.,
   1.456 +    // before trying to read anything.
   1.457 +    // This just saves a copy of the compressed data block; it does NOT check
   1.458 +    // that the block can be successfully decompressed, or that it contains
   1.459 +    // well-formed/valid XML metadata.
   1.460 +    if (aLength < sizeof(WOFFHeader)) {
   1.461 +        return;
   1.462 +    }
   1.463 +    const WOFFHeader* woff = reinterpret_cast<const WOFFHeader*>(aFontData);
   1.464 +    uint32_t metaOffset = woff->metaOffset;
   1.465 +    uint32_t metaCompLen = woff->metaCompLen;
   1.466 +    if (!metaOffset || !metaCompLen || !woff->metaOrigLen) {
   1.467 +        return;
   1.468 +    }
   1.469 +    if (metaOffset >= aLength || metaCompLen > aLength - metaOffset) {
   1.470 +        return;
   1.471 +    }
   1.472 +    if (!aMetadata->SetLength(woff->metaCompLen)) {
   1.473 +        return;
   1.474 +    }
   1.475 +    memcpy(aMetadata->Elements(), aFontData + metaOffset, metaCompLen);
   1.476 +    *aMetaOrigLen = woff->metaOrigLen;
   1.477 +}
   1.478 +
   1.479 +// This is called when a font download finishes.
   1.480 +// Ownership of aFontData passes in here, and the font set must
   1.481 +// ensure that it is eventually deleted via NS_Free().
   1.482 +bool
   1.483 +gfxUserFontSet::OnLoadComplete(gfxMixedFontFamily *aFamily,
   1.484 +                               gfxProxyFontEntry *aProxy,
   1.485 +                               const uint8_t *aFontData, uint32_t aLength,
   1.486 +                               nsresult aDownloadStatus)
   1.487 +{
   1.488 +    // forget about the loader, as we no longer potentially need to cancel it
   1.489 +    // if the entry is obsoleted
   1.490 +    aProxy->mLoader = nullptr;
   1.491 +
   1.492 +    // download successful, make platform font using font data
   1.493 +    if (NS_SUCCEEDED(aDownloadStatus)) {
   1.494 +        gfxFontEntry *fe = LoadFont(aFamily, aProxy, aFontData, aLength);
   1.495 +        aFontData = nullptr;
   1.496 +
   1.497 +        if (fe) {
   1.498 +            IncrementGeneration();
   1.499 +            return true;
   1.500 +        }
   1.501 +
   1.502 +    } else {
   1.503 +        // download failed
   1.504 +        LogMessage(aFamily, aProxy,
   1.505 +                   "download failed", nsIScriptError::errorFlag,
   1.506 +                   aDownloadStatus);
   1.507 +    }
   1.508 +
   1.509 +    if (aFontData) {
   1.510 +        NS_Free((void*)aFontData);
   1.511 +    }
   1.512 +
   1.513 +    // error occurred, load next src
   1.514 +    (void)LoadNext(aFamily, aProxy);
   1.515 +
   1.516 +    // We ignore the status returned by LoadNext();
   1.517 +    // even if loading failed, we need to bump the font-set generation
   1.518 +    // and return true in order to trigger reflow, so that fallback
   1.519 +    // will be used where the text was "masked" by the pending download
   1.520 +    IncrementGeneration();
   1.521 +    return true;
   1.522 +}
   1.523 +
   1.524 +
   1.525 +gfxUserFontSet::LoadStatus
   1.526 +gfxUserFontSet::LoadNext(gfxMixedFontFamily *aFamily,
   1.527 +                         gfxProxyFontEntry *aProxyEntry)
   1.528 +{
   1.529 +    uint32_t numSrc = aProxyEntry->mSrcList.Length();
   1.530 +
   1.531 +    NS_ASSERTION(aProxyEntry->mSrcIndex < numSrc,
   1.532 +                 "already at the end of the src list for user font");
   1.533 +
   1.534 +    if (aProxyEntry->mLoadingState == gfxProxyFontEntry::NOT_LOADING) {
   1.535 +        aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_STARTED;
   1.536 +        aProxyEntry->mUnsupportedFormat = false;
   1.537 +    } else {
   1.538 +        // we were already loading; move to the next source,
   1.539 +        // but don't reset state - if we've already timed out,
   1.540 +        // that counts against the new download
   1.541 +        aProxyEntry->mSrcIndex++;
   1.542 +    }
   1.543 +
   1.544 +    /* If there are any urls, prefer them to local */
   1.545 +    bool listHasURL = false; 
   1.546 +    for (uint32_t i = aProxyEntry->mSrcIndex; i < numSrc; i++) {
   1.547 +        const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[i];
   1.548 +        if (!currSrc.mIsLocal) {
   1.549 +           listHasURL = true;
   1.550 +           break;
   1.551 +        }
   1.552 +    }
   1.553 +    nsPresContext *pres = GetPresContext();
   1.554 +    /* If we have no pres context, simply fail this load */
   1.555 +    if (!pres) listHasURL = true;
   1.556 +
   1.557 +    // load each src entry in turn, until a local face is found
   1.558 +    // or a download begins successfully
   1.559 +    while (aProxyEntry->mSrcIndex < numSrc) {
   1.560 +        const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[aProxyEntry->mSrcIndex];
   1.561 +
   1.562 +        // src local ==> lookup and load immediately
   1.563 +
   1.564 +        if (!listHasURL && currSrc.mIsLocal) {
   1.565 +            nsFont font;
   1.566 +            font.name = currSrc.mLocalName;
   1.567 +            gfxFontEntry *fe =
   1.568 +                gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry,
   1.569 +                                                            currSrc.mLocalName);                                                            
   1.570 +            pres->AddFontAttempt(font);
   1.571 +
   1.572 +            /* No more fonts for you */
   1.573 +            if (pres->FontAttemptCountReached(font) || 
   1.574 +                pres->FontUseCountReached(font)) {
   1.575 +                break;
   1.576 +            }
   1.577 +
   1.578 +            mLocalRulesUsed = true;
   1.579 +            if (fe) {
   1.580 +                pres->AddFontUse(font);
   1.581 +                LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
   1.582 +                     this, aProxyEntry->mSrcIndex,
   1.583 +                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
   1.584 +                     NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
   1.585 +                     uint32_t(mGeneration)));
   1.586 +                fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
   1.587 +                fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
   1.588 +                // For src:local(), we don't care whether the request is from
   1.589 +                // a private window as there's no issue of caching resources;
   1.590 +                // local fonts are just available all the time.
   1.591 +                StoreUserFontData(fe, aProxyEntry, false, nsString(), nullptr, 0);
   1.592 +                ReplaceFontEntry(aFamily, aProxyEntry, fe);
   1.593 +                return STATUS_LOADED;
   1.594 +            } else {
   1.595 +                LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
   1.596 +                     this, aProxyEntry->mSrcIndex,
   1.597 +                     NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
   1.598 +                     NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
   1.599 +            }
   1.600 +        }
   1.601 +
   1.602 +        // src url ==> start the load process
   1.603 +        else {
   1.604 +            if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
   1.605 +                    currSrc.mFormatFlags)) {
   1.606 +
   1.607 +                nsIPrincipal *principal = nullptr;
   1.608 +                bool bypassCache;
   1.609 +                nsresult rv = CheckFontLoad(&currSrc, &principal, &bypassCache);
   1.610 +
   1.611 +                if (NS_SUCCEEDED(rv) && principal != nullptr) {
   1.612 +                    if (!bypassCache) {
   1.613 +                        // see if we have an existing entry for this source
   1.614 +                        gfxFontEntry *fe =
   1.615 +                            UserFontCache::GetFont(currSrc.mURI, principal,
   1.616 +                                                   aProxyEntry,
   1.617 +                                                   GetPrivateBrowsing());
   1.618 +                        if (fe) {
   1.619 +                            ReplaceFontEntry(aFamily, aProxyEntry, fe);
   1.620 +                            return STATUS_LOADED;
   1.621 +                        }
   1.622 +                    }
   1.623 +
   1.624 +                    // record the principal returned by CheckFontLoad,
   1.625 +                    // for use when creating a channel
   1.626 +                    // and when caching the loaded entry
   1.627 +                    aProxyEntry->mPrincipal = principal;
   1.628 +
   1.629 +                    bool loadDoesntSpin = false;
   1.630 +                    rv = NS_URIChainHasFlags(currSrc.mURI,
   1.631 +                           nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
   1.632 +                           &loadDoesntSpin);
   1.633 +                    if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
   1.634 +                        uint8_t *buffer = nullptr;
   1.635 +                        uint32_t bufferLength = 0;
   1.636 +
   1.637 +                        // sync load font immediately
   1.638 +                        rv = SyncLoadFontData(aProxyEntry, &currSrc,
   1.639 +                                              buffer, bufferLength);
   1.640 +                        if (NS_SUCCEEDED(rv) && LoadFont(aFamily, aProxyEntry,
   1.641 +                                                         buffer, bufferLength)) {
   1.642 +                            return STATUS_LOADED;
   1.643 +                        } else {
   1.644 +                            LogMessage(aFamily, aProxyEntry,
   1.645 +                                       "font load failed",
   1.646 +                                       nsIScriptError::errorFlag, rv);
   1.647 +                        }
   1.648 +                    } else {
   1.649 +                        // otherwise load font async
   1.650 +                        rv = StartLoad(aFamily, aProxyEntry, &currSrc);
   1.651 +                        if (NS_SUCCEEDED(rv)) {
   1.652 +#ifdef PR_LOGGING
   1.653 +                            if (LOG_ENABLED()) {
   1.654 +                                nsAutoCString fontURI;
   1.655 +                                currSrc.mURI->GetSpec(fontURI);
   1.656 +                                LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
   1.657 +                                     this, aProxyEntry->mSrcIndex, fontURI.get(),
   1.658 +                                     NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
   1.659 +                            }
   1.660 +#endif
   1.661 +                            return STATUS_LOADING;
   1.662 +                        } else {
   1.663 +                            LogMessage(aFamily, aProxyEntry,
   1.664 +                                       "download failed",
   1.665 +                                       nsIScriptError::errorFlag, rv);
   1.666 +                        }
   1.667 +                    }
   1.668 +                } else {
   1.669 +                    LogMessage(aFamily, aProxyEntry, "download not allowed",
   1.670 +                               nsIScriptError::errorFlag, rv);
   1.671 +                }
   1.672 +            } else {
   1.673 +                // We don't log a warning to the web console yet,
   1.674 +                // as another source may load successfully
   1.675 +                aProxyEntry->mUnsupportedFormat = true;
   1.676 +            }
   1.677 +        }
   1.678 +
   1.679 +        aProxyEntry->mSrcIndex++;
   1.680 +    }
   1.681 +
   1.682 +    if (aProxyEntry->mUnsupportedFormat) {
   1.683 +        LogMessage(aFamily, aProxyEntry, "no supported format found",
   1.684 +                   nsIScriptError::warningFlag);
   1.685 +    }
   1.686 +
   1.687 +    // all src's failed; mark this entry as unusable (so fallback will occur)
   1.688 +    LOG(("userfonts (%p) failed all src for (%s)\n",
   1.689 +        this, NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
   1.690 +    aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_FAILED;
   1.691 +
   1.692 +    return STATUS_END_OF_LIST;
   1.693 +}
   1.694 +
   1.695 +void
   1.696 +gfxUserFontSet::IncrementGeneration()
   1.697 +{
   1.698 +    // add one, increment again if zero
   1.699 +    ++sFontSetGeneration;
   1.700 +    if (sFontSetGeneration == 0)
   1.701 +       ++sFontSetGeneration;
   1.702 +    mGeneration = sFontSetGeneration;
   1.703 +}
   1.704 +
   1.705 +void
   1.706 +gfxUserFontSet::RebuildLocalRules()
   1.707 +{
   1.708 +    if (mLocalRulesUsed) {
   1.709 +        DoRebuildUserFontSet();
   1.710 +    }
   1.711 +}
   1.712 +
   1.713 +gfxFontEntry*
   1.714 +gfxUserFontSet::LoadFont(gfxMixedFontFamily *aFamily,
   1.715 +                         gfxProxyFontEntry *aProxy,
   1.716 +                         const uint8_t *aFontData, uint32_t &aLength)
   1.717 +{
   1.718 +    gfxFontEntry *fe = nullptr;
   1.719 +
   1.720 +    gfxUserFontType fontType =
   1.721 +        gfxFontUtils::DetermineFontDataType(aFontData, aLength);
   1.722 +
   1.723 +    // Unwrap/decompress/sanitize or otherwise munge the downloaded data
   1.724 +    // to make a usable sfnt structure.
   1.725 +
   1.726 +    // Because platform font activation code may replace the name table
   1.727 +    // in the font with a synthetic one, we save the original name so that
   1.728 +    // it can be reported via the nsIDOMFontFace API.
   1.729 +    nsAutoString originalFullName;
   1.730 +
   1.731 +    // Call the OTS sanitizer; this will also decode WOFF to sfnt
   1.732 +    // if necessary. The original data in aFontData is left unchanged.
   1.733 +    uint32_t saneLen;
   1.734 +    const uint8_t* saneData =
   1.735 +        SanitizeOpenTypeData(aFamily, aProxy, aFontData, aLength, saneLen,
   1.736 +                             fontType == GFX_USERFONT_WOFF);
   1.737 +    if (!saneData) {
   1.738 +        LogMessage(aFamily, aProxy, "rejected by sanitizer");
   1.739 +    }
   1.740 +    if (saneData) {
   1.741 +        // The sanitizer ensures that we have a valid sfnt and a usable
   1.742 +        // name table, so this should never fail unless we're out of
   1.743 +        // memory, and GetFullNameFromSFNT is not directly exposed to
   1.744 +        // arbitrary/malicious data from the web.
   1.745 +        gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
   1.746 +                                          originalFullName);
   1.747 +        // Here ownership of saneData is passed to the platform,
   1.748 +        // which will delete it when no longer required
   1.749 +        fe = gfxPlatform::GetPlatform()->MakePlatformFont(aProxy,
   1.750 +                                                          saneData,
   1.751 +                                                          saneLen);
   1.752 +        if (!fe) {
   1.753 +            LogMessage(aFamily, aProxy, "not usable by platform");
   1.754 +        }
   1.755 +    }
   1.756 +
   1.757 +    if (fe) {
   1.758 +        // Save a copy of the metadata block (if present) for nsIDOMFontFace
   1.759 +        // to use if required. Ownership of the metadata block will be passed
   1.760 +        // to the gfxUserFontData record below.
   1.761 +        FallibleTArray<uint8_t> metadata;
   1.762 +        uint32_t metaOrigLen = 0;
   1.763 +        if (fontType == GFX_USERFONT_WOFF) {
   1.764 +            CopyWOFFMetadata(aFontData, aLength, &metadata, &metaOrigLen);
   1.765 +        }
   1.766 +
   1.767 +        // copy OpenType feature/language settings from the proxy to the
   1.768 +        // newly-created font entry
   1.769 +        fe->mFeatureSettings.AppendElements(aProxy->mFeatureSettings);
   1.770 +        fe->mLanguageOverride = aProxy->mLanguageOverride;
   1.771 +        StoreUserFontData(fe, aProxy, GetPrivateBrowsing(),
   1.772 +                          originalFullName, &metadata, metaOrigLen);
   1.773 +#ifdef PR_LOGGING
   1.774 +        if (LOG_ENABLED()) {
   1.775 +            nsAutoCString fontURI;
   1.776 +            aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
   1.777 +            LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
   1.778 +                 this, aProxy->mSrcIndex, fontURI.get(),
   1.779 +                 NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
   1.780 +                 uint32_t(mGeneration)));
   1.781 +        }
   1.782 +#endif
   1.783 +        ReplaceFontEntry(aFamily, aProxy, fe);
   1.784 +        UserFontCache::CacheFont(fe);
   1.785 +    } else {
   1.786 +#ifdef PR_LOGGING
   1.787 +        if (LOG_ENABLED()) {
   1.788 +            nsAutoCString fontURI;
   1.789 +            aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
   1.790 +            LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
   1.791 +                 " error making platform font\n",
   1.792 +                 this, aProxy->mSrcIndex, fontURI.get(),
   1.793 +                 NS_ConvertUTF16toUTF8(aFamily->Name()).get()));
   1.794 +        }
   1.795 +#endif
   1.796 +    }
   1.797 +
   1.798 +    // The downloaded data can now be discarded; the font entry is using the
   1.799 +    // sanitized copy
   1.800 +    NS_Free((void*)aFontData);
   1.801 +
   1.802 +    return fe;
   1.803 +}
   1.804 +
   1.805 +gfxFontFamily*
   1.806 +gfxUserFontSet::GetFamily(const nsAString& aFamilyName) const
   1.807 +{
   1.808 +    nsAutoString key(aFamilyName);
   1.809 +    ToLowerCase(key);
   1.810 +
   1.811 +    return mFontFamilies.GetWeak(key);
   1.812 +}
   1.813 +
   1.814 +struct FindFamilyCallbackData {
   1.815 +    gfxFontEntry  *mFontEntry;
   1.816 +    gfxFontFamily *mFamily;
   1.817 +};
   1.818 +
   1.819 +static PLDHashOperator
   1.820 +FindFamilyCallback(const nsAString&    aName,
   1.821 +                   gfxMixedFontFamily* aFamily,
   1.822 +                   void*               aUserArg)
   1.823 +{
   1.824 +    FindFamilyCallbackData *d = static_cast<FindFamilyCallbackData*>(aUserArg);
   1.825 +    if (aFamily->ContainsFace(d->mFontEntry)) {
   1.826 +        d->mFamily = aFamily;
   1.827 +        return PL_DHASH_STOP;
   1.828 +    }
   1.829 +
   1.830 +    return PL_DHASH_NEXT;
   1.831 +}
   1.832 +
   1.833 +gfxFontFamily*
   1.834 +gfxUserFontSet::FindFamilyFor(gfxFontEntry* aFontEntry) const
   1.835 +{
   1.836 +    FindFamilyCallbackData d = { aFontEntry, nullptr };
   1.837 +    mFontFamilies.EnumerateRead(FindFamilyCallback, &d);
   1.838 +    return d.mFamily;
   1.839 +}
   1.840 +
   1.841 +///////////////////////////////////////////////////////////////////////////////
   1.842 +// gfxUserFontSet::UserFontCache - re-use platform font entries for user fonts
   1.843 +// across pages/fontsets rather than instantiating new platform fonts.
   1.844 +//
   1.845 +// Entries are added to this cache when a platform font is instantiated from
   1.846 +// downloaded data, and removed when the platform font entry is destroyed.
   1.847 +// We don't need to use a timed expiration scheme here because the gfxFontEntry
   1.848 +// for a downloaded font will be kept alive by its corresponding gfxFont
   1.849 +// instance(s) until they are deleted, and *that* happens using an expiration
   1.850 +// tracker (gfxFontCache). The result is that the downloaded font instances
   1.851 +// recorded here will persist between pages and can get reused (provided the
   1.852 +// source URI and principal match, of course).
   1.853 +///////////////////////////////////////////////////////////////////////////////
   1.854 +
   1.855 +nsTHashtable<gfxUserFontSet::UserFontCache::Entry>*
   1.856 +    gfxUserFontSet::UserFontCache::sUserFonts = nullptr;
   1.857 +
   1.858 +NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::Flusher, nsIObserver)
   1.859 +
   1.860 +PLDHashOperator
   1.861 +gfxUserFontSet::UserFontCache::Entry::RemoveIfPrivate(Entry* aEntry,
   1.862 +                                                      void* aUserData)
   1.863 +{
   1.864 +    return aEntry->mPrivate ? PL_DHASH_REMOVE : PL_DHASH_NEXT;
   1.865 +}
   1.866 +
   1.867 +PLDHashOperator
   1.868 +gfxUserFontSet::UserFontCache::Entry::RemoveIfMatches(Entry* aEntry,
   1.869 +                                                      void* aUserData)
   1.870 +{
   1.871 +    return aEntry->GetFontEntry() == static_cast<gfxFontEntry*>(aUserData) ?
   1.872 +        PL_DHASH_REMOVE : PL_DHASH_NEXT;
   1.873 +}
   1.874 +
   1.875 +PLDHashOperator
   1.876 +gfxUserFontSet::UserFontCache::Entry::DisconnectSVG(Entry* aEntry,
   1.877 +                                                    void* aUserData)
   1.878 +{
   1.879 +    aEntry->GetFontEntry()->DisconnectSVG();
   1.880 +    return PL_DHASH_NEXT;
   1.881 +}
   1.882 +
   1.883 +NS_IMETHODIMP
   1.884 +gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject,
   1.885 +                                                const char* aTopic,
   1.886 +                                                const char16_t* aData)
   1.887 +{
   1.888 +    if (!sUserFonts) {
   1.889 +        return NS_OK;
   1.890 +    }
   1.891 +
   1.892 +    if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID)) {
   1.893 +        sUserFonts->Clear();
   1.894 +    } else if (!strcmp(aTopic, "last-pb-context-exited")) {
   1.895 +        sUserFonts->EnumerateEntries(Entry::RemoveIfPrivate, nullptr);
   1.896 +    } else if (!strcmp(aTopic, "xpcom-shutdown")) {
   1.897 +        sUserFonts->EnumerateEntries(Entry::DisconnectSVG, nullptr);
   1.898 +    } else {
   1.899 +        NS_NOTREACHED("unexpected topic");
   1.900 +    }
   1.901 +
   1.902 +    return NS_OK;
   1.903 +}
   1.904 +
   1.905 +bool
   1.906 +gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
   1.907 +{
   1.908 +    bool equal;
   1.909 +    if (NS_FAILED(mURI->Equals(aKey->mURI, &equal)) || !equal) {
   1.910 +        return false;
   1.911 +    }
   1.912 +
   1.913 +    if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &equal)) || !equal) {
   1.914 +        return false;
   1.915 +    }
   1.916 +
   1.917 +    if (mPrivate != aKey->mPrivate) {
   1.918 +        return false;
   1.919 +    }
   1.920 +
   1.921 +    const gfxFontEntry *fe = aKey->mFontEntry;
   1.922 +    if (mFontEntry->mItalic           != fe->mItalic          ||
   1.923 +        mFontEntry->mWeight           != fe->mWeight          ||
   1.924 +        mFontEntry->mStretch          != fe->mStretch         ||
   1.925 +        mFontEntry->mFeatureSettings  != fe->mFeatureSettings ||
   1.926 +        mFontEntry->mLanguageOverride != fe->mLanguageOverride ||
   1.927 +        mFontEntry->mFamilyName       != fe->mFamilyName) {
   1.928 +        return false;
   1.929 +    }
   1.930 +
   1.931 +    return true;
   1.932 +}
   1.933 +
   1.934 +void
   1.935 +gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry)
   1.936 +{
   1.937 +    NS_ASSERTION(aFontEntry->mFamilyName.Length() != 0,
   1.938 +                 "caching a font associated with no family yet");
   1.939 +    if (!sUserFonts) {
   1.940 +        sUserFonts = new nsTHashtable<Entry>;
   1.941 +
   1.942 +        nsCOMPtr<nsIObserverService> obs =
   1.943 +            mozilla::services::GetObserverService();
   1.944 +        if (obs) {
   1.945 +            Flusher *flusher = new Flusher;
   1.946 +            obs->AddObserver(flusher, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID,
   1.947 +                             false);
   1.948 +            obs->AddObserver(flusher, "last-pb-context-exited", false);
   1.949 +            obs->AddObserver(flusher, "xpcom-shutdown", false);
   1.950 +        }
   1.951 +    }
   1.952 +
   1.953 +    gfxUserFontData *data = aFontEntry->mUserFontData;
   1.954 +    sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry,
   1.955 +                             data->mPrivate));
   1.956 +
   1.957 +#ifdef DEBUG_USERFONT_CACHE
   1.958 +    printf("userfontcache added fontentry: %p\n", aFontEntry);
   1.959 +    Dump();
   1.960 +#endif
   1.961 +}
   1.962 +
   1.963 +void
   1.964 +gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry *aFontEntry)
   1.965 +{
   1.966 +    if (!sUserFonts) {
   1.967 +        // if we've already deleted the cache (i.e. during shutdown),
   1.968 +        // just ignore this
   1.969 +        return;
   1.970 +    }
   1.971 +
   1.972 +    // We can't simply use RemoveEntry here because it's possible the principal
   1.973 +    // may have changed since the font was cached, in which case the lookup
   1.974 +    // would no longer find the entry (bug 838105).
   1.975 +    sUserFonts->EnumerateEntries(
   1.976 +        gfxUserFontSet::UserFontCache::Entry::RemoveIfMatches, aFontEntry);
   1.977 +
   1.978 +#ifdef DEBUG_USERFONT_CACHE
   1.979 +    printf("userfontcache removed fontentry: %p\n", aFontEntry);
   1.980 +    Dump();
   1.981 +#endif
   1.982 +}
   1.983 +
   1.984 +gfxFontEntry*
   1.985 +gfxUserFontSet::UserFontCache::GetFont(nsIURI            *aSrcURI,
   1.986 +                                       nsIPrincipal      *aPrincipal,
   1.987 +                                       gfxProxyFontEntry *aProxy,
   1.988 +                                       bool               aPrivate)
   1.989 +{
   1.990 +    if (!sUserFonts) {
   1.991 +        return nullptr;
   1.992 +    }
   1.993 +
   1.994 +    Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, aPrincipal, aProxy,
   1.995 +                                            aPrivate));
   1.996 +    if (entry) {
   1.997 +        return entry->GetFontEntry();
   1.998 +    }
   1.999 +
  1.1000 +    return nullptr;
  1.1001 +}
  1.1002 +
  1.1003 +void
  1.1004 +gfxUserFontSet::UserFontCache::Shutdown()
  1.1005 +{
  1.1006 +    if (sUserFonts) {
  1.1007 +        delete sUserFonts;
  1.1008 +        sUserFonts = nullptr;
  1.1009 +    }
  1.1010 +}
  1.1011 +
  1.1012 +#ifdef DEBUG_USERFONT_CACHE
  1.1013 +
  1.1014 +PLDHashOperator
  1.1015 +gfxUserFontSet::UserFontCache::Entry::DumpEntry(Entry* aEntry, void* aUserData)
  1.1016 +{
  1.1017 +    nsresult rv;
  1.1018 +
  1.1019 +    nsAutoCString principalURISpec;
  1.1020 +
  1.1021 +    nsCOMPtr<nsIURI> principalURI;
  1.1022 +    rv = aEntry->mPrincipal->GetURI(getter_AddRefs(principalURI));
  1.1023 +    if (NS_SUCCEEDED(rv)) {
  1.1024 +        principalURI->GetSpec(principalURISpec);
  1.1025 +    }
  1.1026 +
  1.1027 +    bool setDomain = false;
  1.1028 +    nsCOMPtr<nsIURI> domainURI;
  1.1029 +
  1.1030 +    aEntry->mPrincipal->GetDomain(getter_AddRefs(domainURI));
  1.1031 +    if (domainURI) {
  1.1032 +        setDomain = true;
  1.1033 +    }
  1.1034 +
  1.1035 +    NS_ASSERTION(aEntry->mURI, "null URI in userfont cache entry");
  1.1036 +
  1.1037 +    printf("userfontcache fontEntry: %p fonturihash: %8.8x family: %s domainset: %s principal: [%s]\n",
  1.1038 +            aEntry->mFontEntry,
  1.1039 +            nsURIHashKey::HashKey(aEntry->mURI),
  1.1040 +            NS_ConvertUTF16toUTF8(aEntry->mFontEntry->FamilyName()).get(),
  1.1041 +            (setDomain ? "true" : "false"),
  1.1042 +            principalURISpec.get()
  1.1043 +           );
  1.1044 +    return PL_DHASH_NEXT;
  1.1045 +}
  1.1046 +
  1.1047 +void
  1.1048 +gfxUserFontSet::UserFontCache::Dump()
  1.1049 +{
  1.1050 +    if (!sUserFonts) {
  1.1051 +        return;
  1.1052 +    }
  1.1053 +
  1.1054 +    printf("userfontcache dump count: %d ========\n", sUserFonts->Count());
  1.1055 +    sUserFonts->EnumerateEntries(Entry::DumpEntry, nullptr);
  1.1056 +    printf("userfontcache dump ==================\n");
  1.1057 +}
  1.1058 +
  1.1059 +#endif

mercurial