Closed Bug 499292 Opened 15 years ago Closed 13 years ago

[@font-face] hide fallback text for a short time while a font downloads

Categories

(Core :: CSS Parsing and Computation, defect, P2)

defect

Tracking

()

RESOLVED FIXED
Tracking Status
blocking2.0 --- -

People

(Reporter: IDontUseMozillaAnyMore, Assigned: jfkthame)

References

(Depends on 1 open bug, )

Details

Attachments

(1 file, 5 obsolete files)

User-Agent:       Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b99) Gecko/20090605 Firefox/3.5b99
Build Identifier: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b99) Gecko/20090605 Firefox/3.5b99

If you design a webpage that uses the CSS @font-face to download an embedded font for a web page then the text items on that page that use the downloaded font are first rendered with a standard font and then re-rendered using the correct font. 

- First this is extremely ugly
- Second @font-face was added for partity with Safari and it does not do this.
- It would also seem to be a waste of CPU resources to render the text twice.

The issue seems to be that the 'bad' font is displayed while the page is still downloading.

Reproducible: Always

Steps to Reproduce:
1. Load the page specified above.

Actual Results:  
The header item is rendered in the incorrect font while the page is downloading and then re-rendered when the page completes.

Expected Results:  
The font should be downloaded and used the first time.

This may only be apparent when the page takes a little time to download.
Agree. I was really looking forward to seeing this feature implemented in FF but was a bit disappointed to find out this bug. This prevents me from using this feature in web pages for now. The sudden change of fonts might be acceptable for some headlines but not for long text. As I understand the intended reason for this "feature" was to allow people start reading earlier. I'd like to note that even this is not really possible or rather quite confusing for the user because the text loaded subsequently often has a different run-length and all line breaks jump after the font has loaded which IMO is more annoying than keeping the user from starting to read before the font has loaded altogether.

Another reason to the ones already stated why this should at least perhaps be somehow configurable via CSS (sth. like font-family-prerender:disable):

When you use a graphical font like musical notation or foreign language fonts where no similiar font is already installed on the system etc for some seconds it appears as garbage on your screen.

Anyway, the first step toward a wider use of web fonts is done and the concept is already now far superior to the clumsy .eot stuff from MS. Thanks to anyone involved.
This is not a bug, this is as intended behavior.  Text using downloaded fonts is rendered using the fallback font until the font load completes, hence the pop of seeing the fallback font followed by the downloaded font.  Definitely sucks, I agree, but seeing a blank page also sucks, especially when the font takes a long time to load.

One possible solution would be to display the equivalent of visibility: hidden and add a timer to display the fallback font after a given delay (e.g. 10secs).  For slow-loading pages, users might end up seeing a double pop but for fast loading pages this would avoid some of the popping behavior.

For authors, one workaround is to set the default visibility to hidden, then set it to visible after the page loads or when a resize event happens on the element.

Keeping this open as a placeholder for similar issues, I realize lots of folks hate the popping.
Component: Layout: View Rendering → Style System (CSS)
OS: Mac OS X → All
QA Contact: layout.view-rendering → style-system
Hardware: x86 → All
Summary: Text rendered using a font downloaded via @font-face first render in an incorrect font. → [@font-face] text using a downloaded font renders briefly using fallback font
Version: unspecified → Trunk
So there are several issues here:

1)  Painting.  Safari doesn't pain the text at all while the font is loading,
    iirc.  This leads to various issues if the font is slow to load; I think we
    could do this if we had a timeout (but shorter than 10s, I would think).
2)  Layout.  This has to be done even before the font is loaded.  Safari makes
    up some font metrics (those of the fallback font?) to do this with.  This
    cannot be avoided, because scripts commonly ask for layout information.  So
    once the font loads content on the page will move around no matter what we
    do with painting.

Note that here was a thread on www-style about these issues; I suggest everyone read it.  There's just no good solution other than "make sure your font files are small and load fast".
I think we should keep using the metrics of the fallback font as we do now, and simply not paint the fallback text for the first N few seconds of the font load. That should be pretty easy to do, since it can be done entirely in the font code, I think.

Also what would be really cool is after N/2 seconds, check how much of the font has been loaded. If we're less than halfway through, start painting the fallback text immediately. That would avoid most cases of displaying the fallback text and then immediately switching to the downloaded font.
This is really annoying effect. I suggest calling it "flash of unfonted content".
Lots of kvetching about this:
http://www.stevesouders.com/blog/2009/10/13/font-face-and-performance/

