1/*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "Node.h"
29#include "Position.h"
30
31namespace WebCore {
32
33class RangeBoundaryPoint {
34public:
35 explicit RangeBoundaryPoint(Node* container);
36
37 const Position toPosition() const;
38
39 Node* container() const;
40 unsigned offset() const;
41 Node* childBefore() const;
42
43 void clear();
44
45 void set(Ref<Node>&& container, unsigned offset, Node* childBefore);
46 void setOffset(unsigned);
47
48 void setToBeforeChild(Node&);
49 void setToAfterChild(Node&);
50 void setToStartOfNode(Ref<Node>&&);
51 void setToEndOfNode(Ref<Node>&&);
52
53 void childBeforeWillBeRemoved();
54 void invalidateOffset() const;
55 void ensureOffsetIsValid() const;
56
57private:
58 RefPtr<Node> m_containerNode;
59 mutable Optional<unsigned> m_offsetInContainer { 0 };
60 RefPtr<Node> m_childBeforeBoundary;
61};
62
63inline RangeBoundaryPoint::RangeBoundaryPoint(Node* container)
64 : m_containerNode(container)
65{
66 ASSERT(m_containerNode);
67}
68
69inline Node* RangeBoundaryPoint::container() const
70{
71 return m_containerNode.get();
72}
73
74inline Node* RangeBoundaryPoint::childBefore() const
75{
76 return m_childBeforeBoundary.get();
77}
78
79inline void RangeBoundaryPoint::ensureOffsetIsValid() const
80{
81 if (m_offsetInContainer)
82 return;
83
84 ASSERT(m_childBeforeBoundary);
85 m_offsetInContainer = m_childBeforeBoundary->computeNodeIndex() + 1;
86}
87
88inline const Position RangeBoundaryPoint::toPosition() const
89{
90 ensureOffsetIsValid();
91 return createLegacyEditingPosition(m_containerNode.get(), m_offsetInContainer.value());
92}
93
94inline unsigned RangeBoundaryPoint::offset() const
95{
96 ensureOffsetIsValid();
97 return m_offsetInContainer.value();
98}
99
100inline void RangeBoundaryPoint::clear()
101{
102 m_containerNode = nullptr;
103 m_offsetInContainer = 0;
104 m_childBeforeBoundary = nullptr;
105}
106
107inline void RangeBoundaryPoint::set(Ref<Node>&& container, unsigned offset, Node* childBefore)
108{
109 ASSERT(childBefore == (offset ? container->traverseToChildAt(offset - 1) : 0));
110 m_containerNode = WTFMove(container);
111 m_offsetInContainer = offset;
112 m_childBeforeBoundary = childBefore;
113}
114
115inline void RangeBoundaryPoint::setOffset(unsigned offset)
116{
117 ASSERT(m_containerNode);
118 ASSERT(m_containerNode->isCharacterDataNode());
119 ASSERT(m_offsetInContainer);
120 ASSERT(!m_childBeforeBoundary);
121 m_offsetInContainer = offset;
122}
123
124inline void RangeBoundaryPoint::setToBeforeChild(Node& child)
125{
126 ASSERT(child.parentNode());
127 m_childBeforeBoundary = child.previousSibling();
128 m_containerNode = child.parentNode();
129 m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : Optional<unsigned>(0);
130}
131
132inline void RangeBoundaryPoint::setToAfterChild(Node& child)
133{
134 ASSERT(child.parentNode());
135 m_childBeforeBoundary = &child;
136 m_containerNode = child.parentNode();
137 m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : Optional<unsigned>(0);
138}
139
140inline void RangeBoundaryPoint::setToStartOfNode(Ref<Node>&& container)
141{
142 m_containerNode = WTFMove(container);
143 m_offsetInContainer = 0;
144 m_childBeforeBoundary = nullptr;
145}
146
147inline void RangeBoundaryPoint::setToEndOfNode(Ref<Node>&& container)
148{
149 m_containerNode = WTFMove(container);
150 if (m_containerNode->isCharacterDataNode()) {
151 m_offsetInContainer = m_containerNode->maxCharacterOffset();
152 m_childBeforeBoundary = nullptr;
153 } else {
154 m_childBeforeBoundary = m_containerNode->lastChild();
155 m_offsetInContainer = m_childBeforeBoundary ? WTF::nullopt : Optional<unsigned>(0);
156 }
157}
158
159inline void RangeBoundaryPoint::childBeforeWillBeRemoved()
160{
161 ASSERT(!m_offsetInContainer || m_offsetInContainer.value());
162 m_childBeforeBoundary = m_childBeforeBoundary->previousSibling();
163 if (!m_childBeforeBoundary)
164 m_offsetInContainer = 0;
165 else if (m_offsetInContainer && m_offsetInContainer.value() > 0)
166 --(m_offsetInContainer.value());
167}
168
169inline void RangeBoundaryPoint::invalidateOffset() const
170{
171 m_offsetInContainer = WTF::nullopt;
172}
173
174inline bool operator==(const RangeBoundaryPoint& a, const RangeBoundaryPoint& b)
175{
176 if (a.container() != b.container())
177 return false;
178 if (a.childBefore() || b.childBefore()) {
179 if (a.childBefore() != b.childBefore())
180 return false;
181 } else {
182 if (a.offset() != b.offset())
183 return false;
184 }
185 return true;
186}
187
188} // namespace WebCore
189