summaryrefslogtreecommitdiffstats
path: root/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp
blob: 517591390ba63625e89f096a9ec3f1a60cc83828 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "core/paint/PaintInvalidationCapableScrollableArea.h"

#include "core/frame/Settings.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/layout/LayoutBox.h"
#include "core/layout/LayoutScrollbar.h"
#include "core/layout/LayoutScrollbarPart.h"
#include "core/layout/PaintInvalidationState.h"
#include "core/paint/PaintLayer.h"
#include "platform/graphics/GraphicsLayer.h"

namespace blink {

void PaintInvalidationCapableScrollableArea::willRemoveScrollbar(Scrollbar& scrollbar, ScrollbarOrientation orientation)
{
    if (!scrollbar.isCustomScrollbar()
        && !(orientation == HorizontalScrollbar ? layerForHorizontalScrollbar() : layerForVerticalScrollbar()))
        boxForScrollControlPaintInvalidation().invalidateDisplayItemClient(scrollbar);

    ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
}

static LayoutRect scrollControlPaintInvalidationRect(const IntRect& scrollControlRect, const LayoutBox& box, const PaintInvalidationState& paintInvalidationState)
{
    LayoutRect paintInvalidationRect(scrollControlRect);
    if (!paintInvalidationRect.isEmpty())
        paintInvalidationState.mapLocalRectToPaintInvalidationBacking(paintInvalidationRect);
    return paintInvalidationRect;
}

// Returns true if the scroll control is invalidated.
static bool invalidatePaintOfScrollControlIfNeeded(const LayoutRect& newPaintInvalidationRect, const LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidation, LayoutBox& box, const LayoutBoxModelObject& paintInvalidationContainer)
{
    bool shouldInvalidateNewRect = needsPaintInvalidation;
    if (newPaintInvalidationRect != previousPaintInvalidationRect) {
        box.invalidatePaintUsingContainer(paintInvalidationContainer, previousPaintInvalidationRect, PaintInvalidationScroll);
        shouldInvalidateNewRect = true;
    }
    if (shouldInvalidateNewRect) {
        box.invalidatePaintUsingContainer(paintInvalidationContainer, newPaintInvalidationRect, PaintInvalidationScroll);
        box.enclosingLayer()->setNeedsRepaint();
        return true;
    }
    return false;
}

static void invalidatePaintOfScrollbarIfNeeded(Scrollbar* scrollbar, GraphicsLayer* graphicsLayer, bool& previouslyWasOverlay, LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidationArg, LayoutBox& box, const PaintInvalidationState& paintInvalidationState)
{
    bool isOverlay = scrollbar && scrollbar->isOverlayScrollbar();

    // Calculate paint invalidation rect of the scrollbar, except overlay composited scrollbars because we invalidate the graphics layer only.
    LayoutRect newPaintInvalidationRect;
    if (scrollbar && !(graphicsLayer && isOverlay))
        newPaintInvalidationRect = scrollControlPaintInvalidationRect(scrollbar->frameRect(), box, paintInvalidationState);

    bool needsPaintInvalidation = needsPaintInvalidationArg;
    if (graphicsLayer) {
        // If the scrollbar needs paint invalidation but didn't change location/size or the scrollbar is an
        // overlay scrollbar (paint invalidation rect is empty), invalidating the graphics layer is enough
        // (which has been done in ScrollableArea::setScrollbarNeedsPaintInvalidation()).
        // Otherwise invalidatePaintOfScrollControlIfNeeded() below will invalidate the old and new location
        // of the scrollbar on the box's paint invalidation container to ensure newly expanded/shrunk areas
        // of the box to be invalidated.
        needsPaintInvalidation = false;

        graphicsLayer->invalidateDisplayItemClient(*graphicsLayer, PaintInvalidationScroll);
    }

    // Invalidate the box's display item client if the box's padding box size is affected by change of the
    // non-overlay scrollbar width. We detect change of paint invalidation rect size instead of change of
    // scrollbar width change, which may have some false-positives (e.g. the scrollbar changed length but
    // not width) but won't invalidate more than expected because in the false-positive case the box must
    // have changed size and have been invalidated.
    const LayoutBoxModelObject& paintInvalidationContainer = paintInvalidationState.paintInvalidationContainer();
    LayoutSize newScrollbarUsedSpaceInBox;
    if (!isOverlay)
        newScrollbarUsedSpaceInBox = newPaintInvalidationRect.size();
    LayoutSize previousScrollbarUsedSpaceInBox;
    if (!previouslyWasOverlay)
        previousScrollbarUsedSpaceInBox= previousPaintInvalidationRect.size();
    if (newScrollbarUsedSpaceInBox != previousScrollbarUsedSpaceInBox)
        paintInvalidationContainer.invalidateDisplayItemClientOnBacking(box, PaintInvalidationScroll);

    bool invalidated = invalidatePaintOfScrollControlIfNeeded(newPaintInvalidationRect, previousPaintInvalidationRect, needsPaintInvalidation, box, paintInvalidationContainer);

    previousPaintInvalidationRect = newPaintInvalidationRect;
    previouslyWasOverlay = isOverlay;

    if (!invalidated || !scrollbar || graphicsLayer)
        return;

    paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*scrollbar, PaintInvalidationScroll);
    if (scrollbar->isCustomScrollbar())
        toLayoutScrollbar(scrollbar)->invalidateDisplayItemClientsOfScrollbarParts(paintInvalidationContainer);
}

