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 33namespace blink { 34 35class RangeBoundaryPoint { 36 DISALLOW_ALLOCATION(); 37public: 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 63private: 64 static const int invalidOffset = -1; 65 66 RefPtrWillBeMember<Node> m_containerNode; 67 mutable int m_offsetInContainer; 68 RefPtrWillBeMember<Node> m_childBeforeBoundary; 69}; 70 71inline RangeBoundaryPoint::RangeBoundaryPoint(PassRefPtrWillBeRawPtr<Node> container) 72 : m_containerNode(container) 73 , m_offsetInContainer(0) 74 , m_childBeforeBoundary(nullptr) 75{ 76 ASSERT(m_containerNode); 77} 78 79inline RangeBoundaryPoint::RangeBoundaryPoint(const RangeBoundaryPoint& other) 80 : m_containerNode(other.container()) 81 , m_offsetInContainer(other.offset()) 82 , m_childBeforeBoundary(other.childBefore()) 83{ 84} 85 86inline Node* RangeBoundaryPoint::container() const 87{ 88 return m_containerNode.get(); 89} 90 91inline Node* RangeBoundaryPoint::childBefore() const 92{ 93 return m_childBeforeBoundary.get(); 94} 95 96inline 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 105inline const Position RangeBoundaryPoint::toPosition() const 106{ 107 ensureOffsetIsValid(); 108 return createLegacyEditingPosition(m_containerNode.get(), m_offsetInContainer); 109} 110 111inline int RangeBoundaryPoint::offset() const 112{ 113 ensureOffsetIsValid(); 114 return m_offsetInContainer; 115} 116 117inline void RangeBoundaryPoint::clear() 118{ 119 m_containerNode.clear(); 120 m_offsetInContainer = 0; 121 m_childBeforeBoundary = nullptr; 122} 123 124inline 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 134inline 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 143inline 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 151inline void RangeBoundaryPoint::setToStartOfNode(Node& container) 152{ 153 m_containerNode = &container; 154 m_offsetInContainer = 0; 155 m_childBeforeBoundary = nullptr; 156} 157 158inline 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 170inline 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 180inline void RangeBoundaryPoint::invalidateOffset() const 181{ 182 m_offsetInContainer = invalidOffset; 183} 184 185inline void RangeBoundaryPoint::trace(Visitor* visitor) 186{ 187 visitor->trace(m_containerNode); 188 visitor->trace(m_childBeforeBoundary); 189} 190 191inline 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