diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index cf8c5696bf7b..00e44a743b20 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1955,6 +1955,8 @@ gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyl mUserFontSet = nsnull; SetUserFontSet(aUserFontSet); + mSkipDrawing = PR_FALSE; + mPageLang = gfxPlatform::GetFontPrefLangFor(mStyle.language); BuildFontList(); } @@ -2035,14 +2037,20 @@ gfxFontGroup::FindPlatformFont(const nsAString& aName, gfxFontGroup *fontGroup = static_cast(aClosure); const gfxFontStyle *fontStyle = fontGroup->GetStyle(); - PRBool needsBold; gfxFontEntry *fe = nsnull; // first, look up in the user font set gfxUserFontSet *fs = fontGroup->GetUserFontSet(); if (fs) { - fe = fs->FindFontEntry(aName, *fontStyle, needsBold); + // if the fontSet matches the family, but the font has not yet finished + // loading (nor has its load timeout fired), the fontGroup should wait + // for the download, and not actually draw its text yet + PRBool waitForUserFont = PR_FALSE; + fe = fs->FindFontEntry(aName, *fontStyle, needsBold, waitForUserFont); + if (!fe && waitForUserFont) { + fontGroup->mSkipDrawing = PR_TRUE; + } } // nothing in the user font set ==> check system fonts @@ -2240,15 +2248,21 @@ gfxFontGroup::ForEachFontInternal(const nsAString& aFamilies, ResolveData data(fc, gf, closure); PRBool aborted = PR_FALSE, needsBold; nsresult rv; - - if (mUserFontSet && mUserFontSet->FindFontEntry(family, mStyle, needsBold)) { + PRBool waitForUserFont = PR_FALSE; + if (mUserFontSet && + mUserFontSet->FindFontEntry(family, mStyle, needsBold, + waitForUserFont)) + { gfxFontGroup::FontResolverProc(family, &data); rv = NS_OK; } else { + if (waitForUserFont) { + mSkipDrawing = PR_TRUE; + } gfxPlatform *pf = gfxPlatform::GetPlatform(); rv = pf->ResolveFontName(family, - gfxFontGroup::FontResolverProc, - &data, aborted); + gfxFontGroup::FontResolverProc, + &data, aborted); } if (NS_FAILED(rv) || aborted) return PR_FALSE; @@ -2650,6 +2664,7 @@ gfxFontGroup::UpdateFontList() // xxx - can probably improve this to detect when all fonts were found, so no need to update list mFonts.Clear(); mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET; + mSkipDrawing = PR_FALSE; // bug 548184 - need to clean up FT2, OS/2 platform code to use BuildFontList #if defined(XP_MACOSX) || defined(XP_WIN) @@ -3043,6 +3058,7 @@ gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void #endif mUserFontSetGeneration = mFontGroup->GetGeneration(); + mSkipDrawing = mFontGroup->ShouldSkipDrawing(); } gfxTextRun::~gfxTextRun() @@ -3472,6 +3488,21 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, NS_ASSERTION(aStart + aLength <= mCharacterCount, "Substring out of range"); gfxFloat direction = GetDirection(); + + if (mSkipDrawing) { + // We're waiting for a user font to finish downloading; + // but if the caller wants advance width, we need to compute it here + if (aAdvanceWidth) { + gfxTextRun::Metrics metrics = MeasureText(aStart, aLength, + gfxFont::LOOSE_INK_EXTENTS, + aContext, aProvider); + *aAdvanceWidth = metrics.mAdvanceWidth * direction; + } + + // return without drawing + return; + } + gfxPoint pt = aPt; // synthetic bolding draws glyphs twice ==> colors with opacity won't draw correctly unless first drawn without alpha @@ -4088,6 +4119,10 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, PRUint32 aStart, NS_ASSERTION(aDest + aLength <= GetLength(), "Destination substring out of range"); + if (aSource->mSkipDrawing) { + mSkipDrawing = PR_TRUE; + } + // Copy base glyph data, and DetailedGlyph data where present for (PRUint32 i = 0; i < aLength; ++i) { CompressedGlyph g = aSource->mCharacterGlyphs[i + aStart]; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index b8ed3c004b5b..4cf2265b8c5d 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -2195,6 +2195,10 @@ private: PRUint32 mCharacterCount; PRUint32 mHashCode; PRUint64 mUserFontSetGeneration; // user font set generation when text run created + + PRBool mSkipDrawing; // true if the font group we used had a user font + // download that's in progress, so we should hide text + // until the download completes (or timeout fires) }; class THEBES_API gfxFontGroup : public gfxTextRunFactory { @@ -2322,6 +2326,10 @@ public: // caches need updating. virtual void UpdateFontList(); + PRBool ShouldSkipDrawing() const { + return mSkipDrawing; + } + protected: nsString mFamilies; gfxFontStyle mStyle; @@ -2335,8 +2343,12 @@ protected: nsRefPtr mLastPrefFamily; nsRefPtr mLastPrefFont; eFontPrefLang mLastPrefLang; // lang group for last pref font - PRBool mLastPrefFirstFont; // is this the first font in the list of pref fonts for this lang group? eFontPrefLang mPageLang; + PRPackedBool mLastPrefFirstFont; // is this the first font in the list of pref fonts for this lang group? + + PRPackedBool mSkipDrawing; // hide text while waiting for a font + // download to complete (or fallback + // timer to fire) // Used for construction/destruction. Not intended to change the font set // as invalidation of font lists and caches is not considered. diff --git a/gfx/thebes/gfxPangoFonts.cpp b/gfx/thebes/gfxPangoFonts.cpp index d9117694054b..86fbd9a3870d 100644 --- a/gfx/thebes/gfxPangoFonts.cpp +++ b/gfx/thebes/gfxPangoFonts.cpp @@ -1095,9 +1095,12 @@ public: explicit gfxFcFontSet(FcPattern *aPattern, gfxUserFontSet *aUserFontSet) : mSortPattern(aPattern), mUserFontSet(aUserFontSet), - mFcFontSet(SortPreferredFonts()), mFcFontsTrimmed(0), + mFcFontsTrimmed(0), mHaveFallbackFonts(PR_FALSE) { + PRBool waitForUserFont; + mFcFontSet = SortPreferredFonts(waitForUserFont); + mWaitingForUserFont = waitForUserFont; } // A reference is held by the FontSet. @@ -1118,8 +1121,12 @@ public: FcPattern *GetFontPatternAt(PRUint32 i); + PRBool WaitingForUserFont() const { + return mWaitingForUserFont; + } + private: - nsReturnRef SortPreferredFonts(); + nsReturnRef SortPreferredFonts(PRBool& aWaitForUserFont); nsReturnRef SortFallbackFonts(); struct FontEntry { @@ -1167,13 +1174,17 @@ private: // True iff fallback fonts are either stored in mFcFontSet or have been // trimmed and added to mFonts (so that mFcFontSet is NULL). PRPackedBool mHaveFallbackFonts; + // True iff there was a user font set with pending downloads, + // so the set may be updated when downloads complete + PRPackedBool mWaitingForUserFont; }; // Find the FcPattern for an @font-face font suitable for CSS family |aFamily| // and style |aStyle| properties. static const nsTArray< nsCountedRef >* FindFontPatterns(gfxUserFontSet *mUserFontSet, - const nsACString &aFamily, PRUint8 aStyle, PRUint16 aWeight) + const nsACString &aFamily, PRUint8 aStyle, PRUint16 aWeight, + PRBool& aWaitForUserFont) { // Convert to UTF16 NS_ConvertUTF8toUTF16 utf16Family(aFamily); @@ -1188,13 +1199,15 @@ FindFontPatterns(gfxUserFontSet *mUserFontSet, style.weight = aWeight; gfxUserFcFontEntry *fontEntry = static_cast - (mUserFontSet->FindFontEntry(utf16Family, style, needsBold)); + (mUserFontSet->FindFontEntry(utf16Family, style, needsBold, + aWaitForUserFont)); // Accept synthetic oblique for italic and oblique. if (!fontEntry && aStyle != FONT_STYLE_NORMAL) { style.style = FONT_STYLE_NORMAL; fontEntry = static_cast - (mUserFontSet->FindFontEntry(utf16Family, style, needsBold)); + (mUserFontSet->FindFontEntry(utf16Family, style, needsBold, + aWaitForUserFont)); } if (!fontEntry) @@ -1270,8 +1283,10 @@ SizeIsAcceptable(FcPattern *aFont, double aRequestedSize) // Sorting only the preferred fonts first usually saves having to sort through // every font on the system. nsReturnRef -gfxFcFontSet::SortPreferredFonts() +gfxFcFontSet::SortPreferredFonts(PRBool &aWaitForUserFont) { + aWaitForUserFont = PR_FALSE; + gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); if (!utils) return nsReturnRef(); @@ -1350,8 +1365,13 @@ gfxFcFontSet::SortPreferredFonts() PRUint16 thebesWeight = gfxFontconfigUtils::GetThebesWeight(mSortPattern); + PRBool waitForUserFont; familyFonts = FindFontPatterns(mUserFontSet, cssFamily, - thebesStyle, thebesWeight); + thebesStyle, thebesWeight, + waitForUserFont); + if (waitForUserFont) { + aWaitForUserFont = PR_TRUE; + } } } @@ -1860,6 +1880,7 @@ gfxPangoFontGroup::UpdateFontList() mFontSets.Clear(); mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET; mCurrGeneration = newGeneration; + mSkipDrawing = PR_FALSE; } already_AddRefed @@ -1889,6 +1910,8 @@ gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, nsRefPtr fontset = new gfxFcFontSet(pattern, mUserFontSet); + mSkipDrawing = fontset->WaitingForUserFont(); + if (aMatchPattern) aMatchPattern->steal(pattern); diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index 42b526e4938a..a80ef57717b8 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -73,7 +73,8 @@ gfxProxyFontEntry::gfxProxyFontEntry(const nsTArray& aFontFaceSr const nsTArray& aFeatureSettings, PRUint32 aLanguageOverride, gfxSparseBitSet *aUnicodeRanges) - : gfxFontEntry(NS_LITERAL_STRING("Proxy"), aFamily), mIsLoading(PR_FALSE) + : gfxFontEntry(NS_LITERAL_STRING("Proxy"), aFamily), + mLoadingState(NOT_LOADING) { mIsProxy = PR_TRUE; mSrcList = aFontFaceSrcList; @@ -162,25 +163,32 @@ gfxUserFontSet::AddFontFace(const nsAString& aFamilyName, gfxFontEntry* gfxUserFontSet::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle, - PRBool& aNeedsBold) + PRBool& aNeedsBold, + PRBool& aWaitForUserFont) { + aWaitForUserFont = PR_FALSE; gfxMixedFontFamily *family = GetFamily(aName); // no user font defined for this name - if (!family) + if (!family) { return nsnull; + } gfxFontEntry* fe = family->FindFontForStyle(aFontStyle, aNeedsBold); // if not a proxy, font has already been loaded - if (!fe->mIsProxy) + if (!fe->mIsProxy) { return fe; + } gfxProxyFontEntry *proxyEntry = static_cast (fe); // if currently loading, return null for now - if (proxyEntry->mIsLoading) + if (proxyEntry->mLoadingState > gfxProxyFontEntry::NOT_LOADING) { + aWaitForUserFont = + (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY); return nsnull; + } // hasn't been loaded yet, start the load process LoadStatus status; @@ -189,10 +197,13 @@ gfxUserFontSet::FindFontEntry(const nsAString& aName, // if the load succeeded immediately, the font entry was replaced so // search again - if (status == STATUS_LOADED) + if (status == STATUS_LOADED) { return family->FindFontForStyle(aFontStyle, aNeedsBold); + } // if either loading or an error occurred, return null + aWaitForUserFont = + (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY); return nsnull; } @@ -568,14 +579,12 @@ gfxUserFontSet::OnLoadComplete(gfxFontEntry *aFontToLoad, LoadStatus status; status = LoadNext(pe); - if (status == STATUS_LOADED) { - // load may succeed if external font resource followed by - // local font, in this case need to bump generation - IncrementGeneration(); - return PR_TRUE; - } - return PR_FALSE; + // Even if loading failed, we need to bump the font-set generation + // and return true in order to trigger reflow, so that fallback + // will be used where the text was "masked" by the pending download + IncrementGeneration(); + return PR_TRUE; } @@ -586,10 +595,13 @@ gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry) NS_ASSERTION(aProxyEntry->mSrcIndex < numSrc, "already at the end of the src list for user font"); - if (aProxyEntry->mIsLoading) { - aProxyEntry->mSrcIndex++; + if (aProxyEntry->mLoadingState == gfxProxyFontEntry::NOT_LOADING) { + aProxyEntry->mLoadingState = gfxProxyFontEntry::LOADING_STARTED; } else { - aProxyEntry->mIsLoading = PR_TRUE; + // we were already loading; move to the next source, + // but don't reset state - if we've already timed out, + // that counts against the new download + aProxyEntry->mSrcIndex++; } // load each src entry in turn, until a local face is found or a download begins successfully diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 2006ad391fbb..625a2eee86aa 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -190,7 +190,8 @@ public: // lookup a font entry for a given style, returns null if not loaded gfxFontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle, - PRBool& aNeedsBold); + PRBool& aNeedsBold, + PRBool& aWaitForUserFont); // initialize the process that loads external font data, which upon // completion will call OnLoadComplete method @@ -211,14 +212,14 @@ public: // incremented so that the change can be recognized PRUint64 GetGeneration() { return mGeneration; } + // increment the generation on font load + void IncrementGeneration(); + protected: // for a given proxy font entry, attempt to load the next resource // in the src list LoadStatus LoadNext(gfxProxyFontEntry *aProxyEntry); - // increment the generation on font load - void IncrementGeneration(); - gfxMixedFontFamily *GetFamily(const nsAString& aName) const; // remove family @@ -249,9 +250,19 @@ public: virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold); - PRPackedBool mIsLoading; - nsTArray mSrcList; - PRUint32 mSrcIndex; // index of loading src item + // note that code depends on the ordering of these values! + enum LoadingState { + NOT_LOADING = 0, // not started to load any font resources yet + LOADING_STARTED, // loading has started; hide fallback font + LOADING_ALMOST_DONE, // timeout happened but we're nearly done, + // so keep hiding fallback font + LOADING_SLOWLY // timeout happened and we're not nearly done, + // so use the fallback font + }; + LoadingState mLoadingState; + + nsTArray mSrcList; + PRUint32 mSrcIndex; // index of loading src item }; diff --git a/layout/generic/nsHTMLContainerFrame.cpp b/layout/generic/nsHTMLContainerFrame.cpp index d448f7884e49..dc73723bd198 100644 --- a/layout/generic/nsHTMLContainerFrame.cpp +++ b/layout/generic/nsHTMLContainerFrame.cpp @@ -337,7 +337,15 @@ nsHTMLContainerFrame::DisplayTextDecorations(nsDisplayListBuilder* aBuilder, return NS_OK; if (!IsVisibleForPainting(aBuilder)) return NS_OK; - + + // Hide text decorations if we're currently hiding @font-face fallback text + nsCOMPtr fm; + nsresult rv = nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); + NS_ENSURE_SUCCESS(rv, rv); + nsIThebesFontMetrics* tfm = static_cast(fm.get()); + if (tfm->GetThebesFontGroup()->ShouldSkipDrawing()) + return NS_OK; + // Do standards mode painting of 'text-decoration's: under+overline // behind children, line-through in front. For Quirks mode, see // nsTextFrame::PaintTextDecorations. (See bug 1777.) @@ -353,25 +361,25 @@ nsHTMLContainerFrame::DisplayTextDecorations(nsDisplayListBuilder* aBuilder, // shadow applied to them. So draw the shadows as part of the display // list, underneath the text and all decorations. if (GetStyleText()->mTextShadow) { - nsresult rv = aBelowTextDecorations->AppendNewToTop(new (aBuilder) + rv = aBelowTextDecorations->AppendNewToTop(new (aBuilder) nsDisplayTextShadow(aBuilder, this, decorations, aLine)); NS_ENSURE_SUCCESS(rv, rv); } if (decorations & NS_STYLE_TEXT_DECORATION_UNDERLINE) { - nsresult rv = aBelowTextDecorations->AppendNewToTop(new (aBuilder) + rv = aBelowTextDecorations->AppendNewToTop(new (aBuilder) nsDisplayTextDecoration(aBuilder, this, NS_STYLE_TEXT_DECORATION_UNDERLINE, underColor, aLine)); NS_ENSURE_SUCCESS(rv, rv); } if (decorations & NS_STYLE_TEXT_DECORATION_OVERLINE) { - nsresult rv = aBelowTextDecorations->AppendNewToTop(new (aBuilder) + rv = aBelowTextDecorations->AppendNewToTop(new (aBuilder) nsDisplayTextDecoration(aBuilder, this, NS_STYLE_TEXT_DECORATION_OVERLINE, overColor, aLine)); NS_ENSURE_SUCCESS(rv, rv); } if (decorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH) { - nsresult rv = aAboveTextDecorations->AppendNewToTop(new (aBuilder) + rv = aAboveTextDecorations->AppendNewToTop(new (aBuilder) nsDisplayTextDecoration(aBuilder, this, NS_STYLE_TEXT_DECORATION_LINE_THROUGH, strikeColor, aLine)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 8aeaccc4b0f6..8e47950efc8b 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -4310,6 +4310,10 @@ nsTextFrame::PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect, if (!decorations.HasDecorationlines()) return; + // Hide text decorations if we're currently hiding @font-face fallback text + if (aProvider.GetFontGroup()->ShouldSkipDrawing()) + return; + gfxFont* firstFont = aProvider.GetFontGroup()->GetFontAt(0); if (!firstFont) return; // OOM @@ -4860,6 +4864,10 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx, PropertyProvider& aProvider, nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails, SelectionType aSelectionType) { + // Hide text decorations if we're currently hiding @font-face fallback text + if (aProvider.GetFontGroup()->ShouldSkipDrawing()) + return; + PRInt32 contentOffset = aProvider.GetStart().GetOriginalOffset(); PRInt32 contentLength = aProvider.GetOriginalLength(); diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp index 7db7e3bd0249..c2c8305aeafd 100644 --- a/layout/style/nsFontFaceLoader.cpp +++ b/layout/style/nsFontFaceLoader.cpp @@ -54,6 +54,7 @@ #include "nsIChannelEventSink.h" #include "nsIInterfaceRequestor.h" #include "nsContentUtils.h" +#include "nsIPrefService.h" #include "nsPresContext.h" #include "nsIPresShell.h" @@ -89,11 +90,94 @@ nsFontFaceLoader::nsFontFaceLoader(gfxFontEntry *aFontToLoad, nsIURI *aFontURI, nsFontFaceLoader::~nsFontFaceLoader() { + if (mLoadTimer) { + mLoadTimer->Cancel(); + mLoadTimer = nsnull; + } if (mFontSet) { mFontSet->RemoveLoader(this); } } +void +nsFontFaceLoader::StartedLoading(nsIStreamLoader *aStreamLoader) +{ + PRInt32 loadTimeout = 3000; + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + prefs->GetIntPref("gfx.downloadable_fonts.fallback_delay", &loadTimeout); + } + if (loadTimeout > 0) { + mLoadTimer = do_CreateInstance("@mozilla.org/timer;1"); + if (mLoadTimer) { + mLoadTimer->InitWithFuncCallback(LoadTimerCallback, + static_cast(this), + loadTimeout, + nsITimer::TYPE_ONE_SHOT); + } + } else { + gfxProxyFontEntry *pe = + static_cast(mFontEntry.get()); + pe->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY; + } + mStreamLoader = aStreamLoader; +} + +void +nsFontFaceLoader::LoadTimerCallback(nsITimer *aTimer, void *aClosure) +{ + nsFontFaceLoader *loader = static_cast(aClosure); + + if (!loader->mFontEntry->mIsProxy) { + return; + } + + gfxProxyFontEntry *pe = + static_cast(loader->mFontEntry.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 (pe->mLoadingState == gfxProxyFontEntry::LOADING_STARTED) { + PRInt32 contentLength; + loader->mChannel->GetContentLength(&contentLength); + PRUint32 numBytesRead; + loader->mStreamLoader->GetNumBytesRead(&numBytesRead); + + if (contentLength > 0 && + numBytesRead > 3 * (PRUint32(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. + pe->mLoadingState = gfxProxyFontEntry::LOADING_ALMOST_DONE; + PRUint32 delay; + loader->mLoadTimer->GetDelay(&delay); + loader->mLoadTimer->InitWithFuncCallback(LoadTimerCallback, + static_cast(loader), + delay >> 1, + nsITimer::TYPE_ONE_SHOT); + updateUserFontSet = false; + LOG(("fontdownloader (%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) { + pe->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY; + nsPresContext *ctx = loader->mFontSet->GetPresContext(); + NS_ASSERTION(ctx, "fontSet doesn't have a presContext?"); + gfxUserFontSet *fontSet; + if (ctx && (fontSet = ctx->GetUserFontSet()) != nsnull) { + fontSet->IncrementGeneration(); + ctx->UserFontSetUpdated(); + LOG(("fontdownloader (%p) timeout reflow\n", loader)); + } + } +} + NS_IMPL_ISUPPORTS1(nsFontFaceLoader, nsIStreamLoaderObserver) NS_IMETHODIMP @@ -156,6 +240,10 @@ void nsFontFaceLoader::Cancel() { mFontSet = nsnull; + if (mLoadTimer) { + mLoadTimer->Cancel(); + mLoadTimer = nsnull; + } mChannel->Cancel(NS_BINDING_ABORTED); } @@ -343,6 +431,7 @@ nsUserFontSet::StartLoad(gfxFontEntry *aFontToLoad, if (NS_SUCCEEDED(rv)) { mLoaders.PutEntry(fontLoader); + fontLoader->StartedLoading(streamLoader); } return rv; diff --git a/layout/style/nsFontFaceLoader.h b/layout/style/nsFontFaceLoader.h index d28e85e81f7e..42236a754d0e 100644 --- a/layout/style/nsFontFaceLoader.h +++ b/layout/style/nsFontFaceLoader.h @@ -46,6 +46,7 @@ #include "nsIStreamLoader.h" #include "nsIURI.h" #include "nsIChannel.h" +#include "nsITimer.h" #include "gfxUserFontSet.h" #include "nsHashKeys.h" #include "nsTHashtable.h" @@ -105,6 +106,10 @@ public: void DropChannel() { mChannel = nsnull; } + void StartedLoading(nsIStreamLoader *aStreamLoader); + + static void LoadTimerCallback(nsITimer *aTimer, void *aClosure); + static nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal, nsIURI* aTargetURI, nsISupports* aContext); @@ -114,6 +119,9 @@ private: nsCOMPtr mFontURI; nsRefPtr mFontSet; nsCOMPtr mChannel; + nsCOMPtr mLoadTimer; + + nsIStreamLoader *mStreamLoader; }; #endif /* !defined(nsFontFaceLoader_h_) */ diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 1b2ae391e4c9..7d0f00ba5822 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -192,6 +192,7 @@ pref("gfx.color_management.display_profile", ""); pref("gfx.color_management.rendering_intent", 0); pref("gfx.downloadable_fonts.enabled", true); +pref("gfx.downloadable_fonts.fallback_delay", 3000); pref("gfx.downloadable_fonts.sanitize", true); #ifdef XP_MACOSX pref("gfx.downloadable_fonts.sanitize.preserve_otl_tables", false);