mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1157064 - implementation of font-display. r=heycam,khuey
This commit is contained in:
parent
40dd7eed07
commit
ade0c810ea
@ -19,6 +19,7 @@ dictionary FontFaceDescriptors {
|
||||
DOMString unicodeRange = "U+0-10FFFF";
|
||||
DOMString variant = "normal";
|
||||
DOMString featureSettings = "normal";
|
||||
DOMString display = "auto";
|
||||
};
|
||||
|
||||
enum FontFaceLoadStatus { "unloaded", "loading", "loaded", "error" };
|
||||
@ -37,6 +38,7 @@ interface FontFace {
|
||||
[SetterThrows] attribute DOMString unicodeRange;
|
||||
[SetterThrows] attribute DOMString variant;
|
||||
[SetterThrows] attribute DOMString featureSettings;
|
||||
[SetterThrows, Pref="layout.css.font-display.enabled"] attribute DOMString display;
|
||||
|
||||
readonly attribute FontFaceLoadStatus status;
|
||||
|
||||
|
@ -111,11 +111,13 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges)
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
: gfxFontEntry(NS_LITERAL_STRING("userfont")),
|
||||
mUserFontLoadState(STATUS_NOT_LOADED),
|
||||
mFontDataLoadingState(NOT_LOADING),
|
||||
mUnsupportedFormat(false),
|
||||
mFontDisplay(aFontDisplay),
|
||||
mLoader(nullptr),
|
||||
mFontSet(aFontSet)
|
||||
{
|
||||
@ -146,7 +148,8 @@ gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges)
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
{
|
||||
return mWeight == aWeight &&
|
||||
mStretch == aStretch &&
|
||||
@ -154,6 +157,7 @@ gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
mFeatureSettings == aFeatureSettings &&
|
||||
mLanguageOverride == aLanguageOverride &&
|
||||
mSrcList == aFontFaceSrcList &&
|
||||
mFontDisplay == aFontDisplay &&
|
||||
((!aUnicodeRanges && !mCharacterMap) ||
|
||||
(aUnicodeRanges && mCharacterMap && mCharacterMap->Equals(aUnicodeRanges)));
|
||||
}
|
||||
@ -727,7 +731,8 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
|
||||
mLoader = nullptr;
|
||||
|
||||
// download successful, make platform font using font data
|
||||
if (NS_SUCCEEDED(aDownloadStatus)) {
|
||||
if (NS_SUCCEEDED(aDownloadStatus) &&
|
||||
mFontDataLoadingState != LOADING_TIMED_OUT) {
|
||||
bool loaded = LoadPlatformFont(aFontData, aLength);
|
||||
aFontData = nullptr;
|
||||
|
||||
@ -739,7 +744,9 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
|
||||
} else {
|
||||
// download failed
|
||||
mFontSet->LogMessage(this,
|
||||
"download failed", nsIScriptError::errorFlag,
|
||||
(mFontDataLoadingState != LOADING_TIMED_OUT ?
|
||||
"download failed" : "download timed out"),
|
||||
nsIScriptError::errorFlag,
|
||||
aDownloadStatus);
|
||||
}
|
||||
|
||||
@ -747,8 +754,10 @@ gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
|
||||
free((void*)aFontData);
|
||||
}
|
||||
|
||||
// error occurred, load next src
|
||||
LoadNextSrc();
|
||||
// error occurred, load next src if load not yet timed out
|
||||
if (mFontDataLoadingState != LOADING_TIMED_OUT) {
|
||||
LoadNextSrc();
|
||||
}
|
||||
|
||||
// We ignore the status returned by LoadNext();
|
||||
// even if loading failed, we need to bump the font-set generation
|
||||
@ -795,7 +804,8 @@ gfxUserFontSet::FindOrCreateUserFontEntry(
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges)
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
{
|
||||
RefPtr<gfxUserFontEntry> entry;
|
||||
|
||||
@ -810,13 +820,14 @@ gfxUserFontSet::FindOrCreateUserFontEntry(
|
||||
entry = FindExistingUserFontEntry(family, aFontFaceSrcList, aWeight,
|
||||
aStretch, aStyle,
|
||||
aFeatureSettings, aLanguageOverride,
|
||||
aUnicodeRanges);
|
||||
aUnicodeRanges, aFontDisplay);
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
entry = CreateUserFontEntry(aFontFaceSrcList, aWeight, aStretch,
|
||||
aStyle, aFeatureSettings,
|
||||
aLanguageOverride, aUnicodeRanges);
|
||||
aLanguageOverride, aUnicodeRanges,
|
||||
aFontDisplay);
|
||||
entry->mFamilyName = aFamilyName;
|
||||
}
|
||||
|
||||
@ -831,13 +842,14 @@ gfxUserFontSet::CreateUserFontEntry(
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges)
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
{
|
||||
|
||||
RefPtr<gfxUserFontEntry> userFontEntry =
|
||||
new gfxUserFontEntry(this, aFontFaceSrcList, aWeight,
|
||||
aStretch, aStyle, aFeatureSettings,
|
||||
aLanguageOverride, aUnicodeRanges);
|
||||
aLanguageOverride, aUnicodeRanges, aFontDisplay);
|
||||
return userFontEntry.forget();
|
||||
}
|
||||
|
||||
@ -850,7 +862,8 @@ gfxUserFontSet::FindExistingUserFontEntry(
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges)
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
{
|
||||
MOZ_ASSERT(aWeight != 0,
|
||||
"aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
|
||||
@ -867,7 +880,7 @@ gfxUserFontSet::FindExistingUserFontEntry(
|
||||
if (!existingUserFontEntry->Matches(aFontFaceSrcList,
|
||||
aWeight, aStretch, aStyle,
|
||||
aFeatureSettings, aLanguageOverride,
|
||||
aUnicodeRanges)) {
|
||||
aUnicodeRanges, aFontDisplay)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -886,11 +899,12 @@ gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %d "
|
||||
"stretch: %d",
|
||||
"stretch: %d display: %d",
|
||||
this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry,
|
||||
(aUserFontEntry->IsItalic() ? "italic" :
|
||||
(aUserFontEntry->IsOblique() ? "oblique" : "normal")),
|
||||
aUserFontEntry->Weight(), aUserFontEntry->Stretch()));
|
||||
aUserFontEntry->Weight(), aUserFontEntry->Stretch(),
|
||||
aUserFontEntry->GetFontDisplay()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,8 @@ public:
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges) = 0;
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay) = 0;
|
||||
|
||||
// creates a font face for the specified family, or returns an existing
|
||||
// matching entry on the family if there is one
|
||||
@ -226,7 +227,8 @@ public:
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges);
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay);
|
||||
|
||||
// add in a font face for which we have the gfxUserFontEntry already
|
||||
void AddUserFontEntry(const nsAString& aFamilyName,
|
||||
@ -508,7 +510,8 @@ protected:
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges);
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay);
|
||||
|
||||
// creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
|
||||
// family if there is one
|
||||
@ -551,7 +554,8 @@ public:
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges);
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay);
|
||||
|
||||
virtual ~gfxUserFontEntry();
|
||||
|
||||
@ -562,7 +566,8 @@ public:
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges);
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay);
|
||||
|
||||
virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle,
|
||||
bool aNeedsBold);
|
||||
@ -591,6 +596,8 @@ public:
|
||||
return mCharacterMap.get();
|
||||
}
|
||||
|
||||
uint8_t GetFontDisplay() const { return mFontDisplay; }
|
||||
|
||||
// load the font - starts the loading of sources which continues until
|
||||
// a valid font resource is found or all sources fail
|
||||
void Load();
|
||||
@ -661,11 +668,13 @@ protected:
|
||||
// so keep hiding fallback font
|
||||
LOADING_SLOWLY, // timeout happened and we're not nearly done,
|
||||
// so use the fallback font
|
||||
LOADING_TIMED_OUT, // font load took too long
|
||||
LOADING_FAILED // failed to load any source: use fallback
|
||||
};
|
||||
FontDataLoadingState mFontDataLoadingState;
|
||||
|
||||
bool mUnsupportedFormat;
|
||||
uint8_t mFontDisplay; // timing of userfont fallback
|
||||
|
||||
RefPtr<gfxFontEntry> mPlatformFontEntry;
|
||||
nsTArray<gfxFontFaceSrc> mSrcList;
|
||||
|
@ -355,6 +355,20 @@ FontFace::SetFeatureSettings(const nsAString& aValue, ErrorResult& aRv)
|
||||
SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetDisplay(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
GetDesc(eCSSFontDesc_Display, eCSSProperty_UNKNOWN, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetDisplay(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_Display, aValue, aRv);
|
||||
}
|
||||
|
||||
FontFaceLoadStatus
|
||||
FontFace::Status()
|
||||
{
|
||||
@ -548,7 +562,10 @@ FontFace::SetDescriptors(const nsAString& aFamily,
|
||||
mDescriptors->mUnicodeRange) ||
|
||||
!ParseDescriptor(eCSSFontDesc_FontFeatureSettings,
|
||||
aDescriptors.mFeatureSettings,
|
||||
mDescriptors->mFontFeatureSettings)) {
|
||||
mDescriptors->mFontFeatureSettings) ||
|
||||
!ParseDescriptor(eCSSFontDesc_Display,
|
||||
aDescriptors.mDisplay,
|
||||
mDescriptors->mDisplay)) {
|
||||
// XXX Handle font-variant once we support it (bug 1055385).
|
||||
|
||||
// If any of the descriptors failed to parse, none of them should be set
|
||||
@ -584,6 +601,7 @@ FontFace::GetDesc(nsCSSFontDesc aDescID,
|
||||
nsString& aResult) const
|
||||
{
|
||||
MOZ_ASSERT(aDescID == eCSSFontDesc_UnicodeRange ||
|
||||
aDescID == eCSSFontDesc_Display ||
|
||||
aPropID != eCSSProperty_UNKNOWN,
|
||||
"only pass eCSSProperty_UNKNOWN for eCSSFontDesc_UnicodeRange");
|
||||
|
||||
@ -596,6 +614,8 @@ FontFace::GetDesc(nsCSSFontDesc aDescID,
|
||||
if (value.GetUnit() == eCSSUnit_Null) {
|
||||
if (aDescID == eCSSFontDesc_UnicodeRange) {
|
||||
aResult.AssignLiteral("U+0-10FFFF");
|
||||
} else if (aDescID == eCSSFontDesc_Display) {
|
||||
aResult.AssignLiteral("auto");
|
||||
} else if (aDescID != eCSSFontDesc_Family &&
|
||||
aDescID != eCSSFontDesc_Src) {
|
||||
aResult.AssignLiteral("normal");
|
||||
@ -607,6 +627,10 @@ FontFace::GetDesc(nsCSSFontDesc aDescID,
|
||||
// Since there's no unicode-range property, we can't use
|
||||
// nsCSSValue::AppendToString to serialize this descriptor.
|
||||
nsStyleUtil::AppendUnicodeRange(value, aResult);
|
||||
} else if (aDescID == eCSSFontDesc_Display) {
|
||||
AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(value.GetIntValue(),
|
||||
nsCSSProps::kFontDisplayKTable),
|
||||
aResult);
|
||||
} else {
|
||||
value.AppendToString(aPropID, aResult, nsCSSValue::eNormalized);
|
||||
}
|
||||
|
@ -47,10 +47,11 @@ public:
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges)
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
: gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
|
||||
aStyle, aFeatureSettings, aLanguageOverride,
|
||||
aUnicodeRanges) {}
|
||||
aUnicodeRanges, aFontDisplay) {}
|
||||
|
||||
virtual void SetLoadState(UserFontLoadState aLoadState) override;
|
||||
virtual void GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) override;
|
||||
@ -148,6 +149,8 @@ public:
|
||||
void SetVariant(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetFeatureSettings(nsString& aResult);
|
||||
void SetFeatureSettings(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetDisplay(nsString& aResult);
|
||||
void SetDisplay(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
|
||||
mozilla::dom::FontFaceLoadStatus Status();
|
||||
mozilla::dom::Promise* Load(mozilla::ErrorResult& aRv);
|
||||
|
@ -976,6 +976,7 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
|
||||
int32_t stretch = NS_STYLE_FONT_STRETCH_NORMAL;
|
||||
uint8_t italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
|
||||
uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
|
||||
uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
|
||||
|
||||
// set up weight
|
||||
aFontFace->GetDesc(eCSSFontDesc_Weight, val);
|
||||
@ -1016,6 +1017,16 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
|
||||
"@font-face style has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font display
|
||||
aFontFace->GetDesc(eCSSFontDesc_Display, val);
|
||||
unit = val.GetUnit();
|
||||
if (unit == eCSSUnit_Enumerated) {
|
||||
fontDisplay = val.GetIntValue();
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"@font-face style has unexpected unit");
|
||||
}
|
||||
|
||||
// set up font features
|
||||
nsTArray<gfxFontFeature> featureSettings;
|
||||
aFontFace->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
|
||||
@ -1161,7 +1172,7 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
|
||||
stretch, italicStyle,
|
||||
featureSettings,
|
||||
languageOverride,
|
||||
unicodeRanges);
|
||||
unicodeRanges, fontDisplay);
|
||||
return entry.forget();
|
||||
}
|
||||
|
||||
@ -1805,11 +1816,13 @@ FontFaceSet::UserFontSet::CreateUserFontEntry(
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges)
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
{
|
||||
RefPtr<gfxUserFontEntry> entry =
|
||||
new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aStyle,
|
||||
aFeatureSettings, aLanguageOverride, aUnicodeRanges);
|
||||
aFeatureSettings, aLanguageOverride, aUnicodeRanges,
|
||||
aFontDisplay);
|
||||
return entry.forget();
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,8 @@ public:
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges) override;
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay) override;
|
||||
|
||||
private:
|
||||
RefPtr<FontFaceSet> mFontFaceSet;
|
||||
|
@ -31,6 +31,18 @@ using namespace mozilla::dom;
|
||||
#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,
|
||||
@ -60,8 +72,15 @@ nsFontFaceLoader::~nsFontFaceLoader()
|
||||
void
|
||||
nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader)
|
||||
{
|
||||
int32_t loadTimeout =
|
||||
Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000);
|
||||
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) {
|
||||
@ -87,39 +106,72 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
}
|
||||
|
||||
gfxUserFontEntry* ufe = loader->mUserFontEntry.get();
|
||||
bool updateUserFontSet = true;
|
||||
uint8_t fontDisplay = loader->GetFontDisplay();
|
||||
|
||||
// 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));
|
||||
// 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) {
|
||||
ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
|
||||
nsTArray<gfxUserFontSet*> fontSets;
|
||||
ufe->GetUserFontSets(fontSets);
|
||||
for (gfxUserFontSet* fontSet : fontSets) {
|
||||
@ -127,8 +179,8 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure)
|
||||
if (ctx) {
|
||||
fontSet->IncrementGeneration();
|
||||
ctx->UserFontSetUpdated(ufe);
|
||||
LOG(("userfonts (%p) timeout reflow for pres context %p\n",
|
||||
loader, ctx));
|
||||
LOG(("userfonts (%p) timeout reflow for pres context %p display %d\n",
|
||||
loader, ctx, fontDisplay));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,6 +207,16 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
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);
|
||||
@ -271,3 +333,13 @@ nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -50,6 +50,9 @@ public:
|
||||
protected:
|
||||
virtual ~nsFontFaceLoader();
|
||||
|
||||
// helper method for determining the font-display value
|
||||
uint8_t GetFontDisplay();
|
||||
|
||||
private:
|
||||
RefPtr<gfxUserFontEntry> mUserFontEntry;
|
||||
nsCOMPtr<nsIURI> mFontURI;
|
||||
|
@ -63,5 +63,10 @@ var gCSSFontFaceDescriptors = {
|
||||
domProp: null,
|
||||
values: [ "U+0-10FFFF", "U+3-7B3", "U+3??", "U+6A", "U+3????", "U+???", "U+302-302", "U+0-7,U+A-C", "U+100-17F,U+200-17F", "U+3??, U+500-513 ,U+612 , U+4????", "U+1FFF,U+200-27F" ],
|
||||
invalid_values: [ "U+1????-2????", "U+0-7,A-C", "U+100-17F,200-17F", "U+6A!important", "U+6A)" ]
|
||||
},
|
||||
"font-display": {
|
||||
domProp: null,
|
||||
values: [ "auto", "block", "swap", "fallback", "optional" ],
|
||||
invalid_values: [ "normal", "initial" ]
|
||||
}
|
||||
}
|
||||
|
@ -91,19 +91,27 @@ function test_descriptor(descriptor)
|
||||
// To avoid triggering the slow script dialog, we have to test one
|
||||
// descriptor at a time.
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var descs = [];
|
||||
for (var desc in gCSSFontFaceDescriptors)
|
||||
descs.push(desc);
|
||||
descs = descs.reverse();
|
||||
function do_one() {
|
||||
if (descs.length == 0) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
function runTest() {
|
||||
var descs = [];
|
||||
for (var desc in gCSSFontFaceDescriptors)
|
||||
descs.push(desc);
|
||||
descs = descs.reverse();
|
||||
function do_one() {
|
||||
if (descs.length == 0) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
test_descriptor(descs.pop());
|
||||
SimpleTest.executeSoon(do_one);
|
||||
}
|
||||
test_descriptor(descs.pop());
|
||||
SimpleTest.executeSoon(do_one);
|
||||
}
|
||||
SimpleTest.executeSoon(do_one);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestLongerTimeout(5);
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [["layout.css.font-display.enabled", true]] },
|
||||
runTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -19,7 +19,8 @@ var descriptorNames = {
|
||||
stretch: "font-stretch",
|
||||
unicodeRange: "unicode-range",
|
||||
variant: "font-variant",
|
||||
featureSettings: "font-feature-settings"
|
||||
featureSettings: "font-feature-settings",
|
||||
display: "font-display"
|
||||
};
|
||||
|
||||
// Default values for the FontFace descriptor attributes other than family, as
|
||||
@ -30,7 +31,8 @@ var defaultValues = {
|
||||
stretch: "normal",
|
||||
unicodeRange: "U+0-10FFFF",
|
||||
variant: "normal",
|
||||
featureSettings: "normal"
|
||||
featureSettings: "normal",
|
||||
display: "auto"
|
||||
};
|
||||
|
||||
// Non-default values for the FontFace descriptor attributes other than family
|
||||
@ -42,7 +44,8 @@ var nonDefaultValues = {
|
||||
stretch: ["Ultra-Condensed", "ultra-condensed"],
|
||||
unicodeRange: ["U+3??", "U+300-3FF"],
|
||||
variant: ["Small-Caps", "small-caps"],
|
||||
featureSettings: ["'dlig' on", "\"dlig\""]
|
||||
featureSettings: ["'dlig' on", "\"dlig\""],
|
||||
display: ["Block", "block"]
|
||||
};
|
||||
|
||||
// Invalid values for the FontFace descriptor attributes other than family.
|
||||
@ -52,7 +55,8 @@ var invalidValues = {
|
||||
stretch: "wider",
|
||||
unicodeRange: "U+1????-2????",
|
||||
variant: "inherit",
|
||||
featureSettings: "dlig"
|
||||
featureSettings: "dlig",
|
||||
display: "normal"
|
||||
};
|
||||
|
||||
// Invalid font family names.
|
||||
@ -159,8 +163,6 @@ function awaitRefresh() {
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Document and window from inside the display:none iframe.
|
||||
var nframe = document.getElementById("n");
|
||||
var ndocument = nframe.contentDocument;
|
||||
@ -1859,11 +1861,16 @@ function runTest() {
|
||||
|
||||
function start() {
|
||||
if (SpecialPowers.getBoolPref("layout.css.font-loading-api.enabled")) {
|
||||
runTest();
|
||||
SpecialPowers.pushPrefEnv({ set: [["layout.css.font-display.enabled", true]] },
|
||||
runTest);
|
||||
} else {
|
||||
ok(true, "CSS Font Loading API is not enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestLongerTimeout(5);
|
||||
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -630,6 +630,7 @@ pref("gfx.color_management.enablev4", false);
|
||||
|
||||
pref("gfx.downloadable_fonts.enabled", true);
|
||||
pref("gfx.downloadable_fonts.fallback_delay", 3000);
|
||||
pref("gfx.downloadable_fonts.fallback_delay_short", 100);
|
||||
|
||||
// disable downloadable font cache so that behavior is consistently
|
||||
// the uncached load behavior across pages (useful for testing reflow problems)
|
||||
|
Loading…
Reference in New Issue
Block a user