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#include "core/rendering/InlineBox.h"
37
38namespace WebCore {
39
40static inline RenderObject* rendererFromPosition(const Position& position)
41{
42    ASSERT(position.isNotNull());
43    Node* rendererNode = 0;
44    switch (position.anchorType()) {
45    case Position::PositionIsOffsetInAnchor:
46        rendererNode = position.computeNodeAfterPosition();
47        if (!rendererNode || !rendererNode->renderer())
48            rendererNode = position.anchorNode()->lastChild();
49        break;
50
51    case Position::PositionIsBeforeAnchor:
52    case Position::PositionIsAfterAnchor:
53        break;
54
55    case Position::PositionIsBeforeChildren:
56        rendererNode = position.anchorNode()->firstChild();
57        break;
58    case Position::PositionIsAfterChildren:
59        rendererNode = position.anchorNode()->lastChild();
60        break;
61    }
62    if (!rendererNode || !rendererNode->renderer())
63        rendererNode = position.anchorNode();
64    return rendererNode->renderer();
65}
66
67RenderedPosition::RenderedPosition(const VisiblePosition& position)
68    : m_renderer(0)
69    , m_inlineBox(0)
70    , m_offset(0)
71    , m_prevLeafChild(uncachedInlineBox())
72    , m_nextLeafChild(uncachedInlineBox())
73{
74    if (position.isNull())
75        return;
76    position.getInlineBoxAndOffset(m_inlineBox, m_offset);
77    if (m_inlineBox)
78        m_renderer = m_inlineBox->renderer();
79    else
80        m_renderer = rendererFromPosition(position.deepEquivalent());
81}
82
83RenderedPosition::RenderedPosition(const Position& position, EAffinity affinity)
84    : m_renderer(0)
85    , m_inlineBox(0)
86    , m_offset(0)
87    , m_prevLeafChild(uncachedInlineBox())
88    , m_nextLeafChild(uncachedInlineBox())
89{
90    if (position.isNull())
91        return;
92    position.getInlineBoxAndOffset(affinity, m_inlineBox, m_offset);
93    if (m_inlineBox)
94        m_renderer = m_inlineBox->renderer();
95    else
96        m_renderer = rendererFromPosition(position);
97}
98
99InlineBox* RenderedPosition::prevLeafChild() const
100{
101    if (m_prevLeafChild == uncachedInlineBox())
102        m_prevLeafChild = m_inlineBox->prevLeafChildIgnoringLineBreak();
103    return m_prevLeafChild;
104}
105
106InlineBox* RenderedPosition::nextLeafChild() const
107{
108    if (m_nextLeafChild == uncachedInlineBox())
109        m_nextLeafChild = m_inlineBox->nextLeafChildIgnoringLineBreak();
110    return m_nextLeafChild;
111}
112
113bool RenderedPosition::isEquivalent(const RenderedPosition& other) const
114{
115    return (m_renderer == other.m_renderer && m_inlineBox == other.m_inlineBox && m_offset == other.m_offset)
116        || (atLeftmostOffsetInBox() && other.atRightmostOffsetInBox() && prevLeafChild() == other.m_inlineBox)
117        || (atRightmostOffsetInBox() && other.atLeftmostOffsetInBox() && nextLeafChild() == other.m_inlineBox);
118}
119
120unsigned char RenderedPosition::bidiLevelOnLeft() const
121{
122    InlineBox* box = atLeftmostOffsetInBox() ? prevLeafChild() : m_inlineBox;
123    return box ? box->bidiLevel() : 0;
124}
125
126unsigned char RenderedPosition::bidiLevelOnRight() const
127{
128    InlineBox* box = atRightmostOffsetInBox() ? nextLeafChild() : m_inlineBox;
129    return box ? box->bidiLevel() : 0;
130}
131
132RenderedPosition RenderedPosition::leftBoundaryOfBidiRun(unsigned char bidiLevelOfRun)
133{
134    if (!m_inlineBox || bidiLevelOfRun > m_inlineBox->bidiLevel())
135        return RenderedPosition();
136
137    InlineBox* box = m_inlineBox;
138    do {
139        InlineBox* prev = box->prevLeafChildIgnoringLineBreak();
140        if (!prev || prev->bidiLevel() < bidiLevelOfRun)
141            return RenderedPosition(box->renderer(), box, box->caretLeftmostOffset());
142        box = prev;
143    } while (box);
144
145    ASSERT_NOT_REACHED();
146    return RenderedPosition();
147}
148
149RenderedPosition RenderedPosition::rightBoundaryOfBidiRun(unsigned char bidiLevelOfRun)
150{
151    if (!m_inlineBox || bidiLevelOfRun > m_inlineBox->bidiLevel())
152        return RenderedPosition();
153
154    InlineBox* box = m_inlineBox;
155    do {
156        InlineBox* next = box->nextLeafChildIgnoringLineBreak();
157        if (!next || next->bidiLevel() < bidiLevelOfRun)
158            return RenderedPosition(box->renderer(), box, box->caretRightmostOffset());
159        box = next;
160    } while (box);
161
162    ASSERT_NOT_REACHED();
163    return RenderedPosition();
164}
165
166bool RenderedPosition::atLeftBoundaryOfBidiRun(ShouldMatchBidiLevel shouldMatchBidiLevel, unsigned char bidiLevelOfRun) const
167{
168    if (!m_inlineBox)
169        return false;
170
171    if (atLeftmostOffsetInBox()) {
172        if (shouldMatchBidiLevel == IgnoreBidiLevel)
173            return !prevLeafChild() || prevLeafChild()->bidiLevel() < m_inlineBox->bidiLevel();
174        return m_inlineBox->bidiLevel() >= bidiLevelOfRun && (!prevLeafChild() || prevLeafChild()->bidiLevel() < bidiLevelOfRun);
175    }
176
177    if (atRightmostOffsetInBox()) {
178        if (shouldMatchBidiLevel == IgnoreBidiLevel)
179            return nextLeafChild() && m_inlineBox->bidiLevel() < nextLeafChild()->bidiLevel();
180        return nextLeafChild() && m_inlineBox->bidiLevel() < bidiLevelOfRun && nextLeafChild()->bidiLevel() >= bidiLevelOfRun;
181    }
182
183    return false;
184}
185
186bool RenderedPosition::atRightBoundaryOfBidiRun(ShouldMatchBidiLevel shouldMatchBidiLevel, unsigned char bidiLevelOfRun) const
187{
188    if (!m_inlineBox)
189        return false;
190
191    if (atRightmostOffsetInBox()) {
192        if (shouldMatchBidiLevel == IgnoreBidiLevel)
193            return !nextLeafChild() || nextLeafChild()->bidiLevel() < m_inlineBox->bidiLevel();
194        return m_inlineBox->bidiLevel() >= bidiLevelOfRun && (!nextLeafChild() || nextLeafChild()->bidiLevel() < bidiLevelOfRun);
195    }
196
197    if (atLeftmostOffsetInBox()) {
198        if (shouldMatchBidiLevel == IgnoreBidiLevel)
199            return prevLeafChild() && m_inlineBox->bidiLevel() < prevLeafChild()->bidiLevel();
200        return prevLeafChild() && m_inlineBox->bidiLevel() < bidiLevelOfRun && prevLeafChild()->bidiLevel() >= bidiLevelOfRun;
201    }
202
203    return false;
204}
205
206Position RenderedPosition::positionAtLeftBoundaryOfBiDiRun() const
207{
208    ASSERT(atLeftBoundaryOfBidiRun());
209
210    if (atLeftmostOffsetInBox())
211        return createLegacyEditingPosition(m_renderer->node(), m_offset);
212
213    return createLegacyEditingPosition(nextLeafChild()->renderer()->node(), nextLeafChild()->caretLeftmostOffset());
214}
215
216Position RenderedPosition::positionAtRightBoundaryOfBiDiRun() const
217{
218    ASSERT(atRightBoundaryOfBidiRun());
219
220    if (atRightmostOffsetInBox())
221        return createLegacyEditingPosition(m_renderer->node(), m_offset);
222
223    return createLegacyEditingPosition(prevLeafChild()->renderer()->node(), prevLeafChild()->caretRightmostOffset());
224}
225
226IntRect RenderedPosition::absoluteRect(LayoutUnit* extraWidthToEndOfLine) const
227{
228    if (isNull())
229        return IntRect();
230
231    IntRect localRect = pixelSnappedIntRect(m_renderer->localCaretRect(m_inlineBox, m_offset, extraWidthToEndOfLine));
232    return localRect == IntRect() ? IntRect() : m_renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
233}
234
235bool renderObjectContainsPosition(RenderObject* target, const Position& position)
236{
237    for (RenderObject* renderer = rendererFromPosition(position); renderer && renderer->node(); renderer = renderer->parent()) {
238        if (renderer == target)
239            return true;
240    }
241    return false;
242}
243
244};
245