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 "core/dom/PositionIterator.h"
28
29 #include "HTMLNames.h"
30 #include "core/editing/htmlediting.h"
31 #include "core/html/HTMLHtmlElement.h"
32 #include "core/rendering/RenderBlock.h"
33
34 namespace WebCore {
35
36 using namespace HTMLNames;
37
operator Position() const38 PositionIterator::operator Position() const
39 {
40 if (m_nodeAfterPositionInAnchor) {
41 ASSERT(m_nodeAfterPositionInAnchor->parentNode() == m_anchorNode);
42 // FIXME: This check is inadaquete because any ancestor could be ignored by editing
43 if (editingIgnoresContent(m_nodeAfterPositionInAnchor->parentNode()))
44 return positionBeforeNode(m_anchorNode);
45 return positionInParentBeforeNode(m_nodeAfterPositionInAnchor);
46 }
47 if (m_anchorNode->hasChildNodes())
48 return lastPositionInOrAfterNode(m_anchorNode);
49 return createLegacyEditingPosition(m_anchorNode, m_offsetInAnchor);
50 }
51
increment()52 void PositionIterator::increment()
53 {
54 if (!m_anchorNode)
55 return;
56
57 if (m_nodeAfterPositionInAnchor) {
58 m_anchorNode = m_nodeAfterPositionInAnchor;
59 m_nodeAfterPositionInAnchor = m_anchorNode->firstChild();
60 m_offsetInAnchor = 0;
61 return;
62 }
63
64 if (!m_anchorNode->hasChildNodes() && m_offsetInAnchor < lastOffsetForEditing(m_anchorNode))
65 m_offsetInAnchor = Position::uncheckedNextOffset(m_anchorNode, m_offsetInAnchor);
66 else {
67 m_nodeAfterPositionInAnchor = m_anchorNode;
68 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode();
69 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->nextSibling();
70 m_offsetInAnchor = 0;
71 }
72 }
73
decrement()74 void PositionIterator::decrement()
75 {
76 if (!m_anchorNode)
77 return;
78
79 if (m_nodeAfterPositionInAnchor) {
80 m_anchorNode = m_nodeAfterPositionInAnchor->previousSibling();
81 if (m_anchorNode) {
82 m_nodeAfterPositionInAnchor = 0;
83 m_offsetInAnchor = m_anchorNode->hasChildNodes() ? 0 : lastOffsetForEditing(m_anchorNode);
84 } else {
85 m_nodeAfterPositionInAnchor = m_nodeAfterPositionInAnchor->parentNode();
86 m_anchorNode = m_nodeAfterPositionInAnchor->parentNode();
87 m_offsetInAnchor = 0;
88 }
89 return;
90 }
91
92 if (m_anchorNode->hasChildNodes()) {
93 m_anchorNode = m_anchorNode->lastChild();
94 m_offsetInAnchor = m_anchorNode->hasChildNodes()? 0: lastOffsetForEditing(m_anchorNode);
95 } else {
96 if (m_offsetInAnchor)
97 m_offsetInAnchor = Position::uncheckedPreviousOffset(m_anchorNode, m_offsetInAnchor);
98 else {
99 m_nodeAfterPositionInAnchor = m_anchorNode;
100 m_anchorNode = m_anchorNode->parentNode();
101 }
102 }
103 }
104
atStart() const105 bool PositionIterator::atStart() const
106 {
107 if (!m_anchorNode)
108 return true;
109 if (m_anchorNode->parentNode())
110 return false;
111 return (!m_anchorNode->hasChildNodes() && !m_offsetInAnchor) || (m_nodeAfterPositionInAnchor && !m_nodeAfterPositionInAnchor->previousSibling());
112 }
113
atEnd() const114 bool PositionIterator::atEnd() const
115 {
116 if (!m_anchorNode)
117 return true;
118 if (m_nodeAfterPositionInAnchor)
119 return false;
120 return !m_anchorNode->parentNode() && (m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode));
121 }
122
atStartOfNode() const123 bool PositionIterator::atStartOfNode() const
124 {
125 if (!m_anchorNode)
126 return true;
127 if (!m_nodeAfterPositionInAnchor)
128 return !m_anchorNode->hasChildNodes() && !m_offsetInAnchor;
129 return !m_nodeAfterPositionInAnchor->previousSibling();
130 }
131
atEndOfNode() const132 bool PositionIterator::atEndOfNode() const
133 {
134 if (!m_anchorNode)
135 return true;
136 if (m_nodeAfterPositionInAnchor)
137 return false;
138 return m_anchorNode->hasChildNodes() || m_offsetInAnchor >= lastOffsetForEditing(m_anchorNode);
139 }
140
isCandidate() const141 bool PositionIterator::isCandidate() const
142 {
143 if (!m_anchorNode)
144 return false;
145
146 RenderObject* renderer = m_anchorNode->renderer();
147 if (!renderer)
148 return false;
149
150 if (renderer->style()->visibility() != VISIBLE)
151 return false;
152
153 if (renderer->isBR())
154 return !m_offsetInAnchor && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode());
155
156 if (renderer->isText())
157 return !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).inRenderedText();
158
159 if (isTableElement(m_anchorNode) || editingIgnoresContent(m_anchorNode))
160 return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_anchorNode->parentNode());
161
162 if (!isHTMLHtmlElement(m_anchorNode) && renderer->isRenderBlockFlow()) {
163 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName(bodyTag)) {
164 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
165 return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode);
166 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary();
167 }
168 }
169
170 return false;
171 }
172
173 } // namespace WebCore
174