Bug 220231 - REGRESSION: animated iframe painted blank
Summary: REGRESSION: animated iframe painted blank
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Animations (show other bugs)
Version: Safari 14
Hardware: Unspecified Unspecified
: P1 Normal
Assignee: Simon Fraser (smfr)
URL: https://hofman-stripe-payments-demo.a...
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2021-01-03 18:52 PST by Mathieu Hofman
Modified: 2021-01-11 10:54 PST (History)
6 users (show)

See Also:


Attachments
Screen capture of the reproduction of the CSS animation bug (796.48 KB, video/quicktime)
2021-01-03 18:52 PST, Mathieu Hofman
no flags Details
Screen capture of the reproduction of the Javascript animation bug (976.02 KB, video/quicktime)
2021-01-03 18:52 PST, Mathieu Hofman
no flags Details
iframe painted when window dragged to built-in display (6.69 MB, video/quicktime)
2021-01-04 13:19 PST, Mathieu Hofman
no flags Details
iframe not painted when window dragged to other display (5.13 MB, video/quicktime)
2021-01-04 13:20 PST, Mathieu Hofman
no flags Details
Patch (5.38 KB, patch)
2021-01-05 15:34 PST, Simon Fraser (smfr)
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mathieu Hofman 2021-01-03 18:52:11 PST
Created attachment 416919 [details]
Screen capture of the reproduction of the CSS animation bug

We have a couple iframe paint bugs in Safari we've finally been able to consistently reproduce on some systems.

In Safari 13+ (and possibly earlier versions), a loaded iframe faded into view through a JavaScript based animation (e.g. `$.fadeIn()`) would sometimes paint blank. In those cases, no composite layer for the iframe would exist. Any reflow of the container would trigger the iframe paint. Applying a transform or other CSS style that would force a composite layer for the iframe would prevent the occurrence of this bug.

To reproduce:
- In Safari 13+ , open https://hofman-stripe-payments-demo.appspot.com/jq-repro/?stripeStaticLayer=false&stripeTransitionFix=false
- Click CB (the frame is painted correctly)
- Refresh
- Click CB again (make sure network cache is not disabled if devtools are open)
- Observe blank painted iframe where card input should be
- The iframe is actually functional, can be filed through keyboard or autofill.
- Any resize of the container (window) caused the iframe to be painted


However, the workaround to force a composite layer through CSS style causes another blank paint bug in Safari 14+. If the loaded iframe is animated into view through a CSS transition on an ancestor, the iframe is painted blank. Without the forced promotion to its own composition layer, the iframe would render fine. A forced reflow of the parent doesn't help repaint the iframe since it has its own composite layer. We have implemented another workaround to listen for transition start events on any ancestor and force a reflow on the iframe itself, however it's very hacky, and we are worried of other undiscovered cases where this bug might trigger.

To reproduce:
- In Safari 14+, open https://hofman-stripe-payments-demo.appspot.com/?stripeStaticLayer=true&stripeTransitionFix=false
- Observe the card iframe painted blank
- The iframe is actually functional, can be filed through keyboard or autofill.


We've had multiple bug reports from our users about these issues including:
- https://github.com/stripe/react-stripe-js/issues/136
- https://github.com/stripe/stripe-js/issues/128
- https://github.com/stripe/stripe-js/issues/113
- https://github.com/stripe/react-stripe-elements/issues/35

While the above reproductions are for desktop Safari, we've had reports of these bugs also happening on iPhone and iPad.

There are some triggers we still don't fully understand. For the first reproduction, we don't know why caching seem to have an impact. For the second reproduction, the issue only manifests if the iframe has loaded before the CSS transition starts (the reproduction delays CSS animation until load for consistency). We unfortunately haven't been able to create more minimal reproductions.
Comment 1 Mathieu Hofman 2021-01-03 18:52:55 PST
Created attachment 416920 [details]
Screen capture of the reproduction of the Javascript animation bug
Comment 2 Alexey Proskuryakov 2021-01-04 09:49:06 PST
> - In Safari 13+ , open https://hofman-stripe-payments-demo.appspot.com/jq-repro/?stripeStaticLayer=false&stripeTransitionFix=false

