2009-03-31 Darin Adler <darin@apple.com>
[WebKit-https.git] / WebCore / dom / PositionIterator.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009 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_parent->hasChildNodes()) {
89         ASSERT(!m_offset);
90         m_parent = m_parent->lastChild();
91         if (!m_parent->hasChildNodes())
92             m_offset = lastOffsetForEditing(m_parent);
93     } else {
94         if (m_offset) {
95             m_offset = Position::uncheckedPreviousOffset(m_parent, m_offset);
96         } else {
97             m_child = m_parent;
98             m_parent = m_parent->parentNode();
99         }
100     }
101 }
102
103 bool PositionIterator::atStart() const
104 {
105     if (!m_parent)
106         return true;
107     if (m_parent->parentNode())
108         return false;
109     return (!m_parent->hasChildNodes() && !m_offset) || (m_child && !m_child->previousSibling());
110 }
111
112 bool PositionIterator::atEnd() const
113 {
114     if (!m_parent)
115         return true;
116     if (m_child)
117         return false;
118     return !m_parent->parentNode() && (m_parent->hasChildNodes() || m_offset >= lastOffsetForEditing(m_parent));
119 }
120
121 bool PositionIterator::atStartOfNode() const
122 {
123     if (!m_parent)
124         return true;
125     if (!m_child)
126         return !m_parent->hasChildNodes() && !m_offset;
127     return !m_child->previousSibling();
128 }
129
130 bool PositionIterator::atEndOfNode() const
131 {
132     if (!m_parent)
133         return true;
134     if (m_child)
135         return false;
136     return m_parent->hasChildNodes() || m_offset >= lastOffsetForEditing(m_parent);
137 }
138
139 bool PositionIterator::isCandidate() const
140 {
141     if (!m_parent)
142         return false;
143
144     RenderObject* renderer = m_parent->renderer();
145     if (!renderer)
146         return false;
147     
148     if (renderer->style()->visibility() != VISIBLE)
149         return false;
150
151     if (renderer->isBR())
152         return !m_offset && !Position::nodeIsUserSelectNone(m_parent->parent());
153
154     if (renderer->isText())
155         return Position(*this).inRenderedText() && !Position::nodeIsUserSelectNone(m_parent);
156
157     if (isTableElement(m_parent) || editingIgnoresContent(m_parent))
158         return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_parent->parent());
159
160     if (!m_parent->hasTagName(htmlTag) && renderer->isBlockFlow() && !Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
161        (toRenderBlock(renderer)->height() || m_parent->hasTagName(bodyTag)))
162         return atStartOfNode() && !Position::nodeIsUserSelectNone(m_parent);
163     
164     return false;
165 }
166
167 } // namespace WebCore