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 |