Files
palemoon27/layout/style/nsFontFaceLoader.cpp
T
roytam1 3f625686df import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1157064 - implementation of font-display. r=heycam,khuey (43fe566f45)
- Bug 1235186 - fix small userfont logging nit. r=m_kato (d40bead913)
- Bug 1188802 - only rebuild local webfont rules when needed. r=heycam (f74200aeb2)
- Backout unrelated code landed in dee3e26cc1c0 by mistake. (5d254b78b6)
- Bug 1236506: Add support for "-webkit-filter" as an alias for CSS property "filter". r=heycam (1e7ac6554a)
- Bug 1230426 - Remove support for -webkit-border-image longhand CSS property aliases. r=dholbert (a1a2d5e82a)
- Bug 1246101 - Restore some auto-completion for the align-/justify-* properties. r=dholbert (a33dd2e7c2)
- Bug 1195142 patch 1 - Set CSS_PROPERTY_CREATES_STACKING_CONTEXT for the opacity property. r=BenWa (e547f7b420)
- Bug 1195142 patch 2 - Add reftests for will-change creating a stacking context. r=BenWa (3bb9dc17b9)
- Bug 1195142 patch 3 - Link to correct specification URLs so the CSSWG test suite system is happy. (a8121cdcf0)
- Bug 1234966 - nsStylePosition::MaxDifference should include nsChangeHint_NeutralChange because CalcDiffrence returns it. r=heycam (aa0bf89e54)
- Bug 1244166: Don't ignore stroke/fill properties in high-contrast mode, since doing so can produce icons that are invisible or whose colors are unrelated to the user's chosen high-contrast colors. r=longsonr (6448b05118)
- Bug 1157057 - Rewrite the handling of the nsITimer object in nrappkitTimerCallback; r=ekr (7cc88409b0)
- Bug 1117984: added proxy connection state enum. r=bwc (0c643ff34a)
- Bug 1231971 - Refactor the NAT simulator to use e10s sockets when appropriate. r=drno (c0722c431b)
- Bug 1231973 - Allow NAT simulator to be enabled with the pref system. r=drno (c92ca4fefa)
- Bug 1201209 - Extend the timeout on socket readiness in test_nr_socket_unittest. r=drno (e9e5400902)
- Bug 1216815 - fix memory leaks in test TCP STUN server. r=mjf (11219f41fc)
- Bug 1194385 - Add new unit tests which demonstrate the current behavior. r=bwc (900c621491)
- crashreporte (2ac99868b6)
- Bug 1150966: Check whether |streams_| is null on stats methods in NrIceMediaStream. r=drno (130a9ac2da)
- Bug 1241690: reduce logging output for unconnected PCs. r=bwc (aa236d7184)
- Bug 1224845 - close sockets on errors and don't connect to IPv4 TURN TCP from IPv6 sockets. r=jesup (f128a67692)
- Bug 1189961 - added DNS AAAA convertion to nICEr transport addr. r=bwc (30c14fe7dd)
- Bug 1247536 - Fix -Wunreachable-code warning in media/mtransport/. r=drno (f6768f8539)
- Bug 1194259: nsresult != NS_IMETHODIMP rs=bustage (3a922e6e14)
- Bug 1237909 part 1 - Remove unused TransportLayer::RunOnThread function. r=bwc (d2d219d63a)
- Bug 1237909 part 2 - Do not return value from task for sync dispatch. r=froydnj (c5ec2aecfc)
- Bug 1245035 - Move LOCAL_INCLUDES to moz.build in media/omx-plugin/lib/ics/libvideoeditorplayer. r=mshal (54c363c9f7)
- Bug 1232069 - Check box sizes before alloc&copy. r=jya (86cfe660e7)
- Bug 1234778: Mark all audio frames as keyframes. r=kentuckyfriedtakahe (5e4f1b54d5)
- Bug 1231169 - report rust mp4parse track status in telemetry. r=kinetik,vladan (260d0fed99)
- Bug 1238420 - Update mp4parse-rust invocations in MP4Metadata to match CAPI changes. r=rillian (64c5d6a1ef)
- Bug 1238420 - Report mp4parse-rust errors via Telemetry. r=rillian,vladan (ff72f8dead)
- Bug 1219452 - Update script for rust mp4parser. r=kinetik (9abc268b60)
- Bug 1220754 - Update rust mp4parse import script for v0.1.3. r=kinetik (7185657598)
- Bug 1224785, Part 1 - Implement alert favicons backend. r=wchen (665c44b0cb)
- Bug 1224785, Part 2 - Show the site favicon in OS X notifications. r=mstange (814ff022ba)
- Bug 1224785, Part 3 - Don't include ShowWith{Icon}Backend on Android. r=me (fe323c2960)
- Bug 1243418 - Fix up incorrect 'aOverwrite' usage and impl in GLUploadHelpers r=jgilbert (67677b4921)
- clarify comment (88003aaf96)
- Bug 1204284: Show paper size options in OS X print dialog. r=smichaud (8bb40b4349)
- Bug 1214511 - Show copies, page range selection, and more on the expanded OSX print dialog. r=mstange (301d5cdccc)
- Bug 1216478 - prefer tooltiptext on a XUL element over title attribute on a containing toolbaritem when determining accessible name, r=surkov (ec1dfcad37)
- Bug 1248838 - ARIA owns change may fail, r=yzen (d183be3f3c)
- Bug 1222531 - turn off -Wextra-tokens on clang-cl in accessible/ directories; r=tbsaunde (6dd4dcae20)
- bug 1241453 - add DocAccessibleParent::GetXPCAccessible() r=davidb (f243398399)
- Bug 1087608 - eliminating a pref observer leak and fixing test timeout overflow that cause intermittents. r=eeejay (413354c349)
- Bug 1238368 - Re-introduce workaround for Android tap gesture. r=yzen (04bb9cea5a)
- Bug 1233863 - ARM64: Disable tests that require ion.enable = 1. r=jimb (b268c03c22)
- Bug 1191976 - Intentionally crash if we hit an IPC FatalError in the  parent process. r=billm (b6e9d90d34)
- Bug 1194721: Add |DaemonRunnable8|, r=shuang (0b293cb8a5)
- Bug 1194721: Add PDU_ prefix to daemon PDU constants, r=shuang (834240b14b)
- Bug 1228546 - Implement peripheral mode support for GATT API. r=brsun, r=mrbkap (01a711cac6)
- Bug 1194721: Add helpers for Gonk sensors daemon, r=gsvelto (524d1d6792)
2024-01-02 22:59:35 +08:00

346 lines
11 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 "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()) {
nsAutoCString fontURI;
mFontURI->GetSpec(fontURI);
if (NS_SUCCEEDED(aStatus)) {
LOG(("userfonts (%p) download completed - font uri: (%s) time: %d ms\n",
this, fontURI.get(), downloadTimeMS));
} 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.
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);
}
/* static */ 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;
}
uint8_t
nsFontFaceLoader::GetFontDisplay()
{
uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
if (Preferences::GetBool("layout.css.font-display.enabled")) {
fontDisplay = mUserFontEntry->GetFontDisplay();
}
return fontDisplay;
}