| Index: third_party/WebKit/Source/core/fetch/ImageResource.cpp
|
| diff --git a/third_party/WebKit/Source/core/fetch/ImageResource.cpp b/third_party/WebKit/Source/core/fetch/ImageResource.cpp
|
| index 929cb375d24e5dcb1ae3a954288a0506d43996ba..dba77fe8f5ee36c3f854c9ad3502e47b888015f0 100644
|
| --- a/third_party/WebKit/Source/core/fetch/ImageResource.cpp
|
| +++ b/third_party/WebKit/Source/core/fetch/ImageResource.cpp
|
| @@ -46,6 +46,12 @@
|
| #include <v8.h>
|
|
|
| namespace blink {
|
| +namespace {
|
| +// The amount of time to wait before informing the clients that the image has
|
| +// been updated (in seconds). This effectively throttles invalidations that
|
| +// result from new data arriving for this image.
|
| +constexpr double kFlushDelaySeconds = 1.;
|
| +} // namespace
|
|
|
| class ImageResource::ImageResourceFactory : public ResourceFactory {
|
| STACK_ALLOCATED();
|
| @@ -107,7 +113,8 @@ ImageResource::ImageResource(const ResourceRequest& resourceRequest,
|
| m_image(nullptr),
|
| m_hasDevicePixelRatioHeaderValue(false),
|
| m_isSchedulingReload(false),
|
| - m_isPlaceholder(isPlaceholder) {
|
| + m_isPlaceholder(isPlaceholder),
|
| + m_flushTimer(this, &ImageResource::flushImageIfNeeded) {
|
| RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
|
| }
|
|
|
| @@ -118,7 +125,8 @@ ImageResource::ImageResource(blink::Image* image,
|
| m_image(image),
|
| m_hasDevicePixelRatioHeaderValue(false),
|
| m_isSchedulingReload(false),
|
| - m_isPlaceholder(false) {
|
| + m_isPlaceholder(false),
|
| + m_flushTimer(this, &ImageResource::flushImageIfNeeded) {
|
| RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this;
|
| setStatus(Cached);
|
| }
|
| @@ -292,6 +300,41 @@ void ImageResource::appendData(const char* data, size_t length) {
|
| m_multipartParser->appendData(data, length);
|
| } else {
|
| Resource::appendData(data, length);
|
| +
|
| + // If we don't have the size available yet, then update immediately since
|
| + // we need to know the image size as soon as possible. Likewise for
|
| + // animated images, update right away since we shouldn't throttle animated
|
| + // images.
|
| + if (m_sizeAvailable == Image::SizeUnavailable ||
|
| + (m_image && m_image->maybeAnimated())) {
|
| + updateImage(false);
|
| + return;
|
| + }
|
| +
|
| + // For other cases, only update at |kFlushDelaySeconds| intervals. This
|
| + // throttles how frequently we update |m_image| and how frequently we
|
| + // inform the clients which causes an invalidation of this image. In other
|
| + // words, we only invalidate this image every |kFlushDelaySeconds| seconds
|
| + // while loading.
|
| + if (!m_flushTimer.isActive()) {
|
| + double now = WTF::monotonicallyIncreasingTime();
|
| + if (!m_lastFlushTime)
|
| + m_lastFlushTime = now;
|
| +
|
| + DCHECK_LE(m_lastFlushTime, now);
|
| + double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds;
|
| + if (flushDelay < 0.)
|
| + flushDelay = 0.;
|
| + m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ImageResource::flushImageIfNeeded(TimerBase*) {
|
| + // We might have already loaded the image fully, in which case we don't need
|
| + // to call |updateImage()|.
|
| + if (isLoading()) {
|
| + m_lastFlushTime = WTF::monotonicallyIncreasingTime();
|
| updateImage(false);
|
| }
|
| }
|
| @@ -414,6 +457,7 @@ inline void ImageResource::clearImage() {
|
| // pointer before dropping our reference.
|
| m_image->clearImageObserver();
|
| m_image.clear();
|
| + m_sizeAvailable = Image::SizeUnavailable;
|
| }
|
|
|
| void ImageResource::updateImage(bool allDataReceived) {
|
| @@ -422,24 +466,22 @@ void ImageResource::updateImage(bool allDataReceived) {
|
| if (data())
|
| createImage();
|
|
|
| - Image::SizeAvailability sizeAvailable = Image::SizeUnavailable;
|
| -
|
| // Have the image update its data from its internal buffer. It will not do
|
| // anything now, but will delay decoding until queried for info (like size or
|
| // specific image frames).
|
| if (data()) {
|
| DCHECK(m_image);
|
| - sizeAvailable = m_image->setData(data(), allDataReceived);
|
| + m_sizeAvailable = m_image->setData(data(), allDataReceived);
|
| }
|
|
|
| // Go ahead and tell our observers to try to draw if we have either received
|
| // all the data or the size is known. Each chunk from the network causes
|
| // observers to repaint, which will force that chunk to decode.
|
| - if (sizeAvailable == Image::SizeUnavailable && !allDataReceived)
|
| + if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived)
|
| return;
|
|
|
| if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) {
|
| - if (sizeAvailable == Image::SizeAvailable) {
|
| + if (m_sizeAvailable == Image::SizeAvailable) {
|
| // TODO(sclittle): Show the original image if the response consists of the
|
| // entire image, such as if the entire image response body is smaller than
|
| // the requested range.
|
|
|