Open Bug 1211853 Opened 6 years ago Updated 3 years ago

Allow applications to have more control over first paint

Categories

(Core :: Web Painting, defect)

ARM
Gonk (Firefox OS)
defect
Not set
normal

Tracking

()

People

(Reporter: vnicolas, Unassigned)

References

Details

Attachments

(2 files)

So far, first paint of an application or an application panel (when it lives into a separate document) happens once nglayout.initialpaint.delay ms have passed once css file have been parsed and the <body> tag is encountered.

This heuristic makes it tricky from the app side to know exactly when firstpaint will occur.
For example in Gaia, we use the visuallyLoaded custom metric has an optimization target. This metric means the application considered it is ready to be displayed.

We are currently looking at this number to know if applications have been enhance or have regressed since the last version.
While this number is useful it may be very far from the firstpaint event which may occurs hundreds of ms later if the event loop is busy.
It also means it is very hard for Gaia to know exactly when does the cover needs to be removed on app launch. It is currently removed on the 'load' event which may be disconnected from when the app is ready to be displayed.
It may be possible to remove it on the firstpaint of the app but so far this is hard to control and it may be removed while the app layout is building itself, which is not visually very pleasant.

In order to make the situation saner, the attached patches does 2 things to offer more control to the application itself:
 1. Avoid painting until something really need to be painted. It basically does not issue paint command until there is a frame for the <body> tag and <html> element is visible.
    It allow applications to hide their layout until it is ready to be displayed.

 2. Dispatch a "mozfirstpaint" event to the application when the first paint command occurs.
    It will let applications write optimized startup path to display something quickly to the user, without delaying gecko paint. And once Gecko has issued its paint command, the event can be handle to continue the remaining application work.
    I don't think mozfirstpaint expose the same security issue as MozAfterPaint, and it may be useful for other app developers as well.
Attachment #8670186 - Flags: review?(roc)
Asking feedback as it seems that there is no clear agreement on the definition of what exactly is firstpaint. In our case the idea is to ensure the platform can request painting to the underlying OS without beeing disturbed by the JS that may run.
If this is an f+ I will also add the necessary tests.
Attachment #8670187 - Flags: feedback?(roc)
Blocks: 1199674
Wasn't this discussed on dev-platform in August, under the subject "Allowing web apps to delay layout/rendering on startup"?

In that thread, James Burke concluded:

> There does not seem to be a need for extra APIs in the browser for
> controlling layouts or paints using this approach:
>
> * Set the background-color for the body to be transparent.
> * The body content consists of a `<template>` element with the initial
> content. It can include custom elements, but they are inert given the
> `<template>` usage.
> * Async load the scripts that will provide the implementation of the
> custom elements.
> * Once all the elements have been registered, document.importNode the
> body template's content, and append to the body.

If we do that, what do we need here? Just #2 from comment #0? Or have we decided not to follow James' plan for some reason?
Flags: needinfo?(vnicolas)
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #2)
> Wasn't this discussed on dev-platform in August, under the subject "Allowing
> web apps to delay layout/rendering on startup"?
> 

It was. See my answer about why I'm not completely convinced by conclusion.

> In that thread, James Burke concluded:
> 
> > There does not seem to be a need for extra APIs in the browser for
> > controlling layouts or paints using this approach:
> >
> > * Set the background-color for the body to be transparent.
> > * The body content consists of a `<template>` element with the initial
> > content. It can include custom elements, but they are inert given the
> > `<template>` usage.
> > * Async load the scripts that will provide the implementation of the
> > custom elements.
> > * Once all the elements have been registered, document.importNode the
> > body template's content, and append to the body.
> 
> If we do that, what do we need here? Just #2 from comment #0? Or have we
> decided not to follow James' plan for some reason?

This is a nice trick, it likely work because:
 1. The background-color of the page is retrieved when the load event happens at http://mxr.mozilla.org/mozilla-central/source/dom/browser-element/BrowserElementChildPreload.js#1897 and forwarded to the parent process to use it as a background-color for the iframe (otherwise it defaults to a white background).

 2. The cover is removed when the load event happens. At the same time the background is set.

