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