From ade0c810eae7834655e93a5c07854461df221b8f Mon Sep 17 00:00:00 2001 From: John Daggett Date: Thu, 7 Jan 2016 14:03:05 +0900 Subject: [PATCH] Bug 1157064 - implementation of font-display. r=heycam,khuey --- dom/webidl/FontFace.webidl | 2 + gfx/thebes/gfxUserFontSet.cpp | 44 ++++-- gfx/thebes/gfxUserFontSet.h | 19 ++- layout/style/FontFace.cpp | 26 +++- layout/style/FontFace.h | 7 +- layout/style/FontFaceSet.cpp | 19 ++- layout/style/FontFaceSet.h | 3 +- layout/style/nsFontFaceLoader.cpp | 130 ++++++++++++++---- layout/style/nsFontFaceLoader.h | 3 + layout/style/test/descriptor_database.js | 5 + .../style/test/test_descriptor_storage.html | 28 ++-- layout/style/test/test_font_loading_api.html | 21 ++- modules/libpref/init/all.js | 1 + 13 files changed, 235 insertions(+), 73 deletions(-) diff --git a/dom/webidl/FontFace.webidl b/dom/webidl/FontFace.webidl index d4221a39737d..136658cc7cd6 100644 --- a/dom/webidl/FontFace.webidl +++ b/dom/webidl/FontFace.webidl @@ -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; diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index 75dd5a6cbc37..302ffa8913c0 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -111,11 +111,13 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet, uint8_t aStyle, const nsTArray& 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& aFontFaceSrcList, uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { return mWeight == aWeight && mStretch == aStretch && @@ -154,6 +157,7 @@ gfxUserFontEntry::Matches(const nsTArray& 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& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { RefPtr 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& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { RefPtr 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& 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())); } } diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 8f6a5fcb949d..eb4720a5f369 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -214,7 +214,8 @@ public: uint8_t aStyle, const nsTArray& 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& 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& 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& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges); + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay); virtual ~gfxUserFontEntry(); @@ -562,7 +566,8 @@ public: uint8_t aStyle, const nsTArray& 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 mPlatformFontEntry; nsTArray mSrcList; diff --git a/layout/style/FontFace.cpp b/layout/style/FontFace.cpp index 5b1893785634..3c54aff6452e 100644 --- a/layout/style/FontFace.cpp +++ b/layout/style/FontFace.cpp @@ -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); } diff --git a/layout/style/FontFace.h b/layout/style/FontFace.h index 58072b6e507d..4893b4c39606 100644 --- a/layout/style/FontFace.h +++ b/layout/style/FontFace.h @@ -47,10 +47,11 @@ public: uint8_t aStyle, const nsTArray& 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& 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); diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index dfb6deea10e8..2d4e546fc340 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -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 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& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) { RefPtr entry = new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aStyle, - aFeatureSettings, aLanguageOverride, aUnicodeRanges); + aFeatureSettings, aLanguageOverride, aUnicodeRanges, + aFontDisplay); return entry.forget(); } diff --git a/layout/style/FontFaceSet.h b/layout/style/FontFaceSet.h index 869e9b7cd66e..ae96a2298acc 100644 --- a/layout/style/FontFaceSet.h +++ b/layout/style/FontFaceSet.h @@ -89,7 +89,8 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges) override; + gfxSparseBitSet* aUnicodeRanges, + uint8_t aFontDisplay) override; private: RefPtr mFontFaceSet; diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp index 2b8fb0698b49..15c97d305597 100644 --- a/layout/style/nsFontFaceLoader.cpp +++ b/layout/style/nsFontFaceLoader.cpp @@ -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(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(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 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; +} diff --git a/layout/style/nsFontFaceLoader.h b/layout/style/nsFontFaceLoader.h index 6ccda0f0f2d1..83b1270633f0 100644 --- a/layout/style/nsFontFaceLoader.h +++ b/layout/style/nsFontFaceLoader.h @@ -50,6 +50,9 @@ public: protected: virtual ~nsFontFaceLoader(); + // helper method for determining the font-display value + uint8_t GetFontDisplay(); + private: RefPtr mUserFontEntry; nsCOMPtr mFontURI; diff --git a/layout/style/test/descriptor_database.js b/layout/style/test/descriptor_database.js index d3531842de4d..da672d03b2c2 100644 --- a/layout/style/test/descriptor_database.js +++ b/layout/style/test/descriptor_database.js @@ -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" ] } } diff --git a/layout/style/test/test_descriptor_storage.html b/layout/style/test/test_descriptor_storage.html index c7504117c2c9..50017f642b81 100644 --- a/layout/style/test/test_descriptor_storage.html +++ b/layout/style/test/test_descriptor_storage.html @@ -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); diff --git a/layout/style/test/test_font_loading_api.html b/layout/style/test/test_font_loading_api.html index 122d4e46d92a..dcd9148b8e8a 100644 --- a/layout/style/test/test_font_loading_api.html +++ b/layout/style/test/test_font_loading_api.html @@ -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); + diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 919a183f920d..8b397173574f 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -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)