layout: Fix first-paint detection#42975
Conversation
first-paint onlyfirst-paint
|
|
||
| // From <https://www.w3.org/TR/paint-timing/#sec-terminology>: | ||
| // First paint ... includes non-default background paint and the enclosing box of an iframe. | ||
| if background_color != AbsoluteColor::WHITE { |
There was a problem hiding this comment.
I do not understand this code. White is not the default background color in style. You should be checking the value from the style itself, not the final color. In addition, the specification text says "First paint excludes the default background paint, but includes non-default background paint." This isn't talking about the color, but the background itself, so my reading is that it should include all kinds of background paints, including images.
There was a problem hiding this comment.
IMO it is about color. We should mark default color in prefs or somewhere.
If I don't check for white presumably default, It will result in failing of first-contentful-paint.html
There was a problem hiding this comment.
Can you justify this interpretation of the specification somehow? A "default background color" of <div>s does not sound like the kind of feature that the web platform usually contains. Also does "default background paint" here refer to the background of individual fragments or the page canvas background of the HTML <body> element (https://drafts.csswg.org/css-backgrounds/#body-background)?
There was a problem hiding this comment.
I understand now that this code is only about the page canvas background.
There was a problem hiding this comment.
If you observe the behavior of this code in Chrome you can see that background images should trigger first-paint. I am pretty sure that "non-default" here should mean when any background that eventually propagates to be the HTML page canvas is not transparent and does not match the backdrop color (pref!(shell_background_color_rgba)) including images.
<!doctype html>
<html>
<head>
<style>
html {
background-image: url(data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+P//PwAF/wL+wMZ2tgAAAABJRU5ErkJggg==);
}
</style>
</head>
<body>
<script>
setTimeout(() => {
console.log(performance.getEntriesByType('paint'));
}, 2000);
</script>
</body>
</html>Also observe that this works the same way with a 1 pixel by 1 pixel transparent or white image
<!doctype html>
<html>
<head>
<style>
html {
/* background-image: url(data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+P//PwAF/wL+wMZ2tgAAAABJRU5ErkJggg==);*/
background-image: url(data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2P4DwQACfsD/Z8fLAAAAAAASUVORK5CYII=);
}
</style>
</head>
<body>
<script>
setTimeout(() => {
console.log(performance.getEntriesByType('paint'));
}, 2000);
</script>
</body>
</html>There was a problem hiding this comment.
All the other background like background-image, border-image are already considered for FP.
Only non-default background color is not considered. So, i marked it here.
There was a problem hiding this comment.
Still, you will need to consider the backdrop color from the preferences. Also, it's unclear what should happen here when the page is loading in the iframe. I suspect the behavior might end up being different depending on where the content is loading (main frame versus iframe).
There was a problem hiding this comment.
Still, you will need to consider the backdrop color from the preferences. Also, it's unclear what should happen here when the page is loading in the iframe. I suspect the behavior might end up being different depending on where the content is loading (main frame versus iframe).
Considered the backdrop color from preference. And consolidated all the changes here.
Yeah, for iframe, it is not considered here. Since, I'm fixing the WPT tests, I will submit it in a separate PR when WPT tests are updated after weekly sync. Added a TODO in this PR description for same.
Please review
There was a problem hiding this comment.
The latest commit (4a6f9c4) looks correct to me in handling non-default background color of the root.
There was a problem hiding this comment.
The spec is vague on this. We should provide some test cases to ensure that our behavior is correct in at least common cases.
mrobinson
left a comment
There was a problem hiding this comment.
This doesn't look to me like what the specification is saying and I think we need to work out what is actually meant here by "non-default background paint" before landing.
|
|
||
| // From <https://www.w3.org/TR/paint-timing/#sec-terminology>: | ||
| // First paint ... includes non-default background paint and the enclosing box of an iframe. | ||
| if background_color != AbsoluteColor::WHITE { |
There was a problem hiding this comment.
If you observe the behavior of this code in Chrome you can see that background images should trigger first-paint. I am pretty sure that "non-default" here should mean when any background that eventually propagates to be the HTML page canvas is not transparent and does not match the backdrop color (pref!(shell_background_color_rgba)) including images.
<!doctype html>
<html>
<head>
<style>
html {
background-image: url(data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+P//PwAF/wL+wMZ2tgAAAABJRU5ErkJggg==);
}
</style>
</head>
<body>
<script>
setTimeout(() => {
console.log(performance.getEntriesByType('paint'));
}, 2000);
</script>
</body>
</html>Also observe that this works the same way with a 1 pixel by 1 pixel transparent or white image
<!doctype html>
<html>
<head>
<style>
html {
/* background-image: url(data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+P//PwAF/wL+wMZ2tgAAAABJRU5ErkJggg==);*/
background-image: url(data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2P4DwQACfsD/Z8fLAAAAAAASUVORK5CYII=);
}
</style>
</head>
<body>
<script>
setTimeout(() => {
console.log(performance.getEntriesByType('paint'));
}, 2000);
</script>
</body>
</html>| // An element el is paintable when all of the following apply: | ||
| // > el is being rendered. | ||
| // > el’s used visibility is visible. | ||
| // This is sufficient to mark the first paint |
There was a problem hiding this comment.
I know this is from the other PR, but I think these two should be combined into a single PR.
Why is this sufficient? Please provide specification text and a link so that those reading the code can understand why this is the case.
There was a problem hiding this comment.
Updated please take a look and review.
|
|
||
| // From <https://www.w3.org/TR/paint-timing/#sec-terminology>: | ||
| // First paint ... includes non-default background paint and the enclosing box of an iframe. | ||
| if background_color != AbsoluteColor::WHITE { |
There was a problem hiding this comment.
Still, you will need to consider the backdrop color from the preferences. Also, it's unclear what should happen here when the page is loading in the iframe. I suspect the behavior might end up being different depending on where the content is loading (main frame versus iframe).
first-paintfirst-paint detection
first-paint detectionfirst-paint detection
Yeah, As I understand anything other than default color is "non-default background paint". Whether it is border-image, background-image, background color or even gradient also. |
| /// First paint | ||
| /// See <https://w3c.github.io/paint-timing/#first-paint>. | ||
| pub first_paint: bool, |
There was a problem hiding this comment.
IIUC this is marking whether anything is painted. If so, it seems better to change it into:
| /// First paint | |
| /// See <https://w3c.github.io/paint-timing/#first-paint>. | |
| pub first_paint: bool, | |
| /// Whether anything has been painted. Used to mark first paint. | |
| /// See <https://w3c.github.io/paint-timing/#first-paint>. | |
| pub has_paint: bool, |
All the other relevant variables and methods should also be renamed.
There was a problem hiding this comment.
Might be irrelevant to this PR but this doesn't match the definition of contentful. Something seems wrong here.
Do we really have a genuine implementation of FCP, or are we simply reporting FP as FCP?
There was a problem hiding this comment.
Yeah, It looks like that.
But FCP is quite consistent.
If document contains at least one element that is both paintable and contentful, then return true.
We are checking paintable for sure, and most elements from contentful list as we only call this API if element is of that relevant type.
And FP needed some extra addition, which are being handled in this one.
There was a problem hiding this comment.
But we can reach here for non-contentful paints, like the background paint of the root context, or an element with a non-image background.
There was a problem hiding this comment.
Discussed offline:
PaintDisplayListInfoshould maintain two independent booleans,is_paintableandis_contentful, following exactly the definition in speccheck_if_paintableshould mark paintable only- When painting a fragment, callers should never bypass
check_if_paintableas otherwise some necessary checks will be bypassed - When painting an image or text fragment, callers should mark contentful
| // > > From <https://w3c.github.io/paint-timing/#first-paint>: | ||
| // > > First paint entry contains a DOMHighResTimeStamp reporting the time when the user agent first rendered after navigation. | ||
| // > > Hence, This is sufficient to mark the first paint. | ||
| self.mark_first_paint(); |
There was a problem hiding this comment.
Per spec, first paint should be marked only after all of visibility, opacity and bounding rect intersection have been checked and passed.
There was a problem hiding this comment.
Aaah right. Updating
|
|
||
| // From <https://www.w3.org/TR/paint-timing/#sec-terminology>: | ||
| // First paint ... includes non-default background paint and the enclosing box of an iframe. | ||
| if background_color != AbsoluteColor::WHITE { |
There was a problem hiding this comment.
The latest commit (4a6f9c4) looks correct to me in handling non-default background color of the root.
There was a problem hiding this comment.
Discussed offline:
PaintDisplayListInfoshould maintain two independent booleans,is_paintableandis_contentful, following exactly the definition in speccheck_if_paintableshould mark paintable only- When painting a fragment, callers should never bypass
check_if_paintableas otherwise some necessary checks will be bypassed - When painting an image or text fragment, callers should mark contentful
|
📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58544). |
Signed-off-by: Shubham Gupta <[email protected]>
Signed-off-by: Shubham Gupta <[email protected]>
Signed-off-by: Shubham Gupta <[email protected]>
Signed-off-by: Shubham Gupta <[email protected]>
|
📝 Transplanted new upstreamable changes to existing upstream WPT pull request (web-platform-tests/wpt#58544). |
|
✍ Updated existing upstream WPT pull request (web-platform-tests/wpt#58544) title and body. |
Comments have been addressed
`iframe` should be considered for `first-paint`. TODO of: #42975 Synced: web-platform-tests/wpt#58243 Refer for some history: #42498 Testing: - `wpt/paint-timing/first-paint-only/child-painting-first-image.html` - `wpt/paint-timing/first-paint-only/sibling-painting-first-image.html` Fixes: #42455 --------- Signed-off-by: Shubham Gupta <[email protected]>
This PR comprises 1. Segregate `paintable` and `contentful`. 2. Adds Checking of non-default background for eligibility to mark `first-paint`. 3. Adds a bool `is_paintable` to `display_list` and use same for marking `first-paint`. TODO: This doesn't consider `iframes`. Will add PR after fixing WPT tests. Raised an issue for some incomplete definitions: w3c/paint-timing#122 Testing: - `wpt/tests/paint-timing/first-paint-only/first-paint-bg-color.html` - Updated WPT tests expectations. - `wpt/paint-timing/first-image-child.html` - `wpt/paint-timing/first-paint-only/sibling-painting-first-image.html` - Unit Test: `servo/tests/performance_paint_timings.rs`. Following Tests Cases are covered: Background Pref |Root Background|FP|TC --|--|--|-- |Default|Unset|:x: | `test_default_pref_with_unset_background` |Non-Default|Unset|:x: | `test_non_default_pref_with_unset_background` |Default|Transparent|:x:|`test_default_pref_with_transparent_background` |Non-Default|Unset|:x:|`test_non_default_pref_with_transparent_background` |Default|Set|:white_check_mark:|`test_default_pref_with_background` |Non-Default|Set|:white_check_mark:|`test_non_default_pref_with_background` |Non-Default|Set (same as pref)|:x:|`test_non_default_pref_with_same_background` Fixes: servo#42148 --------- Signed-off-by: Shubham Gupta <[email protected]>
This PR comprises
paintableandcontentful.first-paint.is_paintabletodisplay_listand use same for markingfirst-paint.TODO: This doesn't consider
iframes. Will add PR after fixing WPT tests.Raised an issue for some incomplete definitions: w3c/paint-timing#122
Testing:
wpt/tests/paint-timing/first-paint-only/first-paint-bg-color.htmlwpt/paint-timing/first-image-child.htmlwpt/paint-timing/first-paint-only/sibling-painting-first-image.htmlservo/tests/performance_paint_timings.rs. Following Tests Cases are covered:test_default_pref_with_unset_backgroundtest_non_default_pref_with_unset_backgroundtest_default_pref_with_transparent_backgroundtest_non_default_pref_with_transparent_backgroundtest_default_pref_with_backgroundtest_non_default_pref_with_backgroundtest_non_default_pref_with_same_backgroundFixes: #42148