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 #ifndef RangeBoundaryPoint_h
27 #define RangeBoundaryPoint_h
28 
29 #include "Node.h"
30 #include "Position.h"
31 
32 namespace WebCore {
33 
34 class RangeBoundaryPoint {
35 public:
36     explicit RangeBoundaryPoint(PassRefPtr<Node> container);
37 
38     const Position toPosition() const;
39 
40     Node* container() const;
41     int offset() const;
42     Node* childBefore() const;
43 
44     void clear();
45 
46     void set(PassRefPtr<Node> container, int offset, Node* childBefore);
47     void setOffset(int offset);
48 
49     void setToBeforeChild(Node*);
50     void setToStartOfNode(PassRefPtr<Node>);
51     void setToEndOfNode(PassRefPtr<Node>);
52 
53     void childBeforeWillBeRemoved();
54     void invalidateOffset() const;
55     void ensureOffsetIsValid() const;
56 
57 private:
58     static const int invalidOffset = -1;
59 
60     RefPtr<Node> m_containerNode;
61     mutable int m_offsetInContainer;
62     Node* m_childBeforeBoundary;
63 };
64 
RangeBoundaryPoint(PassRefPtr<Node> container)65 inline RangeBoundaryPoint::RangeBoundaryPoint(PassRefPtr<Node> container)
66     : m_containerNode(container)
67     , m_offsetInContainer(0)
68     , m_childBeforeBoundary(0)
69 {
70     ASSERT(m_containerNode);
71 }
72 
container()73 inline Node* RangeBoundaryPoint::container() const
74 {
75     return m_containerNode.get();
76 }
77 
childBefore()78 inline Node* RangeBoundaryPoint::childBefore() const
79 {
80     return m_childBeforeBoundary;
81 }
82 
ensureOffsetIsValid()83 inline void RangeBoundaryPoint::ensureOffsetIsValid() const
84 {
85     if (m_offsetInContainer >= 0)
86         return;
87 
88     ASSERT(m_childBeforeBoundary);
89     m_offsetInContainer = m_childBeforeBoundary->nodeIndex() + 1;
90 }
91 
toPosition()92 inline const Position RangeBoundaryPoint::toPosition() const
93 {
94     ensureOffsetIsValid();
95     return Position(m_containerNode.get(), m_offsetInContainer);
96 }
97 
offset()98 inline int RangeBoundaryPoint::offset() const
99 {
100     ensureOffsetIsValid();
101     return m_offsetInContainer;
102 }
103 
clear()104 inline void RangeBoundaryPoint::clear()
105 {
106     m_containerNode.clear();
107     m_offsetInContainer = 0;
108     m_childBeforeBoundary = 0;
109 }
110 
set(PassRefPtr<Node> container,int offset,Node * childBefore)111 inline void RangeBoundaryPoint::set(PassRefPtr<Node> container, int offset, Node* childBefore)
112 {
113     ASSERT(container);
114     ASSERT(offset >= 0);
115     ASSERT(childBefore == (offset ? container->childNode(offset - 1) : 0));
116     m_containerNode = container;
117     m_offsetInContainer = offset;
118     m_childBeforeBoundary = childBefore;
119 }
120 
setOffset(int offset)121 inline void RangeBoundaryPoint::setOffset(int offset)
122 {
123     ASSERT(m_containerNode);
124     ASSERT(m_containerNode->offsetInCharacters());
125     ASSERT(m_offsetInContainer >= 0);
126     ASSERT(!m_childBeforeBoundary);
127     m_offsetInContainer = offset;
128 }
129 
setToBeforeChild(Node * child)130 inline void RangeBoundaryPoint::setToBeforeChild(Node* child)
131 {
132     ASSERT(child);
133     ASSERT(child->parentNode());
134     m_childBeforeBoundary = child->previousSibling();
135     m_containerNode = child->parentNode();
136     m_offsetInContainer = m_childBeforeBoundary ? invalidOffset : 0;
137 }
138 
setToStartOfNode(PassRefPtr<Node> container)139 inline void RangeBoundaryPoint::setToStartOfNode(PassRefPtr<Node> container)
140 {
141     ASSERT(container);
142     m_containerNode = container;
143     m_offsetInContainer = 0;
144     m_childBeforeBoundary = 0;
145 }
146 
setToEndOfNode(PassRefPtr<Node> container)147 inline void RangeBoundaryPoint::setToEndOfNode(PassRefPtr<Node> container)
148 {
149     ASSERT(container);
150     m_containerNode = container;
151     if (m_containerNode->offsetInCharacters()) {
152         m_offsetInContainer = m_containerNode->maxCharacterOffset();
153         m_childBeforeBoundary = 0;
154     } else {
155         m_childBeforeBoundary = m_containerNode->lastChild();
156         m_offsetInContainer = m_childBeforeBoundary ? invalidOffset : 0;
157     }
158 }
159 
childBeforeWillBeRemoved()160 inline void RangeBoundaryPoint::childBeforeWillBeRemoved()
161 {
162     ASSERT(m_offsetInContainer);
163     m_childBeforeBoundary = m_childBeforeBoundary->previousSibling();
164     if (!m_childBeforeBoundary)
165         m_offsetInContainer = 0;
166     else if (m_offsetInContainer > 0)
167         --m_offsetInContainer;
168 }
169 
invalidateOffset()170 inline void RangeBoundaryPoint::invalidateOffset() const
171 {
172     m_offsetInContainer = invalidOffset;
173 }
174 
175 inline bool operator==(const RangeBoundaryPoint& a, const RangeBoundaryPoint& b)
176 {
177     if (a.container() != b.container())
178         return false;
179     if (a.childBefore() || b.childBefore()) {
180         if (a.childBefore() != b.childBefore())
181             return false;
182     } else {
183         if (a.offset() != b.offset())
184             return false;
185     }
186     return true;
187 }
188 
189 }
190 
191 #endif
192