Skip to content

Commit df8600f

Browse files
shallawaBunioFH
authored andcommitted
Avoid flickering when showing a layer on a painted background for the first time by disabling async image decoding
https://bugs.webkit.org/show_bug.cgi?id=270330 rdar://117533495 Reviewed by Simon Fraser; If an image is decoded asynchronously for a sizeForDrawing different from the current one, a flicker may happen. To avoid this flicker, decode the image synchronously if it has more than one RenderElement in the page and the last time it was decoded asynchronously. * LayoutTests/TestExpectations: * Source/WebCore/loader/cache/CachedImage.h: * Source/WebCore/platform/graphics/BitmapImage.cpp: (WebCore::BitmapImage::destroyDecodedData): (WebCore::BitmapImage::draw): (WebCore::BitmapImage::lastDecodingOptions const): (WebCore::BitmapImage::lastDecodingOptionsForTesting const): Deleted. * Source/WebCore/platform/graphics/BitmapImage.h: * Source/WebCore/platform/graphics/ImageObserver.h: (WebCore::ImageObserver::numberOfClients const): * Source/WebCore/rendering/RenderBoxModelObject.cpp: (WebCore::RenderBoxModelObject::decodingModeForImageDraw const): * Source/WebCore/testing/Internals.cpp: (WebCore::Internals::imageLastDecodingOptions): Canonical link: https://commits.webkit.org/276513@main
1 parent f569f2b commit df8600f

6 files changed

Lines changed: 17 additions & 3 deletions

File tree

Source/WebCore/loader/cache/CachedImage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class CachedImage final : public CachedResource {
147147
// ImageObserver API
148148
URL sourceUrl() const override { return !m_cachedImages.isEmpty() ? (*m_cachedImages.begin())->url() : URL(); }
149149
String mimeType() const override { return !m_cachedImages.isEmpty() ? (*m_cachedImages.begin())->mimeType() : emptyString(); }
150+
unsigned numberOfClients() const override { return !m_cachedImages.isEmpty() ? (*m_cachedImages.begin())->numberOfClients() : 0; }
150151
long long expectedContentLength() const override { return !m_cachedImages.isEmpty() ? (*m_cachedImages.begin())->expectedContentLength() : 0; }
151152

152153
void encodedDataStatusChanged(const Image&, EncodedDataStatus) final;

Source/WebCore/platform/graphics/BitmapImage.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ void BitmapImage::destroyDecodedData(bool destroyAll)
8686
} else {
8787
m_source->destroyDecodedData(0, frameCount());
8888
m_currentFrameDecodingStatus = DecodingStatus::Invalid;
89+
m_lastDecodingOptions = { DecodingMode::Auto };
8990
}
9091

9192
// There's no need to throw away the decoder unless we're explicitly asked
@@ -257,6 +258,7 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des
257258
// it is currently being decoded. New data may have been received since the previous request was made.
258259
if ((!frameIsCompatible && !frameIsBeingDecoded) || m_currentFrameDecodingStatus == DecodingStatus::Invalid) {
259260
LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
261+
m_lastDecodingOptions = { options.decodingMode() };
260262
m_source->requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, sizeForDrawing);
261263
m_currentFrameDecodingStatus = DecodingStatus::Decoding;
262264
}
@@ -300,6 +302,7 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des
300302
}
301303
return ImageDrawResult::DidRequestDecoding;
302304
} else {
305+
m_lastDecodingOptions = { options.decodingMode() };
303306
image = frameImageAtIndexCacheIfNeeded(m_currentFrame, m_currentSubsamplingLevel);
304307
LOG(Images, "BitmapImage::%s - %p - url: %s [an image frame will be decoded synchronously]", __FUNCTION__, this, sourceURL().string().utf8().data());
305308
}
@@ -666,6 +669,11 @@ unsigned BitmapImage::decodeCountForTesting() const
666669
return m_decodeCountForTesting;
667670
}
668671

672+
DecodingOptions BitmapImage::lastDecodingOptions() const
673+
{
674+
return m_lastDecodingOptions;
675+
}
676+
669677
void BitmapImage::dump(TextStream& ts) const
670678
{
671679
Image::dump(ts);

Source/WebCore/platform/graphics/BitmapImage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class BitmapImage final : public Image {
158158

159159
void imageFrameAvailableAtIndex(size_t);
160160
void decode(Function<void()>&&);
161+
WEBCORE_EXPORT DecodingOptions lastDecodingOptions() const;
161162

162163
private:
163164
WEBCORE_EXPORT BitmapImage(Ref<NativeImage>&&);
@@ -258,6 +259,7 @@ class BitmapImage final : public Image {
258259
#endif
259260

260261
unsigned m_decodeCountForTesting { 0 };
262+
DecodingOptions m_lastDecodingOptions { DecodingMode::Auto };
261263

262264
#if USE(APPKIT)
263265
mutable RetainPtr<NSImage> m_nsImage; // A cached NSImage of all the frames. Only built lazily if someone actually queries for one.

Source/WebCore/platform/graphics/DecodingOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ enum class DecodingMode : uint8_t {
4040

4141
class DecodingOptions {
4242
public:
43-
explicit DecodingOptions(DecodingMode decodingMode = DecodingMode::Auto)
43+
DecodingOptions(DecodingMode decodingMode = DecodingMode::Auto)
4444
: m_decodingModeOrSize(decodingMode)
4545
{
4646
}

Source/WebCore/platform/graphics/ImageObserver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class ImageObserver {
4141
public:
4242
virtual URL sourceUrl() const = 0;
4343
virtual String mimeType() const = 0;
44+
virtual unsigned numberOfClients() const { return 0; }
4445
virtual long long expectedContentLength() const = 0;
4546

4647
virtual void encodedDataStatusChanged(const Image&, EncodedDataStatus) { };

Source/WebCore/rendering/RenderBoxModelObject.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,10 @@ DecodingMode RenderBoxModelObject::decodingModeForImageDraw(const Image& image,
325325

326326
// First tile paint.
327327
if (paintInfo.paintBehavior.contains(PaintBehavior::TileFirstPaint)) {
328-
// And the images has not been painted in this element yet.
329-
if (element() && !element()->hasEverPaintedImages())
328+
// No image has been painted in this element yet and it should not flicker with previous painting.
329+
auto observer = bitmapImage.imageObserver();
330+
bool mayOverlapOtherClients = observer && observer->numberOfClients() > 1 && bitmapImage.lastDecodingOptions().isAsynchronous();
331+
if (element() && !element()->hasEverPaintedImages() && !mayOverlapOtherClients)
330332
return DecodingMode::Asynchronous;
331333
}
332334

0 commit comments

Comments
 (0)