I can reproduce this issue with a recent WebKit build that I have on my machine.

> - In Safari 14+, open https://hofman-stripe-payments-demo.appspot.com/?stripeStaticLayer=true&stripeTransitionFix=false

But I cannot reproduces this one. Perhaps it's a Safari 14 regression that's been fixed already.
Comment 3 Radar WebKit Bug Importer 2021-01-04 09:49:15 PST
<rdar://problem/72793724>
Comment 4 Mathieu Hofman 2021-01-04 11:09:28 PST
> But I cannot reproduces this one. Perhaps it's a Safari 14 regression that's been fixed already.

Apparently we still have inconsistent reproduction on this depending on the machine. We're trying to figure out if there is some other factor (e.g. dedicated graphics).

Can you reproduce in Safari 14.0.2 (15610.3.7.1.10, 15610)? My machine is a MacBookPro15,2 i7 running macOS 10.15.7 (19H15)
Comment 5 Mathieu Hofman 2021-01-04 13:19:27 PST
Created attachment 416961 [details]
iframe painted when window dragged to built-in display
Comment 6 Mathieu Hofman 2021-01-04 13:20:08 PST
Created attachment 416963 [details]
iframe not painted when window dragged to other display
Comment 7 Mathieu Hofman 2021-01-04 13:22:09 PST
I believe we've isolated a necessary trigger for this bug: the window needs to be rendered on a secondary display (non-retina?), not the built-in display of the MacBook Pro.

Then dragging that window to the built-in display will cause the iframe to be painted. The same is not true if dragging the window to another (non-retina?) display.
Comment 8 Mathieu Hofman 2021-01-04 14:12:12 PST
I've verified that rendering on a secondary retina monitor does not trigger this bug. It seems that the trigger for the CSS animation based bug is for the window to be rendered on a non-retina display.
Comment 9 Simon Fraser (smfr) 2021-01-05 09:28:01 PST
I can reproduce the Safari 14 version on a non-retina display.
Comment 10 Simon Fraser (smfr) 2021-01-05 11:33:15 PST
I can see that the GraphicsLayers are connected across frame boundaries, but the CALayers are not.
Comment 11 Simon Fraser (smfr) 2021-01-05 11:53:29 PST
Doesn't happen if we don't call m_graphicsLayer->setContentsVisible(false) on the iframe's layer.

Hardcoding the deviceScaleFactor() to 1 makes it happen on Retina screens.
Comment 12 Simon Fraser (smfr) 2021-01-05 11:59:01 PST
Found it.
Comment 13 Simon Fraser (smfr) 2021-01-05 14:49:21 PST
The "non-retina" part is related to m_compositedBoundsOffsetFromGraphicsLayer which affects whether the iframe's GraphicsLayer uses a m_contentsClippingLayer or not.
Comment 14 Simon Fraser (smfr) 2021-01-05 15:34:43 PST
Created attachment 417044 [details]
Patch
Comment 15 EWS 2021-01-05 19:55:27 PST
Committed r271191: <https://trac.webkit.org/changeset/271191>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 417044 [details].
Comment 16 Mathieu Hofman 2021-01-05 22:12:40 PST
Thanks for the quick turnaround. For clarification, does the patch also fix the JavaScript based animation bug present since at least Safari 13? Sorry for filing a combined bug on this one, they seemed related since our workaround for the first one triggered the second one.
Comment 17 Simon Fraser (smfr) 2021-01-06 09:29:36 PST
The Safari 13+ bug does seem to still reproduce after this fix. I'll investigate.
Comment 18 Simon Fraser (smfr) 2021-01-11 10:54:16 PST
Doing so in bug 220498.