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