Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / editing / RenderedPosition.cpp
1 /*
2  * Copyright (C) 2011 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "core/editing/RenderedPosition.h"
33
34 #include "core/dom/Position.h"
35 #include "core/editing/VisiblePosition.h"
36
37 namespace blink {
38
39 static inline RenderObject* rendererFromPosition(const Position& position)
40 {
41     ASSERT(position.isNotNull());
42     Node* rendererNode = 0;
43     switch (position.anchorType()) {
44     case Position::PositionIsOffsetInAnchor:
45         rendererNode = position.computeNodeAfterPosition();
46         if (!rendererNode || !rendererNode->renderer())
47             rendererNode = position.anchorNode()->lastChild();
48         break;
49
50     case Position::PositionIsBeforeAnchor:
51     case Position::PositionIsAfterAnchor:
52         break;
53
54     case Position::PositionIsBeforeChildren:
55         rendererNode = position.anchorNode()->firstChild();
56         break;
57     case Position::PositionIsAfterChildren:
58         rendererNode = position.anchorNode()->lastChild();
59         break;
60     }
61     if (!rendererNode || !rendererNode->renderer())
62         rendererNode = position.anchorNode();
63     return rendererNode->renderer();
64 }
65
66 RenderedPosition::RenderedPosition(const VisiblePosition& position)
67     : m_renderer(0)
68     , m_inlineBox(0)
69     , m_offset(0)
70     , m_prevLeafChild(uncachedInlineBox())
71     , m_nextLeafChild(uncachedInlineBox())
72 {
73     if (position.isNull())
74         return;
75     position.getInlineBoxAndOffset(m_inlineBox, m_offset);
76     if (m_inlineBox)
77         m_renderer = &m_inlineBox->renderer();
78     else
79         m_renderer = rendererFromPosition(position.deepEquivalent());
80 }
81
82 RenderedPosition::RenderedPosition(const Position& position, EAffinity affinity)
83     : m_renderer(0)
84     , m_inlineBox(0)
85     , m_offset(0)
86     , m_prevLeafChild(uncachedInlineBox())
87     , m_nextLeafChild(uncachedInlineBox())
88 {
89     if (position.isNull())
90         return;
91     position.getInlineBoxAndOffset(affinity, m_inlineBox, m_offset);
92     if (m_inlineBox)
93         m_renderer = &m_inlineBox->renderer();
94     else
95         m_renderer = rendererFromPosition(position);
96 }
97
98 InlineBox* RenderedPosition::prevLeafChild() const
99 {
100     if (m_prevLeafChild == uncachedInlineBox())
101         m_prevLeafChild = m_inlineBox->prevLeafChildIgnoringLineBreak();
102     return m_prevLeafChild;
103 }
104
105 InlineBox* RenderedPosition::nextLeafChild() const
106 {
107     if (m_nextLeafChild == uncachedInlineBox())
108         m_nextLeafChild = m_inlineBox->nextLeafChildIgnoringLineBreak();
109     return m_nextLeafChild;
110 }
111
112 bool RenderedPosition::isEquivalent(const RenderedPosition& other) const
113 {
114     return (m_renderer == other.m_renderer && m_inlineBox == other.m_inlineBox && m_offset == other.m_offset)
115         || (atLeftmostOffsetInBox() && other.atRightmostOffsetInBox() && prevLeafChild() == other.m_inlineBox)
116         || (atRightmostOffsetInBox() && other.atLeftmostOffsetInBox() && nextLeafChild() == other.m_inlineBox);
117 }
118
119 unsigned char RenderedPosition::bidiLevelOnLeft() const
120 {
121     InlineBox* box = atLeftmostOffsetInBox() ? prevLeafChild() : m_inlineBox;
122     return box ? box->bidiLevel() : 0;
123 }
124
125 unsigned char RenderedPosition::bidiLevelOnRight() const
126 {
127     InlineBox* box = atRightmostOffsetInBox() ? nextLeafChild() : m_inlineBox;
128     return box ? box->bidiLevel() : 0;
129 }
130
131 RenderedPosition RenderedPosition::leftBoundaryOfBidiRun(unsigned char bidiLevelOfRun)
132 {
133     if (!m_inlineBox || bidiLevelOfRun > m_inlineBox->bidiLevel())
134         return RenderedPosition();
135
136     InlineBox* box = m_inlineBox;
137     do {
138         InlineBox* prev = box->prevLeafChildIgnoringLineBreak();
139         if (!prev || prev->bidiLevel() < bidiLevelOfRun)
140             return RenderedPosition(&box->renderer(), box, box->caretLeftmostOffset());
141         box = prev;
142     } while (box);
143
144     ASSERT_NOT_REACHED();
145     return RenderedPosition();
146 }
147
148 RenderedPosition RenderedPosition::rightBoundaryOfBidiRun(unsigned char bidiLevelOfRun)
149 {
150     if (!m_inlineBox || bidiLevelOfRun > m_inlineBox->bidiLevel())
151         return RenderedPosition();
152
153     InlineBox* box = m_inlineBox;
154     do {
155         InlineBox* next = box->nextLeafChildIgnoringLineBreak();
156         if (!next || next->bidiLevel() < bidiLevelOfRun)
157             return RenderedPosition(&box->renderer(), box, box->caretRightmostOffset());
158         box = next;
159     } while (box);
160
161     ASSERT_NOT_REACHED();
162     return RenderedPosition();
163 }
164
165 bool RenderedPosition::atLeftBoundaryOfBidiRun(ShouldMatchBidiLevel shouldMatchBidiLevel, unsigned char bidiLevelOfRun) const
166 {
167     if (!m_inlineBox)
168         return false;
169
170     if (atLeftmostOffsetInBox()) {
171         if (shouldMatchBidiLevel == IgnoreBidiLevel)
172             return !prevLeafChild() || prevLeafChild()->bidiLevel() < m_inlineBox->bidiLevel();
173         return m_inlineBox->bidiLevel() >= bidiLevelOfRun && (!prevLeafChild() || prevLeafChild()->bidiLevel() < bidiLevelOfRun);
174     }
175
176     if (atRightmostOffsetInBox()) {
177         if (shouldMatchBidiLevel == IgnoreBidiLevel)
178             return nextLeafChild() && m_inlineBox->bidiLevel() < nextLeafChild()->bidiLevel();
179         return nextLeafChild() && m_inlineBox->bidiLevel() < bidiLevelOfRun && nextLeafChild()->bidiLevel() >= bidiLevelOfRun;
180     }
181
182     return false;
183 }
184
185 bool RenderedPosition::atRightBoundaryOfBidiRun(ShouldMatchBidiLevel shouldMatchBidiLevel, unsigned char bidiLevelOfRun) const
186 {
187     if (!m_inlineBox)
188         return false;
189
190     if (atRightmostOffsetInBox()) {
191         if (shouldMatchBidiLevel == IgnoreBidiLevel)
192             return !nextLeafChild() || nextLeafChild()->bidiLevel() < m_inlineBox->bidiLevel();
193         return m_inlineBox->bidiLevel() >= bidiLevelOfRun && (!nextLeafChild() || nextLeafChild()->bidiLevel() < bidiLevelOfRun);
194     }
195
196     if (atLeftmostOffsetInBox()) {
197         if (shouldMatchBidiLevel == IgnoreBidiLevel)
198             return prevLeafChild() && m_inlineBox->bidiLevel() < prevLeafChild()->bidiLevel();
199         return prevLeafChild() && m_inlineBox->bidiLevel() < bidiLevelOfRun && prevLeafChild()->bidiLevel() >= bidiLevelOfRun;
200     }
201
202     return false;
203 }
204
205 Position RenderedPosition::positionAtLeftBoundaryOfBiDiRun() const
206 {
207     ASSERT(atLeftBoundaryOfBidiRun());
208
209     if (atLeftmostOffsetInBox())
210         return createLegacyEditingPosition(m_renderer->node(), m_offset);
211
212     return createLegacyEditingPosition(nextLeafChild()->renderer().node(), nextLeafChild()->caretLeftmostOffset());
213 }
214
215 Position RenderedPosition::positionAtRightBoundaryOfBiDiRun() const
216 {
217     ASSERT(atRightBoundaryOfBidiRun());
218
219     if (atRightmostOffsetInBox())
220         return createLegacyEditingPosition(m_renderer->node(), m_offset);
221
222     return createLegacyEditingPosition(prevLeafChild()->renderer().node(), prevLeafChild()->caretRightmostOffset());
223 }
224
225 IntRect RenderedPosition::absoluteRect(LayoutUnit* extraWidthToEndOfLine) const
226 {
227     if (isNull())
228         return IntRect();
229
230     IntRect localRect = pixelSnappedIntRect(m_renderer->localCaretRect(m_inlineBox, m_offset, extraWidthToEndOfLine));
231     return localRect == IntRect() ? IntRect() : m_renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
232 }
233
234 bool renderObjectContainsPosition(RenderObject* target, const Position& position)
235 {
236     for (RenderObject* renderer = rendererFromPosition(position); renderer && renderer->node(); renderer = renderer->parent()) {
237         if (renderer == target)
238             return true;
239     }
240     return false;
241 }
242
243 };