layout/style/nsFontFaceLoader.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 // vim:cindent:ts=2:et:sw=2:
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* code for loading in @font-face defined font data */
michael@0 8
michael@0 9 #ifdef MOZ_LOGGING
michael@0 10 #define FORCE_PR_LOG /* Allow logging in the release build */
michael@0 11 #endif /* MOZ_LOGGING */
michael@0 12 #include "prlog.h"
michael@0 13
michael@0 14 #include "nsFontFaceLoader.h"
michael@0 15
michael@0 16 #include "nsError.h"
michael@0 17 #include "nsNetUtil.h"
michael@0 18 #include "nsContentUtils.h"
michael@0 19 #include "mozilla/Preferences.h"
michael@0 20
michael@0 21 #include "nsPresContext.h"
michael@0 22 #include "nsIPresShell.h"
michael@0 23 #include "nsIPrincipal.h"
michael@0 24 #include "nsIScriptSecurityManager.h"
michael@0 25
michael@0 26 #include "nsIContentPolicy.h"
michael@0 27 #include "nsContentPolicyUtils.h"
michael@0 28 #include "nsCrossSiteListenerProxy.h"
michael@0 29 #include "nsIContentSecurityPolicy.h"
michael@0 30 #include "nsIDocShell.h"
michael@0 31 #include "nsIWebNavigation.h"
michael@0 32 #include "nsISupportsPriority.h"
michael@0 33 #include "nsINetworkSeer.h"
michael@0 34
michael@0 35 #include "nsIConsoleService.h"
michael@0 36
michael@0 37 #include "nsStyleSet.h"
michael@0 38 #include "nsPrintfCString.h"
michael@0 39 #include "mozilla/gfx/2D.h"
michael@0 40
michael@0 41 using namespace mozilla;
michael@0 42
michael@0 43 #ifdef PR_LOGGING
michael@0 44 static PRLogModuleInfo*
michael@0 45 GetFontDownloaderLog()
michael@0 46 {
michael@0 47 static PRLogModuleInfo* sLog;
michael@0 48 if (!sLog)
michael@0 49 sLog = PR_NewLogModule("fontdownloader");
michael@0 50 return sLog;
michael@0 51 }
michael@0 52 #endif /* PR_LOGGING */
michael@0 53
michael@0 54 #define LOG(args) PR_LOG(GetFontDownloaderLog(), PR_LOG_DEBUG, args)
michael@0 55 #define LOG_ENABLED() PR_LOG_TEST(GetFontDownloaderLog(), PR_LOG_DEBUG)
michael@0 56
michael@0 57
michael@0 58 nsFontFaceLoader::nsFontFaceLoader(gfxMixedFontFamily* aFontFamily,
michael@0 59 gfxProxyFontEntry* aProxy,
michael@0 60 nsIURI* aFontURI,
michael@0 61 nsUserFontSet* aFontSet,
michael@0 62 nsIChannel* aChannel)
michael@0 63 : mFontFamily(aFontFamily),
michael@0 64 mFontEntry(aProxy),
michael@0 65 mFontURI(aFontURI),
michael@0 66 mFontSet(aFontSet),
michael@0 67 mChannel(aChannel)
michael@0 68 {
michael@0 69 }
michael@0 70
michael@0 71 nsFontFaceLoader::~nsFontFaceLoader()
michael@0 72 {
michael@0 73 if (mFontEntry) {
michael@0 74 mFontEntry->mLoader = nullptr;
michael@0 75 }
michael@0 76 if (mLoadTimer) {
michael@0 77 mLoadTimer->Cancel();
michael@0 78 mLoadTimer = nullptr;
michael@0 79 }
michael@0 80 if (mFontSet) {
michael@0 81 mFontSet->RemoveLoader(this);
michael@0 82 }
michael@0 83 }
michael@0 84
michael@0 85 void
michael@0 86 nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader)
michael@0 87 {
michael@0 88 int32_t loadTimeout =
michael@0 89 Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000);
michael@0 90 if (loadTimeout > 0) {
michael@0 91 mLoadTimer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 92 if (mLoadTimer) {
michael@0 93 mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
michael@0 94 static_cast<void*>(this),
michael@0 95 loadTimeout,
michael@0 96 nsITimer::TYPE_ONE_SHOT);
michael@0 97 }
michael@0 98 } else if (loadTimeout == 0) {
michael@0 99 mFontEntry->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY;
michael@0 100 } // -1 disables fallback
michael@0 101 mStreamLoader = aStreamLoader;
michael@0 102 }
michael@0 103
michael@0 104 void
michael@0 105 nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
michael@0 106 {
michael@0 107 nsFontFaceLoader* loader = static_cast<nsFontFaceLoader*>(aClosure);
michael@0 108
michael@0 109 if (!loader->mFontSet) {
michael@0 110 // We've been canceled
michael@0 111 return;
michael@0 112 }
michael@0 113
michael@0 114 gfxProxyFontEntry* pe = loader->mFontEntry.get();
michael@0 115 bool updateUserFontSet = true;
michael@0 116
michael@0 117 // If the entry is loading, check whether it's >75% done; if so,
michael@0 118 // we allow another timeout period before showing a fallback font.
michael@0 119 if (pe->mLoadingState == gfxProxyFontEntry::LOADING_STARTED) {
michael@0 120 int64_t contentLength;
michael@0 121 uint32_t numBytesRead;
michael@0 122 if (NS_SUCCEEDED(loader->mChannel->GetContentLength(&contentLength)) &&
michael@0 123 contentLength > 0 &&
michael@0 124 contentLength < UINT32_MAX &&
michael@0 125 NS_SUCCEEDED(loader->mStreamLoader->GetNumBytesRead(&numBytesRead)) &&
michael@0 126 numBytesRead > 3 * (uint32_t(contentLength) >> 2))
michael@0 127 {
michael@0 128 // More than 3/4 the data has been downloaded, so allow 50% extra
michael@0 129 // time and hope the remainder will arrive before the additional
michael@0 130 // time expires.
michael@0 131 pe->mLoadingState = gfxProxyFontEntry::LOADING_ALMOST_DONE;
michael@0 132 uint32_t delay;
michael@0 133 loader->mLoadTimer->GetDelay(&delay);
michael@0 134 loader->mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
michael@0 135 static_cast<void*>(loader),
michael@0 136 delay >> 1,
michael@0 137 nsITimer::TYPE_ONE_SHOT);
michael@0 138 updateUserFontSet = false;
michael@0 139 LOG(("fontdownloader (%p) 75%% done, resetting timer\n", loader));
michael@0 140 }
michael@0 141 }
michael@0 142
michael@0 143 // If the font is not 75% loaded, or if we've already timed out once
michael@0 144 // before, we mark this entry as "loading slowly", so the fallback
michael@0 145 // font will be used in the meantime, and tell the context to refresh.
michael@0 146 if (updateUserFontSet) {
michael@0 147 pe->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY;
michael@0 148 gfxUserFontSet* fontSet = loader->mFontSet;
michael@0 149 nsPresContext* ctx = loader->mFontSet->GetPresContext();
michael@0 150 NS_ASSERTION(ctx, "userfontset doesn't have a presContext?");
michael@0 151 if (ctx) {
michael@0 152 fontSet->IncrementGeneration();
michael@0 153 ctx->UserFontSetUpdated();
michael@0 154 LOG(("fontdownloader (%p) timeout reflow\n", loader));
michael@0 155 }
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 NS_IMPL_ISUPPORTS(nsFontFaceLoader, nsIStreamLoaderObserver)
michael@0 160
michael@0 161 NS_IMETHODIMP
michael@0 162 nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
michael@0 163 nsISupports* aContext,
michael@0 164 nsresult aStatus,
michael@0 165 uint32_t aStringLen,
michael@0 166 const uint8_t* aString)
michael@0 167 {
michael@0 168 if (!mFontSet) {
michael@0 169 // We've been canceled
michael@0 170 return aStatus;
michael@0 171 }
michael@0 172
michael@0 173 mFontSet->RemoveLoader(this);
michael@0 174
michael@0 175 #ifdef PR_LOGGING
michael@0 176 if (LOG_ENABLED()) {
michael@0 177 nsAutoCString fontURI;
michael@0 178 mFontURI->GetSpec(fontURI);
michael@0 179 if (NS_SUCCEEDED(aStatus)) {
michael@0 180 LOG(("fontdownloader (%p) download completed - font uri: (%s)\n",
michael@0 181 this, fontURI.get()));
michael@0 182 } else {
michael@0 183 LOG(("fontdownloader (%p) download failed - font uri: (%s) error: %8.8x\n",
michael@0 184 this, fontURI.get(), aStatus));
michael@0 185 }
michael@0 186 }
michael@0 187 #endif
michael@0 188
michael@0 189 nsPresContext* ctx = mFontSet->GetPresContext();
michael@0 190 NS_ASSERTION(ctx && !ctx->PresShell()->IsDestroying(),
michael@0 191 "We should have been canceled already");
michael@0 192
michael@0 193 if (NS_SUCCEEDED(aStatus)) {
michael@0 194 // for HTTP requests, check whether the request _actually_ succeeded;
michael@0 195 // the "request status" in aStatus does not necessarily indicate this,
michael@0 196 // because HTTP responses such as 404 (Not Found) will still result in
michael@0 197 // a success code and potentially an HTML error page from the server
michael@0 198 // as the resulting data. We don't want to use that as a font.
michael@0 199 nsCOMPtr<nsIRequest> request;
michael@0 200 nsCOMPtr<nsIHttpChannel> httpChannel;
michael@0 201 aLoader->GetRequest(getter_AddRefs(request));
michael@0 202 httpChannel = do_QueryInterface(request);
michael@0 203 if (httpChannel) {
michael@0 204 bool succeeded;
michael@0 205 nsresult rv = httpChannel->GetRequestSucceeded(&succeeded);
michael@0 206 if (NS_SUCCEEDED(rv) && !succeeded) {
michael@0 207 aStatus = NS_ERROR_NOT_AVAILABLE;
michael@0 208 }
michael@0 209 }
michael@0 210 }
michael@0 211
michael@0 212 // The userFontSet is responsible for freeing the downloaded data
michael@0 213 // (aString) when finished with it; the pointer is no longer valid
michael@0 214 // after OnLoadComplete returns.
michael@0 215 // This is called even in the case of a failed download (HTTP 404, etc),
michael@0 216 // as there may still be data to be freed (e.g. an error page),
michael@0 217 // and we need the fontSet to initiate loading the next source.
michael@0 218 bool fontUpdate = mFontSet->OnLoadComplete(mFontFamily, mFontEntry, aString,
michael@0 219 aStringLen, aStatus);
michael@0 220
michael@0 221 // when new font loaded, need to reflow
michael@0 222 if (fontUpdate) {
michael@0 223 // Update layout for the presence of the new font. Since this is
michael@0 224 // asynchronous, reflows will coalesce.
michael@0 225 ctx->UserFontSetUpdated();
michael@0 226 LOG(("fontdownloader (%p) reflow\n", this));
michael@0 227 }
michael@0 228
michael@0 229 // done with font set
michael@0 230 mFontSet = nullptr;
michael@0 231 if (mLoadTimer) {
michael@0 232 mLoadTimer->Cancel();
michael@0 233 mLoadTimer = nullptr;
michael@0 234 }
michael@0 235
michael@0 236 return NS_SUCCESS_ADOPTED_DATA;
michael@0 237 }
michael@0 238
michael@0 239 void
michael@0 240 nsFontFaceLoader::Cancel()
michael@0 241 {
michael@0 242 mFontEntry->mLoadingState = gfxProxyFontEntry::NOT_LOADING;
michael@0 243 mFontEntry->mLoader = nullptr;
michael@0 244 mFontSet = nullptr;
michael@0 245 if (mLoadTimer) {
michael@0 246 mLoadTimer->Cancel();
michael@0 247 mLoadTimer = nullptr;
michael@0 248 }
michael@0 249 mChannel->Cancel(NS_BINDING_ABORTED);
michael@0 250 }
michael@0 251
michael@0 252 nsresult
michael@0 253 nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
michael@0 254 nsIURI* aTargetURI,
michael@0 255 nsISupports* aContext)
michael@0 256 {
michael@0 257 nsresult rv;
michael@0 258
michael@0 259 if (!aSourcePrincipal)
michael@0 260 return NS_OK;
michael@0 261
michael@0 262 // check with the security manager
michael@0 263 nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
michael@0 264 rv = secMan->CheckLoadURIWithPrincipal(aSourcePrincipal, aTargetURI,
michael@0 265 nsIScriptSecurityManager::STANDARD);
michael@0 266 if (NS_FAILED(rv)) {
michael@0 267 return rv;
michael@0 268 }
michael@0 269
michael@0 270 // check content policy
michael@0 271 int16_t shouldLoad = nsIContentPolicy::ACCEPT;
michael@0 272 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
michael@0 273 aTargetURI,
michael@0 274 aSourcePrincipal,
michael@0 275 aContext,
michael@0 276 EmptyCString(), // mime type
michael@0 277 nullptr,
michael@0 278 &shouldLoad,
michael@0 279 nsContentUtils::GetContentPolicy(),
michael@0 280 nsContentUtils::GetSecurityManager());
michael@0 281
michael@0 282 if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
michael@0 283 return NS_ERROR_CONTENT_BLOCKED;
michael@0 284 }
michael@0 285
michael@0 286 return NS_OK;
michael@0 287 }
michael@0 288
michael@0 289 nsUserFontSet::nsUserFontSet(nsPresContext* aContext)
michael@0 290 : mPresContext(aContext)
michael@0 291 {
michael@0 292 NS_ASSERTION(mPresContext, "null context passed to nsUserFontSet");
michael@0 293 }
michael@0 294
michael@0 295 nsUserFontSet::~nsUserFontSet()
michael@0 296 {
michael@0 297 NS_ASSERTION(mLoaders.Count() == 0, "mLoaders should have been emptied");
michael@0 298 }
michael@0 299
michael@0 300 static PLDHashOperator DestroyIterator(nsPtrHashKey<nsFontFaceLoader>* aKey,
michael@0 301 void* aUserArg)
michael@0 302 {
michael@0 303 aKey->GetKey()->Cancel();
michael@0 304 return PL_DHASH_REMOVE;
michael@0 305 }
michael@0 306
michael@0 307 void
michael@0 308 nsUserFontSet::Destroy()
michael@0 309 {
michael@0 310 mPresContext = nullptr;
michael@0 311 mLoaders.EnumerateEntries(DestroyIterator, nullptr);
michael@0 312 mRules.Clear();
michael@0 313 }
michael@0 314
michael@0 315 void
michael@0 316 nsUserFontSet::RemoveLoader(nsFontFaceLoader* aLoader)
michael@0 317 {
michael@0 318 mLoaders.RemoveEntry(aLoader);
michael@0 319 }
michael@0 320
michael@0 321 nsresult
michael@0 322 nsUserFontSet::StartLoad(gfxMixedFontFamily* aFamily,
michael@0 323 gfxProxyFontEntry* aProxy,
michael@0 324 const gfxFontFaceSrc* aFontFaceSrc)
michael@0 325 {
michael@0 326 nsresult rv;
michael@0 327
michael@0 328 nsIPresShell* ps = mPresContext->PresShell();
michael@0 329 if (!ps)
michael@0 330 return NS_ERROR_FAILURE;
michael@0 331
michael@0 332 nsCOMPtr<nsIStreamLoader> streamLoader;
michael@0 333 nsCOMPtr<nsILoadGroup> loadGroup(ps->GetDocument()->GetDocumentLoadGroup());
michael@0 334
michael@0 335 nsCOMPtr<nsIChannel> channel;
michael@0 336 // get Content Security Policy from principal to pass into channel
michael@0 337 nsCOMPtr<nsIChannelPolicy> channelPolicy;
michael@0 338 nsCOMPtr<nsIContentSecurityPolicy> csp;
michael@0 339 rv = aProxy->mPrincipal->GetCsp(getter_AddRefs(csp));
michael@0 340 NS_ENSURE_SUCCESS(rv, rv);
michael@0 341 if (csp) {
michael@0 342 channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
michael@0 343 channelPolicy->SetContentSecurityPolicy(csp);
michael@0 344 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
michael@0 345 }
michael@0 346 rv = NS_NewChannel(getter_AddRefs(channel),
michael@0 347 aFontFaceSrc->mURI,
michael@0 348 nullptr,
michael@0 349 loadGroup,
michael@0 350 nullptr,
michael@0 351 nsIRequest::LOAD_NORMAL,
michael@0 352 channelPolicy);
michael@0 353
michael@0 354 NS_ENSURE_SUCCESS(rv, rv);
michael@0 355
michael@0 356 nsRefPtr<nsFontFaceLoader> fontLoader =
michael@0 357 new nsFontFaceLoader(aFamily, aProxy, aFontFaceSrc->mURI, this, channel);
michael@0 358
michael@0 359 if (!fontLoader)
michael@0 360 return NS_ERROR_OUT_OF_MEMORY;
michael@0 361
michael@0 362 #ifdef PR_LOGGING
michael@0 363 if (LOG_ENABLED()) {
michael@0 364 nsAutoCString fontURI, referrerURI;
michael@0 365 aFontFaceSrc->mURI->GetSpec(fontURI);
michael@0 366 if (aFontFaceSrc->mReferrer)
michael@0 367 aFontFaceSrc->mReferrer->GetSpec(referrerURI);
michael@0 368 LOG(("fontdownloader (%p) download start - font uri: (%s) "
michael@0 369 "referrer uri: (%s)\n",
michael@0 370 fontLoader.get(), fontURI.get(), referrerURI.get()));
michael@0 371 }
michael@0 372 #endif
michael@0 373
michael@0 374 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
michael@0 375 if (httpChannel)
michael@0 376 httpChannel->SetReferrer(aFontFaceSrc->mReferrer);
michael@0 377 nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
michael@0 378 if (priorityChannel) {
michael@0 379 priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
michael@0 380 }
michael@0 381
michael@0 382 rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
michael@0 383 NS_ENSURE_SUCCESS(rv, rv);
michael@0 384
michael@0 385 nsIDocument *document = ps->GetDocument();
michael@0 386 mozilla::net::SeerLearn(aFontFaceSrc->mURI, document->GetDocumentURI(),
michael@0 387 nsINetworkSeer::LEARN_LOAD_SUBRESOURCE, loadGroup);
michael@0 388
michael@0 389 bool inherits = false;
michael@0 390 rv = NS_URIChainHasFlags(aFontFaceSrc->mURI,
michael@0 391 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
michael@0 392 &inherits);
michael@0 393 if (NS_SUCCEEDED(rv) && inherits) {
michael@0 394 // allow data, javascript, etc URI's
michael@0 395 rv = channel->AsyncOpen(streamLoader, nullptr);
michael@0 396 } else {
michael@0 397 nsRefPtr<nsCORSListenerProxy> listener =
michael@0 398 new nsCORSListenerProxy(streamLoader, aProxy->mPrincipal, false);
michael@0 399 rv = listener->Init(channel);
michael@0 400 if (NS_SUCCEEDED(rv)) {
michael@0 401 rv = channel->AsyncOpen(listener, nullptr);
michael@0 402 }
michael@0 403 if (NS_FAILED(rv)) {
michael@0 404 fontLoader->DropChannel(); // explicitly need to break ref cycle
michael@0 405 }
michael@0 406 }
michael@0 407
michael@0 408 if (NS_SUCCEEDED(rv)) {
michael@0 409 mLoaders.PutEntry(fontLoader);
michael@0 410 fontLoader->StartedLoading(streamLoader);
michael@0 411 aProxy->mLoader = fontLoader; // let the font entry remember the loader,
michael@0 412 // in case we need to cancel it
michael@0 413 }
michael@0 414
michael@0 415 return rv;
michael@0 416 }
michael@0 417
michael@0 418 static PLDHashOperator DetachFontEntries(const nsAString& aKey,
michael@0 419 nsRefPtr<gfxMixedFontFamily>& aFamily,
michael@0 420 void* aUserArg)
michael@0 421 {
michael@0 422 aFamily->DetachFontEntries();
michael@0 423 return PL_DHASH_NEXT;
michael@0 424 }
michael@0 425
michael@0 426 static PLDHashOperator RemoveIfEmpty(const nsAString& aKey,
michael@0 427 nsRefPtr<gfxMixedFontFamily>& aFamily,
michael@0 428 void* aUserArg)
michael@0 429 {
michael@0 430 return aFamily->GetFontList().Length() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
michael@0 431 }
michael@0 432
michael@0 433 bool
michael@0 434 nsUserFontSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
michael@0 435 {
michael@0 436 bool modified = false;
michael@0 437
michael@0 438 // The @font-face rules that make up the user font set have changed,
michael@0 439 // so we need to update the set. However, we want to preserve existing
michael@0 440 // font entries wherever possible, so that we don't discard and then
michael@0 441 // re-download resources in the (common) case where at least some of the
michael@0 442 // same rules are still present.
michael@0 443
michael@0 444 nsTArray<FontFaceRuleRecord> oldRules;
michael@0 445 mRules.SwapElements(oldRules);
michael@0 446
michael@0 447 // Remove faces from the font family records; we need to re-insert them
michael@0 448 // because we might end up with faces in a different order even if they're
michael@0 449 // the same font entries as before. (The order can affect font selection
michael@0 450 // where multiple faces match the requested style, perhaps with overlapping
michael@0 451 // unicode-range coverage.)
michael@0 452 mFontFamilies.Enumerate(DetachFontEntries, nullptr);
michael@0 453
michael@0 454 for (uint32_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
michael@0 455 // Insert each rule into our list, migrating old font entries if possible
michael@0 456 // rather than creating new ones; set modified to true if we detect
michael@0 457 // that rule ordering has changed, or if a new entry is created.
michael@0 458 InsertRule(aRules[i].mRule, aRules[i].mSheetType, oldRules, modified);
michael@0 459 }
michael@0 460
michael@0 461 // Remove any residual families that have no font entries (i.e., they were
michael@0 462 // not defined at all by the updated set of @font-face rules).
michael@0 463 mFontFamilies.Enumerate(RemoveIfEmpty, nullptr);
michael@0 464
michael@0 465 // If any rules are left in the old list, note that the set has changed
michael@0 466 // (even if the new set was built entirely by migrating old font entries).
michael@0 467 if (oldRules.Length() > 0) {
michael@0 468 modified = true;
michael@0 469 // Any in-progress loaders for obsolete rules should be cancelled,
michael@0 470 // as the resource being downloaded will no longer be required.
michael@0 471 // We need to explicitly remove any loaders here, otherwise the loaders
michael@0 472 // will keep their "orphaned" font entries alive until they complete,
michael@0 473 // even after the oldRules array is deleted.
michael@0 474 size_t count = oldRules.Length();
michael@0 475 for (size_t i = 0; i < count; ++i) {
michael@0 476 gfxFontEntry* fe = oldRules[i].mFontEntry;
michael@0 477 if (!fe->mIsProxy) {
michael@0 478 continue;
michael@0 479 }
michael@0 480 gfxProxyFontEntry* proxy = static_cast<gfxProxyFontEntry*>(fe);
michael@0 481 nsFontFaceLoader* loader = proxy->mLoader;
michael@0 482 if (loader) {
michael@0 483 loader->Cancel();
michael@0 484 RemoveLoader(loader);
michael@0 485 }
michael@0 486 }
michael@0 487 }
michael@0 488
michael@0 489 if (modified) {
michael@0 490 IncrementGeneration();
michael@0 491 }
michael@0 492
michael@0 493 // local rules have been rebuilt, so clear the flag
michael@0 494 mLocalRulesUsed = false;
michael@0 495
michael@0 496 return modified;
michael@0 497 }
michael@0 498
michael@0 499 static bool
michael@0 500 HasLocalSrc(const nsCSSValue::Array *aSrcArr)
michael@0 501 {
michael@0 502 size_t numSrc = aSrcArr->Count();
michael@0 503 for (size_t i = 0; i < numSrc; i++) {
michael@0 504 if (aSrcArr->Item(i).GetUnit() == eCSSUnit_Local_Font) {
michael@0 505 return true;
michael@0 506 }
michael@0 507 }
michael@0 508 return false;
michael@0 509 }
michael@0 510
michael@0 511 void
michael@0 512 nsUserFontSet::InsertRule(nsCSSFontFaceRule* aRule, uint8_t aSheetType,
michael@0 513 nsTArray<FontFaceRuleRecord>& aOldRules,
michael@0 514 bool& aFontSetModified)
michael@0 515 {
michael@0 516 NS_ABORT_IF_FALSE(aRule->GetType() == mozilla::css::Rule::FONT_FACE_RULE,
michael@0 517 "InsertRule passed a non-fontface CSS rule");
michael@0 518
michael@0 519 // set up family name
michael@0 520 nsAutoString fontfamily;
michael@0 521 nsCSSValue val;
michael@0 522 uint32_t unit;
michael@0 523
michael@0 524 aRule->GetDesc(eCSSFontDesc_Family, val);
michael@0 525 unit = val.GetUnit();
michael@0 526 if (unit == eCSSUnit_String) {
michael@0 527 val.GetStringValue(fontfamily);
michael@0 528 } else {
michael@0 529 NS_ASSERTION(unit == eCSSUnit_Null,
michael@0 530 "@font-face family name has unexpected unit");
michael@0 531 }
michael@0 532 if (fontfamily.IsEmpty()) {
michael@0 533 // If there is no family name, this rule cannot contribute a
michael@0 534 // usable font, so there is no point in processing it further.
michael@0 535 return;
michael@0 536 }
michael@0 537
michael@0 538 // first, we check in oldRules; if the rule exists there, just move it
michael@0 539 // to the new rule list, and put the entry into the appropriate family
michael@0 540 for (uint32_t i = 0; i < aOldRules.Length(); ++i) {
michael@0 541 const FontFaceRuleRecord& ruleRec = aOldRules[i];
michael@0 542
michael@0 543 if (ruleRec.mContainer.mRule == aRule &&
michael@0 544 ruleRec.mContainer.mSheetType == aSheetType) {
michael@0 545
michael@0 546 // if local rules were used, don't use the old font entry
michael@0 547 // for rules containing src local usage
michael@0 548 if (mLocalRulesUsed) {
michael@0 549 aRule->GetDesc(eCSSFontDesc_Src, val);
michael@0 550 unit = val.GetUnit();
michael@0 551 if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
michael@0 552 break;
michael@0 553 }
michael@0 554 }
michael@0 555
michael@0 556 AddFontFace(fontfamily, ruleRec.mFontEntry);
michael@0 557 mRules.AppendElement(ruleRec);
michael@0 558 aOldRules.RemoveElementAt(i);
michael@0 559 // note the set has been modified if an old rule was skipped to find
michael@0 560 // this one - something has been dropped, or ordering changed
michael@0 561 if (i > 0) {
michael@0 562 aFontSetModified = true;
michael@0 563 }
michael@0 564 return;
michael@0 565 }
michael@0 566 }
michael@0 567
michael@0 568 // this is a new rule:
michael@0 569
michael@0 570 uint32_t weight = NS_STYLE_FONT_WEIGHT_NORMAL;
michael@0 571 int32_t stretch = NS_STYLE_FONT_STRETCH_NORMAL;
michael@0 572 uint32_t italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
michael@0 573 nsString languageOverride;
michael@0 574
michael@0 575 // set up weight
michael@0 576 aRule->GetDesc(eCSSFontDesc_Weight, val);
michael@0 577 unit = val.GetUnit();
michael@0 578 if (unit == eCSSUnit_Integer || unit == eCSSUnit_Enumerated) {
michael@0 579 weight = val.GetIntValue();
michael@0 580 } else if (unit == eCSSUnit_Normal) {
michael@0 581 weight = NS_STYLE_FONT_WEIGHT_NORMAL;
michael@0 582 } else {
michael@0 583 NS_ASSERTION(unit == eCSSUnit_Null,
michael@0 584 "@font-face weight has unexpected unit");
michael@0 585 }
michael@0 586
michael@0 587 // set up stretch
michael@0 588 aRule->GetDesc(eCSSFontDesc_Stretch, val);
michael@0 589 unit = val.GetUnit();
michael@0 590 if (unit == eCSSUnit_Enumerated) {
michael@0 591 stretch = val.GetIntValue();
michael@0 592 } else if (unit == eCSSUnit_Normal) {
michael@0 593 stretch = NS_STYLE_FONT_STRETCH_NORMAL;
michael@0 594 } else {
michael@0 595 NS_ASSERTION(unit == eCSSUnit_Null,
michael@0 596 "@font-face stretch has unexpected unit");
michael@0 597 }
michael@0 598
michael@0 599 // set up font style
michael@0 600 aRule->GetDesc(eCSSFontDesc_Style, val);
michael@0 601 unit = val.GetUnit();
michael@0 602 if (unit == eCSSUnit_Enumerated) {
michael@0 603 italicStyle = val.GetIntValue();
michael@0 604 } else if (unit == eCSSUnit_Normal) {
michael@0 605 italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
michael@0 606 } else {
michael@0 607 NS_ASSERTION(unit == eCSSUnit_Null,
michael@0 608 "@font-face style has unexpected unit");
michael@0 609 }
michael@0 610
michael@0 611 // set up font features
michael@0 612 nsTArray<gfxFontFeature> featureSettings;
michael@0 613 aRule->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
michael@0 614 unit = val.GetUnit();
michael@0 615 if (unit == eCSSUnit_Normal) {
michael@0 616 // empty list of features
michael@0 617 } else if (unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep) {
michael@0 618 nsRuleNode::ComputeFontFeatures(val.GetPairListValue(), featureSettings);
michael@0 619 } else {
michael@0 620 NS_ASSERTION(unit == eCSSUnit_Null,
michael@0 621 "@font-face font-feature-settings has unexpected unit");
michael@0 622 }
michael@0 623
michael@0 624 // set up font language override
michael@0 625 aRule->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
michael@0 626 unit = val.GetUnit();
michael@0 627 if (unit == eCSSUnit_Normal) {
michael@0 628 // empty feature string
michael@0 629 } else if (unit == eCSSUnit_String) {
michael@0 630 val.GetStringValue(languageOverride);
michael@0 631 } else {
michael@0 632 NS_ASSERTION(unit == eCSSUnit_Null,
michael@0 633 "@font-face font-language-override has unexpected unit");
michael@0 634 }
michael@0 635
michael@0 636 // set up src array
michael@0 637 nsTArray<gfxFontFaceSrc> srcArray;
michael@0 638
michael@0 639 aRule->GetDesc(eCSSFontDesc_Src, val);
michael@0 640 unit = val.GetUnit();
michael@0 641 if (unit == eCSSUnit_Array) {
michael@0 642 nsCSSValue::Array* srcArr = val.GetArrayValue();
michael@0 643 size_t numSrc = srcArr->Count();
michael@0 644
michael@0 645 for (size_t i = 0; i < numSrc; i++) {
michael@0 646 val = srcArr->Item(i);
michael@0 647 unit = val.GetUnit();
michael@0 648 gfxFontFaceSrc* face = srcArray.AppendElements(1);
michael@0 649 if (!face)
michael@0 650 return;
michael@0 651
michael@0 652 switch (unit) {
michael@0 653
michael@0 654 case eCSSUnit_Local_Font:
michael@0 655 val.GetStringValue(face->mLocalName);
michael@0 656 face->mIsLocal = true;
michael@0 657 face->mURI = nullptr;
michael@0 658 face->mFormatFlags = 0;
michael@0 659 break;
michael@0 660 case eCSSUnit_URL:
michael@0 661 face->mIsLocal = false;
michael@0 662 face->mURI = val.GetURLValue();
michael@0 663 face->mReferrer = val.GetURLStructValue()->mReferrer;
michael@0 664 face->mOriginPrincipal = val.GetURLStructValue()->mOriginPrincipal;
michael@0 665 NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
michael@0 666
michael@0 667 // agent and user stylesheets are treated slightly differently,
michael@0 668 // the same-site origin check and access control headers are
michael@0 669 // enforced against the sheet principal rather than the document
michael@0 670 // principal to allow user stylesheets to include @font-face rules
michael@0 671 face->mUseOriginPrincipal = (aSheetType == nsStyleSet::eUserSheet ||
michael@0 672 aSheetType == nsStyleSet::eAgentSheet);
michael@0 673
michael@0 674 face->mLocalName.Truncate();
michael@0 675 face->mFormatFlags = 0;
michael@0 676 while (i + 1 < numSrc && (val = srcArr->Item(i+1),
michael@0 677 val.GetUnit() == eCSSUnit_Font_Format)) {
michael@0 678 nsDependentString valueString(val.GetStringBufferValue());
michael@0 679 if (valueString.LowerCaseEqualsASCII("woff")) {
michael@0 680 face->mFormatFlags |= FLAG_FORMAT_WOFF;
michael@0 681 } else if (valueString.LowerCaseEqualsASCII("opentype")) {
michael@0 682 face->mFormatFlags |= FLAG_FORMAT_OPENTYPE;
michael@0 683 } else if (valueString.LowerCaseEqualsASCII("truetype")) {
michael@0 684 face->mFormatFlags |= FLAG_FORMAT_TRUETYPE;
michael@0 685 } else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
michael@0 686 face->mFormatFlags |= FLAG_FORMAT_TRUETYPE_AAT;
michael@0 687 } else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
michael@0 688 face->mFormatFlags |= FLAG_FORMAT_EOT;
michael@0 689 } else if (valueString.LowerCaseEqualsASCII("svg")) {
michael@0 690 face->mFormatFlags |= FLAG_FORMAT_SVG;
michael@0 691 } else {
michael@0 692 // unknown format specified, mark to distinguish from the
michael@0 693 // case where no format hints are specified
michael@0 694 face->mFormatFlags |= FLAG_FORMAT_UNKNOWN;
michael@0 695 }
michael@0 696 i++;
michael@0 697 }
michael@0 698 if (!face->mURI) {
michael@0 699 // if URI not valid, omit from src array
michael@0 700 srcArray.RemoveElementAt(srcArray.Length() - 1);
michael@0 701 NS_WARNING("null url in @font-face rule");
michael@0 702 continue;
michael@0 703 }
michael@0 704 break;
michael@0 705 default:
michael@0 706 NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
michael@0 707 "strange unit type in font-face src array");
michael@0 708 break;
michael@0 709 }
michael@0 710 }
michael@0 711 } else {
michael@0 712 NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
michael@0 713 }
michael@0 714
michael@0 715 if (srcArray.Length() > 0) {
michael@0 716 FontFaceRuleRecord ruleRec;
michael@0 717 ruleRec.mContainer.mRule = aRule;
michael@0 718 ruleRec.mContainer.mSheetType = aSheetType;
michael@0 719 ruleRec.mFontEntry = AddFontFace(fontfamily, srcArray,
michael@0 720 weight, stretch, italicStyle,
michael@0 721 featureSettings, languageOverride);
michael@0 722 if (ruleRec.mFontEntry) {
michael@0 723 mRules.AppendElement(ruleRec);
michael@0 724 }
michael@0 725 // this was a new rule and fontEntry, so note that the set was modified
michael@0 726 aFontSetModified = true;
michael@0 727 }
michael@0 728 }
michael@0 729
michael@0 730 void
michael@0 731 nsUserFontSet::ReplaceFontEntry(gfxMixedFontFamily* aFamily,
michael@0 732 gfxProxyFontEntry* aProxy,
michael@0 733 gfxFontEntry* aFontEntry)
michael@0 734 {
michael@0 735 // aProxy is being supplanted by the "real" font aFontEntry, so we need to
michael@0 736 // update any rules that refer to it. Note that there may be multiple rules
michael@0 737 // that refer to the same proxy - e.g. if a stylesheet was loaded multiple
michael@0 738 // times, so that several identical @font-face rules are present.
michael@0 739 for (uint32_t i = 0; i < mRules.Length(); ++i) {
michael@0 740 if (mRules[i].mFontEntry == aProxy) {
michael@0 741 mRules[i].mFontEntry = aFontEntry;
michael@0 742 }
michael@0 743 }
michael@0 744 aFamily->ReplaceFontEntry(aProxy, aFontEntry);
michael@0 745 }
michael@0 746
michael@0 747 nsCSSFontFaceRule*
michael@0 748 nsUserFontSet::FindRuleForEntry(gfxFontEntry* aFontEntry)
michael@0 749 {
michael@0 750 for (uint32_t i = 0; i < mRules.Length(); ++i) {
michael@0 751 if (mRules[i].mFontEntry == aFontEntry) {
michael@0 752 return mRules[i].mContainer.mRule;
michael@0 753 }
michael@0 754 }
michael@0 755 return nullptr;
michael@0 756 }
michael@0 757
michael@0 758 nsresult
michael@0 759 nsUserFontSet::LogMessage(gfxMixedFontFamily* aFamily,
michael@0 760 gfxProxyFontEntry* aProxy,
michael@0 761 const char* aMessage,
michael@0 762 uint32_t aFlags,
michael@0 763 nsresult aStatus)
michael@0 764 {
michael@0 765 nsCOMPtr<nsIConsoleService>
michael@0 766 console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
michael@0 767 if (!console) {
michael@0 768 return NS_ERROR_NOT_AVAILABLE;
michael@0 769 }
michael@0 770
michael@0 771 NS_ConvertUTF16toUTF8 familyName(aFamily->Name());
michael@0 772 nsAutoCString fontURI;
michael@0 773 if (aProxy->mSrcIndex == aProxy->mSrcList.Length()) {
michael@0 774 fontURI.AppendLiteral("(end of source list)");
michael@0 775 } else {
michael@0 776 if (aProxy->mSrcList[aProxy->mSrcIndex].mURI) {
michael@0 777 aProxy->mSrcList[aProxy->mSrcIndex].mURI->GetSpec(fontURI);
michael@0 778 } else {
michael@0 779 fontURI.AppendLiteral("(invalid URI)");
michael@0 780 }
michael@0 781 }
michael@0 782
michael@0 783 char weightKeywordBuf[8]; // plenty to sprintf() a uint16_t
michael@0 784 const char* weightKeyword;
michael@0 785 const nsAFlatCString& weightKeywordString =
michael@0 786 nsCSSProps::ValueToKeyword(aProxy->Weight(),
michael@0 787 nsCSSProps::kFontWeightKTable);
michael@0 788 if (weightKeywordString.Length() > 0) {
michael@0 789 weightKeyword = weightKeywordString.get();
michael@0 790 } else {
michael@0 791 sprintf(weightKeywordBuf, "%u", aProxy->Weight());
michael@0 792 weightKeyword = weightKeywordBuf;
michael@0 793 }
michael@0 794
michael@0 795 nsPrintfCString message
michael@0 796 ("downloadable font: %s "
michael@0 797 "(font-family: \"%s\" style:%s weight:%s stretch:%s src index:%d)",
michael@0 798 aMessage,
michael@0 799 familyName.get(),
michael@0 800 aProxy->IsItalic() ? "italic" : "normal",
michael@0 801 weightKeyword,
michael@0 802 nsCSSProps::ValueToKeyword(aProxy->Stretch(),
michael@0 803 nsCSSProps::kFontStretchKTable).get(),
michael@0 804 aProxy->mSrcIndex);
michael@0 805
michael@0 806 if (NS_FAILED(aStatus)) {
michael@0 807 message.Append(": ");
michael@0 808 switch (aStatus) {
michael@0 809 case NS_ERROR_DOM_BAD_URI:
michael@0 810 message.Append("bad URI or cross-site access not allowed");
michael@0 811 break;
michael@0 812 case NS_ERROR_CONTENT_BLOCKED:
michael@0 813 message.Append("content blocked");
michael@0 814 break;
michael@0 815 default:
michael@0 816 message.Append("status=");
michael@0 817 message.AppendInt(static_cast<uint32_t>(aStatus));
michael@0 818 break;
michael@0 819 }
michael@0 820 }
michael@0 821 message.Append("\nsource: ");
michael@0 822 message.Append(fontURI);
michael@0 823
michael@0 824 #ifdef PR_LOGGING
michael@0 825 if (PR_LOG_TEST(GetUserFontsLog(), PR_LOG_DEBUG)) {
michael@0 826 PR_LOG(GetUserFontsLog(), PR_LOG_DEBUG,
michael@0 827 ("userfonts (%p) %s", this, message.get()));
michael@0 828 }
michael@0 829 #endif
michael@0 830
michael@0 831 // try to give the user an indication of where the rule came from
michael@0 832 nsCSSFontFaceRule* rule = FindRuleForEntry(aProxy);
michael@0 833 nsString href;
michael@0 834 nsString text;
michael@0 835 nsresult rv;
michael@0 836 if (rule) {
michael@0 837 rv = rule->GetCssText(text);
michael@0 838 NS_ENSURE_SUCCESS(rv, rv);
michael@0 839 nsCOMPtr<nsIDOMCSSStyleSheet> sheet;
michael@0 840 rv = rule->GetParentStyleSheet(getter_AddRefs(sheet));
michael@0 841 NS_ENSURE_SUCCESS(rv, rv);
michael@0 842 // if the style sheet is removed while the font is loading can be null
michael@0 843 if (sheet) {
michael@0 844 rv = sheet->GetHref(href);
michael@0 845 NS_ENSURE_SUCCESS(rv, rv);
michael@0 846 } else {
michael@0 847 NS_WARNING("null parent stylesheet for @font-face rule");
michael@0 848 href.AssignLiteral("unknown");
michael@0 849 }
michael@0 850 }
michael@0 851
michael@0 852 nsCOMPtr<nsIScriptError> scriptError =
michael@0 853 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
michael@0 854 NS_ENSURE_SUCCESS(rv, rv);
michael@0 855
michael@0 856 uint64_t innerWindowID = GetPresContext()->Document()->InnerWindowID();
michael@0 857 rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(message),
michael@0 858 href, // file
michael@0 859 text, // src line
michael@0 860 0, 0, // line & column number
michael@0 861 aFlags, // flags
michael@0 862 "CSS Loader", // category (make separate?)
michael@0 863 innerWindowID);
michael@0 864 if (NS_SUCCEEDED(rv)) {
michael@0 865 console->LogMessage(scriptError);
michael@0 866 }
michael@0 867
michael@0 868 return NS_OK;
michael@0 869 }
michael@0 870
michael@0 871 nsresult
michael@0 872 nsUserFontSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
michael@0 873 nsIPrincipal** aPrincipal,
michael@0 874 bool* aBypassCache)
michael@0 875 {
michael@0 876 // check same-site origin
michael@0 877 nsIPresShell* ps = mPresContext->PresShell();
michael@0 878 if (!ps)
michael@0 879 return NS_ERROR_FAILURE;
michael@0 880
michael@0 881 NS_ASSERTION(aFontFaceSrc && !aFontFaceSrc->mIsLocal,
michael@0 882 "bad font face url passed to fontloader");
michael@0 883 NS_ASSERTION(aFontFaceSrc->mURI, "null font uri");
michael@0 884 if (!aFontFaceSrc->mURI)
michael@0 885 return NS_ERROR_FAILURE;
michael@0 886
michael@0 887 // use document principal, original principal if flag set
michael@0 888 // this enables user stylesheets to load font files via
michael@0 889 // @font-face rules
michael@0 890 *aPrincipal = ps->GetDocument()->NodePrincipal();
michael@0 891
michael@0 892 NS_ASSERTION(aFontFaceSrc->mOriginPrincipal,
michael@0 893 "null origin principal in @font-face rule");
michael@0 894 if (aFontFaceSrc->mUseOriginPrincipal) {
michael@0 895 *aPrincipal = aFontFaceSrc->mOriginPrincipal;
michael@0 896 }
michael@0 897
michael@0 898 nsresult rv = nsFontFaceLoader::CheckLoadAllowed(*aPrincipal,
michael@0 899 aFontFaceSrc->mURI,
michael@0 900 ps->GetDocument());
michael@0 901 if (NS_FAILED(rv)) {
michael@0 902 return rv;
michael@0 903 }
michael@0 904
michael@0 905 *aBypassCache = false;
michael@0 906
michael@0 907 nsCOMPtr<nsIDocShell> docShell = ps->GetDocument()->GetDocShell();
michael@0 908 if (docShell) {
michael@0 909 uint32_t loadType;
michael@0 910 if (NS_SUCCEEDED(docShell->GetLoadType(&loadType))) {
michael@0 911 if ((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) {
michael@0 912 *aBypassCache = true;
michael@0 913 }
michael@0 914 }
michael@0 915 }
michael@0 916
michael@0 917 return rv;
michael@0 918 }
michael@0 919
michael@0 920 nsresult
michael@0 921 nsUserFontSet::SyncLoadFontData(gfxProxyFontEntry* aFontToLoad,
michael@0 922 const gfxFontFaceSrc* aFontFaceSrc,
michael@0 923 uint8_t*& aBuffer,
michael@0 924 uint32_t& aBufferLength)
michael@0 925 {
michael@0 926 nsresult rv;
michael@0 927
michael@0 928 nsCOMPtr<nsIChannel> channel;
michael@0 929 // get Content Security Policy from principal to pass into channel
michael@0 930 nsCOMPtr<nsIChannelPolicy> channelPolicy;
michael@0 931 nsCOMPtr<nsIContentSecurityPolicy> csp;
michael@0 932 rv = aFontToLoad->mPrincipal->GetCsp(getter_AddRefs(csp));
michael@0 933 NS_ENSURE_SUCCESS(rv, rv);
michael@0 934 if (csp) {
michael@0 935 channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
michael@0 936 channelPolicy->SetContentSecurityPolicy(csp);
michael@0 937 channelPolicy->SetLoadType(nsIContentPolicy::TYPE_FONT);
michael@0 938 }
michael@0 939 rv = NS_NewChannel(getter_AddRefs(channel),
michael@0 940 aFontFaceSrc->mURI,
michael@0 941 nullptr,
michael@0 942 nullptr,
michael@0 943 nullptr,
michael@0 944 nsIRequest::LOAD_NORMAL,
michael@0 945 channelPolicy);
michael@0 946
michael@0 947 NS_ENSURE_SUCCESS(rv, rv);
michael@0 948
michael@0 949 // blocking stream is OK for data URIs
michael@0 950 nsCOMPtr<nsIInputStream> stream;
michael@0 951 rv = channel->Open(getter_AddRefs(stream));
michael@0 952 NS_ENSURE_SUCCESS(rv, rv);
michael@0 953
michael@0 954 uint64_t bufferLength64;
michael@0 955 rv = stream->Available(&bufferLength64);
michael@0 956 NS_ENSURE_SUCCESS(rv, rv);
michael@0 957 if (bufferLength64 == 0) {
michael@0 958 return NS_ERROR_FAILURE;
michael@0 959 }
michael@0 960 if (bufferLength64 > UINT32_MAX) {
michael@0 961 return NS_ERROR_FILE_TOO_BIG;
michael@0 962 }
michael@0 963 aBufferLength = static_cast<uint32_t>(bufferLength64);
michael@0 964
michael@0 965 // read all the decoded data
michael@0 966 aBuffer = static_cast<uint8_t*> (NS_Alloc(sizeof(uint8_t) * aBufferLength));
michael@0 967 if (!aBuffer) {
michael@0 968 aBufferLength = 0;
michael@0 969 return NS_ERROR_OUT_OF_MEMORY;
michael@0 970 }
michael@0 971
michael@0 972 uint32_t numRead, totalRead = 0;
michael@0 973 while (NS_SUCCEEDED(rv =
michael@0 974 stream->Read(reinterpret_cast<char*>(aBuffer + totalRead),
michael@0 975 aBufferLength - totalRead, &numRead)) &&
michael@0 976 numRead != 0)
michael@0 977 {
michael@0 978 totalRead += numRead;
michael@0 979 if (totalRead > aBufferLength) {
michael@0 980 rv = NS_ERROR_FAILURE;
michael@0 981 break;
michael@0 982 }
michael@0 983 }
michael@0 984
michael@0 985 // make sure there's a mime type
michael@0 986 if (NS_SUCCEEDED(rv)) {
michael@0 987 nsAutoCString mimeType;
michael@0 988 rv = channel->GetContentType(mimeType);
michael@0 989 aBufferLength = totalRead;
michael@0 990 }
michael@0 991
michael@0 992 if (NS_FAILED(rv)) {
michael@0 993 NS_Free(aBuffer);
michael@0 994 aBuffer = nullptr;
michael@0 995 aBufferLength = 0;
michael@0 996 return rv;
michael@0 997 }
michael@0 998
michael@0 999 return NS_OK;
michael@0 1000 }
michael@0 1001
michael@0 1002 bool
michael@0 1003 nsUserFontSet::GetPrivateBrowsing()
michael@0 1004 {
michael@0 1005 nsIPresShell* ps = mPresContext->PresShell();
michael@0 1006 if (!ps) {
michael@0 1007 return false;
michael@0 1008 }
michael@0 1009
michael@0 1010 nsCOMPtr<nsILoadContext> loadContext = ps->GetDocument()->GetLoadContext();
michael@0 1011 return loadContext && loadContext->UsePrivateBrowsing();
michael@0 1012 }
michael@0 1013
michael@0 1014 void
michael@0 1015 nsUserFontSet::DoRebuildUserFontSet()
michael@0 1016 {
michael@0 1017 if (!mPresContext) {
michael@0 1018 // AFAICS, this can only happen if someone has already called Destroy() on
michael@0 1019 // this font-set, which means it is in the process of being torn down --
michael@0 1020 // so there's no point trying to update its rules.
michael@0 1021 return;
michael@0 1022 }
michael@0 1023
michael@0 1024 mPresContext->RebuildUserFontSet();
michael@0 1025 }

mercurial