Bug 186336

Summary: TileFirstPaint strategy for async image decoding should be disabled for non root RenderLayers
Product: WebKit Reporter: Chris Dumez <cdumez>
Component: ImagesAssignee: Said Abou-Hallawa <sabouhallawa>
Status: RESOLVED FIXED    
Severity: Normal CC: ap, commit-queue, jonlee, sabouhallawa, simon.fraser, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Repro case
none
image
none
workaround
none
Patch
none
Patch none

Description Chris Dumez 2018-06-05 20:36:07 PDT
HTML 'load' event fires before images have rendered. This causes flickr for some apps / sites. I will attach a demo.
Comment 1 Chris Dumez 2018-06-05 20:36:32 PDT
<rdar://problem/40808099>
Comment 2 Chris Dumez 2018-06-05 20:42:29 PDT
Created attachment 342025 [details]
Repro case

Here is a very simple repro case.

Open test.html in Safari, then hit the reload button.

Expected result: There should be no red flash
Actual result: We see a red flash before the image shows

Works in Chrome.

The page has a red div with opacity 0 and a background image in CSS. When the 'load' event fires, opacity of the is changed to 1.

Was reported at WWDC today.
Comment 3 Chris Dumez 2018-06-05 20:43:54 PDT
I confirmed it is a regression from async image decoding by updating RenderBoxModelObject::decodingModeForImageDraw(const Image&, const PaintInfo&) to always return DecodingMode::Synchronous. This made the bug go away.

I seem to remember there is a way for users to opt out of async image decoding for <img> elements. However, I do not think there is such thing for images loaded from CSS?
Comment 4 Chris Dumez 2018-06-05 20:58:14 PDT
(paintInfo.paintBehavior & PaintBehaviorTileFirstPaint) is true in RenderBoxModelObject::decodingModeForImageDraw(const Image&, const PaintInfo&).
Comment 5 Said Abou-Hallawa 2018-06-07 09:29:12 PDT
What is the spec of the load event regarding painting the image? Does firing the load event guarantees the image will be painted with the next window update? If this is the case we can disable the async image decoding for large images if the image element has a load event handler. The reason will be: in the image load event handler there might be a script which assumes the image will be painted synchronously.

Meanwhile there is an easy workaround which uses the HTMLImageElement::decode API. When the decode promise is resolved, the image has to be be painted in the next window update. The workaround test case is attached.
Comment 6 Said Abou-Hallawa 2018-06-07 09:29:49 PDT
Created attachment 342178 [details]
image
Comment 7 Said Abou-Hallawa 2018-06-07 09:33:18 PDT
Created attachment 342179 [details]
workaround
Comment 8 Said Abou-Hallawa 2018-06-12 13:41:44 PDT
Created attachment 342590 [details]
Patch
Comment 9 Simon Fraser (smfr) 2018-06-12 14:55:55 PDT
Comment on attachment 342590 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=342590&action=review

> Source/WebCore/ChangeLog:14
> +        had to be generalized for large and animated images. The logic for making 
> +        the image decoding takes the required duration was moved from BitmapImage

"the logic for making the image decoding" doesn't make sense grammatically.

> Source/WebCore/rendering/RenderLayer.h:189
> +    bool isRoot() const { return !parent(); }

We already have isRenderViewLayer(), which should give the same answer.
Comment 10 Said Abou-Hallawa 2018-06-12 17:37:15 PDT
Created attachment 342614 [details]
Patch
Comment 11 WebKit Commit Bot 2018-06-13 12:10:23 PDT
Comment on attachment 342614 [details]
Patch

Clearing flags on attachment: 342614

Committed r232802: <https://trac.webkit.org/changeset/232802>
Comment 12 WebKit Commit Bot 2018-06-13 12:10:25 PDT
All reviewed patches have been landed.  Closing bug.