Files
palemoon27/layout/style/nsFontFaceLoader.cpp
T
roytam1 bb8d235286 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1143537 - Part 1: Fix test numbering. r=jdaggett (b991d2fca)
- Bug 1143537 - Part 2: Test descriptor getters for CSS-connected FontFaces when the descriptor isn't present. r=jdaggett (2ed363737)
- Bug 1143537 - Part 3: Serialize unicode-range without leading zeroes. r=jdaggett (f3e6cfe5f)
- Bug 1143537 - Part 4: Serialize FontFace unicodeRange and fontFeatureBug 1143537 - Part 4: Serialize FontFace unicodeRange and fontFeature (acf97f1c6)
- Bug 1143537 - Part 5: Test status of FontFace and FontFaceSet with @font-face rules. r=jdaggett (477d01717)
- Bug 1145506 - Make FontFace constructor fail on invalid src strings but otherwise create user font entries immediately. r=jdaggett (7c19fa8e7)
- Bug 1153628 - Break FontFaceSet <-> UserFontSet cycle when a document's pres shell is going away. r=mccr8 (280ecbcbc)
- Bug 1152647 - Part 1: Test. r=jdaggett (802141c54)
- Bug 1152647 - Part 2: Ignore requests to add/delete a rule-backed FontFace to/from a FontFaceSet. r=jdaggett (2dc5f06a9)
- Bug 1162855 - Traverse FontFaceSet's mUserFontSet's pointer back to the FontFaceSet. r=smaug (eb86c10d9)
- Bug 1163449 - Remove OOM check when creating new nsFontFaceLoader. r=jdaggett (67c23c744)
- Bug 1163865 - Remove [Throws] from FontFaceSet.delete. r=smaug (c83f95505)
- Bug 1173001 - Initialize reader task queue in the constructor. r=jww (efecb4a62)
- Bug 1173001 - Enable tail dispatch for the decode task queue. r=jww (11e8feaad)
- Bug 1161413 - Part 1: Create FontFaceSet with a document rather than a pres context. r=jdaggett (1d5e642c7)
- Bug 1161413 - Part 2: Create FontFace objects with a FontFaceSet rather than a pres context. r=jdaggett (0076f1907)
- Bug 1161413 - Part 3: Only reflow from the font face loader if we have a pres context. r=jdaggett (7a6aab61a)
- bug 1144602 - preconnect test handler should only count 1 syn r=test-only (4d6022758)
- bug 1144602 - test_rel_preconnect orange r=test-only (05dac1e9f)
- Bug 1162243 - add anonymous speculative connections r=hurley (6bd6bffc3)
- bug 1174152 - crossorigin attribute for link rel=preconnect r=hsivonen (7b1178fa4)
- Bug 1173289 - Remove WakeDecoderRunnable from MDSM. r=roc. (9782c6dd6)
- Bug 1161413 - Part 4: Move FontFaceSet ownership from nsPresContext to nsIDocument. r=smaug (bc9dc2b87)
- Bug 1161413 - Part 5: Cancel font loads on FontFaceSet destruction. r=jdaggett (37595e28e)
- Bug 1161413 - Part 6: Update test assertion annotations. r=jdaggett (23c93ca28)
- Bug 1161413 - Part 7: Test Font Loading API in a display:none iframe. r=jdaggett (377222287)
- Bug 1173248 - Remove the workaround introduced to MDSM by bug 951278. r=cpearce. (43ecb0e42)
- Bug 1163879 - Remove FontFaceSet::mUnavailableFontFaces. r=jdaggett (b86a68998)
- Bug 1155015 - Hide FontFaceSet.load() until we implement it. r=bzbarsky (8ba0953f0)
- Bug 1072102 - Part 1: Implement FontFaceSet load and check. r=jdaggett,bzbarsky (7f4c8c7f1)
- Bug 1143995 - Remove unnecessary layout flushes from test_font_loading_api.html. r=jdaggett (38a3df578)
- Bug 1146199 - Return empty string from FontFace.family if the FontFace was constructed with an invalid family name. r=jdaggett (dd2d9b6eb)
- Bug 1072102 - Part 2: Tests. r=jdaggett (5966dd4ac)
- Bug 1179675 - Make FontFaceSet.cpp compile as part of UNIFIED_SOURCES. r=jdaggett (665712d80)
- Bug 1134096 - Revise docs for ::NewChannel2, ::GetChannelPrincipal and add deprecation warnings (r=tanvi,sicking) (64fe28638)
- Bug 647010 - Limit when HTTP authentication dialog is shown. Block cross-origin http auth prompts with pref. r=mayhemer, r=tanvi (bf3f529d0)
- Bug 1147699 follow-up: Disable the plugin test on Mulet (bdca19965)
- Bug 1168676 - Switch off embed/object ServiceWorker interception. r=ehsan (9d0b09b66)
- Bug 1125325 - Store TabParents with their WindowRoot. r=smaug (9e651f902)
2021-04-02 00:12:09 +08:00

