- Revision
- 224510
- Author
- [email protected]
- Date
- 2017-11-06 13:41:12 -0800 (Mon, 06 Nov 2017)
Log Message
UIWebView is not rendering content that comes on screen during overflow scroll
https://bugs.webkit.org/show_bug.cgi?id=179277
rdar://problem/34272949
Reviewed by Tim Horton
When page or overflow scrolling happens, we do a traversal of GraphicsLayers to determine
whether the exposed part of tiled layers changed in a way that requires a change in the tile
coverage. If so, we schedule a compositing layer flush.
There was no equivalent logic for computing whether the "backing store detached" state
of a layer changed (which we use to throw away backing store of layers outside the viewport),
so after scrolling an accelerated overflow:scroll which contained composited layers, we
would sometimes fail to recompute that we should re-create backing store for revealed
layers.
Fix by having GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush() determine
whether 'intersectsCoverageRect' changed, and if so trigger a flush. This requires
tracking CommitState for isViewportConstrained-ness, just like we do during commits.
Also clean up code related to computing the visible rect passed into visibleRectChangeRequiresFlush() and
flushCompositingState(); these diverged for no good reason. Also clean up the logging a little.
Not testable because UIWebView layout tests are unreliable.
* page/ios/FrameIOS.mm:
(WebCore::Frame::viewportOffsetChanged):
(WebCore::Frame::overflowScrollPositionChangedForNode):
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush const):
(WebCore::GraphicsLayerCA::visibleRectChangeRequiresFlush const):
* platform/graphics/ca/GraphicsLayerCA.h:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::visibleRectForLayerFlushing const):
(WebCore::RenderLayerCompositor::flushPendingLayerChanges):
(WebCore::RenderLayerCompositor::didChangeVisibleRect):
* rendering/RenderLayerCompositor.h:
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (224509 => 224510)
--- trunk/Source/WebCore/ChangeLog 2017-11-06 21:35:11 UTC (rev 224509)
+++ trunk/Source/WebCore/ChangeLog 2017-11-06 21:41:12 UTC (rev 224510)
@@ -1,3 +1,43 @@
+2017-11-03 Simon Fraser <[email protected]>
+
+ UIWebView is not rendering content that comes on screen during overflow scroll
+ https://bugs.webkit.org/show_bug.cgi?id=179277
+ rdar://problem/34272949
+
+ Reviewed by Tim Horton
+
+ When page or overflow scrolling happens, we do a traversal of GraphicsLayers to determine
+ whether the exposed part of tiled layers changed in a way that requires a change in the tile
+ coverage. If so, we schedule a compositing layer flush.
+
+ There was no equivalent logic for computing whether the "backing store detached" state
+ of a layer changed (which we use to throw away backing store of layers outside the viewport),
+ so after scrolling an accelerated overflow:scroll which contained composited layers, we
+ would sometimes fail to recompute that we should re-create backing store for revealed
+ layers.
+
+ Fix by having GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush() determine
+ whether 'intersectsCoverageRect' changed, and if so trigger a flush. This requires
+ tracking CommitState for isViewportConstrained-ness, just like we do during commits.
+
+ Also clean up code related to computing the visible rect passed into visibleRectChangeRequiresFlush() and
+ flushCompositingState(); these diverged for no good reason. Also clean up the logging a little.
+
+ Not testable because UIWebView layout tests are unreliable.
+
+ * page/ios/FrameIOS.mm:
+ (WebCore::Frame::viewportOffsetChanged):
+ (WebCore::Frame::overflowScrollPositionChangedForNode):
+ * platform/graphics/ca/GraphicsLayerCA.cpp:
+ (WebCore::GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush const):
+ (WebCore::GraphicsLayerCA::visibleRectChangeRequiresFlush const):
+ * platform/graphics/ca/GraphicsLayerCA.h:
+ * rendering/RenderLayerCompositor.cpp:
+ (WebCore::RenderLayerCompositor::visibleRectForLayerFlushing const):
+ (WebCore::RenderLayerCompositor::flushPendingLayerChanges):
+ (WebCore::RenderLayerCompositor::didChangeVisibleRect):
+ * rendering/RenderLayerCompositor.h:
+
2017-11-06 Chris Dumez <[email protected]>
[Service Workers] Add proper implementation for 'updatefound' event
Modified: trunk/Source/WebCore/page/ios/FrameIOS.mm (224509 => 224510)
--- trunk/Source/WebCore/page/ios/FrameIOS.mm 2017-11-06 21:35:11 UTC (rev 224509)
+++ trunk/Source/WebCore/page/ios/FrameIOS.mm 2017-11-06 21:41:12 UTC (rev 224510)
@@ -47,6 +47,7 @@
#import "HTMLObjectElement.h"
#import "HitTestRequest.h"
#import "HitTestResult.h"
+#import "Logging.h"
#import "MainFrame.h"
#import "NodeRenderStyle.h"
#import "NodeTraversal.h"
@@ -67,6 +68,7 @@
#import "WAKWindow.h"
#import <runtime/JSLock.h>
#import <wtf/BlockObjCExceptions.h>
+#import <wtf/text/TextStream.h>
using namespace WebCore::HTMLNames;
using namespace WTF::Unicode;
@@ -708,6 +710,8 @@
void Frame::viewportOffsetChanged(ViewportOffsetChangeType changeType)
{
+ LOG_WITH_STREAM(Scrolling, stream << "Frame::viewportOffsetChanged - " << (changeType == IncrementalScrollOffset ? "incremental" : "completed"));
+
if (changeType == IncrementalScrollOffset) {
if (anyFrameHasTiledLayers(this)) {
if (RenderView* root = contentRenderer())
@@ -731,6 +735,8 @@
void Frame::overflowScrollPositionChangedForNode(const IntPoint& position, Node* node, bool isUserScroll)
{
+ LOG_WITH_STREAM(Scrolling, stream << "Frame::overflowScrollPositionChangedForNode " << node << " position " << position);
+
RenderObject* renderer = node->renderer();
if (!renderer || !renderer->hasLayer())
return;
Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp (224509 => 224510)
--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp 2017-11-06 21:35:11 UTC (rev 224509)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp 2017-11-06 21:41:12 UTC (rev 224510)
@@ -1235,15 +1235,23 @@
return !layer.masksToBounds() && (layer.preserves3D() || (layer.parent() && layer.parent()->preserves3D()));
}
-bool GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush(const TransformState& state) const
+bool GraphicsLayerCA::recursiveVisibleRectChangeRequiresFlush(const CommitState& commitState, const TransformState& state) const
{
TransformState localState = state;
-
+ CommitState childCommitState = commitState;
+
// This may be called at times when layout has not been updated, so we want to avoid calling out to the client
// for animating transforms.
VisibleAndCoverageRects rects = computeVisibleAndCoverageRect(localState, accumulatesTransform(*this), 0);
adjustCoverageRect(rects, m_visibleRect);
+ auto bounds = FloatRect(m_boundsOrigin, size());
+
+ bool isViewportConstrained = m_isViewportConstrained || commitState.ancestorIsViewportConstrained;
+ bool intersectsCoverageRect = isViewportConstrained || rects.coverageRect.intersects(bounds);
+ if (intersectsCoverageRect != m_intersectsCoverageRect)
+ return true;
+
if (rects.coverageRect != m_coverageRect) {
if (TiledBacking* tiledBacking = this->tiledBacking()) {
if (tiledBacking->tilesWouldChangeForCoverageRect(rects.coverageRect))
@@ -1251,9 +1259,11 @@
}
}
+ childCommitState.ancestorIsViewportConstrained |= m_isViewportConstrained;
+
if (m_maskLayer) {
GraphicsLayerCA& maskLayerCA = downcast<GraphicsLayerCA>(*m_maskLayer);
- if (maskLayerCA.recursiveVisibleRectChangeRequiresFlush(localState))
+ if (maskLayerCA.recursiveVisibleRectChangeRequiresFlush(childCommitState, localState))
return true;
}
@@ -1262,12 +1272,12 @@
for (size_t i = 0; i < numChildren; ++i) {
GraphicsLayerCA& currentChild = downcast<GraphicsLayerCA>(*childLayers[i]);
- if (currentChild.recursiveVisibleRectChangeRequiresFlush(localState))
+ if (currentChild.recursiveVisibleRectChangeRequiresFlush(childCommitState, localState))
return true;
}
if (m_replicaLayer)
- if (downcast<GraphicsLayerCA>(*m_replicaLayer).recursiveVisibleRectChangeRequiresFlush(localState))
+ if (downcast<GraphicsLayerCA>(*m_replicaLayer).recursiveVisibleRectChangeRequiresFlush(childCommitState, localState))
return true;
return false;
@@ -1276,7 +1286,8 @@
bool GraphicsLayerCA::visibleRectChangeRequiresFlush(const FloatRect& clipRect) const
{
TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
- return recursiveVisibleRectChangeRequiresFlush(state);
+ CommitState commitState;
+ return recursiveVisibleRectChangeRequiresFlush(commitState, state);
}
TiledBacking* GraphicsLayerCA::tiledBacking() const
Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h (224509 => 224510)
--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h 2017-11-06 21:35:11 UTC (rev 224509)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h 2017-11-06 21:41:12 UTC (rev 224510)
@@ -314,7 +314,7 @@
static FloatRect adjustTiledLayerVisibleRect(TiledBacking*, const FloatRect& oldVisibleRect, const FloatRect& newVisibleRect, const FloatSize& oldSize, const FloatSize& newSize);
- bool recursiveVisibleRectChangeRequiresFlush(const TransformState&) const;
+ bool recursiveVisibleRectChangeRequiresFlush(const CommitState&, const TransformState&) const;
bool isPageTiledBackingLayer() const { return type() == Type::PageTiledBacking; }
Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (224509 => 224510)
--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2017-11-06 21:35:11 UTC (rev 224509)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2017-11-06 21:41:12 UTC (rev 224510)
@@ -412,6 +412,22 @@
scheduleLayerFlushNow();
}
+FloatRect RenderLayerCompositor::visibleRectForLayerFlushing() const
+{
+ const FrameView& frameView = m_renderView.frameView();
+#if PLATFORM(IOS)
+ return frameView.exposedContentRect();
+#else
+ // Having a m_clipLayer indicates that we're doing scrolling via GraphicsLayers.
+ FloatRect visibleRect = m_clipLayer ? FloatRect({ }, frameView.sizeForVisibleContent()) : frameView.visibleContentRect();
+
+ if (frameView.viewExposedRect())
+ visibleRect.intersect(frameView.viewExposedRect().value());
+
+ return visibleRect;
+#endif
+}
+
void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
{
// FrameView::flushCompositingStateIncludingSubframes() flushes each subframe,
@@ -436,23 +452,9 @@
m_flushingLayers = true;
if (auto* rootLayer = rootGraphicsLayer()) {
-#if PLATFORM(IOS)
- FloatRect exposedRect = frameView.exposedContentRect();
- LOG_WITH_STREAM(Compositing, stream << "\nRenderLayerCompositor " << this << " flushPendingLayerChanges (is root " << isFlushRoot << ") exposedRect " << exposedRect);
-
- // FIXME: Use optimized flushes.
- rootLayer->flushCompositingState(exposedRect);
-#else
- // Having a m_clipLayer indicates that we're doing scrolling via GraphicsLayers.
- FloatRect visibleRect = m_clipLayer ? FloatRect({ 0, 0 }, frameView.sizeForVisibleContent()) : frameView.visibleContentRect();
-
- if (frameView.viewExposedRect())
- visibleRect.intersect(frameView.viewExposedRect().value());
-
+ FloatRect visibleRect = visibleRectForLayerFlushing();
LOG_WITH_STREAM(Compositing, stream << "\nRenderLayerCompositor " << this << " flushPendingLayerChanges (is root " << isFlushRoot << ") visible rect " << visibleRect);
rootLayer->flushCompositingState(visibleRect);
- LOG_WITH_STREAM(Compositing, stream << "RenderLayerCompositor " << this << " flush complete\n");
-#endif
}
ASSERT(m_flushingLayers);
@@ -559,16 +561,11 @@
if (!rootLayer)
return;
- const FrameView& frameView = m_renderView.frameView();
-
-#if PLATFORM(IOS)
- IntRect visibleRect = enclosingIntRect(frameView.exposedContentRect());
-#else
- IntRect visibleRect = m_clipLayer ? IntRect(IntPoint(), frameView.contentsSize()) : frameView.visibleContentRect();
-#endif
- if (!rootLayer->visibleRectChangeRequiresFlush(visibleRect))
- return;
- scheduleLayerFlushNow();
+ FloatRect visibleRect = visibleRectForLayerFlushing();
+ bool requiresFlush = rootLayer->visibleRectChangeRequiresFlush(visibleRect);
+ LOG_WITH_STREAM(Compositing, stream << "RenderLayerCompositor::didChangeVisibleRect " << visibleRect << " requiresFlush " << requiresFlush);
+ if (requiresFlush)
+ scheduleLayerFlushNow();
}
void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*)
Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.h (224509 => 224510)
--- trunk/Source/WebCore/rendering/RenderLayerCompositor.h 2017-11-06 21:35:11 UTC (rev 224509)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.h 2017-11-06 21:41:12 UTC (rev 224510)
@@ -407,6 +407,8 @@
bool isFlushingLayers() const { return m_flushingLayers; }
void updateScrollCoordinatedLayersAfterFlushIncludingSubframes();
void updateScrollCoordinatedLayersAfterFlush();
+
+ FloatRect visibleRectForLayerFlushing() const;
Page& page() const;