My questions with this solution are:
 1. Do we really want to allow transparent color for a webpage to show what is displayed underneath by the system app ? On Firefox there is always a default bgcolor (which is retrieved here afaik: http://mxr.mozilla.org/mozilla-central/source/layout/base/nsPresContext.cpp#623)

 2. The background-color is defined when the load event happens. It likely work for app that loads under the 250ms allowed by nglayout.initialpaint.delay but it may fail if the app takes longer than this to load its dependencies (js, css, locales, images, etc..). So it seems a bit racy to me.
    I guess the system app can start the iframe with a transparent background to get rid of the race, but then it may look weird for apps that expect a default background color underneath.


Also I would like to have a more unified solution with what Chromium is doing for webapps. Which is, afaik, removing the cover on the first non-empty paint.
See https://codereview.chromium.org/306823002/ and https://groups.google.com/a/chromium.org/forum/#!msg/apps-dev/y39qqrqoxjs/o6lb7utaEoEJ
Flags: needinfo?(vnicolas)
I also forgot to say that I would like to remove the code that read the bgcolor of the page. It is expensive in some scenarios. See bug 926452
I think it would be best to follow up on that conversation in dev-platform rather than change its direction in this bug with just the two of us.
Flags: needinfo?(vnicolas)
Will do.
Flags: needinfo?(vnicolas)
Fwiw I also forgot to say that the proposed solution in the thread will not solve the bug blocked by this one :/
I like this solution for l10n purposes.

As an experiment, could we take any of the apps that we have today in gaia and link "navigationLoaded" to firstPaint this way and check the performance numbers?

I can also see some apps (Settings) linking "visuallyLoaded" to firstPaint instead.

Overall, I would imagine Gaia apps choosing one of those two standardized performance marks for when should firstPaint happen for that app, and I would love to avoid apps throwing it separately at different moments than the marks.
(In reply to Zibi Braniecki [:gandalf][:zibi] from comment #8)
> I like this solution for l10n purposes.
> 
> As an experiment, could we take any of the apps that we have today in gaia
> and link "navigationLoaded" to firstPaint this way and check the performance
> numbers?


I have something similar locally. For some apps like email, dialer, sms, firstpaint may arrive hundreds of ms after visuallyLoaded.

For other apps like settings or calendar, firstpaint may happens hundreds of ms before visuallyLoaded.

The one that are closer to the reality are media apps, where visuallyLoaded happens a 20 or 30ms before firstpaint. Which is great.

> 
> I can also see some apps (Settings) linking "visuallyLoaded" to firstPaint
> instead.
> 

Using display:none in order to control firstpaint, it shapes around 400ms of visuallyLoaded time. It avoid some reflows/repaints that happens a lot during the startup of this app :)

> Overall, I would imagine Gaia apps choosing one of those two standardized
> performance marks for when should firstPaint happen for that app, and I
> would love to avoid apps throwing it separately at different moments than
> the marks.

Me too. I believe firstpaint should happens similarly to what the media apps does. Right after visuallyLoaded.
> Me too. I believe firstpaint should happens similarly to what the media apps does. Right after visuallyLoaded.

For many apps, yes. But there apps that have a usable chrome far before they can display the content. Example is SMS. Chrome of SMS app with "new message" button available is extremely useful even before the above-the-fold messages are loaded.

In those cases, firstpaint should happen when chrome is ready (navigationLoaded).

In other cases, like Settings where chrome is basically a header and everything else is content, firstpaint doesn't make sense until visuallyLoaded.
(In reply to Zibi Braniecki [:gandalf][:zibi] from comment #10)
> > Me too. I believe firstpaint should happens similarly to what the media apps does. Right after visuallyLoaded.
> 
> For many apps, yes. But there apps that have a usable chrome far before they
> can display the content. Example is SMS. Chrome of SMS app with "new
> message" button available is extremely useful even before the above-the-fold
> messages are loaded.
> 
> In those cases, firstpaint should happen when chrome is ready
> (navigationLoaded).

Makes sense.
OS: Unspecified → Gonk (Firefox OS)
Hardware: Unspecified → ARM
Component: Layout: View Rendering → Layout: Web Painting
You need to log in before you can comment on or make changes to this bug.