253 lines
8.3 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim:cindent:ts=2:et:sw=2:
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* code for loading in @font-face defined font data */
#include "mozilla/Logging.h"
#include "nsFontFaceLoader.h"
#include "nsError.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
#include "FontFaceSet.h"
#include "nsPresContext.h"
#include "nsIPrincipal.h"
#include "nsIScriptSecurityManager.h"
#include "nsIHttpChannel.h"
#include "nsIContentPolicy.h"
#include "nsContentPolicyUtils.h"
#include "mozilla/gfx/2D.h"
using namespace mozilla;
#define LOG(args) MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
#define LOG_ENABLED() MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \
LogLevel::Debug)
nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry,
nsIURI* aFontURI,
mozilla::dom::FontFaceSet* aFontFaceSet,
nsIChannel* aChannel)
: mUserFontEntry(aUserFontEntry),
mFontURI(aFontURI),
mFontFaceSet(aFontFaceSet),
mChannel(aChannel)
{
}
nsFontFaceLoader::~nsFontFaceLoader()
{
if (mUserFontEntry) {
mUserFontEntry->mLoader = nullptr;
}
if (mLoadTimer) {
mLoadTimer->Cancel();
mLoadTimer = nullptr;
}
if (mFontFaceSet) {
mFontFaceSet->RemoveLoader(this);
}
}
void
nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader)
{
int32_t loadTimeout =
Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000);
if (loadTimeout > 0) {
mLoadTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mLoadTimer) {
mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
static_cast<void*>(this),
loadTimeout,
nsITimer::TYPE_ONE_SHOT);
}
} else {
mUserFontEntry->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
}
mStreamLoader = aStreamLoader;
}
void
nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
{
nsFontFaceLoader* loader = static_cast<nsFontFaceLoader*>(aClosure);
if (!loader->mFontFaceSet) {
// We've been canceled
return;
}
gfxUserFontEntry* ufe = loader->mUserFontEntry.get();
bool updateUserFontSet = true;
// If the entry is loading, check whether it's >75% done; if so,
// we allow another timeout period before showing a fallback font.
if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) {
int64_t contentLength;
uint32_t numBytesRead;
if (NS_SUCCEEDED(loader->mChannel->GetContentLength(&contentLength)) &&
contentLength > 0 &&
contentLength < UINT32_MAX &&
NS_SUCCEEDED(loader->mStreamLoader->GetNumBytesRead(&numBytesRead)) &&
numBytesRead > 3 * (uint32_t(contentLength) >> 2))
{
// More than 3/4 the data has been downloaded, so allow 50% extra
// time and hope the remainder will arrive before the additional
// time expires.
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_ALMOST_DONE;
uint32_t delay;
loader->mLoadTimer->GetDelay(&delay);
loader->mLoadTimer->InitWithFuncCallback(LoadTimerCallback,
static_cast<void*>(loader),
delay >> 1,
nsITimer::TYPE_ONE_SHOT);
updateUserFontSet = false;
LOG(("userfonts (%p) 75%% done, resetting timer\n", loader));
}
}
// If the font is not 75% loaded, or if we've already timed out once
// before, we mark this entry as "loading slowly", so the fallback
// font will be used in the meantime, and tell the context to refresh.
if (updateUserFontSet) {
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
nsPresContext* ctx = loader->mFontFaceSet->GetPresContext();
if (ctx) {
loader->mFontFaceSet->IncrementGeneration();
ctx->UserFontSetUpdated(loader->GetUserFontEntry());
LOG(("userfonts (%p) timeout reflow\n", loader));
}
}
}
NS_IMPL_ISUPPORTS(nsFontFaceLoader, nsIStreamLoaderObserver)
NS_IMETHODIMP
nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* aContext,
nsresult aStatus,
uint32_t aStringLen,
const uint8_t* aString)
{
if (!mFontFaceSet) {
// We've been canceled
return aStatus;
}
mFontFaceSet->RemoveLoader(this);
if (LOG_ENABLED()) {
nsAutoCString fontURI;
mFontURI->GetSpec(fontURI);
if (NS_SUCCEEDED(aStatus)) {
LOG(("userfonts (%p) download completed - font uri: (%s)\n",
this, fontURI.get()));
} else {
LOG(("userfonts (%p) download failed - font uri: (%s) error: %8.8x\n",
this, fontURI.get(), aStatus));
}
}
if (NS_SUCCEEDED(aStatus)) {
// for HTTP requests, check whether the request _actually_ succeeded;
// the "request status" in aStatus does not necessarily indicate this,
// because HTTP responses such as 404 (Not Found) will still result in
// a success code and potentially an HTML error page from the server
// as the resulting data. We don't want to use that as a font.
nsCOMPtr<nsIRequest> request;
nsCOMPtr<nsIHttpChannel> httpChannel;
aLoader->GetRequest(getter_AddRefs(request));
httpChannel = do_QueryInterface(request);
if (httpChannel) {
bool succeeded;
nsresult rv = httpChannel->GetRequestSucceeded(&succeeded);
if (NS_SUCCEEDED(rv) && !succeeded) {
aStatus = NS_ERROR_NOT_AVAILABLE;
}
}
}
// The userFontEntry is responsible for freeing the downloaded data
// (aString) when finished with it; the pointer is no longer valid
// after FontDataDownloadComplete returns.
// This is called even in the case of a failed download (HTTP 404, etc),
// as there may still be data to be freed (e.g. an error page),
// and we need to load the next source.
nsPresContext* ctx = mFontFaceSet->GetPresContext();
bool fontUpdate =
mUserFontEntry->FontDataDownloadComplete(aString, aStringLen, aStatus);
// when new font loaded, need to reflow
if (fontUpdate && ctx) {
// Update layout for the presence of the new font. Since this is
// asynchronous, reflows will coalesce.
ctx->UserFontSetUpdated(mUserFontEntry);
LOG(("userfonts (%p) reflow\n", this));
}
// done with font set
mFontFaceSet = nullptr;
if (mLoadTimer) {
mLoadTimer->Cancel();
mLoadTimer = nullptr;
}
return NS_SUCCESS_ADOPTED_DATA;
}
void
nsFontFaceLoader::Cancel()
{
mUserFontEntry->mFontDataLoadingState = gfxUserFontEntry::NOT_LOADING;
mUserFontEntry->mLoader = nullptr;
mFontFaceSet = nullptr;
if (mLoadTimer) {
mLoadTimer->Cancel();
mLoadTimer = nullptr;
}
mChannel->Cancel(NS_BINDING_ABORTED);
}
nsresult
nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
nsIURI* aTargetURI,
nsISupports* aContext)
{
nsresult rv;
if (!aSourcePrincipal)
return NS_OK;
// check with the security manager
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
rv = secMan->CheckLoadURIWithPrincipal(aSourcePrincipal, aTargetURI,
nsIScriptSecurityManager::STANDARD);
if (NS_FAILED(rv)) {
return rv;
}
// check content policy
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
aTargetURI,
aSourcePrincipal,
aContext,
EmptyCString(), // mime type
nullptr,
&shouldLoad,
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
return NS_ERROR_CONTENT_BLOCKED;
}
return NS_OK;
}