Changeset 213618 in webkit
- Timestamp:
- Mar 8, 2017 6:16:51 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 25 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r213616 r213618 1 2017-03-08 Said Abou-Hallawa <sabouhallawa@apple.com> 2 3 Enable async image decoding for large images 4 https://bugs.webkit.org/show_bug.cgi?id=165039 5 6 Reviewed by Simon Fraser. 7 8 Once FrameView finishes flushing compositing, it will request all its 9 images, which intersect with the tileCoverageRect (aka the futureRect) 10 of the TileController, to start asynchronously decoding their image frames. 11 This should improve the image first time paint and the scrolling scenarios. 12 It also makes the scrolling more responsive by removing the decoding step 13 from the main thread. 14 15 For now we are going to disable the asynchronous image decoding for the 16 webkit test runner because drawing the image does not block the page rendering 17 anymore. An image can be repainted later when its frame is ready for painting. 18 This can cause a test to fail because the webkit test runner may capture 19 an image for the page before painting all the images. The asynchronous image 20 decoding can to be explicitly enabled from the test page. Once the specs 21 of the image 'async' attribute and 'ready' event is approved, this should 22 be revisited. It is important to test what we ship and eventually async 23 image decoding should be enabled in the webkit test runner. 24 25 * html/HTMLImageElement.cpp: 26 (WebCore::HTMLImageElement::didAttachRenderers): 27 (WebCore::HTMLImageElement::willDetachRenderers): 28 Register/unregister the renderer of the HTMLImageElement for async image decoding 29 from the RenderView. I followed what HTMLMediaElement to registerForVisibleInViewportCallback(). 30 * html/HTMLImageElement.h: 31 32 * page/FrameView.cpp: 33 (WebCore::FrameView::flushCompositingStateForThisFrame): For all the images inside 34 the tileCoverageRect of the TileController, request async image decoding. 35 (WebCore::FrameView::applyRecursivelyWithAbsoluteRect): Request the async image decoding for the 36 the images inside this FrameView and then recursively do the same thing for all sub FrameViews. 37 (WebCore::FrameView::requestAsyncDecodingForImagesInAbsoluteRect): Calls the RenderView to 38 make the request. 39 (WebCore::FrameView::requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes): Calls 40 applyRecursivelyWithAbsoluteRect giving an apply lambda which calls requestAsyncDecodingForImagesInAbsoluteRect. 41 * page/FrameView.h: 42 43 * platform/graphics/BitmapImage.cpp: 44 (WebCore::BitmapImage::destroyDecodedData): ImageSource::hasDecodingQueue() is renamed to ImageSource::hasAsyncDecodingQueue(). 45 (WebCore::BitmapImage::dataChanged): Use String::utf8().data() instead of String::characters8(). 46 (WebCore::BitmapImage::draw): If drawing the current frame is called while it is being 47 decoded, draw the the image if the current frame was decoded but for a different size 48 and and will not invoke decoding while painting. If the frame is being decoded and there 49 isn't a decoded frame, return without drawing but set a flag that that this image needs 50 a repaint. 51 (WebCore::BitmapImage::internalStartAnimation): Use String::utf8().data() instead of String::characters8(). 52 (WebCore::BitmapImage::advanceAnimation): Ditto. 53 (WebCore::BitmapImage::internalAdvanceAnimation): Ditto. 54 (WebCore::BitmapImage::newFrameNativeImageAvailableAtIndex): Now this callback can be 55 called form the ImageFrameCache when finishing a frame of an animated image or the 56 frame of a large image. For large images, we need to call CachedImage::changedInRect() 57 if this image needs a repaint. If the decoding queue is idle, we should close it. 58 (WebCore::BitmapImage::requestAsyncDecoding): This is called form 59 RenderView::requestAsyncDecodingForImagesInRect(). 60 * platform/graphics/BitmapImage.h: 61 62 * platform/graphics/Image.h: 63 (WebCore::Image::requestAsyncDecoding): Add the default implementation of a virtual function. 64 65 * platform/graphics/ImageFrameCache.cpp: 66 (WebCore::ImageFrameCache::~ImageFrameCache): hasDecodingQueue() was renamed to hasAsyncDecodingQueue(). 67 (WebCore::ImageFrameCache::decodingQueue): Change the QNS of the decoding thread to be WorkQueue::QOS::Default. 68 WorkQueue::QOS::UserInteractive causes the scrolling thread to preempted which can make the scrolling choppy. 69 (WebCore::ImageFrameCache::startAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue(). 70 (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Ditto. 71 (WebCore::ImageFrameCache::isAsyncDecodingQueueIdle): A helper function to tell whether the decoding thread is idle. 72 (WebCore::ImageFrameCache::stopAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue(). 73 * platform/graphics/ImageFrameCache.h: 74 (WebCore::ImageFrameCache::hasAsyncDecodingQueue): Rename this function to be consistent with the rest of the functions. 75 (WebCore::ImageFrameCache::hasDecodingQueue): Deleted. 76 77 * platform/graphics/ImageSource.h: 78 (WebCore::ImageSource::hasAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue(). 79 (WebCore::ImageSource::isAsyncDecodingQueueIdle): A wrapper for ImageFrameCache::isAsyncDecodingQueueIdle(). 80 (WebCore::ImageSource::hasDecodingQueue): Deleted. 81 82 * platform/graphics/TiledBacking.h: Fix a comment. tileGridExtent() is the only one that is used for testing. 83 84 * rendering/RenderElement.cpp: 85 (WebCore::RenderElement::~RenderElement): 86 (WebCore::RenderElement::intersectsAbsoluteRect): Make this function does what shouldRepaintForImageAnimation() 87 was doing expect the check for document.activeDOMObjectsAreSuspended(). 88 (WebCore::RenderElement::newImageAnimationFrameAvailable): Replace the call to 89 shouldRepaintForImageAnimation() by checking document().activeDOMObjectsAreSuspended() then a call to 90 RenderElement::intersectsAbsoluteRect(). 91 (WebCore::RenderElement::repaintForPausedImageAnimationsIfNeeded): Ditto. 92 (WebCore::RenderElement::registerForAsyncImageDecodingCallback): Call the RenderView to register the renderer.. 93 (WebCore::RenderElement::unregisterForAsyncImageDecodingCallback): Call the RenderView to unregister the renderer.. 94 (WebCore::shouldRepaintForImageAnimation): Deleted. 95 * rendering/RenderElement.h: 96 97 * rendering/RenderObject.cpp: 98 (WebCore::RenderObject::setIsRegisteredForAsyncImageDecodingCallback): 99 * rendering/RenderObject.h: 100 (WebCore::RenderObject::isRegisteredForAsyncImageDecodingCallback): 101 (WebCore::RenderObject::RenderObjectRareData::RenderObjectRareData): 102 Mark/unmark the renderer for being RegisteredForAsyncImageDecodingCallback. 103 104 * rendering/RenderReplaced.h: Make intrinsicSize() be a public function. 105 106 * rendering/RenderView.cpp: 107 (WebCore::RenderView::registerForAsyncImageDecodingCallback): Register a renderer for async image decoding. 108 (WebCore::RenderView::unregisterForAsyncImageDecodingCallback): Remove a renderer from the list of async image decoding. 109 (WebCore::RenderView::requestAsyncDecodingForImagesInAbsoluteRect):This loops through all the registered RenderImages 110 inside this RenderView and if any of them intersects with the rectangle, requestAsyncDecoding for it. 111 * rendering/RenderView.h: 112 1 113 2017-03-08 Michael Catanzaro <mcatanzaro@igalia.com> 2 114 -
trunk/Source/WebCore/html/HTMLImageElement.cpp
r211964 r213618 290 290 if (!m_imageLoader.image() && !renderImageResource.cachedImage()) 291 291 renderImage.setImageSizeForAltText(); 292 293 renderImage.registerForAsyncImageDecodingCallback(); 294 } 295 296 void HTMLImageElement::willDetachRenderers() 297 { 298 if (!is<RenderImage>(renderer())) 299 return; 300 301 renderer()->unregisterForAsyncImageDecodingCallback(); 292 302 } 293 303 -
trunk/Source/WebCore/html/HTMLImageElement.h
r209810 r213618 106 106 107 107 void didAttachRenderers() override; 108 void willDetachRenderers() override; 108 109 RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override; 109 110 void setBestFitURLAndDPRFromImageCandidate(const ImageCandidate&); -
trunk/Source/WebCore/page/FrameView.cpp
r213214 r213618 1059 1059 1060 1060 renderView->compositor().flushPendingLayerChanges(&rootFrameForFlush == m_frame.ptr()); 1061 1062 if (TiledBacking* tiledBacking = this->tiledBacking()) 1063 requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes(tiledBacking->tileCoverageRect()); 1064 1061 1065 return true; 1062 1066 } … … 2528 2532 viewportContentsChanged(); 2529 2533 } 2534 2535 void FrameView::applyRecursivelyWithAbsoluteRect(const IntRect& rect, const std::function<void(FrameView&, const IntRect&)>& apply) 2536 { 2537 apply(*this, rect); 2538 2539 // Recursive call for subframes. We cache the current FrameView's windowClipRect to avoid recomputing it for every subframe. 2540 IntRect windowClipRect = contentsToWindow(rect); 2541 SetForScope<IntRect*> windowClipRectCache(m_cachedWindowClipRect, &windowClipRect); 2542 for (Frame* childFrame = frame().tree().firstChild(); childFrame; childFrame = childFrame->tree().nextSibling()) { 2543 if (auto* childView = childFrame->view()) 2544 childView->applyRecursivelyWithAbsoluteRect(rect, apply); 2545 } 2546 } 2530 2547 2531 2548 void FrameView::applyRecursivelyWithVisibleRect(const std::function<void (FrameView& frameView, const IntRect& visibleRect)>& apply) … … 2579 2596 applyRecursivelyWithVisibleRect([] (FrameView& frameView, const IntRect& visibleRect) { 2580 2597 frameView.resumeVisibleImageAnimations(visibleRect); 2598 }); 2599 } 2600 2601 void FrameView::requestAsyncDecodingForImagesInAbsoluteRect(const IntRect& rect) 2602 { 2603 if (!frame().view()) { 2604 // The frame is being destroyed. 2605 return; 2606 } 2607 2608 if (rect.isEmpty()) 2609 return; 2610 2611 if (auto* renderView = frame().contentRenderer()) 2612 renderView->requestAsyncDecodingForImagesInAbsoluteRect(rect); 2613 } 2614 2615 void FrameView::requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes(const IntRect& rect) 2616 { 2617 if (!frame().settings().largeImageAsyncDecodingEnabled()) 2618 return; 2619 2620 applyRecursivelyWithAbsoluteRect(rect, [] (FrameView& frameView, const IntRect& rect) { 2621 frameView.requestAsyncDecodingForImagesInAbsoluteRect(rect); 2581 2622 }); 2582 2623 } -
trunk/Source/WebCore/page/FrameView.h
r211910 r213618 276 276 void viewportContentsChanged(); 277 277 WEBCORE_EXPORT void resumeVisibleImageAnimationsIncludingSubframes(); 278 void requestAsyncDecodingForImagesInAbsoluteRectIncludingSubframes(const IntRect&); 278 279 279 280 String mediaType() const; … … 646 647 void autoSizeIfEnabled(); 647 648 649 void applyRecursivelyWithAbsoluteRect(const IntRect&, const std::function<void(FrameView& frameView, const IntRect& rect)>&); 648 650 void applyRecursivelyWithVisibleRect(const std::function<void (FrameView& frameView, const IntRect& visibleRect)>&); 649 651 void resumeVisibleImageAnimations(const IntRect& visibleRect); 650 652 void updateScriptedAnimationsAndTimersThrottlingState(const IntRect& visibleRect); 653 void requestAsyncDecodingForImagesInAbsoluteRect(const IntRect&); 651 654 652 655 void updateLayerFlushThrottling(); -
trunk/Source/WebCore/platform/graphics/BitmapImage.cpp
r213563 r213618 68 68 if (!destroyAll) 69 69 m_source.destroyDecodedDataBeforeFrame(m_currentFrame); 70 else if (m_source.has DecodingQueue())70 else if (m_source.hasAsyncDecodingQueue()) 71 71 m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame); 72 72 else … … 75 75 // There's no need to throw away the decoder unless we're explicitly asked 76 76 // to destroy all of the frames. 77 if (!destroyAll || m_source.has DecodingQueue())77 if (!destroyAll || m_source.hasAsyncDecodingQueue()) 78 78 m_source.clearFrameBufferCache(m_currentFrame); 79 79 else … … 104 104 { 105 105 if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing)) { 106 LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL(). characters8(), static_cast<int>(frameSubsamplingLevelAtIndex(index)));106 LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL().utf8().data(), static_cast<int>(frameSubsamplingLevelAtIndex(index))); 107 107 invalidatePlatformData(); 108 108 } … … 165 165 StartAnimationResult result = internalStartAnimation(); 166 166 167 Color color; 168 if (result == StartAnimationResult::DecodingActive && showDebugBackground()) 169 color = Color::yellow; 170 else 171 color = singlePixelSolidColor(); 172 167 if (result == StartAnimationResult::DecodingActive && showDebugBackground()) { 168 fillWithSolidColor(context, destRect, Color::yellow, op); 169 return; 170 } 171 172 NativeImagePtr image; 173 if (frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing)) { 174 ASSERT(!canAnimate() && !m_currentFrame); 175 m_needsRepaint = true; 176 177 if (!frameHasDecodedNativeImage(m_currentFrame)) { 178 if (showDebugBackground()) 179 fillWithSolidColor(context, destRect, Color::yellow, op); 180 return; 181 } 182 183 image = frameImageAtIndex(m_currentFrame); 184 } else { 185 float scale = subsamplingScale(context, destRect, srcRect); 186 m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default; 187 LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel = %d scale = %.4f]", __FUNCTION__, this, sourceURL().utf8().data(), static_cast<int>(m_currentSubsamplingLevel), scale); 188 189 ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing)); 190 image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &context); 191 } 192 193 if (!image) // If it's too early we won't have an image yet. 194 return; 195 196 Color color = singlePixelSolidColor(); 173 197 if (color.isValid()) { 174 198 fillWithSolidColor(context, destRect, color, op); 175 199 return; 176 200 } 177 178 float scale = subsamplingScale(context, destRect, srcRect);179 m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;180 LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld subsamplingLevel = %d scale = %.4f]", __FUNCTION__, this, sourceURL().characters8(), m_currentFrame, static_cast<int>(m_currentSubsamplingLevel), scale);181 182 ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));183 auto image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &context);184 if (!image) // If it's too early we won't have an image yet.185 return;186 201 187 202 ImageOrientation orientation(description.imageOrientation()); … … 268 283 if (m_frameTimer) 269 284 return StartAnimationResult::TimerActive; 270 285 271 286 // Don't start a new animation until we draw the frame that is currently being decoded. 272 287 size_t nextFrame = (m_currentFrame + 1) % frameCount(); 273 288 if (frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing)) { 274 LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL(). characters8(), nextFrame);289 LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL().utf8().data(), nextFrame); 275 290 return StartAnimationResult::DecodingActive; 276 291 } … … 318 333 #if !LOG_DISABLED 319 334 if (isAsyncDecode) 320 LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL(). characters8(), nextFrame);335 LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), nextFrame); 321 336 else 322 LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL(). characters8(), ++m_cachedFrameCount, nextFrame);337 LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), ++m_cachedFrameCount, nextFrame); 323 338 #else 324 339 UNUSED_PARAM(isAsyncDecode); … … 347 362 } 348 363 } 349 364 350 365 // Don't advance to nextFrame unless its decoding has finished or was not required. 351 366 size_t nextFrame = (m_currentFrame + 1) % frameCount(); … … 356 371 if (showDebugBackground()) 357 372 imageObserver()->changedInRect(this); 358 LOG(Images, "BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL(). characters8(), ++m_lateFrameCount, nextFrame);373 LOG(Images, "BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), ++m_lateFrameCount, nextFrame); 359 374 } 360 375 } … … 370 385 imageObserver()->animationAdvanced(this); 371 386 372 LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL(). characters8(), m_currentFrame);387 LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), m_currentFrame); 373 388 } 374 389 … … 396 411 { 397 412 UNUSED_PARAM(index); 398 ASSERT(index == (m_currentFrame + 1) % frameCount()); 399 400 // Don't advance to nextFrame unless the timer was fired before its decoding finishes. 401 if (canAnimate() && !m_frameTimer) 402 internalAdvanceAnimation(); 403 else 404 LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), ++m_earlyFrameCount, index); 413 if (canAnimate()) { 414 ASSERT(index == (m_currentFrame + 1) % frameCount()); 415 416 // Don't advance to nextFrame unless the timer was fired before its decoding finishes. 417 if (canAnimate() && !m_frameTimer) 418 internalAdvanceAnimation(); 419 else 420 LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), ++m_earlyFrameCount, index); 421 } else { 422 ASSERT(index == m_currentFrame && !m_currentFrame); 423 424 if (m_needsRepaint) { 425 imageObserver()->changedInRect(this, nullptr); 426 m_needsRepaint = false; 427 } 428 429 // Keep the number of decoding threads under control. 430 if (m_source.isAsyncDecodingQueueIdle()) 431 m_source.stopAsyncDecodingQueue(); 432 } 433 } 434 435 void BitmapImage::requestAsyncDecoding(const IntSize& sizeForDrawing) 436 { 437 if (!isLargeImageAsyncDecodingRequired()) 438 return; 439 440 ASSERT(!m_currentFrame); 441 bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing); 442 443 #if !LOG_DISABLED 444 if (isAsyncDecode) 445 LOG(Images, "BitmapImage::%s - %p - url: %s", __FUNCTION__, this, sourceURL().utf8().data()); 446 #else 447 UNUSED_PARAM(isAsyncDecode); 448 #endif 405 449 } 406 450 -
trunk/Source/WebCore/platform/graphics/BitmapImage.h
r213563 r213618 174 174 void resetAnimation() override; 175 175 void newFrameNativeImageAvailableAtIndex(size_t) override; 176 void requestAsyncDecoding(const IntSize& sizeForDrawing) override; 176 177 177 178 // Handle platform-specific data … … 208 209 double m_desiredFrameStartTime { 0 }; // The system time at which we hope to see the next call to startAnimation(). 209 210 bool m_animationFinished { false }; 211 bool m_needsRepaint { false }; 210 212 211 213 float m_frameDecodingDurationForTesting { 0 }; -
trunk/Source/WebCore/platform/graphics/Image.h
r212484 r213618 131 131 virtual void resetAnimation() {} 132 132 virtual void newFrameNativeImageAvailableAtIndex(size_t) { } 133 virtual void requestAsyncDecoding(const IntSize&) { } 133 134 134 135 // Typically the CachedImage that owns us. -
trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp
r213563 r213618 68 68 ImageFrameCache::~ImageFrameCache() 69 69 { 70 ASSERT(!has DecodingQueue());70 ASSERT(!hasAsyncDecodingQueue()); 71 71 } 72 72 … … 257 257 { 258 258 if (!m_decodingQueue) 259 m_decodingQueue = WorkQueue::create("org.webkit.ImageDecoder", WorkQueue::Type::Serial, WorkQueue::QOS:: UserInteractive);259 m_decodingQueue = WorkQueue::create("org.webkit.ImageDecoder", WorkQueue::Type::Serial, WorkQueue::QOS::Default); 260 260 261 261 return *m_decodingQueue; … … 264 264 void ImageFrameCache::startAsyncDecodingQueue() 265 265 { 266 if (has DecodingQueue() || !isDecoderAvailable())266 if (hasAsyncDecodingQueue() || !isDecoderAvailable()) 267 267 return; 268 268 … … 307 307 return false; 308 308 309 if (!has DecodingQueue())309 if (!hasAsyncDecodingQueue()) 310 310 startAsyncDecodingQueue(); 311 311 … … 315 315 } 316 316 317 bool ImageFrameCache::isAsyncDecodingQueueIdle() const 318 { 319 for (const ImageFrame& frame : m_frames) { 320 if (frame.isBeingDecoded()) 321 return false; 322 } 323 return true; 324 } 325 317 326 void ImageFrameCache::stopAsyncDecodingQueue() 318 327 { 319 if (!has DecodingQueue())328 if (!hasAsyncDecodingQueue()) 320 329 return; 321 330 -
trunk/Source/WebCore/platform/graphics/ImageFrameCache.h
r213563 r213618 72 72 bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const IntSize&); 73 73 void stopAsyncDecodingQueue(); 74 bool hasDecodingQueue() { return m_decodingQueue; } 74 bool hasAsyncDecodingQueue() const { return m_decodingQueue; } 75 bool isAsyncDecodingQueueIdle() const; 75 76 76 77 // Image metadata which is calculated either by the ImageDecoder or directly -
trunk/Source/WebCore/platform/graphics/ImageSource.h
r213563 r213618 71 71 bool isAsyncDecodingRequired(); 72 72 bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); } 73 bool hasDecodingQueue() const { return m_frameCache->hasDecodingQueue(); } 73 bool hasAsyncDecodingQueue() const { return m_frameCache->hasAsyncDecodingQueue(); } 74 bool isAsyncDecodingQueueIdle() const { return m_frameCache->isAsyncDecodingQueueIdle(); } 74 75 void stopAsyncDecodingQueue() { m_frameCache->stopAsyncDecodingQueue(); } 75 76 -
trunk/Source/WebCore/platform/graphics/TiledBacking.h
r211910 r213618 146 146 virtual IntRect boundsWithoutMargin() const = 0; 147 147 148 virtual IntRect tileCoverageRect() const = 0; 149 virtual void setScrollingModeIndication(ScrollingModeIndication) = 0; 150 148 151 // Exposed for testing 149 virtual IntRect tileCoverageRect() const = 0;150 152 virtual IntRect tileGridExtent() const = 0; 151 virtual void setScrollingModeIndication(ScrollingModeIndication) = 0;152 153 153 154 #if USE(CA) -
trunk/Source/WebCore/rendering/RenderElement.cpp
r213455 r213618 155 155 if (isRegisteredForVisibleInViewportCallback()) 156 156 view().unregisterForVisibleInViewportCallback(*this); 157 if (isRegisteredForAsyncImageDecodingCallback()) 158 view().unregisterForAsyncImageDecodingCallback(*this); 157 159 } 158 160 … … 1435 1437 } 1436 1438 1437 static bool shouldRepaintForImageAnimation(const RenderElement& renderer, const IntRect& visibleRect) 1438 { 1439 const Document& document = renderer.document(); 1440 if (document.activeDOMObjectsAreSuspended()) 1439 bool RenderElement::intersectsAbsoluteRect(const IntRect& rect) const 1440 { 1441 if (style().visibility() != VISIBLE) 1441 1442 return false; 1442 if (renderer.style().visibility() != VISIBLE) 1443 return false; 1444 if (renderer.view().frameView().isOffscreen()) 1443 if (view().frameView().isOffscreen()) 1445 1444 return false; 1446 1445 … … 1449 1448 // be propagated to the root. At this point, we unfortunately don't have access to the image anymore so we 1450 1449 // can no longer check if it is a background image. 1451 bool backgroundIsPaintedByRoot = renderer.isDocumentElementRenderer();1452 if ( renderer.isBody()) {1453 auto& rootRenderer = * renderer.parent(); // If <body> has a renderer then <html> does too.1450 bool backgroundIsPaintedByRoot = isDocumentElementRenderer(); 1451 if (isBody()) { 1452 auto& rootRenderer = *parent(); // If <body> has a renderer then <html> does too. 1454 1453 ASSERT(rootRenderer.isDocumentElementRenderer()); 1455 1454 ASSERT(is<HTMLHtmlElement>(rootRenderer.element())); … … 1458 1457 1459 1458 } 1460 LayoutRect backgroundPaintingRect = backgroundIsPaintedByRoot ? renderer.view().backgroundRect() : renderer.absoluteClippedOverflowRect(); 1461 if (!visibleRect.intersects(enclosingIntRect(backgroundPaintingRect))) 1462 return false; 1463 1464 return true; 1459 LayoutRect backgroundPaintingRect = backgroundIsPaintedByRoot ? view().backgroundRect() : absoluteClippedOverflowRect(); 1460 return rect.intersects(enclosingIntRect(backgroundPaintingRect)); 1465 1461 } 1466 1462 … … 1497 1493 auto& frameView = view().frameView(); 1498 1494 auto visibleRect = frameView.windowToContents(frameView.windowClipRect()); 1499 if ( !shouldRepaintForImageAnimation(*this,visibleRect)) {1495 if (document().activeDOMObjectsAreSuspended() || !intersectsAbsoluteRect(visibleRect)) { 1500 1496 // FIXME: It would be better to pass the image along with the renderer 1501 1497 // so that we can be smarter about detecting if the image is inside the … … 1510 1506 { 1511 1507 ASSERT(m_hasPausedImageAnimations); 1512 if ( !shouldRepaintForImageAnimation(*this,visibleRect))1508 if (document().activeDOMObjectsAreSuspended() || !intersectsAbsoluteRect(visibleRect)) 1513 1509 return false; 1514 1510 … … 1520 1516 1521 1517 return true; 1518 } 1519 1520 void RenderElement::registerForAsyncImageDecodingCallback() 1521 { 1522 if (isRegisteredForAsyncImageDecodingCallback()) 1523 return; 1524 1525 view().registerForAsyncImageDecodingCallback(*this); 1526 setIsRegisteredForAsyncImageDecodingCallback(true); 1527 } 1528 1529 void RenderElement::unregisterForAsyncImageDecodingCallback() 1530 { 1531 if (!isRegisteredForAsyncImageDecodingCallback()) 1532 return; 1533 1534 view().unregisterForAsyncImageDecodingCallback(*this); 1535 setIsRegisteredForAsyncImageDecodingCallback(false); 1522 1536 } 1523 1537 -
trunk/Source/WebCore/rendering/RenderElement.h
r213455 r213618 139 139 bool borderImageIsLoadedAndCanBeRendered() const; 140 140 bool mayCauseRepaintInsideViewport(const IntRect* visibleRect = nullptr) const; 141 bool intersectsAbsoluteRect(const IntRect&) const; 141 142 142 143 // Returns true if this renderer requires a new stacking context. … … 191 192 bool hasPausedImageAnimations() const { return m_hasPausedImageAnimations; } 192 193 void setHasPausedImageAnimations(bool b) { m_hasPausedImageAnimations = b; } 194 195 void registerForAsyncImageDecodingCallback(); 196 void unregisterForAsyncImageDecodingCallback(); 193 197 194 198 void setRenderBoxNeedsLazyRepaint(bool b) { m_renderBoxNeedsLazyRepaint = b; } -
trunk/Source/WebCore/rendering/RenderObject.cpp
r213455 r213618 1996 1996 ensureRareData().setVisibleInViewportState(visible); 1997 1997 } 1998 1999 void RenderObject::setIsRegisteredForAsyncImageDecodingCallback(bool registered) 2000 { 2001 if (registered || hasRareData()) 2002 ensureRareData().setIsRegisteredForAsyncImageDecodingCallback(registered); 2003 } 1998 2004 1999 2005 RenderObject::RareDataMap& RenderObject::rareDataMap() -
trunk/Source/WebCore/rendering/RenderObject.h
r213455 r213618 459 459 }; 460 460 VisibleInViewportState visibleInViewportState() { return m_bitfields.hasRareData() ? rareData().visibleInViewportState() : VisibilityUnknown; } 461 462 bool isRegisteredForAsyncImageDecodingCallback() { return m_bitfields.hasRareData() && rareData().isRegisteredForAsyncImageDecodingCallback(); } 461 463 462 464 bool hasLayer() const { return m_bitfields.hasLayer(); } … … 570 572 void setIsRegisteredForVisibleInViewportCallback(bool); 571 573 void setVisibleInViewportState(VisibleInViewportState); 574 void setIsRegisteredForAsyncImageDecodingCallback(bool); 572 575 573 576 // Hook so that RenderTextControl can return the line height of its inner renderer. … … 986 989 , m_isRegisteredForVisibleInViewportCallback(false) 987 990 , m_visibleInViewportState(VisibilityUnknown) 991 , m_isRegisteredForAsyncImageDecodingCallback(false) 988 992 { 989 993 } … … 996 1000 ADD_BOOLEAN_BITFIELD(isRegisteredForVisibleInViewportCallback, IsRegisteredForVisibleInViewportCallback); 997 1001 ADD_ENUM_BITFIELD(visibleInViewportState, VisibleInViewportState, VisibleInViewportState, 2); 1002 ADD_BOOLEAN_BITFIELD(isRegisteredForAsyncImageDecodingCallback, IsRegisteredForAsyncImageDecodingCallback); 998 1003 std::unique_ptr<RenderStyle> cachedFirstLineStyle; 999 1004 }; -
trunk/Source/WebCore/rendering/RenderReplaced.h
r208668 r213618 33 33 LayoutUnit computeReplacedLogicalHeight() const override; 34 34 35 LayoutSize intrinsicSize() const final { return m_intrinsicSize; } 35 36 LayoutRect replacedContentRect(const LayoutSize& intrinsicSize) const; 36 37 … … 46 47 void layout() override; 47 48 48 LayoutSize intrinsicSize() const final { return m_intrinsicSize; }49 49 void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const override; 50 50 -
trunk/Source/WebCore/rendering/RenderView.cpp
r212843 r213618 36 36 #include "HTMLIFrameElement.h" 37 37 #include "HitTestResult.h" 38 #include "Image.h" 38 39 #include "ImageQualityController.h" 39 40 #include "NodeTraversal.h" 40 41 #include "Page.h" 42 #include "RenderDescendantIterator.h" 41 43 #include "RenderGeometryMap.h" 44 #include "RenderImage.h" 42 45 #include "RenderIterator.h" 43 46 #include "RenderLayer.h" … … 1422 1425 } 1423 1426 1427 void RenderView::registerForAsyncImageDecodingCallback(RenderElement& renderer) 1428 { 1429 ASSERT(!m_asyncDecodingImageRenderers.contains(&renderer)); 1430 m_asyncDecodingImageRenderers.add(&renderer); 1431 } 1432 1433 void RenderView::unregisterForAsyncImageDecodingCallback(RenderElement& renderer) 1434 { 1435 ASSERT(m_asyncDecodingImageRenderers.contains(&renderer)); 1436 m_asyncDecodingImageRenderers.remove(&renderer); 1437 } 1438 1439 void RenderView::requestAsyncDecodingForImagesInAbsoluteRect(const IntRect& rect) 1440 { 1441 for (auto* renderer : m_asyncDecodingImageRenderers) { 1442 if (!renderer->intersectsAbsoluteRect(rect)) 1443 continue; 1444 1445 auto& renderImage = downcast<RenderImage>(*renderer); 1446 1447 CachedImage* image = renderImage.cachedImage(); 1448 if (!image || !image->hasImage()) 1449 continue; 1450 1451 // Get the destination rectangle of the image scaled by the all the scaling factors 1452 // that will eventually be applied to the graphics context. 1453 LayoutRect replacedContentRect = renderImage.replacedContentRect(renderImage.intrinsicSize()); 1454 FloatRect rect = snapRectToDevicePixels(replacedContentRect, document().deviceScaleFactor()); 1455 rect.scale(frame().page()->pageScaleFactor() * frame().pageZoomFactor() * document().deviceScaleFactor()); 1456 1457 image->image()->requestAsyncDecoding(expandedIntSize(rect.size())); 1458 } 1459 } 1460 1424 1461 RenderView::RepaintRegionAccumulator::RepaintRegionAccumulator(RenderView* view) 1425 1462 : m_rootView(view ? view->document().topDocument().renderView() : nullptr) -
trunk/Source/WebCore/rendering/RenderView.h
r212843 r213618 232 232 void addRendererWithPausedImageAnimations(RenderElement&); 233 233 void removeRendererWithPausedImageAnimations(RenderElement&); 234 void registerForAsyncImageDecodingCallback(RenderElement&); 235 void unregisterForAsyncImageDecodingCallback(RenderElement&); 236 void requestAsyncDecodingForImagesInAbsoluteRect(const IntRect&); 234 237 235 238 class RepaintRegionAccumulator { … … 389 392 HashSet<RenderElement*> m_renderersWithPausedImageAnimation; 390 393 HashSet<RenderElement*> m_visibleInViewportRenderers; 394 HashSet<RenderElement*> m_asyncDecodingImageRenderers; 391 395 Vector<RefPtr<RenderWidget>> m_protectedRenderWidgets; 392 396 -
trunk/Source/WebKit2/ChangeLog
r213614 r213618 1 2017-03-08 Said Abou-Hallawa <sabouhallawa@apple.com> 2 3 Enable async image decoding for large images 4 https://bugs.webkit.org/show_bug.cgi?id=165039 5 6 Reviewed by Simon Fraser. 7 8 Add WK2 preferences for setting/getting LargeImageAsyncDecoding and 9 AnimatedImageAsyncDecoding. 10 11 * UIProcess/API/C/WKPreferences.cpp: 12 (WKPreferencesSetLargeImageAsyncDecodingEnabled): 13 (WKPreferencesGetLargeImageAsyncDecodingEnabled): 14 (WKPreferencesSetAnimatedImageAsyncDecodingEnabled): 15 (WKPreferencesGetAnimatedImageAsyncDecodingEnabled): 16 * UIProcess/API/C/WKPreferencesRefPrivate.h: 17 1 18 2017-03-08 Wenson Hsieh <wenson_hsieh@apple.com> 2 19 -
trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp
r213283 r213618 1682 1682 } 1683 1683 1684 void WKPreferencesSetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag) 1685 { 1686 toImpl(preferencesRef)->setLargeImageAsyncDecodingEnabled(flag); 1687 } 1688 1689 bool WKPreferencesGetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef) 1690 { 1691 return toImpl(preferencesRef)->largeImageAsyncDecodingEnabled(); 1692 } 1693 1694 void WKPreferencesSetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag) 1695 { 1696 toImpl(preferencesRef)->setAnimatedImageAsyncDecodingEnabled(flag); 1697 } 1698 1699 bool WKPreferencesGetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef) 1700 { 1701 return toImpl(preferencesRef)->animatedImageAsyncDecodingEnabled(); 1702 } 1703 1684 1704 void WKPreferencesSetShouldSuppressKeyboardInputDuringProvisionalNavigation(WKPreferencesRef preferencesRef, bool flag) 1685 1705 { -
trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h
r213283 r213618 466 466 WK_EXPORT bool WKPreferencesGetSubtleCryptoEnabled(WKPreferencesRef); 467 467 468 // Defaults to true. 469 WK_EXPORT void WKPreferencesSetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag); 470 WK_EXPORT bool WKPreferencesGetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef); 471 472 // Defaults to true. 473 WK_EXPORT void WKPreferencesSetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag); 474 WK_EXPORT bool WKPreferencesGetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef); 475 468 476 // Defaults to false 469 477 WK_EXPORT void WKPreferencesSetShouldSuppressKeyboardInputDuringProvisionalNavigation(WKPreferencesRef, bool flag); -
trunk/Tools/ChangeLog
r213586 r213618 1 2017-03-08 Said Abou-Hallawa <sabouhallawa@apple.com> 2 3 Enable async image decoding for large images 4 https://bugs.webkit.org/show_bug.cgi?id=165039 5 6 Reviewed by Simon Fraser. 7 8 Disable LargeImageAsyncDecoding for DRT/WTR. 9 10 * DumpRenderTree/mac/DumpRenderTree.mm: 11 (resetWebPreferencesToConsistentValues): 12 * WebKitTestRunner/TestController.cpp: 13 (WTR::TestController::resetPreferencesToConsistentValues): 14 1 15 2017-03-08 Matt Rajca <mrajca@apple.com> 2 16 -
trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm
r213410 r213618 956 956 957 957 [preferences setMediaStreamEnabled:YES]; 958 959 [preferences setLargeImageAsyncDecodingEnabled:NO]; 958 960 959 961 [WebPreferences _clearNetworkLoaderSession]; -
trunk/Tools/WebKitTestRunner/TestController.cpp
r213042 r213618 719 719 720 720 WKPreferencesSetMockCaptureDevicesEnabled(preferences, true); 721 722 WKPreferencesSetLargeImageAsyncDecodingEnabled(preferences, false); 721 723 722 724 platformResetPreferencesToConsistentValues();
Note: See TracChangeset
for help on using the changeset viewer.