781d3521dea66384c7b747116486138418b8909f
[WebKit-https.git] / WebCore / dom / PositionIterator.cpp
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
37 PositionIterator::operator Position() const
38 {
39     if (m_child) {
40         ASSERT(m_child->parentNode() == m_parent);
41         return positionBeforeNode(m_child);
42     }
43     if (m_parent->hasChildNodes())
44         return lastDeepEditingPositionForNode(m_parent);
45     return Position(m_parent, m_offset);
46 }
47
48 void PositionIterator::increment()
49 {
50     if (!m_parent)
51         return;
52
53     if (m_child) {
54         m_parent = m_child;
55         m_child = m_parent->firstChild();
56         m_offset = 0;
57         return;
58     }
59
60     if (!m_parent->hasChildNodes() && m_offset < lastOffsetForEditing(m_parent))
61         m_offset = Position::uncheckedNextOffset(m_parent, m_offset);
62     else {
63         m_child = m_parent;
64         m_parent = m_child->parentNode();
65         m_child = m_child->nextSibling();
66         m_offset = 0;
67     }
68 }
69
70 void PositionIterator::decrement()
71 {
72     if (!m_parent)
73         return;
74
75     if (m_child) {
76         m_parent = m_child->previousSibling();
77         if (m_parent) {
78             m_child = 0;
79             m_offset = m_parent->hasChildNodes() ? 0 : lastOffsetForEditing(m_parent);
80         } else {
81             m_child = m_child->parentNode();
82             m_parent = m_child->parentNode();
83             m_offset = 0;
84         }
85         return;
86     }
87
88     if (m_offset) {
89         m_offset = Position::uncheckedPreviousOffset(m_parent, m_offset);
90     } else {
91         if (m_parent->hasChildNodes()) {
92             m_parent = m_parent->lastChild();
93             if (!m_parent->hasChildNodes())
94                 m_offset = lastOffsetForEditing(m_parent);
95         } else {
96             m_child = m_parent;
97             m_parent = m_parent->parentNode();
98         }
99     }
100 }
101
102 bool PositionIterator::atStart() const
103 {
104     if (!m_parent)
105         return true;
106     if (m_parent->parentNode())
107         return false;
108     return (!m_parent->hasChildNodes() && !m_offset) || (m_child && !m_child->previousSibling());
109 }
110
111 bool PositionIterator::atEnd() const
112 {
113     if (!m_parent)
114         return true;
115     if (m_child)
116         return false;
117     return !m_parent->parentNode() && (m_parent->hasChildNodes() || m_offset >= lastOffsetForEditing(m_parent));
118 }
119
120 bool PositionIterator::atStartOfNode() const
121 {
122     if (!m_parent)
123         return true;
124     if (!m_child)
125         return !m_parent->hasChildNodes() && !m_offset;
126     return !m_child->previousSibling();
127 }
128
129 bool PositionIterator::atEndOfNode() const
130 {
131     if (!m_parent)
132         return true;
133     if (m_child)
134         return false;
135     return m_parent->hasChildNodes() || m_offset >= lastOffsetForEditing(m_parent);
136 }
137
138 bool PositionIterator::isCandidate() const
139 {
140     if (!m_parent)
141         return false;
142
143     RenderObject* renderer = m_parent->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_offset && !Position::nodeIsUserSelectNone(m_parent->parent());
152
153     if (renderer->isText())
154         return Position(*this).inRenderedText() && !Position::nodeIsUserSelectNone(m_parent);
155
156     if (isTableElement(m_parent) || editingIgnoresContent(m_parent))
157         return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_parent->parent());
158
159     if (!m_parent->hasTagName(htmlTag) && renderer->isBlockFlow() && !Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
160        (toRenderBlock(renderer)->height() || m_parent->hasTagName(bodyTag)))
161         return atStartOfNode() && !Position::nodeIsUserSelectNone(m_parent);
162     
163     return false;
164 }
165
166 } // namespace WebCore