| 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 059ae5c56cd837daaecba9df25ae72258ef1403d..e71121faff11ee200dcc7a207578deb68ac927c4 100644
|
| --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
|
| +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
|
| @@ -587,54 +587,41 @@ int PaintLayerScrollableArea::pixelSnappedScrollHeight() const
|
| return snapSizeToPixel(scrollHeight(), box().clientTop() + box().location().y());
|
| }
|
|
|
| -void PaintLayerScrollableArea::computeScrollDimensions()
|
| +void PaintLayerScrollableArea::updateScrollOrigin()
|
| +{
|
| + if (!overflowRect().size().isZero()) {
|
| + LayoutPoint scrollableOverflow = m_overflowRect.location() - LayoutSize(box().borderLeft(), box().borderTop());
|
| + setScrollOrigin(flooredIntPoint(-scrollableOverflow) + box().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) + box().originAdjustmentForScrollbars());
|
| + updateScrollOrigin();
|
| }
|
|
|
| void PaintLayerScrollableArea::scrollToPosition(const DoublePoint& scrollPosition, ScrollOffsetClamping clamp, ScrollBehavior scrollBehavior, ScrollType scrollType)
|
| {
|
| - cancelProgrammaticScrollAnimation();
|
| -
|
| 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();
|
| @@ -652,11 +639,11 @@ bool PaintLayerScrollableArea::updateAfterLayout(SubtreeLayoutScope* delayedLayo
|
|
|
| // We need to layout again if scrollbars are added or removed by overflow:auto,
|
| // or by changing between native and custom.
|
| - bool horizontalScrollBarChanged = (box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow))
|
| + bool horizontalScrollbarChanged = (box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow))
|
| || (box().style()->overflowX() == OverflowScroll && !horizontalScrollbar());
|
| - bool verticalScrollBarChanged = (box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow))
|
| + 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)
|
| @@ -676,29 +663,34 @@ bool PaintLayerScrollableArea::updateAfterLayout(SubtreeLayoutScope* delayedLayo
|
| box().document().setAnnotatedRegionsDirty(true);
|
|
|
| // Our proprietary overflow: overlay value doesn't trigger a layout.
|
| - if ((horizontalScrollBarChanged && box().style()->overflowX() != OverflowOverlay) || (verticalScrollBarChanged && box().style()->overflowY() != OverflowOverlay)) {
|
| + if ((horizontalScrollbarChanged && box().style()->overflowX() != OverflowOverlay) || (verticalScrollbarChanged && box().style()->overflowY() != OverflowOverlay)) {
|
| if (!m_inOverflowRelayout) {
|
| - m_inOverflowRelayout = true;
|
| - if (delayedLayoutScope) {
|
| + if ((verticalScrollbarChanged && box().isHorizontalWritingMode())
|
| + || (horizontalScrollbarChanged && !box().isHorizontalWritingMode())) {
|
| + box().setPreferredLogicalWidthsDirty();
|
| + box().updateLogicalWidth();
|
| + }
|
| + if (relayoutIsPrevented) {
|
| if (box().isLayoutBlock())
|
| - toLayoutBlock(box()).scrollbarsChanged(horizontalScrollBarChanged, verticalScrollBarChanged);
|
| - delayedLayoutScope->setNeedsLayout(&box(), LayoutInvalidationReason::ScrollbarChanged);
|
| - didMarkForDelayedLayout = true;
|
| + toLayoutBlock(box()).scrollbarsChanged(horizontalScrollbarChanged, verticalScrollbarChanged);
|
| + PreventRelayoutScope::setNeedsLayout(box());
|
| } else {
|
| + m_inOverflowRelayout = true;
|
| SubtreeLayoutScope layoutScope(box());
|
| layoutScope.setNeedsLayout(&box(), LayoutInvalidationReason::ScrollbarChanged);
|
| if (box().isLayoutBlock()) {
|
| LayoutBlock& block = toLayoutBlock(box());
|
| - block.scrollbarsChanged(horizontalScrollBarChanged, verticalScrollBarChanged);
|
| + block.scrollbarsChanged(horizontalScrollbarChanged, verticalScrollbarChanged);
|
| block.layoutBlock(true);
|
| } else {
|
| box().layout();
|
| }
|
| + m_inOverflowRelayout = false;
|
| + m_scrollbarManager.destroyDetachedScrollbars();
|
| }
|
| LayoutObject* parent = box().parent();
|
| if (parent && parent->isFlexibleBox())
|
| toLayoutFlexibleBox(parent)->clearCachedMainSizeForChild(box());
|
| - m_inOverflowRelayout = false;
|
| }
|
| }
|
| }
|
| @@ -718,20 +710,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.
|
|
|
| - return didMarkForDelayedLayout;
|
| + if (DelayScrollPositionClampScope::clampingIsDelayed()) {
|
| + DelayScrollPositionClampScope::setNeedsClamp(this);
|
| + return;
|
| + }
|
| +
|
| + DoublePoint newScrollPosition = clampScrollPosition(scrollPositionDouble());
|
| + if (newScrollPosition != scrollPositionDouble())
|
| + ScrollableArea::setScrollPosition(newScrollPosition, ProgrammaticScroll);
|
| + else if (scrollOriginChanged())
|
| + scrollPositionChanged(newScrollPosition, ProgrammaticScroll);
|
| +
|
| + setNeedsScrollPositionClamp(false);
|
| + resetScrollOriginChanged();
|
| }
|
|
|
| ScrollBehavior PaintLayerScrollableArea::scrollBehaviorStyle() const
|
| @@ -799,7 +816,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);
|
|
|
| @@ -870,7 +886,7 @@ bool PaintLayerScrollableArea::updateAfterCompositingChange()
|
|
|
| void PaintLayerScrollableArea::updateAfterOverflowRecalc()
|
| {
|
| - computeScrollDimensions();
|
| + updateScrollDimensions();
|
| if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) {
|
| int clientWidth = box().pixelSnappedClientWidth();
|
| horizontalScrollbar->setProportion(clientWidth, overflowRect().width());
|
| @@ -882,9 +898,9 @@ void PaintLayerScrollableArea::updateAfterOverflowRecalc()
|
|
|
| bool hasHorizontalOverflow = this->hasHorizontalOverflow();
|
| bool hasVerticalOverflow = this->hasVerticalOverflow();
|
| - bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
|
| - bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
|
| - if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged)
|
| + bool autoHorizontalScrollbarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
|
| + bool autoVerticalScrollbarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
|
| + if (autoHorizontalScrollbarChanged || autoVerticalScrollbarChanged)
|
| box().setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::Unknown);
|
| }
|
|
|
| @@ -1002,12 +1018,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())
|
| @@ -1024,12 +1045,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())
|
| @@ -1500,7 +1526,6 @@ CompositorAnimationTimeline* PaintLayerScrollableArea::compositorAnimationTimeli
|
|
|
| PaintLayerScrollableArea::ScrollbarManager::ScrollbarManager(PaintLayerScrollableArea& scrollableArea)
|
| : m_scrollableArea(&scrollableArea)
|
| - , m_canDetachScrollbars(0)
|
| , m_hBarIsAttached(0)
|
| , m_vBarIsAttached(0)
|
| {
|
| @@ -1508,25 +1533,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
|
| @@ -1540,15 +1562,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;
|
| @@ -1560,10 +1581,9 @@ void PaintLayerScrollableArea::ScrollbarManager::setHasVerticalScrollbar(bool ha
|
| } else {
|
| m_vBarIsAttached = 1;
|
| }
|
| -
|
| } else {
|
| m_vBarIsAttached = 0;
|
| - if (!m_canDetachScrollbars)
|
| + if (!canDetach)
|
| destroyScrollbar(VerticalScrollbar);
|
| }
|
| }
|
| @@ -1614,4 +1634,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();
|
| +}
|
| +
|
| +PaintLayerScrollableArea::PreventRelayoutScope::~PreventRelayoutScope()
|
| +{
|
| + PreventRelayoutScope::decrement();
|
| +}
|
| +
|
| +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();
|
| + 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>>();
|
| + ASSERT(m_count > 0 || m_needsClamp->isEmpty());
|
| + DelayScrollPositionClampScope::increment();
|
| +}
|
| +
|
| +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
|
|
|