summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/editing/ephemeral_range.h
blob: c9bc293a7be5d3780bffb42909c6cf2253c9a41e (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// 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 THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_EPHEMERAL_RANGE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_EPHEMERAL_RANGE_H_

#include "third_party/blink/renderer/core/editing/position.h"

namespace blink {

class Document;
class Range;

// We should restrict access to the unwanted version of |TraversalRange::end()|
// function.
template <class Iterator>
class TraversalRangeNodes : private TraversalRange<Iterator> {
  STACK_ALLOCATED();

 public:
  using StartNodeType = typename TraversalRange<Iterator>::StartNodeType;
  TraversalRangeNodes(const StartNodeType* start,
                      const StartNodeType* past_end_node)
      : TraversalRange<Iterator>(start), past_end_node_(past_end_node) {}

  using TraversalRange<Iterator>::begin;

  Iterator end() { return Iterator(past_end_node_); }

 private:
  const Member<const StartNodeType> past_end_node_;
};

// This class acts like |TraversalNextIterator| but in addition
// it allows to set current position and checks |m_current| pointer before
// dereferencing.
template <class TraversalNext>
class CheckedTraversalNextIterator
    : public TraversalIteratorBase<TraversalNext> {
  STACK_ALLOCATED();

  using TraversalIteratorBase<TraversalNext>::current_;

 public:
  using StartNodeType = typename TraversalNext::TraversalNodeType;
  explicit CheckedTraversalNextIterator(const StartNodeType* start)
      : TraversalIteratorBase<TraversalNext>(
            const_cast<StartNodeType*>(start)) {}

  void operator++() {
    DCHECK(current_);
    current_ = TraversalNext::Next(*current_);
  }
};

// Unlike |Range| objects, |EphemeralRangeTemplate| objects aren't relocated.
// You should not use |EphemeralRangeTemplate| objects after DOM modification.
//
// EphemeralRangeTemplate is supposed to use returning or passing start and end
// position.
//
//  Example usage:
//    Range* range = produceRange();
//    consumeRange(range);
//    ... no DOM modification ...
//    consumeRange2(range);
//
//  Above code should be:
//    EphemeralRangeTemplate range = produceRange();
//    consumeRange(range);
//    ... no DOM modification ...
//    consumeRange2(range);
//
//  Because of |Range| objects consume heap memory and inserted into |Range|
//  object list in |Document| for relocation. These operations are redundant
//  if |Range| objects doesn't live after DOM mutation.
//
template <typename Strategy>
class CORE_TEMPLATE_CLASS_EXPORT EphemeralRangeTemplate final {
  STACK_ALLOCATED();

 public:
  using RangeTraversal =
      TraversalRangeNodes<CheckedTraversalNextIterator<Strategy>>;

  EphemeralRangeTemplate(const PositionTemplate<Strategy>& start,
                         const PositionTemplate<Strategy>& end);
  EphemeralRangeTemplate(const EphemeralRangeTemplate& other);
  // |position| should be |Position::isNull()| or in-document.
  explicit EphemeralRangeTemplate(
      const PositionTemplate<Strategy>& /* position */);
  // When |range| is nullptr, |EphemeralRangeTemplate| is |isNull()|.
  explicit EphemeralRangeTemplate(const Range* /* range */);
  EphemeralRangeTemplate();
  ~EphemeralRangeTemplate();

  EphemeralRangeTemplate<Strategy>& operator=(
      const EphemeralRangeTemplate<Strategy>& other);

  bool operator==(const EphemeralRangeTemplate<Strategy>& other) const;
  bool operator!=(const EphemeralRangeTemplate<Strategy>& other) const;

  Document& GetDocument() const;
  PositionTemplate<Strategy> StartPosition() const;
  PositionTemplate<Strategy> EndPosition() const;

  Node* CommonAncestorContainer() const;

  // Returns true if |m_startPositoin| == |m_endPosition| or |isNull()|.
  bool IsCollapsed() const;
  bool IsNull() const {
    DCHECK(IsValid());
    return start_position_.IsNull();
  }
  bool IsNotNull() const { return !IsNull(); }

  RangeTraversal Nodes() const;

  // |node| should be in-document and valid for anchor node of
  // |PositionTemplate<Strategy>|.
  static EphemeralRangeTemplate<Strategy> RangeOfContents(
      const Node& /* node */);

#ifndef NDEBUG
  void ShowTreeForThis() const;
#endif

 private:
  bool IsValid() const;

  PositionTemplate<Strategy> start_position_;
  PositionTemplate<Strategy> end_position_;
#if DCHECK_IS_ON()
  uint64_t dom_tree_version_;
#endif
};

extern template class CORE_EXTERN_TEMPLATE_EXPORT
    EphemeralRangeTemplate<EditingStrategy>;
using EphemeralRange = EphemeralRangeTemplate<EditingStrategy>;

extern template class CORE_EXTERN_TEMPLATE_EXPORT
    EphemeralRangeTemplate<EditingInFlatTreeStrategy>;
using EphemeralRangeInFlatTree =
    EphemeralRangeTemplate<EditingInFlatTreeStrategy>;

// Returns a newly created |Range| object from |range| or |nullptr| if
// |range.isNull()| returns true.
CORE_EXPORT Range* CreateRange(const EphemeralRange& /* range */);

CORE_EXPORT std::ostream& operator<<(std::ostream&, const EphemeralRange&);
CORE_EXPORT std::ostream& operator<<(std::ostream&,
                                     const EphemeralRangeInFlatTree&);

}  // namespace blink

#endif