void PaintInvalidationCapableScrollableArea::invalidatePaintOfScrollControlsIfNeeded(const PaintInvalidationState& paintInvalidationState)
{
    LayoutBox& box = boxForScrollControlPaintInvalidation();
    invalidatePaintOfScrollbarIfNeeded(horizontalScrollbar(), layerForHorizontalScrollbar(), m_horizontalScrollbarPreviouslyWasOverlay, m_horizontalScrollbarPreviousPaintInvalidationRect, horizontalScrollbarNeedsPaintInvalidation(), box, paintInvalidationState);
    invalidatePaintOfScrollbarIfNeeded(verticalScrollbar(), layerForVerticalScrollbar(), m_verticalScrollbarPreviouslyWasOverlay, m_verticalScrollbarPreviousPaintInvalidationRect, verticalScrollbarNeedsPaintInvalidation(), box, paintInvalidationState);

    LayoutRect scrollCornerPaintInvalidationRect = scrollControlPaintInvalidationRect(scrollCornerAndResizerRect(), box, paintInvalidationState);
    const LayoutBoxModelObject& paintInvalidationContainer = paintInvalidationState.paintInvalidationContainer();
    if (invalidatePaintOfScrollControlIfNeeded(scrollCornerPaintInvalidationRect, m_scrollCornerAndResizerPreviousPaintInvalidationRect, scrollCornerNeedsPaintInvalidation(), box, paintInvalidationContainer)) {
        m_scrollCornerAndResizerPreviousPaintInvalidationRect = scrollCornerPaintInvalidationRect;
        if (LayoutScrollbarPart* scrollCorner = this->scrollCorner())
            scrollCorner->invalidateDisplayItemClientsIncludingNonCompositingDescendants(&paintInvalidationContainer, PaintInvalidationScroll);
        if (LayoutScrollbarPart* resizer = this->resizer())
            resizer->invalidateDisplayItemClientsIncludingNonCompositingDescendants(&paintInvalidationContainer, PaintInvalidationScroll);
    }

    clearNeedsPaintInvalidationForScrollControls();
}

void PaintInvalidationCapableScrollableArea::clearPreviousPaintInvalidationRects()
{
    m_horizontalScrollbarPreviousPaintInvalidationRect = LayoutRect();
    m_verticalScrollbarPreviousPaintInvalidationRect = LayoutRect();
    m_scrollCornerAndResizerPreviousPaintInvalidationRect = LayoutRect();
}

LayoutRect PaintInvalidationCapableScrollableArea::visualRectForScrollbarParts() const
{
    LayoutRect fullBounds(m_horizontalScrollbarPreviousPaintInvalidationRect);
    fullBounds.unite(m_verticalScrollbarPreviousPaintInvalidationRect);
    fullBounds.unite(m_scrollCornerAndResizerPreviousPaintInvalidationRect);
    return fullBounds;
}

} // namespace blink