mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 00:08:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
306
layout/style/nsFontFaceLoader.cpp
Normal file
306
layout/style/nsFontFaceLoader.cpp
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/* -*- 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 "mozilla/Telemetry.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;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
#define LOG(args) MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
|
||||
#define LOG_ENABLED() MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \
|
||||
LogLevel::Debug)
|
||||
|
||||
static uint32_t
|
||||
GetFallbackDelay()
|
||||
{
|
||||
return Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
GetShortFallbackDelay()
|
||||
{
|
||||
return Preferences::GetInt("gfx.downloadable_fonts.fallback_delay_short", 100);
|
||||
}
|
||||
|
||||
nsFontFaceLoader::nsFontFaceLoader(gfxUserFontEntry* aUserFontEntry,
|
||||
nsIURI* aFontURI,
|
||||
FontFaceSet* aFontFaceSet,
|
||||
nsIChannel* aChannel)
|
||||
: mUserFontEntry(aUserFontEntry),
|
||||
mFontURI(aFontURI),
|
||||
mFontFaceSet(aFontFaceSet),
|
||||
mChannel(aChannel)
|
||||
{
|
||||
mStartTime = TimeStamp::Now();
|
||||
}
|
||||
|
||||
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;
|
||||
uint8_t fontDisplay = GetFontDisplay();
|
||||
if (fontDisplay == NS_FONT_DISPLAY_AUTO ||
|
||||
fontDisplay == NS_FONT_DISPLAY_BLOCK) {
|
||||
loadTimeout = GetFallbackDelay();
|
||||
} else {
|
||||
loadTimeout = GetShortFallbackDelay();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* static */ 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();
|
||||
uint8_t fontDisplay = loader->GetFontDisplay();
|
||||
|
||||
// Depending upon the value of the font-display descriptor for the font,
|
||||
// their may be one or two timeouts associated with each font. The LOADING_SLOWLY
|
||||
// state indicates that the fallback font is shown. The LOADING_TIMED_OUT
|
||||
// state indicates that the fallback font is shown *and* the downloaded font
|
||||
// resource will not replace the fallback font when the load completes.
|
||||
|
||||
bool updateUserFontSet = true;
|
||||
switch (fontDisplay) {
|
||||
case NS_FONT_DISPLAY_AUTO:
|
||||
case NS_FONT_DISPLAY_BLOCK:
|
||||
// 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 (updateUserFontSet) {
|
||||
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
|
||||
}
|
||||
break;
|
||||
case NS_FONT_DISPLAY_SWAP:
|
||||
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
|
||||
break;
|
||||
case NS_FONT_DISPLAY_FALLBACK: {
|
||||
if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) {
|
||||
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
|
||||
} else {
|
||||
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_TIMED_OUT;
|
||||
updateUserFontSet = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NS_FONT_DISPLAY_OPTIONAL:
|
||||
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_TIMED_OUT;
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_NOTREACHED("strange font-display value");
|
||||
break;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
nsTArray<gfxUserFontSet*> fontSets;
|
||||
ufe->GetUserFontSets(fontSets);
|
||||
for (gfxUserFontSet* fontSet : fontSets) {
|
||||
nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
|
||||
if (ctx) {
|
||||
fontSet->IncrementGeneration();
|
||||
ctx->UserFontSetUpdated(ufe);
|
||||
LOG(("userfonts (%p) timeout reflow for pres context %p display %d\n",
|
||||
loader, ctx, fontDisplay));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
TimeStamp doneTime = TimeStamp::Now();
|
||||
TimeDuration downloadTime = doneTime - mStartTime;
|
||||
uint32_t downloadTimeMS = uint32_t(downloadTime.ToMilliseconds());
|
||||
Telemetry::Accumulate(Telemetry::WEBFONT_DOWNLOAD_TIME, downloadTimeMS);
|
||||
|
||||
if (GetFontDisplay() == NS_FONT_DISPLAY_FALLBACK) {
|
||||
uint32_t loadTimeout = GetFallbackDelay();
|
||||
if (downloadTimeMS > loadTimeout &&
|
||||
(mUserFontEntry->mFontDataLoadingState ==
|
||||
gfxUserFontEntry::LOADING_SLOWLY)) {
|
||||
mUserFontEntry->mFontDataLoadingState =
|
||||
gfxUserFontEntry::LOADING_TIMED_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
LOG(("userfonts (%p) download completed - font uri: (%s) time: %d ms\n",
|
||||
this, mFontURI->GetSpecOrDefault().get(), downloadTimeMS));
|
||||
} else {
|
||||
LOG(("userfonts (%p) download failed - font uri: (%s) error: %8.8x\n",
|
||||
this, mFontURI->GetSpecOrDefault().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.
|
||||
bool fontUpdate =
|
||||
mUserFontEntry->FontDataDownloadComplete(aString, aStringLen, aStatus);
|
||||
|
||||
mFontFaceSet->GetUserFontSet()->RecordFontLoadDone(aStringLen, doneTime);
|
||||
|
||||
// when new font loaded, need to reflow
|
||||
if (fontUpdate) {
|
||||
nsTArray<gfxUserFontSet*> fontSets;
|
||||
mUserFontEntry->GetUserFontSets(fontSets);
|
||||
for (gfxUserFontSet* fontSet : fontSets) {
|
||||
nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
|
||||
if (ctx) {
|
||||
// Update layout for the presence of the new font. Since this is
|
||||
// asynchronous, reflows will coalesce.
|
||||
ctx->UserFontSetUpdated(mUserFontEntry);
|
||||
LOG(("userfonts (%p) reflow for pres context %p\n", this, ctx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
nsFontFaceLoader::GetFontDisplay()
|
||||
{
|
||||
uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
|
||||
if (Preferences::GetBool("layout.css.font-display.enabled")) {
|
||||
fontDisplay = mUserFontEntry->GetFontDisplay();
|
||||
}
|
||||
return fontDisplay;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue