layout/style/nsFontFaceLoader.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/style/nsFontFaceLoader.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1025 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +// vim:cindent:ts=2:et:sw=2:
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* code for loading in @font-face defined font data */
    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 +#include "prlog.h"
    1.16 +
    1.17 +#include "nsFontFaceLoader.h"
    1.18 +
    1.19 +#include "nsError.h"
    1.20 +#include "nsNetUtil.h"
    1.21 +#include "nsContentUtils.h"
    1.22 +#include "mozilla/Preferences.h"
    1.23 +
    1.24 +#include "nsPresContext.h"
    1.25 +#include "nsIPresShell.h"
    1.26 +#include "nsIPrincipal.h"
    1.27 +#include "nsIScriptSecurityManager.h"
    1.28 +
    1.29 +#include "nsIContentPolicy.h"
    1.30 +#include "nsContentPolicyUtils.h"
    1.31 +#include "nsCrossSiteListenerProxy.h"
    1.32 +#include "nsIContentSecurityPolicy.h"
    1.33 +#include "nsIDocShell.h"
    1.34 +#include "nsIWebNavigation.h"
    1.35 +#include "nsISupportsPriority.h"
    1.36 +#include "nsINetworkSeer.h"
    1.37 +
    1.38 +#include "nsIConsoleService.h"
    1.39 +
    1.40 +#include "nsStyleSet.h"
    1.41 +#include "nsPrintfCString.h"
    1.42 +#include "mozilla/gfx/2D.h"
    1.43 +
    1.44 +using namespace mozilla;
    1.45 +
    1.46 +#ifdef PR_LOGGING
    1.47 +static PRLogModuleInfo* 
    1.48 +GetFontDownloaderLog()
    1.49 +{
    1.50 +  static PRLogModuleInfo* sLog;
    1.51 +  if (!sLog)
    1.52 +    sLog = PR_NewLogModule("fontdownloader");
    1.53 +  return sLog;
    1.54 +}
    1.55 +#endif /* PR_LOGGING */
    1.56 +
    1.57 +#define LOG(args) PR_LOG(GetFontDownloaderLog(), PR_LOG_DEBUG, args)
    1.58 +#define LOG_ENABLED() PR_LOG_TEST(GetFontDownloaderLog(), PR_LOG_DEBUG)
    1.59 +
    1.60 +
    1.61 +nsFontFaceLoader::nsFontFaceLoader(gfxMixedFontFamily* aFontFamily,
    1.62 +                                   gfxProxyFontEntry* aProxy,
    1.63 +                                   nsIURI* aFontURI,
    1.64 +                                   nsUserFontSet* aFontSet,
    1.65 +                                   nsIChannel* aChannel)
    1.66 +  : mFontFamily(aFontFamily),
    1.67 +    mFontEntry(aProxy),
    1.68 +    mFontURI(aFontURI),
    1.69 +    mFontSet(aFontSet),
    1.70 +    mChannel(aChannel)
    1.71 +{
    1.72 +}
    1.73 +
    1.74 +nsFontFaceLoader::~nsFontFaceLoader()
    1.75 +{
    1.76 +  if (mFontEntry) {
    1.77 +    mFontEntry->mLoader = nullptr;
    1.78 +  }
    1.79 +  if (mLoadTimer) {
    1.80 +    mLoadTimer->Cancel();
    1.81 +    mLoadTimer = nullptr;
    1.82 +  }
    1.83 +  if (mFontSet) {
    1.84 +    mFontSet->RemoveLoader(this);
    1.85 +  }
    1.86 +}
    1.87 +
    1.88 +void
    1.89 +nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader)
    1.90 +{
    1.91 +  int32_t loadTimeout =
    1.92 +    Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000);
    1.93 +  if (loadTimeout > 0) {
    1.94 +    mLoadTimer = do_CreateInstance("@mozilla.org/timer;1");
    1.95 +    if (mLoadTimer) {
    1.96 +      mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
    1.97 +                                       static_cast<void*>(this),
    1.98 +                                       loadTimeout,
    1.99 +                                       nsITimer::TYPE_ONE_SHOT);
   1.100 +    }
   1.101 +  } else if (loadTimeout == 0) {
   1.102 +    mFontEntry->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY;
   1.103 +  } // -1 disables fallback
   1.104 +  mStreamLoader = aStreamLoader;
   1.105 +}
   1.106 +
   1.107 +void
   1.108 +nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
   1.109 +{
   1.110 +  nsFontFaceLoader* loader = static_cast<nsFontFaceLoader*>(aClosure);
   1.111 +
   1.112 +  if (!loader->mFontSet) {
   1.113 +    // We've been canceled
   1.114 +    return;
   1.115 +  }
   1.116 +
   1.117 +  gfxProxyFontEntry* pe = loader->mFontEntry.get();
   1.118 +  bool updateUserFontSet = true;
   1.119 +
   1.120 +  // If the entry is loading, check whether it's >75% done; if so,
   1.121 +  // we allow another timeout period before showing a fallback font.
   1.122 +  if (pe->mLoadingState == gfxProxyFontEntry::LOADING_STARTED) {
   1.123 +    int64_t contentLength;
   1.124 +    uint32_t numBytesRead;
   1.125 +    if (NS_SUCCEEDED(loader->mChannel->GetContentLength(&contentLength)) &&
   1.126 +        contentLength > 0 &&
   1.127 +        contentLength < UINT32_MAX &&
   1.128 +        NS_SUCCEEDED(loader->mStreamLoader->GetNumBytesRead(&numBytesRead)) &&
   1.129 +        numBytesRead > 3 * (uint32_t(contentLength) >> 2))
   1.130 +    {
   1.131 +      // More than 3/4 the data has been downloaded, so allow 50% extra
   1.132 +      // time and hope the remainder will arrive before the additional
   1.133 +      // time expires.
   1.134 +      pe->mLoadingState = gfxProxyFontEntry::LOADING_ALMOST_DONE;
   1.135 +      uint32_t delay;
   1.136 +      loader->mLoadTimer->GetDelay(&delay);
   1.137 +      loader->mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
   1.138 +                                               static_cast<void*>(loader),
   1.139 +                                               delay >> 1,
   1.140 +                                               nsITimer::TYPE_ONE_SHOT);
   1.141 +      updateUserFontSet = false;
   1.142 +      LOG(("fontdownloader (%p) 75%% done, resetting timer\n", loader));
   1.143 +    }
   1.144 +  }
   1.145 +
   1.146 +  // If the font is not 75% loaded, or if we've already timed out once
   1.147 +  // before, we mark this entry as "loading slowly", so the fallback
   1.148 +  // font will be used in the meantime, and tell the context to refresh.
   1.149 +  if (updateUserFontSet) {
   1.150 +    pe->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY;
   1.151 +    gfxUserFontSet* fontSet = loader->mFontSet;
   1.152 +    nsPresContext* ctx = loader->mFontSet->GetPresContext();
   1.153 +    NS_ASSERTION(ctx, "userfontset doesn't have a presContext?");
   1.154 +    if (ctx) {
   1.155 +      fontSet->IncrementGeneration();
   1.156 +      ctx->UserFontSetUpdated();
   1.157 +      LOG(("fontdownloader (%p) timeout reflow\n", loader));
   1.158 +    }
   1.159 +  }
   1.160 +}
   1.161 +
   1.162 +NS_IMPL_ISUPPORTS(nsFontFaceLoader, nsIStreamLoaderObserver)
   1.163 +
   1.164 +NS_IMETHODIMP
   1.165 +nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
   1.166 +                                   nsISupports* aContext,
   1.167 +                                   nsresult aStatus,
   1.168 +                                   uint32_t aStringLen,
   1.169 +                                   const uint8_t* aString)
   1.170 +{
   1.171 +  if (!mFontSet) {
   1.172 +    // We've been canceled
   1.173 +    return aStatus;
   1.174 +  }
   1.175 +
   1.176 +  mFontSet->RemoveLoader(this);
   1.177 +
   1.178 +#ifdef PR_LOGGING
   1.179 +  if (LOG_ENABLED()) {
   1.180 +    nsAutoCString fontURI;
   1.181 +    mFontURI->GetSpec(fontURI);
   1.182 +    if (NS_SUCCEEDED(aStatus)) {
   1.183 +      LOG(("fontdownloader (%p) download completed - font uri: (%s)\n", 
   1.184 +           this, fontURI.get()));
   1.185 +    } else {
   1.186 +      LOG(("fontdownloader (%p) download failed - font uri: (%s) error: %8.8x\n", 
   1.187 +           this, fontURI.get(), aStatus));
   1.188 +    }
   1.189 +  }
   1.190 +#endif
   1.191 +
   1.192 +  nsPresContext* ctx = mFontSet->GetPresContext();
   1.193 +  NS_ASSERTION(ctx && !ctx->PresShell()->IsDestroying(),
   1.194 +               "We should have been canceled already");
   1.195 +
   1.196 +  if (NS_SUCCEEDED(aStatus)) {
   1.197 +    // for HTTP requests, check whether the request _actually_ succeeded;
   1.198 +    // the "request status" in aStatus does not necessarily indicate this,
   1.199 +    // because HTTP responses such as 404 (Not Found) will still result in
   1.200 +    // a success code and potentially an HTML error page from the server
   1.201 +    // as the resulting data. We don't want to use that as a font.
   1.202 +    nsCOMPtr<nsIRequest> request;
   1.203 +    nsCOMPtr<nsIHttpChannel> httpChannel;
   1.204 +    aLoader->GetRequest(getter_AddRefs(request));
   1.205 +    httpChannel = do_QueryInterface(request);
   1.206 +    if (httpChannel) {
   1.207 +      bool succeeded;
   1.208 +      nsresult rv = httpChannel->GetRequestSucceeded(&succeeded);
   1.209 +      if (NS_SUCCEEDED(rv) && !succeeded) {
   1.210 +        aStatus = NS_ERROR_NOT_AVAILABLE;
   1.211 +      }
   1.212 +    }
   1.213 +  }
   1.214 +
   1.215 +  // The userFontSet is responsible for freeing the downloaded data
   1.216 +  // (aString) when finished with it; the pointer is no longer valid
   1.217 +  // after OnLoadComplete returns.
   1.218 +  // This is called even in the case of a failed download (HTTP 404, etc),
   1.219 +  // as there may still be data to be freed (e.g. an error page),
   1.220 +  // and we need the fontSet to initiate loading the next source.
   1.221 +  bool fontUpdate = mFontSet->OnLoadComplete(mFontFamily, mFontEntry, aString,
   1.222 +                                             aStringLen, aStatus);
   1.223 +
   1.224 +  // when new font loaded, need to reflow
   1.225 +  if (fontUpdate) {
   1.226 +    // Update layout for the presence of the new font.  Since this is
   1.227 +    // asynchronous, reflows will coalesce.
   1.228 +    ctx->UserFontSetUpdated();
   1.229 +    LOG(("fontdownloader (%p) reflow\n", this));
   1.230 +  }
   1.231 +
   1.232 +  // done with font set
   1.233 +  mFontSet = nullptr;
   1.234 +  if (mLoadTimer) {
   1.235 +    mLoadTimer->Cancel();
   1.236 +    mLoadTimer = nullptr;
   1.237 +  }
   1.238 +
   1.239 +  return NS_SUCCESS_ADOPTED_DATA;
   1.240 +}
   1.241 +
   1.242 +void
   1.243 +nsFontFaceLoader::Cancel()
   1.244 +{
   1.245 +  mFontEntry->mLoadingState = gfxProxyFontEntry::NOT_LOADING;
   1.246 +  mFontEntry->mLoader = nullptr;
   1.247 +  mFontSet = nullptr;
   1.248 +  if (mLoadTimer) {
   1.249 +    mLoadTimer->Cancel();
   1.250 +    mLoadTimer = nullptr;
   1.251 +  }
   1.252 +  mChannel->Cancel(NS_BINDING_ABORTED);
   1.253 +}
   1.254 +
   1.255 +nsresult
   1.256 +nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
   1.257 +                                   nsIURI* aTargetURI,
   1.258 +                                   nsISupports* aContext)
   1.259 +{
   1.260 +  nsresult rv;
   1.261 +
   1.262 +  if (!aSourcePrincipal)
   1.263 +    return NS_OK;
   1.264 +
   1.265 +  // check with the security manager
   1.266 +  nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   1.267 +  rv = secMan->CheckLoadURIWithPrincipal(aSourcePrincipal, aTargetURI,
   1.268 +                                        nsIScriptSecurityManager::STANDARD);
   1.269 +  if (NS_FAILED(rv)) {
   1.270 +    return rv;
   1.271 +  }
   1.272 +
   1.273 +  // check content policy
   1.274 +  int16_t shouldLoad = nsIContentPolicy::ACCEPT;
   1.275 +  rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
   1.276 +                                 aTargetURI,
   1.277 +                                 aSourcePrincipal,
   1.278 +                                 aContext,
   1.279 +                                 EmptyCString(), // mime type
   1.280 +                                 nullptr,
   1.281 +                                 &shouldLoad,
   1.282 +                                 nsContentUtils::GetContentPolicy(),
   1.283 +                                 nsContentUtils::GetSecurityManager());
   1.284 +
   1.285 +  if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
   1.286 +    return NS_ERROR_CONTENT_BLOCKED;
   1.287 +  }
   1.288 +
   1.289 +  return NS_OK;
   1.290 +}
   1.291 +
   1.292 +nsUserFontSet::nsUserFontSet(nsPresContext* aContext)
   1.293 +  : mPresContext(aContext)
   1.294 +{
   1.295 +  NS_ASSERTION(mPresContext, "null context passed to nsUserFontSet");
   1.296 +}
   1.297 +
   1.298 +nsUserFontSet::~nsUserFontSet()
   1.299 +{
   1.300 +  NS_ASSERTION(mLoaders.Count() == 0, "mLoaders should have been emptied");
   1.301 +}
   1.302 +
   1.303 +static PLDHashOperator DestroyIterator(nsPtrHashKey<nsFontFaceLoader>* aKey,
   1.304 +                                       void* aUserArg)
   1.305 +{
   1.306 +  aKey->GetKey()->Cancel();
   1.307 +  return PL_DHASH_REMOVE;
   1.308 +}
   1.309 +
   1.310 +void
   1.311 +nsUserFontSet::Destroy()
   1.312 +{
   1.313 +  mPresContext = nullptr;
   1.314 +  mLoaders.EnumerateEntries(DestroyIterator, nullptr);
   1.315 +  mRules.Clear();
   1.316 +}
   1.317 +
   1.318 +void
   1.319 +nsUserFontSet::RemoveLoader(nsFontFaceLoader* aLoader)
   1.320 +{
   1.321 +  mLoaders.RemoveEntry(aLoader);
   1.322 +}
   1.323 +
   1.324 +nsresult
   1.325 +nsUserFontSet::StartLoad(gfxMixedFontFamily* aFamily,
   1.326 +                         gfxProxyFontEntry* aProxy,
   1.327 +                         const gfxFontFaceSrc* aFontFaceSrc)
   1.328 +{
   1.329 +  nsresult rv;
   1.330 +
   1.331 +  nsIPresShell* ps = mPresContext->PresShell();
   1.332 +  if (!ps)
   1.333 +    return NS_ERROR_FAILURE;
   1.334 +
   1.335 +  nsCOMPtr<nsIStreamLoader> streamLoader;
   1.336 +  nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
   1.337 +
   1.338 +  nsCOMPtr<nsIChannel> channel;
   1.339 +  // get Content Security Policy from principal to pass into channel
   1.340 +  nsCOMPtr<nsIChannelPolicy> channelPolicy;
   1.341 +  nsCOMPtr<nsIContentSecurityPolicy> csp;
   1.342 +  rv = aProxy->mPrincipal->GetCsp(getter_AddRefs(csp));
   1.343 +  NS_ENSURE_SUCCESS(rv, rv);
   1.344 +  if (csp) {
   1.345 +    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
   1.346 +    channelPolicy->SetContentSecurityPolicy(csp);
   1.347 +    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
   1.348 +  }
   1.349 +  rv = NS_NewChannel(getter_AddRefs(channel),
   1.350 +                     aFontFaceSrc->mURI,
   1.351 +                     nullptr,
   1.352 +                     loadGroup,
   1.353 +                     nullptr,
   1.354 +                     nsIRequest::LOAD_NORMAL,
   1.355 +                     channelPolicy);
   1.356 +
   1.357 +  NS_ENSURE_SUCCESS(rv, rv);
   1.358 +
   1.359 +  nsRefPtr<nsFontFaceLoader> fontLoader =
   1.360 +    new nsFontFaceLoader(aFamily, aProxy, aFontFaceSrc->mURI, this, channel);
   1.361 +
   1.362 +  if (!fontLoader)
   1.363 +    return NS_ERROR_OUT_OF_MEMORY;
   1.364 +
   1.365 +#ifdef PR_LOGGING
   1.366 +  if (LOG_ENABLED()) {
   1.367 +    nsAutoCString fontURI, referrerURI;
   1.368 +    aFontFaceSrc->mURI->GetSpec(fontURI);
   1.369 +    if (aFontFaceSrc->mReferrer)
   1.370 +      aFontFaceSrc->mReferrer->GetSpec(referrerURI);
   1.371 +    LOG(("fontdownloader (%p) download start - font uri: (%s) "
   1.372 +         "referrer uri: (%s)\n",
   1.373 +         fontLoader.get(), fontURI.get(), referrerURI.get()));
   1.374 +  }
   1.375 +#endif
   1.376 +
   1.377 +  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   1.378 +  if (httpChannel)
   1.379 +    httpChannel->SetReferrer(aFontFaceSrc->mReferrer);
   1.380 +  nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
   1.381 +  if (priorityChannel) {
   1.382 +    priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
   1.383 +  }
   1.384 +
   1.385 +  rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
   1.386 +  NS_ENSURE_SUCCESS(rv, rv);
   1.387 +
   1.388 +  nsIDocument *document = ps->GetDocument();
   1.389 +  mozilla::net::SeerLearn(aFontFaceSrc->mURI, document->GetDocumentURI(),
   1.390 +                          nsINetworkSeer::LEARN_LOAD_SUBRESOURCE, loadGroup);
   1.391 +
   1.392 +  bool inherits = false;
   1.393 +  rv = NS_URIChainHasFlags(aFontFaceSrc->mURI,
   1.394 +                           nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
   1.395 +                           &inherits);
   1.396 +  if (NS_SUCCEEDED(rv) && inherits) {
   1.397 +    // allow data, javascript, etc URI's
   1.398 +    rv = channel->AsyncOpen(streamLoader, nullptr);
   1.399 +  } else {
   1.400 +    nsRefPtr<nsCORSListenerProxy> listener =
   1.401 +      new nsCORSListenerProxy(streamLoader, aProxy->mPrincipal, false);
   1.402 +    rv = listener->Init(channel);
   1.403 +    if (NS_SUCCEEDED(rv)) {
   1.404 +      rv = channel->AsyncOpen(listener, nullptr);
   1.405 +    }
   1.406 +    if (NS_FAILED(rv)) {
   1.407 +      fontLoader->DropChannel();  // explicitly need to break ref cycle
   1.408 +    }
   1.409 +  }
   1.410 +
   1.411 +  if (NS_SUCCEEDED(rv)) {
   1.412 +    mLoaders.PutEntry(fontLoader);
   1.413 +    fontLoader->StartedLoading(streamLoader);
   1.414 +    aProxy->mLoader = fontLoader; // let the font entry remember the loader,
   1.415 +                                  // in case we need to cancel it
   1.416 +  }
   1.417 +
   1.418 +  return rv;
   1.419 +}
   1.420 +
   1.421 +static PLDHashOperator DetachFontEntries(const nsAString& aKey,
   1.422 +                                         nsRefPtr<gfxMixedFontFamily>& aFamily,
   1.423 +                                         void* aUserArg)
   1.424 +{
   1.425 +  aFamily->DetachFontEntries();
   1.426 +  return PL_DHASH_NEXT;
   1.427 +}
   1.428 +
   1.429 +static PLDHashOperator RemoveIfEmpty(const nsAString& aKey,
   1.430 +                                     nsRefPtr<gfxMixedFontFamily>& aFamily,
   1.431 +                                     void* aUserArg)
   1.432 +{
   1.433 +  return aFamily->GetFontList().Length() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
   1.434 +}
   1.435 +
   1.436 +bool
   1.437 +nsUserFontSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
   1.438 +{
   1.439 +  bool modified = false;
   1.440 +
   1.441 +  // The @font-face rules that make up the user font set have changed,
   1.442 +  // so we need to update the set. However, we want to preserve existing
   1.443 +  // font entries wherever possible, so that we don't discard and then
   1.444 +  // re-download resources in the (common) case where at least some of the
   1.445 +  // same rules are still present.
   1.446 +
   1.447 +  nsTArray<FontFaceRuleRecord> oldRules;
   1.448 +  mRules.SwapElements(oldRules);
   1.449 +
   1.450 +  // Remove faces from the font family records; we need to re-insert them
   1.451 +  // because we might end up with faces in a different order even if they're
   1.452 +  // the same font entries as before. (The order can affect font selection
   1.453 +  // where multiple faces match the requested style, perhaps with overlapping
   1.454 +  // unicode-range coverage.)
   1.455 +  mFontFamilies.Enumerate(DetachFontEntries, nullptr);
   1.456 +
   1.457 +  for (uint32_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
   1.458 +    // Insert each rule into our list, migrating old font entries if possible
   1.459 +    // rather than creating new ones; set  modified  to true if we detect
   1.460 +    // that rule ordering has changed, or if a new entry is created.
   1.461 +    InsertRule(aRules[i].mRule, aRules[i].mSheetType, oldRules, modified);
   1.462 +  }
   1.463 +
   1.464 +  // Remove any residual families that have no font entries (i.e., they were
   1.465 +  // not defined at all by the updated set of @font-face rules).
   1.466 +  mFontFamilies.Enumerate(RemoveIfEmpty, nullptr);
   1.467 +
   1.468 +  // If any rules are left in the old list, note that the set has changed
   1.469 +  // (even if the new set was built entirely by migrating old font entries).
   1.470 +  if (oldRules.Length() > 0) {
   1.471 +    modified = true;
   1.472 +    // Any in-progress loaders for obsolete rules should be cancelled,
   1.473 +    // as the resource being downloaded will no longer be required.
   1.474 +    // We need to explicitly remove any loaders here, otherwise the loaders
   1.475 +    // will keep their "orphaned" font entries alive until they complete,
   1.476 +    // even after the oldRules array is deleted.
   1.477 +    size_t count = oldRules.Length();
   1.478 +    for (size_t i = 0; i < count; ++i) {
   1.479 +      gfxFontEntry* fe = oldRules[i].mFontEntry;
   1.480 +      if (!fe->mIsProxy) {
   1.481 +        continue;
   1.482 +      }
   1.483 +      gfxProxyFontEntry* proxy = static_cast<gfxProxyFontEntry*>(fe);
   1.484 +      nsFontFaceLoader* loader = proxy->mLoader;
   1.485 +      if (loader) {
   1.486 +        loader->Cancel();
   1.487 +        RemoveLoader(loader);
   1.488 +      }
   1.489 +    }
   1.490 +  }
   1.491 +
   1.492 +  if (modified) {
   1.493 +    IncrementGeneration();
   1.494 +  }
   1.495 +
   1.496 +  // local rules have been rebuilt, so clear the flag
   1.497 +  mLocalRulesUsed = false;
   1.498 +
   1.499 +  return modified;
   1.500 +}
   1.501 +
   1.502 +static bool
   1.503 +HasLocalSrc(const nsCSSValue::Array *aSrcArr)
   1.504 +{
   1.505 +  size_t numSrc = aSrcArr->Count();
   1.506 +  for (size_t i = 0; i < numSrc; i++) {
   1.507 +    if (aSrcArr->Item(i).GetUnit() == eCSSUnit_Local_Font) {
   1.508 +      return true;
   1.509 +    }
   1.510 +  }
   1.511 +  return false;
   1.512 +}
   1.513 +
   1.514 +void
   1.515 +nsUserFontSet::InsertRule(nsCSSFontFaceRule* aRule, uint8_t aSheetType,
   1.516 +                          nsTArray<FontFaceRuleRecord>& aOldRules,
   1.517 +                          bool& aFontSetModified)
   1.518 +{
   1.519 +  NS_ABORT_IF_FALSE(aRule->GetType() == mozilla::css::Rule::FONT_FACE_RULE,
   1.520 +                    "InsertRule passed a non-fontface CSS rule");
   1.521 +
   1.522 +  // set up family name
   1.523 +  nsAutoString fontfamily;
   1.524 +  nsCSSValue val;
   1.525 +  uint32_t unit;
   1.526 +
   1.527 +  aRule->GetDesc(eCSSFontDesc_Family, val);
   1.528 +  unit = val.GetUnit();
   1.529 +  if (unit == eCSSUnit_String) {
   1.530 +    val.GetStringValue(fontfamily);
   1.531 +  } else {
   1.532 +    NS_ASSERTION(unit == eCSSUnit_Null,
   1.533 +                 "@font-face family name has unexpected unit");
   1.534 +  }
   1.535 +  if (fontfamily.IsEmpty()) {
   1.536 +    // If there is no family name, this rule cannot contribute a
   1.537 +    // usable font, so there is no point in processing it further.
   1.538 +    return;
   1.539 +  }
   1.540 +
   1.541 +  // first, we check in oldRules; if the rule exists there, just move it
   1.542 +  // to the new rule list, and put the entry into the appropriate family
   1.543 +  for (uint32_t i = 0; i < aOldRules.Length(); ++i) {
   1.544 +    const FontFaceRuleRecord& ruleRec = aOldRules[i];
   1.545 +
   1.546 +    if (ruleRec.mContainer.mRule == aRule &&
   1.547 +        ruleRec.mContainer.mSheetType == aSheetType) {
   1.548 +
   1.549 +      // if local rules were used, don't use the old font entry
   1.550 +      // for rules containing src local usage
   1.551 +      if (mLocalRulesUsed) {
   1.552 +        aRule->GetDesc(eCSSFontDesc_Src, val);
   1.553 +        unit = val.GetUnit();
   1.554 +        if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
   1.555 +          break;
   1.556 +        }
   1.557 +      }
   1.558 +
   1.559 +      AddFontFace(fontfamily, ruleRec.mFontEntry);
   1.560 +      mRules.AppendElement(ruleRec);
   1.561 +      aOldRules.RemoveElementAt(i);
   1.562 +      // note the set has been modified if an old rule was skipped to find
   1.563 +      // this one - something has been dropped, or ordering changed
   1.564 +      if (i > 0) {
   1.565 +        aFontSetModified = true;
   1.566 +      }
   1.567 +      return;
   1.568 +    }
   1.569 +  }
   1.570 +
   1.571 +  // this is a new rule:
   1.572 +
   1.573 +  uint32_t weight = NS_STYLE_FONT_WEIGHT_NORMAL;
   1.574 +  int32_t stretch = NS_STYLE_FONT_STRETCH_NORMAL;
   1.575 +  uint32_t italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
   1.576 +  nsString languageOverride;
   1.577 +
   1.578 +  // set up weight
   1.579 +  aRule->GetDesc(eCSSFontDesc_Weight, val);
   1.580 +  unit = val.GetUnit();
   1.581 +  if (unit == eCSSUnit_Integer || unit == eCSSUnit_Enumerated) {
   1.582 +    weight = val.GetIntValue();
   1.583 +  } else if (unit == eCSSUnit_Normal) {
   1.584 +    weight = NS_STYLE_FONT_WEIGHT_NORMAL;
   1.585 +  } else {
   1.586 +    NS_ASSERTION(unit == eCSSUnit_Null,
   1.587 +                 "@font-face weight has unexpected unit");
   1.588 +  }
   1.589 +
   1.590 +  // set up stretch
   1.591 +  aRule->GetDesc(eCSSFontDesc_Stretch, val);
   1.592 +  unit = val.GetUnit();
   1.593 +  if (unit == eCSSUnit_Enumerated) {
   1.594 +    stretch = val.GetIntValue();
   1.595 +  } else if (unit == eCSSUnit_Normal) {
   1.596 +    stretch = NS_STYLE_FONT_STRETCH_NORMAL;
   1.597 +  } else {
   1.598 +    NS_ASSERTION(unit == eCSSUnit_Null,
   1.599 +                 "@font-face stretch has unexpected unit");
   1.600 +  }
   1.601 +
   1.602 +  // set up font style
   1.603 +  aRule->GetDesc(eCSSFontDesc_Style, val);
   1.604 +  unit = val.GetUnit();
   1.605 +  if (unit == eCSSUnit_Enumerated) {
   1.606 +    italicStyle = val.GetIntValue();
   1.607 +  } else if (unit == eCSSUnit_Normal) {
   1.608 +    italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
   1.609 +  } else {
   1.610 +    NS_ASSERTION(unit == eCSSUnit_Null,
   1.611 +                 "@font-face style has unexpected unit");
   1.612 +  }
   1.613 +
   1.614 +  // set up font features
   1.615 +  nsTArray<gfxFontFeature> featureSettings;
   1.616 +  aRule->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
   1.617 +  unit = val.GetUnit();
   1.618 +  if (unit == eCSSUnit_Normal) {
   1.619 +    // empty list of features
   1.620 +  } else if (unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep) {
   1.621 +    nsRuleNode::ComputeFontFeatures(val.GetPairListValue(), featureSettings);
   1.622 +  } else {
   1.623 +    NS_ASSERTION(unit == eCSSUnit_Null,
   1.624 +                 "@font-face font-feature-settings has unexpected unit");
   1.625 +  }
   1.626 +
   1.627 +  // set up font language override
   1.628 +  aRule->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
   1.629 +  unit = val.GetUnit();
   1.630 +  if (unit == eCSSUnit_Normal) {
   1.631 +    // empty feature string
   1.632 +  } else if (unit == eCSSUnit_String) {
   1.633 +    val.GetStringValue(languageOverride);
   1.634 +  } else {
   1.635 +    NS_ASSERTION(unit == eCSSUnit_Null,
   1.636 +                 "@font-face font-language-override has unexpected unit");
   1.637 +  }
   1.638 +
   1.639 +  // set up src array
   1.640 +  nsTArray<gfxFontFaceSrc> srcArray;
   1.641 +
   1.642 +  aRule->GetDesc(eCSSFontDesc_Src, val);
   1.643 +  unit = val.GetUnit();
   1.644 +  if (unit == eCSSUnit_Array) {
   1.645 +    nsCSSValue::Array* srcArr = val.GetArrayValue();
   1.646 +    size_t numSrc = srcArr->Count();
   1.647 +    
   1.648 +    for (size_t i = 0; i < numSrc; i++) {
   1.649 +      val = srcArr->Item(i);
   1.650 +      unit = val.GetUnit();
   1.651 +      gfxFontFaceSrc* face = srcArray.AppendElements(1);
   1.652 +      if (!face)
   1.653 +        return;
   1.654 +
   1.655 +      switch (unit) {
   1.656 +
   1.657 +      case eCSSUnit_Local_Font:
   1.658 +        val.GetStringValue(face->mLocalName);
   1.659 +        face->mIsLocal = true;
   1.660 +        face->mURI = nullptr;
   1.661 +        face->mFormatFlags = 0;
   1.662 +        break;
   1.663 +      case eCSSUnit_URL:
   1.664 +        face->mIsLocal = false;
   1.665 +        face->mURI = val.GetURLValue();
   1.666 +        face->mReferrer = val.GetURLStructValue()->mReferrer;
   1.667 +        face->mOriginPrincipal = val.GetURLStructValue()->mOriginPrincipal;
   1.668 +        NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
   1.669 +
   1.670 +        // agent and user stylesheets are treated slightly differently,
   1.671 +        // the same-site origin check and access control headers are
   1.672 +        // enforced against the sheet principal rather than the document
   1.673 +        // principal to allow user stylesheets to include @font-face rules
   1.674 +        face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
   1.675 +                                     aSheetType == nsStyleSet::eAgentSheet);
   1.676 +
   1.677 +        face->mLocalName.Truncate();
   1.678 +        face->mFormatFlags = 0;
   1.679 +        while (i + 1 < numSrc && (val = srcArr->Item(i+1), 
   1.680 +                 val.GetUnit() == eCSSUnit_Font_Format)) {
   1.681 +          nsDependentString valueString(val.GetStringBufferValue());
   1.682 +          if (valueString.LowerCaseEqualsASCII("woff")) {
   1.683 +            face->mFormatFlags |= FLAG_FORMAT_WOFF;
   1.684 +          } else if (valueString.LowerCaseEqualsASCII("opentype")) {
   1.685 +            face->mFormatFlags |= FLAG_FORMAT_OPENTYPE;
   1.686 +          } else if (valueString.LowerCaseEqualsASCII("truetype")) {
   1.687 +            face->mFormatFlags |= FLAG_FORMAT_TRUETYPE;
   1.688 +          } else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
   1.689 +            face->mFormatFlags |= FLAG_FORMAT_TRUETYPE_AAT;
   1.690 +          } else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
   1.691 +            face->mFormatFlags |= FLAG_FORMAT_EOT;
   1.692 +          } else if (valueString.LowerCaseEqualsASCII("svg")) {
   1.693 +            face->mFormatFlags |= FLAG_FORMAT_SVG;
   1.694 +          } else {
   1.695 +            // unknown format specified, mark to distinguish from the
   1.696 +            // case where no format hints are specified
   1.697 +            face->mFormatFlags |= FLAG_FORMAT_UNKNOWN;
   1.698 +          }
   1.699 +          i++;
   1.700 +        }
   1.701 +        if (!face->mURI) {
   1.702 +          // if URI not valid, omit from src array
   1.703 +          srcArray.RemoveElementAt(srcArray.Length() - 1);
   1.704 +          NS_WARNING("null url in @font-face rule");
   1.705 +          continue;
   1.706 +        }
   1.707 +        break;
   1.708 +      default:
   1.709 +        NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
   1.710 +                     "strange unit type in font-face src array");
   1.711 +        break;
   1.712 +      }
   1.713 +     }
   1.714 +  } else {
   1.715 +    NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
   1.716 +  }
   1.717 +
   1.718 +  if (srcArray.Length() > 0) {
   1.719 +    FontFaceRuleRecord ruleRec;
   1.720 +    ruleRec.mContainer.mRule = aRule;
   1.721 +    ruleRec.mContainer.mSheetType = aSheetType;
   1.722 +    ruleRec.mFontEntry = AddFontFace(fontfamily, srcArray,
   1.723 +                                     weight, stretch, italicStyle,
   1.724 +                                     featureSettings, languageOverride);
   1.725 +    if (ruleRec.mFontEntry) {
   1.726 +      mRules.AppendElement(ruleRec);
   1.727 +    }
   1.728 +    // this was a new rule and fontEntry, so note that the set was modified
   1.729 +    aFontSetModified = true;
   1.730 +  }
   1.731 +}
   1.732 +
   1.733 +void
   1.734 +nsUserFontSet::ReplaceFontEntry(gfxMixedFontFamily* aFamily,
   1.735 +                                gfxProxyFontEntry* aProxy,
   1.736 +                                gfxFontEntry* aFontEntry)
   1.737 +{
   1.738 +  // aProxy is being supplanted by the "real" font aFontEntry, so we need to
   1.739 +  // update any rules that refer to it. Note that there may be multiple rules
   1.740 +  // that refer to the same proxy - e.g. if a stylesheet was loaded multiple
   1.741 +  // times, so that several identical @font-face rules are present.
   1.742 +  for (uint32_t i = 0; i < mRules.Length(); ++i) {
   1.743 +    if (mRules[i].mFontEntry == aProxy) {
   1.744 +      mRules[i].mFontEntry = aFontEntry;
   1.745 +    }
   1.746 +  }
   1.747 +  aFamily->ReplaceFontEntry(aProxy, aFontEntry);
   1.748 +}
   1.749 +
   1.750 +nsCSSFontFaceRule*
   1.751 +nsUserFontSet::FindRuleForEntry(gfxFontEntry* aFontEntry)
   1.752 +{
   1.753 +  for (uint32_t i = 0; i < mRules.Length(); ++i) {
   1.754 +    if (mRules[i].mFontEntry == aFontEntry) {
   1.755 +      return mRules[i].mContainer.mRule;
   1.756 +    }
   1.757 +  }
   1.758 +  return nullptr;
   1.759 +}
   1.760 +
   1.761 +nsresult
   1.762 +nsUserFontSet::LogMessage(gfxMixedFontFamily* aFamily,
   1.763 +                          gfxProxyFontEntry* aProxy,
   1.764 +                          const char*        aMessage,
   1.765 +                          uint32_t          aFlags,
   1.766 +                          nsresult          aStatus)
   1.767 +{
   1.768 +  nsCOMPtr<nsIConsoleService>
   1.769 +    console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   1.770 +  if (!console) {
   1.771 +    return NS_ERROR_NOT_AVAILABLE;
   1.772 +  }
   1.773 +
   1.774 +  NS_ConvertUTF16toUTF8 familyName(aFamily->Name());
   1.775 +  nsAutoCString fontURI;
   1.776 +  if (aProxy->mSrcIndex == aProxy->mSrcList.Length()) {
   1.777 +    fontURI.AppendLiteral("(end of source list)");
   1.778 +  } else {
   1.779 +    if (aProxy->mSrcList[aProxy->mSrcIndex].mURI) {
   1.780 +      aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
   1.781 +    } else {
   1.782 +      fontURI.AppendLiteral("(invalid URI)");
   1.783 +    }
   1.784 +  }
   1.785 +
   1.786 +  char weightKeywordBuf[8]; // plenty to sprintf() a uint16_t
   1.787 +  const char* weightKeyword;
   1.788 +  const nsAFlatCString& weightKeywordString =
   1.789 +    nsCSSProps::ValueToKeyword(aProxy->Weight(),
   1.790 +                               nsCSSProps::kFontWeightKTable);
   1.791 +  if (weightKeywordString.Length() > 0) {
   1.792 +    weightKeyword = weightKeywordString.get();
   1.793 +  } else {
   1.794 +    sprintf(weightKeywordBuf, "%u", aProxy->Weight());
   1.795 +    weightKeyword = weightKeywordBuf;
   1.796 +  }
   1.797 +
   1.798 +  nsPrintfCString message
   1.799 +       ("downloadable font: %s "
   1.800 +        "(font-family: \"%s\" style:%s weight:%s stretch:%s src index:%d)",
   1.801 +        aMessage,
   1.802 +        familyName.get(),
   1.803 +        aProxy->IsItalic() ? "italic" : "normal",
   1.804 +        weightKeyword,
   1.805 +        nsCSSProps::ValueToKeyword(aProxy->Stretch(),
   1.806 +                                   nsCSSProps::kFontStretchKTable).get(),
   1.807 +        aProxy->mSrcIndex);
   1.808 +
   1.809 +  if (NS_FAILED(aStatus)) {
   1.810 +    message.Append(": ");
   1.811 +    switch (aStatus) {
   1.812 +    case NS_ERROR_DOM_BAD_URI:
   1.813 +      message.Append("bad URI or cross-site access not allowed");
   1.814 +      break;
   1.815 +    case NS_ERROR_CONTENT_BLOCKED:
   1.816 +      message.Append("content blocked");
   1.817 +      break;
   1.818 +    default:
   1.819 +      message.Append("status=");
   1.820 +      message.AppendInt(static_cast<uint32_t>(aStatus));
   1.821 +      break;
   1.822 +    }
   1.823 +  }
   1.824 +  message.Append("\nsource: ");
   1.825 +  message.Append(fontURI);
   1.826 +
   1.827 +#ifdef PR_LOGGING
   1.828 +  if (PR_LOG_TEST(GetUserFontsLog(), PR_LOG_DEBUG)) {
   1.829 +    PR_LOG(GetUserFontsLog(), PR_LOG_DEBUG,
   1.830 +           ("userfonts (%p) %s", this, message.get()));
   1.831 +  }
   1.832 +#endif
   1.833 +
   1.834 +  // try to give the user an indication of where the rule came from
   1.835 +  nsCSSFontFaceRule* rule = FindRuleForEntry(aProxy);
   1.836 +  nsString href;
   1.837 +  nsString text;
   1.838 +  nsresult rv;
   1.839 +  if (rule) {
   1.840 +    rv = rule->GetCssText(text);
   1.841 +    NS_ENSURE_SUCCESS(rv, rv);
   1.842 +    nsCOMPtr<nsIDOMCSSStyleSheet> sheet;
   1.843 +    rv = rule->GetParentStyleSheet(getter_AddRefs(sheet));
   1.844 +    NS_ENSURE_SUCCESS(rv, rv);
   1.845 +    // if the style sheet is removed while the font is loading can be null
   1.846 +    if (sheet) {
   1.847 +      rv = sheet->GetHref(href);
   1.848 +      NS_ENSURE_SUCCESS(rv, rv);
   1.849 +    } else {
   1.850 +      NS_WARNING("null parent stylesheet for @font-face rule");
   1.851 +      href.AssignLiteral("unknown");
   1.852 +    }
   1.853 +  }
   1.854 +
   1.855 +  nsCOMPtr<nsIScriptError> scriptError =
   1.856 +    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
   1.857 +  NS_ENSURE_SUCCESS(rv, rv);
   1.858 +
   1.859 +  uint64_t innerWindowID = GetPresContext()->Document()->InnerWindowID();
   1.860 +  rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(message),
   1.861 +                                     href,         // file
   1.862 +                                     text,         // src line
   1.863 +                                     0, 0,         // line & column number
   1.864 +                                     aFlags,       // flags
   1.865 +                                     "CSS Loader", // category (make separate?)
   1.866 +                                     innerWindowID);
   1.867 +  if (NS_SUCCEEDED(rv)) {
   1.868 +    console->LogMessage(scriptError);
   1.869 +  }
   1.870 +
   1.871 +  return NS_OK;
   1.872 +}
   1.873 +
   1.874 +nsresult
   1.875 +nsUserFontSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
   1.876 +                             nsIPrincipal** aPrincipal,
   1.877 +                             bool* aBypassCache)
   1.878 +{
   1.879 +  // check same-site origin
   1.880 +  nsIPresShell* ps = mPresContext->PresShell();
   1.881 +  if (!ps)
   1.882 +    return NS_ERROR_FAILURE;
   1.883 +
   1.884 +  NS_ASSERTION(aFontFaceSrc && !aFontFaceSrc->mIsLocal,
   1.885 +               "bad font face url passed to fontloader");
   1.886 +  NS_ASSERTION(aFontFaceSrc->mURI, "null font uri");
   1.887 +  if (!aFontFaceSrc->mURI)
   1.888 +    return NS_ERROR_FAILURE;
   1.889 +
   1.890 +  // use document principal, original principal if flag set
   1.891 +  // this enables user stylesheets to load font files via
   1.892 +  // @font-face rules
   1.893 +  *aPrincipal = ps->GetDocument()->NodePrincipal();
   1.894 +
   1.895 +  NS_ASSERTION(aFontFaceSrc->mOriginPrincipal,
   1.896 +               "null origin principal in @font-face rule");
   1.897 +  if (aFontFaceSrc->mUseOriginPrincipal) {
   1.898 +    *aPrincipal = aFontFaceSrc->mOriginPrincipal;
   1.899 +  }
   1.900 +
   1.901 +  nsresult rv = nsFontFaceLoader::CheckLoadAllowed(*aPrincipal,
   1.902 +                                                   aFontFaceSrc->mURI,
   1.903 +                                                   ps->GetDocument());
   1.904 +  if (NS_FAILED(rv)) {
   1.905 +    return rv;
   1.906 +  }
   1.907 +
   1.908 +  *aBypassCache = false;
   1.909 +
   1.910 +  nsCOMPtr<nsIDocShell> docShell = ps->GetDocument()->GetDocShell();
   1.911 +  if (docShell) {
   1.912 +    uint32_t loadType;
   1.913 +    if (NS_SUCCEEDED(docShell->GetLoadType(&loadType))) {
   1.914 +      if ((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) {
   1.915 +        *aBypassCache = true;
   1.916 +      }
   1.917 +    }
   1.918 +  }
   1.919 +
   1.920 +  return rv;
   1.921 +}
   1.922 +
   1.923 +nsresult
   1.924 +nsUserFontSet::SyncLoadFontData(gfxProxyFontEntry* aFontToLoad,
   1.925 +                                const gfxFontFaceSrc* aFontFaceSrc,
   1.926 +                                uint8_t*& aBuffer,
   1.927 +                                uint32_t& aBufferLength)
   1.928 +{
   1.929 +  nsresult rv;
   1.930 +
   1.931 +  nsCOMPtr<nsIChannel> channel;
   1.932 +  // get Content Security Policy from principal to pass into channel
   1.933 +  nsCOMPtr<nsIChannelPolicy> channelPolicy;
   1.934 +  nsCOMPtr<nsIContentSecurityPolicy> csp;
   1.935 +  rv = aFontToLoad->mPrincipal->GetCsp(getter_AddRefs(csp));
   1.936 +  NS_ENSURE_SUCCESS(rv, rv);
   1.937 +  if (csp) {
   1.938 +    channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
   1.939 +    channelPolicy->SetContentSecurityPolicy(csp);
   1.940 +    channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
   1.941 +  }
   1.942 +  rv = NS_NewChannel(getter_AddRefs(channel),
   1.943 +                     aFontFaceSrc->mURI,
   1.944 +                     nullptr,
   1.945 +                     nullptr,
   1.946 +                     nullptr,
   1.947 +                     nsIRequest::LOAD_NORMAL,
   1.948 +                     channelPolicy);
   1.949 +
   1.950 +  NS_ENSURE_SUCCESS(rv, rv);
   1.951 +
   1.952 +  // blocking stream is OK for data URIs
   1.953 +  nsCOMPtr<nsIInputStream> stream;
   1.954 +  rv = channel->Open(getter_AddRefs(stream));
   1.955 +  NS_ENSURE_SUCCESS(rv, rv);
   1.956 +
   1.957 +  uint64_t bufferLength64;
   1.958 +  rv = stream->Available(&bufferLength64);
   1.959 +  NS_ENSURE_SUCCESS(rv, rv);
   1.960 +  if (bufferLength64 == 0) {
   1.961 +    return NS_ERROR_FAILURE;
   1.962 +  }
   1.963 +  if (bufferLength64 > UINT32_MAX) {
   1.964 +    return NS_ERROR_FILE_TOO_BIG;
   1.965 +  }
   1.966 +  aBufferLength = static_cast<uint32_t>(bufferLength64);
   1.967 +
   1.968 +  // read all the decoded data
   1.969 +  aBuffer = static_cast<uint8_t*> (NS_Alloc(sizeof(uint8_t) * aBufferLength));
   1.970 +  if (!aBuffer) {
   1.971 +    aBufferLength = 0;
   1.972 +    return NS_ERROR_OUT_OF_MEMORY;
   1.973 +  }
   1.974 +
   1.975 +  uint32_t numRead, totalRead = 0;
   1.976 +  while (NS_SUCCEEDED(rv =
   1.977 +           stream->Read(reinterpret_cast<char*>(aBuffer + totalRead),
   1.978 +                        aBufferLength - totalRead, &numRead)) &&
   1.979 +         numRead != 0)
   1.980 +  {
   1.981 +    totalRead += numRead;
   1.982 +    if (totalRead > aBufferLength) {
   1.983 +      rv = NS_ERROR_FAILURE;
   1.984 +      break;
   1.985 +    }
   1.986 +  }
   1.987 +
   1.988 +  // make sure there's a mime type
   1.989 +  if (NS_SUCCEEDED(rv)) {
   1.990 +    nsAutoCString mimeType;
   1.991 +    rv = channel->GetContentType(mimeType);
   1.992 +    aBufferLength = totalRead;
   1.993 +  }
   1.994 +
   1.995 +  if (NS_FAILED(rv)) {
   1.996 +    NS_Free(aBuffer);
   1.997 +    aBuffer = nullptr;
   1.998 +    aBufferLength = 0;
   1.999 +    return rv;
  1.1000 +  }
  1.1001 +
  1.1002 +  return NS_OK;
  1.1003 +}
  1.1004 +
  1.1005 +bool
  1.1006 +nsUserFontSet::GetPrivateBrowsing()
  1.1007 +{
  1.1008 +  nsIPresShell* ps = mPresContext->PresShell();
  1.1009 +  if (!ps) {
  1.1010 +    return false;
  1.1011 +  }
  1.1012 +
  1.1013 +  nsCOMPtr<nsILoadContext> loadContext = ps->GetDocument()->GetLoadContext();
  1.1014 +  return loadContext && loadContext->UsePrivateBrowsing();
  1.1015 +}
  1.1016 +
  1.1017 +void
  1.1018 +nsUserFontSet::DoRebuildUserFontSet()
  1.1019 +{
  1.1020 +  if (!mPresContext) {
  1.1021 +    // AFAICS, this can only happen if someone has already called Destroy() on
  1.1022 +    // this font-set, which means it is in the process of being torn down --
  1.1023 +    // so there's no point trying to update its rules.
  1.1024 +    return;
  1.1025 +  }
  1.1026 +
  1.1027 +  mPresContext->RebuildUserFontSet();
  1.1028 +}

mercurial