1 /*
2 * Copyright (C) 2007, 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 #include "config.h"
27 #include "PositionIterator.h"
28
29 #include "Node.h"
30 #include "RenderBlock.h"
31 #include "htmlediting.h"
32
33 namespace WebCore {
34
35 using namespace HTMLNames;
36
operator Position() const37 PositionIterator::operator Position() const
38 {
39 if (m_nodeAfterPositionInAnchor) {
40 ASSERT(m_nodeAfterPositionInAnchor->parentNode() == m_anchorNode);
41 return positionInParentBeforeNode(m_nodeAfterPositionInAnchor);
42 }
43 if (m_anchorNode->hasChildNodes())
44 return lastDeepEditingPositionForNode(m_anchorNode);
45 return Position(m_anchorNode, m_offsetInAnchor);
46 }
47
increment()48 void PositionIterator::increment()
49 {
50 if (!m_anchorNode)
51 return;
52
53 if (m_nodeAfterPositionInAnchor) {
54 m_anchorNode = m_nodeAfterPositionInAnchor;
55 m_nodeAfterPositionInAnchor = m_anchorNode->firstChild();
56 m_offsetInAnchor = 0;
57 return;
58 }
59
60 if (!m_anchorNode->hasChildNodes() && m_offsetInAnchor < lastOffsetForEditing(m_anchorNode))
61 m_offsetInAnchor = Position::uncheckedNextOffset(m_anchorNode, m_offsetInAnchor);
62 else {
63 m_nodeAfterPositionInAnchor = m_anchorNode;
64 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode();
65 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->nextSibling();
66 m_offsetInAnchor = 0;
67 }
68 }
69
decrement()70 void PositionIterator::decrement()
71 {
72 if (!m_anchorNode)
73 return;
74
75 if (m_nodeAfterPositionInAnchor) {
76 m_anchorNode = m_nodeAfterPositionInAnchor->previousSibling();
77 if (m_anchorNode) {
78 m_nodeAfterPositionInAnchor = 0;
79 m_offsetInAnchor = m_anchorNode->hasChildNodes() ? 0 : lastOffsetForEditing(m_anchorNode);
80 } else {
81 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->parentNode();
82 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode();
83 m_offsetInAnchor = 0;
84 }
85 return;
86 }
87
88 if (m_offsetInAnchor) {
89 m_offsetInAnchor = Position::uncheckedPreviousOffset(m_anchorNode, m_offsetInAnchor);
90 } else {
91 if (m_anchorNode->hasChildNodes()) {
92 m_anchorNode = m_anchorNode->lastChild();
93 if (!m_anchorNode->hasChildNodes())
94 m_offsetInAnchor = lastOffsetForEditing(m_anchorNode);
95 } else {
96 m_nodeAfterPositionInAnchor = m_anchorNode;
97 m_anchorNode = m_anchorNode->parentNode();
98 }
99 }
100 }
101
atStart() const102 bool PositionIterator::atStart() const
103 {
104 if (!m_anchorNode)
105 return true;
106 if (m_anchorNode->parentNode())
107 return false;
108 return (!m_anchorNode->hasChildNodes() && !m_offsetInAnchor) || (m_nodeAfterPositionInAnchor && !m_nodeAfterPositionInAnchor->previousSibling());
109 }
110
atEnd() const111 bool PositionIterator::atEnd() const
112 {
113 if (!m_anchorNode)
114 return true;
115 if (m_nodeAfterPositionInAnchor)
116 return false;
117 return !m_anchorNode->parentNode() && (m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode));
118 }
119
atStartOfNode() const120 bool PositionIterator::atStartOfNode() const
121 {
122 if (!m_anchorNode)
123 return true;
124 if (!m_nodeAfterPositionInAnchor)
125 return !m_anchorNode->hasChildNodes() && !m_offsetInAnchor;
126 return !m_nodeAfterPositionInAnchor->previousSibling();
127 }
128
atEndOfNode() const129 bool PositionIterator::atEndOfNode() const
130 {
131 if (!m_anchorNode)
132 return true;
133 if (m_nodeAfterPositionInAnchor)
134 return false;
135 return m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode);
136 }
137
isCandidate() const138 bool PositionIterator::isCandidate() const
139 {
140 if (!m_anchorNode)
141 return false;
142
143 RenderObject* renderer = m_anchorNode->renderer();
144 if (!renderer)
145 return false;
146
147 if (renderer->style()->visibility() != VISIBLE)
148 return false;
149
150 if (renderer->isBR())
151 return !m_offsetInAnchor && !Position::nodeIsUserSelectNone(m_anchorNode->parent());
152
153 if (renderer->isText())
154 return Position(*this).inRenderedText() && !Position::nodeIsUserSelectNone(m_anchorNode);
155
156 if (isTableElement(m_anchorNode) || editingIgnoresContent(m_anchorNode))
157 return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_anchorNode->parent());
158
159 if (!m_anchorNode->hasTagName(htmlTag) && renderer->isBlockFlow()) {
160 if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
161 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
162 return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode);
163 return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary();
164 }
165 }
166
167 return false;
168 }
169
170 } // namespace WebCore
171