summaryrefslogtreecommitdiffstats
path: root/third_party/WebKit/Source/core/layout/ScrollAnchor.h
blob: 2cb2d195cc7bd9a1a61293a9dc15fe151647ec92 (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
// 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.

#ifndef ScrollAnchor_h
#define ScrollAnchor_h

#include "core/CoreExport.h"
#include "platform/geometry/LayoutPoint.h"
#include "platform/heap/Handle.h"

namespace blink {

class LayoutObject;
class ScrollableArea;

// Scrolls to compensate for layout movements (bit.ly/scroll-anchoring).
class CORE_EXPORT ScrollAnchor final {
    DISALLOW_NEW();

public:
    ScrollAnchor(ScrollableArea*);
    ~ScrollAnchor();

    // The LayoutObject we are currently anchored to. Lazily computed during
    // save() and cached until the next call to clear().
    LayoutObject* anchorObject() const { return m_anchorObject; }

    // Invalidates the anchor.
    void clear();

    // Records the anchor's location in relation to the scroller. Should be
    // called when the scroller is about to be laid out.
    void save();

    // Scrolls to compensate for any change in the anchor's relative location
    // since the most recent call to save(). Should be called immediately after
    // the scroller has been laid out.
    void restore();

    enum class Corner {
        TopLeft = 0,
        TopRight,
        BottomLeft,
        BottomRight
    };
    // Which corner of the anchor object we are currently anchored to.
    // Only meaningful if anchorObject() is non-null.
    Corner corner() const { return m_corner; }

    DEFINE_INLINE_TRACE() { visitor->trace(m_scroller); }

private:
    void findAnchor();

    enum WalkStatus {
        Skip = 0,
        Constrain,
        Continue,
        Return
    };
    struct ExamineResult {
        ExamineResult(WalkStatus s)
            : status(s)
            , viable(false)
            , corner(Corner::TopLeft) {}

        ExamineResult(WalkStatus s, Corner c)
            : status(s)
            , viable(true)
            , corner(c) {}

        WalkStatus status;
        bool viable;
        Corner corner;
    };
    ExamineResult examine(const LayoutObject*) const;

    // The scroller that owns and is adjusted by this ScrollAnchor.
    RawPtrWillBeMember<ScrollableArea> m_scroller;

    // The LayoutObject we should anchor to. Lazily computed.
    LayoutObject* m_anchorObject;

    // Which corner of m_anchorObject's bounding box to anchor to.
    Corner m_corner;

    // Location of m_layoutObject relative to scroller at time of save().
    LayoutPoint m_savedRelativeOffset;
};

} // namespace blink

#endif // ScrollAnchor_h