Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1484)

Unified Diff: third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp

Issue 1930183002: Refactor scroll updates during flexbox layout. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@rtl-scroll-origin
Patch Set: Fix layout invalidation reason Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index 06d8fea21ad6e59ffb86fbca2ff2044ae4c4a6e4..a6375862b13cece03bc84dace62a6306b28bd223 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -623,54 +623,41 @@ IntSize PaintLayerScrollableArea::originAdjustmentForScrollbars() const
return size;
}
-void PaintLayerScrollableArea::computeScrollDimensions()
+void PaintLayerScrollableArea::updateScrollOrigin()
+{
+ if (!overflowRect().size().isZero()) {
cbiesinger 2016/04/29 20:02:50 if (!overflowRect().isEmpty()) ? But can you expl
szager1 2016/05/12 20:44:50 This is a hack to prevent this from running before
+ LayoutPoint scrollableOverflow = m_overflowRect.location() - LayoutSize(box().borderLeft(), box().borderTop());
+ setScrollOrigin(flooredIntPoint(-scrollableOverflow) + originAdjustmentForScrollbars());
+ }
+}
+
+void PaintLayerScrollableArea::updateScrollDimensions()
{
m_overflowRect = box().layoutOverflowRect();
box().flipForWritingMode(m_overflowRect);
-
- LayoutPoint scrollableOverflow = m_overflowRect.location() - LayoutSize(box().borderLeft(), box().borderTop());
- setScrollOrigin(flooredIntPoint(-scrollableOverflow) + originAdjustmentForScrollbars());
+ updateScrollOrigin();
}
void PaintLayerScrollableArea::scrollToPosition(const DoublePoint& scrollPosition, ScrollOffsetClamping clamp, ScrollBehavior scrollBehavior, ScrollType scrollType)
{
- cancelProgrammaticScrollAnimation();
cbiesinger 2016/04/29 20:02:50 BTW, why did you remove this? Just because it's no
szager1 2016/05/12 20:44:51 It already gets called further down the call stack
-
DoublePoint newScrollPosition = clamp == ScrollOffsetClamped ? clampScrollPosition(scrollPosition) : scrollPosition;
if (newScrollPosition != scrollPositionDouble())
ScrollableArea::setScrollPosition(newScrollPosition, scrollType, scrollBehavior);
}
-bool PaintLayerScrollableArea::updateAfterLayout(SubtreeLayoutScope* delayedLayoutScope)
+void PaintLayerScrollableArea::updateAfterLayout()
{
ASSERT(box().hasOverflowClip());
- bool didMarkForDelayedLayout = false;
+ bool relayoutIsPrevented = PreventRelayoutScope::relayoutIsPrevented();
+ bool scrollbarsAreFrozen = FreezeScrollbarsScope::scrollbarsAreFrozen();
if (needsScrollbarReconstruction()) {
- m_scrollbarManager.setCanDetachScrollbars(false);
setHasHorizontalScrollbar(false);
setHasVerticalScrollbar(false);
}
- m_scrollbarManager.setCanDetachScrollbars(true);
-
- IntPoint originalOrigin = scrollOrigin();
- computeScrollDimensions();
-
- // Layout may cause us to be at an invalid scroll position. In this case we need
- // to pull our scroll offsets back to the max (or push them up to the min).
- DoublePoint clampedScrollPosition = clampScrollPosition(scrollPositionDouble());
- if (clampedScrollPosition != scrollPositionDouble()) {
- scrollToPosition(clampedScrollPosition);
- } else if (originalOrigin != scrollOrigin()) {
- // TODO: We should be able to use scrollOriginChanged() here, but we can't because
- // PaintLayerScrollableArea does not maintain that flag: it gets set, but it never
- // gets unset. We should unset the flag after layout.
- scrollPositionChanged(scrollPositionDouble(), ProgrammaticScroll);
- }
-
- m_scrollbarManager.setCanDetachScrollbars(false);
+ updateScrollDimensions();
bool hasHorizontalOverflow = this->hasHorizontalOverflow();
bool hasVerticalOverflow = this->hasVerticalOverflow();
@@ -692,7 +679,7 @@ bool PaintLayerScrollableArea::updateAfterLayout(SubtreeLayoutScope* delayedLayo
|| (box().style()->overflowX() == OverflowScroll && !horizontalScrollbar());
bool verticalScrollBarChanged = (box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow))
|| (box().style()->overflowY() == OverflowScroll && !verticalScrollbar());
- if (!visualViewportSuppliesScrollbars() && (horizontalScrollBarChanged || verticalScrollBarChanged)) {
+ if (!scrollbarsAreFrozen && !visualViewportSuppliesScrollbars() && (horizontalScrollBarChanged || verticalScrollBarChanged)) {
if (box().hasAutoHorizontalScrollbar())
setHasHorizontalScrollbar(hasHorizontalOverflow);
else if (box().style()->overflowX() == OverflowScroll)
@@ -714,13 +701,12 @@ bool PaintLayerScrollableArea::updateAfterLayout(SubtreeLayoutScope* delayedLayo
// Our proprietary overflow: overlay value doesn't trigger a layout.
if ((horizontalScrollBarChanged && box().style()->overflowX() != OverflowOverlay) || (verticalScrollBarChanged && box().style()->overflowY() != OverflowOverlay)) {
if (!m_inOverflowRelayout) {
- m_inOverflowRelayout = true;
- if (delayedLayoutScope) {
+ if (relayoutIsPrevented) {
if (box().isLayoutBlock())
toLayoutBlock(box()).scrollbarsChanged(horizontalScrollBarChanged, verticalScrollBarChanged);
- delayedLayoutScope->setNeedsLayout(&box(), LayoutInvalidationReason::ScrollbarChanged);
- didMarkForDelayedLayout = true;
+ PreventRelayoutScope::setNeedsLayout(box());
} else {
+ m_inOverflowRelayout = true;
SubtreeLayoutScope layoutScope(box());
layoutScope.setNeedsLayout(&box(), LayoutInvalidationReason::ScrollbarChanged);
if (box().isLayoutBlock()) {
@@ -730,11 +716,12 @@ bool PaintLayerScrollableArea::updateAfterLayout(SubtreeLayoutScope* delayedLayo
} else {
box().layout();
}
+ m_inOverflowRelayout = false;
+ m_scrollbarManager.destroyDetachedScrollbars();
}
LayoutObject* parent = box().parent();
if (parent && parent->isFlexibleBox())
toLayoutFlexibleBox(parent)->clearCachedMainSizeForChild(box());
- m_inOverflowRelayout = false;
}
}
}
@@ -754,20 +741,45 @@ bool PaintLayerScrollableArea::updateAfterLayout(SubtreeLayoutScope* delayedLayo
}
}
- if (hasOverlayScrollbars()) {
+ if (!scrollbarsAreFrozen && hasOverlayScrollbars()) {
if (!scrollSize(HorizontalScrollbar))
setHasHorizontalScrollbar(false);
if (!scrollSize(VerticalScrollbar))
setHasVerticalScrollbar(false);
}
- bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow();
- updateScrollableAreaSet(hasOverflow);
+ clampScrollPositionsAfterLayout();
+
+ if (!scrollbarsAreFrozen) {
+ bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow();
+ updateScrollableAreaSet(hasOverflow);
+ }
DisableCompositingQueryAsserts disabler;
positionOverflowControls();
+}
+
+
+void PaintLayerScrollableArea::clampScrollPositionsAfterLayout()
+{
+ // If a vertical scrollbar was removed, the min/max scroll positions may have changed,
+ // so the scroll positions needs to be clamped. If the scroll position did not change,
+ // but the scroll origin *did* change, we still need to notify the scrollbars to
+ // update their dimensions.
+
+ if (DelayScrollPositionClampScope::clampingIsDelayed()) {
+ DelayScrollPositionClampScope::setNeedsClamp(this);
+ return;
+ }
+
+ DoublePoint newScrollPosition = clampScrollPosition(scrollPositionDouble());
+ if (newScrollPosition != scrollPositionDouble())
+ ScrollableArea::setScrollPosition(newScrollPosition, ProgrammaticScroll);
+ else if (scrollOriginChanged())
+ scrollPositionChanged(newScrollPosition, ProgrammaticScroll);
- return didMarkForDelayedLayout;
+ setNeedsScrollPositionClamp(false);
+ resetScrollOriginChanged();
}
ScrollBehavior PaintLayerScrollableArea::scrollBehaviorStyle() const
@@ -835,7 +847,6 @@ void PaintLayerScrollableArea::updateAfterStyleChange(const ComputedStyle* oldSt
EOverflow overflowX = box().style()->overflowX();
EOverflow overflowY = box().style()->overflowY();
- // To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep any automatic scrollbar that was already present.
bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefinesAutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX);
bool needsVerticalScrollbar = (hasVerticalScrollbar() && overflowDefinesAutomaticScrollbar(overflowY)) || overflowRequiresScrollbar(overflowY);
@@ -906,7 +917,7 @@ bool PaintLayerScrollableArea::updateAfterCompositingChange()
void PaintLayerScrollableArea::updateAfterOverflowRecalc()
{
- computeScrollDimensions();
+ updateScrollDimensions();
if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
int clientWidth = box().pixelSnappedClientWidth();
horizontalScrollbar->setProportion(clientWidth, overflowRect().width());
@@ -1038,12 +1049,17 @@ bool PaintLayerScrollableArea::needsScrollbarReconstruction() const
void PaintLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar)
{
+ if (FreezeScrollbarsScope::scrollbarsAreFrozen())
+ return;
+
if (hasScrollbar == hasHorizontalScrollbar())
return;
setScrollbarNeedsPaintInvalidation(HorizontalScrollbar);
- m_scrollbarManager.setHasHorizontalScrollbar(hasScrollbar);
+ m_scrollbarManager.setHasHorizontalScrollbar(hasScrollbar, !m_inOverflowRelayout);
+
+ updateScrollOrigin();
// Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
if (hasHorizontalScrollbar())
@@ -1060,12 +1076,17 @@ void PaintLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar)
void PaintLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar)
{
+ if (FreezeScrollbarsScope::scrollbarsAreFrozen())
+ return;
+
if (hasScrollbar == hasVerticalScrollbar())
return;
setScrollbarNeedsPaintInvalidation(VerticalScrollbar);
- m_scrollbarManager.setHasVerticalScrollbar(hasScrollbar);
+ m_scrollbarManager.setHasVerticalScrollbar(hasScrollbar, !m_inOverflowRelayout);
+
+ updateScrollOrigin();
// Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
if (hasHorizontalScrollbar())
@@ -1536,7 +1557,6 @@ CompositorAnimationTimeline* PaintLayerScrollableArea::compositorAnimationTimeli
PaintLayerScrollableArea::ScrollbarManager::ScrollbarManager(PaintLayerScrollableArea& scrollableArea)
: m_scrollableArea(&scrollableArea)
- , m_canDetachScrollbars(0)
, m_hBarIsAttached(0)
, m_vBarIsAttached(0)
{
@@ -1544,25 +1564,22 @@ PaintLayerScrollableArea::ScrollbarManager::ScrollbarManager(PaintLayerScrollabl
void PaintLayerScrollableArea::ScrollbarManager::dispose()
{
- m_canDetachScrollbars = m_hBarIsAttached = m_vBarIsAttached = 0;
+ m_hBarIsAttached = m_vBarIsAttached = 0;
destroyScrollbar(HorizontalScrollbar);
destroyScrollbar(VerticalScrollbar);
}
-void PaintLayerScrollableArea::ScrollbarManager::setCanDetachScrollbars(bool detach)
+void PaintLayerScrollableArea::ScrollbarManager::destroyDetachedScrollbars()
{
ASSERT(!m_hBarIsAttached || m_hBar);
ASSERT(!m_vBarIsAttached || m_vBar);
- m_canDetachScrollbars = detach ? 1 : 0;
- if (!detach) {
- if (m_hBar && !m_hBarIsAttached)
- destroyScrollbar(HorizontalScrollbar);
- if (m_vBar && !m_vBarIsAttached)
- destroyScrollbar(VerticalScrollbar);
- }
+ if (m_hBar && !m_hBarIsAttached)
+ destroyScrollbar(HorizontalScrollbar);
+ if (m_vBar && !m_vBarIsAttached)
+ destroyScrollbar(VerticalScrollbar);
}
-void PaintLayerScrollableArea::ScrollbarManager::setHasHorizontalScrollbar(bool hasScrollbar)
+void PaintLayerScrollableArea::ScrollbarManager::setHasHorizontalScrollbar(bool hasScrollbar, bool canDetach)
{
if (hasScrollbar) {
// This doesn't hit in any tests, but since the equivalent code in setHasVerticalScrollbar
@@ -1576,15 +1593,14 @@ void PaintLayerScrollableArea::ScrollbarManager::setHasHorizontalScrollbar(bool
} else {
m_hBarIsAttached = 1;
}
-
} else {
m_hBarIsAttached = 0;
- if (!m_canDetachScrollbars)
+ if (!canDetach)
destroyScrollbar(HorizontalScrollbar);
}
}
-void PaintLayerScrollableArea::ScrollbarManager::setHasVerticalScrollbar(bool hasScrollbar)
+void PaintLayerScrollableArea::ScrollbarManager::setHasVerticalScrollbar(bool hasScrollbar, bool canDetach)
{
if (hasScrollbar) {
DisableCompositingQueryAsserts disabler;
@@ -1596,10 +1612,9 @@ void PaintLayerScrollableArea::ScrollbarManager::setHasVerticalScrollbar(bool ha
} else {
m_vBarIsAttached = 1;
}
-
} else {
m_vBarIsAttached = 0;
- if (!m_canDetachScrollbars)
+ if (!canDetach)
destroyScrollbar(VerticalScrollbar);
}
}
@@ -1650,4 +1665,105 @@ DEFINE_TRACE(PaintLayerScrollableArea::ScrollbarManager)
visitor->trace(m_vBar);
}
+int PaintLayerScrollableArea::PreventRelayoutScope::m_count = 0;
+SubtreeLayoutScope* PaintLayerScrollableArea::PreventRelayoutScope::m_layoutScope = nullptr;
+bool PaintLayerScrollableArea::PreventRelayoutScope::m_relayoutNeeded = false;
+WTF::Vector<LayoutObject*>* PaintLayerScrollableArea::PreventRelayoutScope::m_needsRelayout = nullptr;
+
+PaintLayerScrollableArea::PreventRelayoutScope::PreventRelayoutScope(SubtreeLayoutScope& layoutScope)
+{
+ if (!m_count) {
+ ASSERT(!m_layoutScope);
+ ASSERT(!m_needsRelayout || m_needsRelayout->isEmpty());
+ m_layoutScope = &layoutScope;
+ }
+ PreventRelayoutScope::increment();
cbiesinger 2016/04/29 20:02:50 Why not just increment()? Also, why do increment(
szager1 2016/05/12 20:44:51 Yeah, I had other callers before, but they're gone
+}
+
+PaintLayerScrollableArea::PreventRelayoutScope::~PreventRelayoutScope()
+{
+ PreventRelayoutScope::decrement();
cbiesinger 2016/04/29 20:02:50 same here
szager1 2016/05/12 20:44:51 Done.
+}
+
+void PaintLayerScrollableArea::PreventRelayoutScope::increment()
+{
+ ASSERT(m_count == 0 || m_layoutScope);
+ m_count++;
+}
+
+void PaintLayerScrollableArea::PreventRelayoutScope::decrement()
+{
+ if (--m_count == 0) {
+ if (m_relayoutNeeded) {
+ for (auto layoutObject : *m_needsRelayout)
+ m_layoutScope->setNeedsLayout(layoutObject, LayoutInvalidationReason::ScrollbarChanged);
+ m_needsRelayout->clear();
+ }
+ m_layoutScope = nullptr;
+ }
+}
+
+void PaintLayerScrollableArea::PreventRelayoutScope::setNeedsLayout(LayoutObject& layoutObject)
+{
+ ASSERT(m_count);
+ ASSERT(m_layoutScope);
+ m_relayoutNeeded = true;
+ if (!m_needsRelayout)
+ m_needsRelayout = new WTF::Vector<LayoutObject*>();
+ m_needsRelayout->append(&layoutObject);
+}
+
+void PaintLayerScrollableArea::PreventRelayoutScope::resetRelayoutNeeded()
+{
+ ASSERT(m_count == 0);
+ if (m_needsRelayout)
+ m_needsRelayout->clear();
cbiesinger 2016/04/29 20:02:50 This is for the case that the second pass may have
szager1 2016/05/12 20:44:51 Actually, no, this should ASSERT(!m_needsRelayout
+ m_relayoutNeeded = false;
+}
+
+int PaintLayerScrollableArea::FreezeScrollbarsScope::m_count = 0;
+
+int PaintLayerScrollableArea::DelayScrollPositionClampScope::m_count = 0;
+PersistentHeapVector<Member<PaintLayerScrollableArea>>* PaintLayerScrollableArea::DelayScrollPositionClampScope::m_needsClamp = nullptr;
+
+PaintLayerScrollableArea::DelayScrollPositionClampScope::DelayScrollPositionClampScope()
+{
+ if (!m_needsClamp)
+ m_needsClamp = new PersistentHeapVector<Member<PaintLayerScrollableArea>>();
cbiesinger 2016/04/29 20:02:50 Oilpan confuses me, I trust that this is the right
szager1 2016/05/12 20:44:51 These are basically static vectors that never get
+ ASSERT(m_count > 0 || m_needsClamp->isEmpty());
cbiesinger 2016/04/29 20:02:50 By the way, please name all static members as s_fo
szager1 2016/05/12 20:44:51 Done.
+ DelayScrollPositionClampScope::increment();
cbiesinger 2016/04/29 20:02:50 Again, why have these increment/decrement methods
szager1 2016/05/12 20:44:51 Got rid of these.
+}
+
+PaintLayerScrollableArea::DelayScrollPositionClampScope::~DelayScrollPositionClampScope()
+{
+ DelayScrollPositionClampScope::decrement();
+}
+
+void PaintLayerScrollableArea::DelayScrollPositionClampScope::increment()
+{
+ m_count++;
+}
+
+void PaintLayerScrollableArea::DelayScrollPositionClampScope::decrement()
+{
+ if (--m_count == 0)
+ DelayScrollPositionClampScope::clampScrollableAreas();
+}
+
+void PaintLayerScrollableArea::DelayScrollPositionClampScope::setNeedsClamp(PaintLayerScrollableArea* scrollableArea)
+{
+ if (!scrollableArea->needsScrollPositionClamp()) {
+ scrollableArea->setNeedsScrollPositionClamp(true);
+ m_needsClamp->append(scrollableArea);
+ }
+}
+
+void PaintLayerScrollableArea::DelayScrollPositionClampScope::clampScrollableAreas()
+{
+ for (auto& scrollableArea : *m_needsClamp)
+ scrollableArea->clampScrollPositionsAfterLayout();
+ delete m_needsClamp;
+ m_needsClamp = nullptr;
+}
+
} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698