summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
blob: 787896028d29feb5836c93096a6d7323901bebaf (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
// Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_TEXT_FRAGMENT_ANCHOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_TEXT_FRAGMENT_ANCHOR_H_

#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/page/scrolling/element_fragment_anchor.h"
#include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h"
#include "third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class LocalFrame;
class KURL;

constexpr char kFragmentDirectivePrefix[] = ":~:";
// Subtract 1 because base::size includes the \0 string terminator.
constexpr size_t kFragmentDirectivePrefixStringLength =
    base::size(kFragmentDirectivePrefix) - 1;

constexpr char kTextFragmentIdentifierPrefix[] = "text=";
// Subtract 1 because base::size includes the \0 string terminator.
constexpr size_t kTextFragmentIdentifierPrefixStringLength =
    base::size(kTextFragmentIdentifierPrefix) - 1;

class CORE_EXPORT TextFragmentAnchor final : public FragmentAnchor,
                                             public TextFragmentFinder::Client {
 public:
  static TextFragmentAnchor* TryCreateFragmentDirective(
      const KURL& url,
      LocalFrame& frame,
      bool same_document_navigation,
      bool should_scroll);

  TextFragmentAnchor(
      const Vector<TextFragmentSelector>& text_fragment_selectors,
      LocalFrame& frame,
      bool should_scroll);
  ~TextFragmentAnchor() override = default;

  bool Invoke() override;

  void Installed() override;

  void DidScroll(mojom::blink::ScrollType type) override;

  void PerformPreRafActions() override;

  // Removes text match highlights if any highlight is in view.
  bool Dismiss() override;

  void Trace(Visitor*) override;

  // TextFragmentFinder::Client interface
  void DidFindMatch(
      const EphemeralRangeInFlatTree& range,
      const TextFragmentAnchorMetrics::Match match_metrics) override;
  void DidFindAmbiguousMatch() override;

 private:
  // Called when the search is finished. Reports metrics and activates the
  // element fragment anchor if we didn't find a match.
  void DidFinishSearch();

  void ApplyTargetToCommonAncestor(const EphemeralRangeInFlatTree& range);

  void FireBeforeMatchEvent(Element* element);

  Vector<TextFragmentFinder> text_fragment_finders_;

  Member<LocalFrame> frame_;

  bool search_finished_ = false;
  // Whether the user has scrolled the page.
  bool user_scrolled_ = false;
  // Indicates that we should scroll into view the first match that we find, set
  // to true each time the anchor is invoked if the user hasn't scrolled.
  bool first_match_needs_scroll_ = false;
  // Whether we successfully scrolled into view a match at least once, used for
  // metrics reporting.
  bool did_scroll_into_view_ = false;
  // Whether we found a match. Used to determine if we should activate the
  // element fragment anchor at the end of searching.
  bool did_find_match_ = false;
  // If the text fragment anchor is defined as a fragment directive and we don't
  // find a match, we fall back to the element anchor if it is present.
  Member<ElementFragmentAnchor> element_fragment_anchor_;
  // Whether the text fragment anchor has been dismissed yet. This should be
  // kept alive until dismissed so we can remove text highlighting.
  bool dismissed_ = false;
  // Whether we should scroll the anchor into view. This will be false for
  // history navigations and reloads, where we want to restore the highlight but
  // not scroll into view again.
  bool should_scroll_ = false;

  enum BeforematchState {
    kNoMatchFound,  // DidFindMatch has not been called.
    kEventQueued,   // Beforematch event has been queued, but not fired yet.
    kFiredEvent     // Beforematch event has been fired.
  } beforematch_state_ = kNoMatchFound;

  Member<TextFragmentAnchorMetrics> metrics_;

  DISALLOW_COPY_AND_ASSIGN(TextFragmentAnchor);
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_SCROLLING_TEXT_FRAGMENT_ANCHOR_H_