I'm going to look at a patch for implementing the suggestion in comment 4.
Assignee: nobody → jdaggett
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
If the font download was cached this would be so much better but it isn't, it's downloaded every time, and for every frame if you use frames.
(In reply to comment #7)
> If the font download was cached this would be so much better but it isn't, it's
> downloaded every time, and for every frame if you use frames.

Do you have an example page for which you see this behavior?  Not seeing this behavior at all (i.e. if the same font is used across pages, the second page uses a cached version of the font).
(In reply to comment #8)
> (In reply to comment #7)
> > If the font download was cached this would be so much better but it isn't, it's
> > downloaded every time, and for every frame if you use frames.
> 
> Do you have an example page for which you see this behavior?  Not seeing this
> behavior at all (i.e. if the same font is used across pages, the second page
> uses a cached version of the font).

I was about to comment the same thing - I see caching here.

Example: go to http://people.mozilla.com/~jkew/woff/udhr-sample/index.html. Choose the 3rd option for display; it's a *large* font download, so you see a delay. Close the browser window, then open a new one, return to that page, and choose the same option again. This time it appears without delay, because the font file is in the cache.

This would presumably depend on server configuration; e.g., if you have a server that's set up to send no-cache headers with everything.
My connection here is too fast to notice the issue at the moment I'll check again on a slower connection tonight. However, this was certainly the case with the first version to support @font-face downloads (3.5) when was this changed? Also with each page it seems a new copy of the font is downloaded, even though it's the same file using the same CSS code (in a .css file) to download the font.

You can see the issue on this site http://www.dit.org wait for the site to load and then hit any of the orange buttons on the top strip. When you click the buttons a page will load into a frame on the left hand side of the screen. Each of those pages uses the same CSS to download the same font. As each is loaded it shows the issue. If I watch carefully I can even see it happen on my machine with a fast connection. Given this is the very same font that is used for the top strip and the titles on each page in the main area then I would never expect to see the font download at all, other than when loading the initial page. Except that I do, all the time. Is there a bug number that is supposed to have fixed the cache issue? I can't seem to find one.
(In reply to comment #10)
> You can see the issue on this site http://www.dit.org wait for the site to load
> and then hit any of the orange buttons on the top strip.

I don't see a "top strip" with any "orange buttons" at this site.
Apologies it should read http://www.ditl.org
Please file a new bug for any caching issues.
I notice that the frame in question is being served with explicit no-cache http headers. Is that a significant factor here?
New bug added for this cache issue Bug 522223.
We really need to fix this so that fallback text is hidden until a timer fires.
Summary: [@font-face] text using a downloaded font renders briefly using fallback font → [@font-face] hide fallback text for a short time while a font downloads
Severity: normal → major
Priority: -- → P2
blocking2.0: ? → betaN+
I agree that this should be handled in a nicer way - especially if the font file has already been cached.  In particular, this behaviour definitely seems like a bug to me.  If the font has been cached, there should be no need to use a default font temporarily on subsequent pages.

Regardless of caching, providing an option to override the default behaviour would probably keep everyone happy.

I have spent a lot of time working on using @font-face, and I can get it working very nicely now in all recent versions of IE, Chrome, and Safari without any hacks, but Firefox still flashes the default font and looks terrible unless I introduce a hack to temporarily hide those styles - which I have done for now.
Associated bug filed for Webkit at https://bugs.webkit.org/show_bug.cgi?id=44404

Couldn't find the www-style thread so I'm unsure of suggested timeout or download metrics to suggest.
> If the font has been cached, there should be no need to use
> a default font temporarily on subsequent pages

"cached" just means that it can be asynchronously read in less time.  It doesn't mean it can be read instantaneously, and depending on disk load the time to read it could be substantial.
Some simple experiments with font load timing.

Created a set of fonts with various sizes by adding a bunch of filler
data into each font.

  http://people.mozilla.org/~jdaggett/tests/loadtest/loadtest.html#3

The appended value specifies the delay to hold off showing the
fallback font in number of seconds (3 seconds in this case).  (Note:
cache-control headers are used to disable pulling fonts from cache).

Webkit browsers appear to apply the "no draw" attribute to *any* text
within an element, regardless of whether it's the first font in the
list or not, even if unicode-range is defined:

  http://people.mozilla.org/~jdaggett/tests/loadtest/fallback.html

Clearly, there's no attempt to do fallback handling until after the font is loaded.  Safari also "craps out" sometimes, leaving no text showing.

To simulate load times on systems with slower access times used ipfw
under OSX:

  sudo ipfw add pipe 1 in
  sudo ipfw add pipe 2 out
  sudo ipfw pipe 1 config delay 100ms bw 5Mbit/s
  sudo ipfw pipe 2 config delay 100ms bw 5Mbit/s

This adds a 100ms delay to all incoming/outgoing traffic and caps the bandwidth used at 5Mbps.

Remove these after testing:

  sudo ipfw list
  sudo ipfw delete 00100
  sudo ipfw delete 00200
Re-assigning..... I'm making a start on this.
Assignee: jdaggett → jfkthame
Posting a first-draft patch; this currently breaks things on Linux, but works nicely on Mac & presumably Windows.
This takes a simplified approach, keeping track of the presence of a "pending user font" at the gfxFontGroup level, and on the gfxTextRuns that are created. If a textRun has a pending user font, it won't actually paint its glyphs.

(Originally, I was keeping track of the pending user font status at the level of GlyphRuns within the textRun, as it's possible some of the characters in the text were matched to an available font earlier in the font list than the pending user font. However, at this point I think that's overkill, as in practice a user font will usually be at the beginning of the list. Once we have real unicode-range support in @font-face, we may want to reconsider this, so that pending downloads don't "shadow" other available fonts for characters that are outside their range.)

If a font download is taking too long, it is marked as "loading slowly", and in this state it is no longer treated as a pending user font by the fontGroup, so fallback text is shown; if/when the download finally completes, we'll reflow again with the proper font.

The timeout is configurable in about:config as gfx.downloadable_fonts.fallback_delay, with a default of 2000ms. Note that we don't necessarily show the fallback font immediately when the timeout expires; if we can determine at that point that the download is nearly complete, we allow an additional delay of half the original period (but if the download then stalls, so that the second timeout expires, then we do show the fallback font).
Attachment #497790 - Attachment is obsolete: true
Attachment #507074 - Flags: review?(jdaggett)
Comment on attachment 507074 [details] [diff] [review]
patch, hide fallback text for a short time

I haven't looked at the details too closely yet but I'm seeing funny behavior.  In the example page below, the row titles draw in the default font, *then* change to white, then draw in the downloadable font:

http://people.mozilla.org/~jdaggett/webfonts/salestable.html
Also, this patch shows the same "underlines draw on blank text fields" behavior that Webkit shows.  We definitely need to deal with that properly.

http://people.mozilla.org/~jdaggett/webfonts/gentium-test.html
(In reply to comment #27)
> Also, this patch shows the same "underlines draw on blank text fields" behavior
> that Webkit shows.  We definitely need to deal with that properly.
> 
> http://people.mozilla.org/~jdaggett/webfonts/gentium-test.html

Yes, I'd wondered a bit about that, as I think the webkit behavior looks pretty weird. I'll post a followup that suppresses them.
(In reply to comment #26)
> I haven't looked at the details too closely yet but I'm seeing funny behavior. 
> In the example page below, the row titles draw in the default font, *then*
> change to white, then draw in the downloadable font:
> 
> http://people.mozilla.org/~jdaggett/webfonts/salestable.html

Hmmm. I'll do some tracing, but what I _think_ this indicates is that we're doing an initial reflow and paint _before_ we've actually seen and processed the @font-face declarations. That might be a result of the way TypeKit serves stuff - I believe they don't actually put @font-face rules directly in the page's CSS, but inject them afterwards via JS or something like that. If we reflow before that's happened, then we don't yet know that there will be user fonts that should hide the default font at first.
(In reply to comment #29)
> Hmmm. I'll do some tracing, but what I _think_ this indicates is that we're
> doing an initial reflow and paint _before_ we've actually seen and processed
> the @font-face declarations.

Yes, this is indeed the case. By instrumenting textrun creation and drawing, I confirmed that we're rendering the page *before* any entries get inserted in the gfxUserFontSet. And therefore it's expected that we initially show the text using default fonts.

I'm not sure whether this indicates a bug in how we're loading and processing the page and its associated scripts - i.e. that we're doing reflow and painting too soon, and shouldn't be allowing it to happen yet - or if it's a flaw in the way the page and its resources are structured, and should be fixed at the web-author and/or TypeKit level. Maybe someone like Boris could comment further.
This suppresses the drawing of underlines and other text decorations while we're hiding the fallback font, which avoids the webkit-like weirdness.

I think the TypeKit problem where @font-face rules are not injected until after we've already rendered the page without them should be treated as a separate issue (whether in Gecko or in TypeKit). I've filed bug 629366 on that.
Attachment #507452 - Flags: review?(jdaggett)
Comment on attachment 507452 [details] [diff] [review]
patch 2, don't paint text decorations while we're hiding fallback text

For some reason, auto-spelling generated underlines show up.

1. Enable auto spellcheck

  Prefs > Advanced > General
  Enable "Check my spelling as I type"

2. Enter the URL:

  http://people.mozilla.org/~jdaggett/webfonts/tiramisu.html

Result: several words on the page are automagically underlined while the font is downloading

My guess is this is appearing because the page has content-editable enabled.
Comment on attachment 507074 [details] [diff] [review]
patch, hide fallback text for a short time

+    PRBool            mPendingUserFont; // 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

I think I would prefer these be labeled something like
'skipDraw', since that's really what the logic in various places
implies.

For example, within gfxUserFontSet::FindFontEntry: 

> aPendingUserFont =
>             (proxyEntry->mLoadingState < gfxProxyFontEntry::LOADING_SLOWLY);

I think 'skipDraw' would better capture what you're trying to
define.  It kind of sucks to effectively control this in two
places, in nsFontFaceLoader::LoadTimerCallback and in
gfxUserFontSet::FindFontEntry but I guess I don't see a cleaner
way.

+  PRInt32 loadTimeout = 1500;
+  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+  if (prefs) {
+    prefs->GetIntPref("gfx.downloadable_fonts.fallback_delay", &loadTimeout);
+  }

+pref("gfx.downloadable_fonts.fallback_delay", 2000);

Both in the code and in the prefs, I think the default for this
should be 3000.  I tested both and it feels like lots of pages
still flash at 2000 while 3000 isn't too long of a delay before
seeing something, either a downloaded font or the fallback.

+  if (updateUserFontSet) {
+    pe->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY;
+    nsPresContext *ctx = loader->mFontSet->GetPresContext();
+    gfxUserFontSet *fontSet;
+    if ((fontSet = ctx->GetUserFontSet()) != nsnull) {
+      fontSet->IncrementGeneration();
+      ctx->UserFontSetUpdated();
+      LOG(("fontdownloader (%p) timeout reflow\n", loader));
+    }
+  }

Could you add some assertions and null checks here?  I'm a little
nervous about what exactly happens when a window is closed
suddenly and timeouts are still pending. I doubt this code will
be hit but better to be extra careful here.

Nit:

+        PRBool PendingUserFont;

Capitalization wrong.
Attachment #507074 - Flags: review?(jdaggett) → review+
(carrying forward r=jdaggett)

Updated for review comments; gfxFontGroup and gfxTextRun now have an mSkipDrawing flag, which better indicates how they will behave, and avoids the somewhat misleading "pending user font" terminology.

The out-param from gfxUserFontSet::FindFontEntry etc is now called aWaitForUserFont, as it is used to inform the caller that it should wait for an incoming download - i.e. one that hasn't completed, but also hasn't hit the fallback-timeout yet. So the downloader decides whether to set aWaitForUserFont depending on the progress of the download and the setting of the fallback_delay pref; then the fontGroup sets its skipDrawing flag accordingly.

(Hope you're OK with this naming, John; let me know if you still have concerns, otherwise I'll assume this is clear enough.)
Attachment #507074 - Attachment is obsolete: true
Attachment #508716 - Flags: review+
This now hides the spell-check underline as well. (Just had to deal with PaintTextSelectionDecorations in the same way as PaintTextDecorations.)
Attachment #507452 - Attachment is obsolete: true
Attachment #508717 - Flags: review?(jdaggett)
Attachment #507452 - Flags: review?(jdaggett)
Attachment #508717 - Flags: review?(jdaggett) → review+
(In reply to comment #34)
> (Hope you're OK with this naming, John; let me know if you still have concerns,
> otherwise I'll assume this is clear enough.)

Yup, that seems fine.
Comment on attachment 508716 [details] [diff] [review]
part 1 - hide fallback text for a short time while waiting for @font-face download

Requesting approval-2.0 here. We unblocked on this a little while ago, but given that we have working patches, and that it's a widely-requested feature that substantially improves the user experience, I think we should take this. We have test coverage in the form of our existing @font-face reftests - not for the actual delayed-fallback aspect (tricky to automate testing of that), but at least to verify that we're not breaking things.
Attachment #508716 - Flags: approval2.0?
Attachment #508717 - Flags: approval2.0?
(In reply to comment #37)
> Comment on attachment 508716 [details] [diff] [review]
> part 1 - hide fallback text for a short time while waiting for @font-face
> download
> 
> Requesting approval-2.0 here. We unblocked on this a little while ago, but
> given that we have working patches, and that it's a widely-requested feature
> that substantially improves the user experience, I think we should take this.
> We have test coverage in the form of our existing @font-face reftests - not for
> the actual delayed-fallback aspect (tricky to automate testing of that), but at
> least to verify that we're not breaking things.

I think it would be absolutely fantastic if we could ship this in Firefox 4.  While I understand the concern about risk late in the dev cycle, the patch is specific to an area of the code that has been through several release cycles so I think the chance of problems occurring is limited.  We get constantly dinged in various places for not fixing this.  Fixing this will fit nicely with (1) enabling CT for downloadable fonts on XP (2) using DirectWrite on Win7/Vista and (3) enabling OpenType features.  Without this fixed I think the comments will always be "yeah, nice rendering but it still has that annoying flash".  The reward-to-risk ratio with this one is very high, I think we should make every effort to ship it.
(In reply to comment #37)
> Requesting approval-2.0 here.

This is good for the Web: by addressing this issue in the FF4 release, we can encourage the deployment of webfonts via simple, "clean" HTML+CSS, without use of complex JS hacks just to work around the "flash of unstyled content" - e.g. the "trick" of initially hiding elements, repeatedly measuring a run of text and waiting for its metrics to change, in order to detect that a font has become available, and then showing the hidden elements that want to use the font.

If we land this soon - right after the b11 build? - then major font services like TypeKit can be encouraged to test & update their code to interact better with the browser, ahead of the release of FF4.0 final.
As I've said before, I'm not sure this is helpful for our users. I think it would be better to get *serious* beta feedback from *users*, to make sure this is what they want, rather than try to jam this in at the last moment. Also, it shouldn't be long until we release Fx.next, so I don't think the gain in taking it now is as enormous as some suggest.
As a user I can seriously say that I want this now, it should have been there in the past to wait any longer when you have a solution at hand is just plain annoying.
Same here. As a user I would find this very useful, and it's one of only two issues I voted for.
(In reply to comment #40)
> As I've said before, I'm not sure this is helpful for our users.

We didn't just think this up because it seemed like a good idea.... there has been a lot of discussion of this over the past couple of years (Google for "fighting the @font-face FOUT", for example). It's clear that plenty of people don't like our current behavior, and web authors are going to considerable lengths to try and hack around it.

For anyone who really *doesn't* like the change (yes, there will surely be a few), the patch includes a pref that can be used to disable it (just set gfx.downloadable_fonts.fallback_delay to zero, then our current behavior remains unchanged).

> would be better to get *serious* beta feedback from *users*, 

The way to do this is to land the code now and ship it in b12. If the response turns out to be negative (contrary to current expectations and feedback), we can still flip it off via the preference.
(In reply to comment #43)
> > would be better to get *serious* beta feedback from *users*, 
> 
> The way to do this is to land the code now and ship it in b12. If the response
> turns out to be negative (contrary to current expectations and feedback), we
> can still flip it off via the preference.

I'm sympathetic, but there's a cost to shipping it in b12 and collecting feedback, which is that there's a lot of other arguably more important feedback we need to collect*, and only so much time and attention to collect it with.

* e.g. "are all our blocking issues fixed"
I think John or Jonathan should bring this up to release-drivers, so we get buy-in from the relevant parties for whatever decision gets made.

(I personally would love to see this make 4.0, but I don't think I'd approve it this late in the cycle.)
Merged parts 1+2 and updated for current trunk + bug 631035 pt 1 (which is blocking2.0 and should land shortly).

Still requesting approval to land (for 2.0beta12). This is a low-risk, high-reward fix that will benefit virtually every user, by improving the user experience (and perhaps "perceived speed/snappiness") on pages that use downloadable fonts.... including high-profile introductory pages on Mozilla's own site where we're using @font-face for headings.
Attachment #508716 - Attachment is obsolete: true
Attachment #508717 - Attachment is obsolete: true
Attachment #511206 - Flags: approval2.0?
Attachment #508716 - Flags: approval2.0?
Attachment #508717 - Flags: approval2.0?
I agree with Jonathan, that many users want this fix! We have quite a few users of web fonts who are indeed frustrated by FOUT and resorting to hacks to solve this. So I believe it will be a welcomed fix by an overwhelming number of users.
Remember, the question is not "are we going to get this fix?" We are. The question is whether we get it now or three months from now.
Comment on attachment 511206 [details] [diff] [review]
patch, folded parts 1+2, and updated to current trunk + bug 631035 (carrying forward r=jdaggett)

a=beltzner

Thanks for the evaluation in the newsgroups, everyone.
Attachment #511206 - Flags: approval2.0? → approval2.0+
Pushed to trunk:
http://hg.mozilla.org/mozilla-central/rev/7698f12bbe7d
Status: ASSIGNED → RESOLVED
Closed: 13 years ago
Resolution: --- → FIXED
Depends on: 633174
Further user input: The only reason I signed up with bugzilla was to follow this issue. I've been waiting since the June 30, 2009 release (v3.5) to see this issue resolved in FireFox. 

I am eagerly awaiting Jonathan & John's solution at http://www.mozilla.com/en-US/firefox/beta/ ... (am I correct in thinking that b8 is available for download now and this fix will show up in b12?)

Three cheers when this is made public!
Hmmm ... clicking download shows b11, but Google search info shows b8 ... surprised that the b# isn't posted somewhere on the page: 

http://www.mozilla.com/en-GB/firefox/beta/
The current beta is b11.  That's an internal number, really; it was b10 last week.  ;)  Google is just behind the times.

This fix will be in b12, yes.
Is there going to be a standardized timeout in some spec. that says wait X seconds before falling back to regular text to display while a download is going? I hear that there's a timeout, but will such a timeout be standardized?
I believe that was proposed and rejected, since the optimal timeout depends on the user, network conditions, etc.
There's been some discussion of this; for example, see the recent email thread on "@font-face and slow downloading" on the www-style mailing list (http://lists.w3.org/Archives/Public/www-style/). Whether a specific behavior will end up being recommended in a standard remains to be seen.
Thanks!  There's another condition that causes @font-face text to flash, and doesn't appear to be fixed with this commit:
https://bugzilla.mozilla.org/show_bug.cgi?id=633299
(In reply to comment #54)
> Is there going to be a standardized timeout in some spec. that says wait X
> seconds before falling back to regular text to display while a download is
> going? I hear that there's a timeout, but will such a timeout be standardized?

As you'll see in some of the email threads Jonathan linked to in the comment above, I don't think there's a lot to be gained by standardizing the timeout.  

If you look at the logic in the patch, we use the timeout value as a guide in evaluating when to wait and when to show the fallback font.  If the font is almost done downloading at the timeout point, we wait a tad longer.  I could also see situations where the timeout is set to zero because of a slow network connection, in mobile situations for example.
Depends on: 633500
If a script manipulating a <canvas> set 2dcontext.font = "[some @font-face]", and then called 2dcontext.fillText("foo") (which ends up calling gfxTextRun::Draw()) before "[some @font-face]" was fully loaded, would this patch result in that gfxTextRun::Draw() call doing nothing?
(In reply to comment #59)
> If a script manipulating a <canvas> set 2dcontext.font = "[some
> @font-face]", and then called 2dcontext.fillText("foo") (which ends up
> calling gfxTextRun::Draw()) before "[some @font-face]" was fully loaded,
> would this patch result in that gfxTextRun::Draw() call doing nothing?

Yes, I'd expect so.

You could check whether that's happening in your case by setting gfx.downloadable_fonts.fallback_delay to zero; that should prevent text being "drawn" as blank. (But note that this means you'll get a fallback font if the @font-face isn't loaded yet, which may not be what you really want as a "solution".)
Thanks, that confirms the problem.

The general solution to this will probably be bug 471915, but do you think it's worth filing a bug to disable this behavior specially for canvas?  Unlike HTML, there's no reflow+repaint to bail out the skipped text drawing, so if a page draws text to a canvas using a not-yet-loaded @font-face, no text may ever appear on the canvas.

I would be just as happy with claiming that canvas+@font-face isn't a fully-supported feature until bug 471915 lands.  Please advise.
(In reply to comment #61)

> The general solution to this will probably be bug 471915, 

Right, I think this is an important use case for such events.

> but do you think
> it's worth filing a bug to disable this behavior specially for canvas? 

I'm not sure... what behavior would you expect instead? Just drawing the text with a fallback font is less than optimal - it may even be completely wrong, if the point of the @font-face usage was to supply a specific font such as a dingbat collection, or a font for an unusual script or a very specific graphic-design requirement. And unlike the HTML case, where the fallback (if we draw it, due to a slow @font-face load) will automagically get replaced with the proper font once the load completes, in the canvas case you'd be left with the incorrect rendering. And it'd be an unpredictable result, as what gets drawn would depend on timing and latency issues.

ISTM that the only "somewhat safe" option would be for @font-face loads required for canvas text to be treated as blocking, so that the fillText call simply waits until the font is available. But that has its own problems; what if the download takes "inordinately long", or fails altogether?

IOW, I don't really see a good solution....

> Unlike HTML, there's no reflow+repaint to bail out the skipped text drawing,
> so if a page draws text to a canvas using a not-yet-loaded @font-face, no
> text may ever appear on the canvas.
> 
> I would be just as happy with claiming that canvas+@font-face isn't a
> fully-supported feature until bug 471915 lands.  Please advise.

I think that until bug 471915 lands, the best option is probably to use a Javascript library that emulates such behavior, e.g. by repeatedly laying out a text fragment using the @font-face-defined family, and watching for its metrics to change when the download completes.

You should also do something to initiate the download as early as possible, if you're not already doing so. Note that we don't request the font when the @font-face rule is defined but only when we actually need to lay out some text using it.

(You still need to decide what strategy to use when the font fails to download at all (in a timely manner), but that'll remain true even with 471915.)
(In reply to comment #62)
> ISTM that the only "somewhat safe" option would be for @font-face loads
> required for canvas text to be treated as blocking, so that the fillText
> call simply waits until the font is available. But that has its own
> problems; what if the download takes "inordinately long", or fails
> altogether?

Synchronous waiting for the load to complete is totally out of the question :-).
(In reply to comment #62)
> (In reply to comment #61)
> 
> > The general solution to this will probably be bug 471915, 
> 
> Right, I think this is an important use case for such events.
> 
> > but do you think
> > it's worth filing a bug to disable this behavior specially for canvas? 
> 
> I'm not sure... what behavior would you expect instead? Just drawing the
> text with a fallback font is less than optimal - it may even be completely
> wrong, if the point of the @font-face usage was to supply a specific font
> such as a dingbat collection, or a font for an unusual script or a very
> specific graphic-design requirement. And unlike the HTML case, where the
> fallback (if we draw it, due to a slow @font-face load) will automagically
> get replaced with the proper font once the load completes, in the canvas
> case you'd be left with the incorrect rendering. And it'd be an
> unpredictable result, as what gets drawn would depend on timing and latency
> issues.

Yeah.

> I think that until bug 471915 lands, the best option is probably to use a
> Javascript library that emulates such behavior, e.g. by repeatedly laying
> out a text fragment using the @font-face-defined family, and watching for
> its metrics to change when the download completes.

That doesn't work in general, but there's another hack available.  At any rate, 471915 is the way forward.

(In reply to comment #63)
> (In reply to comment #62)
> > ISTM that the only "somewhat safe" option would be for @font-face loads
> > required for canvas text to be treated as blocking, so that the fillText
> > call simply waits until the font is available. But that has its own
> > problems; what if the download takes "inordinately long", or fails
> > altogether?
> 
> Synchronous waiting for the load to complete is totally out of the question
> :-).

Agreed.  It would be nice for, oh say fonts loaded from data: URIs, but that behavior would put a giant pair of handcuffs on the UA.
Depends on: 703411
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: