2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "core/editing/RenderedPosition.h"
34 #include "core/editing/TextAffinity.h"
35 #include "core/editing/VisiblePosition.h"
36 #include "core/editing/VisibleUnits.h"
37 #include "core/layout/compositing/CompositedSelectionBound.h"
38 #include "core/paint/DeprecatedPaintLayer.h"
42 static inline LayoutObject
* layoutObjectFromPosition(const Position
& position
)
44 ASSERT(position
.isNotNull());
45 Node
* layoutObjectNode
= nullptr;
46 switch (position
.anchorType()) {
47 case PositionAnchorType::OffsetInAnchor
:
48 layoutObjectNode
= position
.computeNodeAfterPosition();
49 if (!layoutObjectNode
|| !layoutObjectNode
->layoutObject())
50 layoutObjectNode
= position
.anchorNode()->lastChild();
53 case PositionAnchorType::BeforeAnchor
:
54 case PositionAnchorType::AfterAnchor
:
57 case PositionAnchorType::BeforeChildren
:
58 layoutObjectNode
= position
.anchorNode()->firstChild();
60 case PositionAnchorType::AfterChildren
:
61 layoutObjectNode
= position
.anchorNode()->lastChild();
64 if (!layoutObjectNode
|| !layoutObjectNode
->layoutObject())
65 layoutObjectNode
= position
.anchorNode();
66 return layoutObjectNode
->layoutObject();
69 RenderedPosition::RenderedPosition(const VisiblePosition
& position
)
70 : RenderedPosition(position
.deepEquivalent(), position
.affinity())
74 RenderedPosition::RenderedPosition(const VisiblePositionInComposedTree
& position
)
75 : RenderedPosition(position
.deepEquivalent(), position
.affinity())
79 RenderedPosition::RenderedPosition(const Position
& position
, TextAffinity affinity
)
80 : m_layoutObject(nullptr)
81 , m_inlineBox(nullptr)
83 , m_prevLeafChild(uncachedInlineBox())
84 , m_nextLeafChild(uncachedInlineBox())
86 if (position
.isNull())
88 InlineBoxPosition boxPosition
= computeInlineBoxPosition(position
, affinity
);
89 m_inlineBox
= boxPosition
.inlineBox
;
90 m_offset
= boxPosition
.offsetInBox
;
92 m_layoutObject
= &m_inlineBox
->layoutObject();
94 m_layoutObject
= layoutObjectFromPosition(position
);
97 RenderedPosition::RenderedPosition(const PositionInComposedTree
& position
, TextAffinity affinity
)
98 : RenderedPosition(toPositionInDOMTree(position
), affinity
)
102 InlineBox
* RenderedPosition::prevLeafChild() const
104 if (m_prevLeafChild
== uncachedInlineBox())
105 m_prevLeafChild
= m_inlineBox
->prevLeafChildIgnoringLineBreak();
106 return m_prevLeafChild
;
109 InlineBox
* RenderedPosition::nextLeafChild() const
111 if (m_nextLeafChild
== uncachedInlineBox())
112 m_nextLeafChild
= m_inlineBox
->nextLeafChildIgnoringLineBreak();
113 return m_nextLeafChild
;
116 bool RenderedPosition::isEquivalent(const RenderedPosition
& other
) const
118 return (m_layoutObject
== other
.m_layoutObject
&& m_inlineBox
== other
.m_inlineBox
&& m_offset
== other
.m_offset
)
119 || (atLeftmostOffsetInBox() && other
.atRightmostOffsetInBox() && prevLeafChild() == other
.m_inlineBox
)
120 || (atRightmostOffsetInBox() && other
.atLeftmostOffsetInBox() && nextLeafChild() == other
.m_inlineBox
);
123 unsigned char RenderedPosition::bidiLevelOnLeft() const
125 InlineBox
* box
= atLeftmostOffsetInBox() ? prevLeafChild() : m_inlineBox
;
126 return box
? box
->bidiLevel() : 0;
129 unsigned char RenderedPosition::bidiLevelOnRight() const
131 InlineBox
* box
= atRightmostOffsetInBox() ? nextLeafChild() : m_inlineBox
;
132 return box
? box
->bidiLevel() : 0;
135 RenderedPosition
RenderedPosition::leftBoundaryOfBidiRun(unsigned char bidiLevelOfRun
)
137 if (!m_inlineBox
|| bidiLevelOfRun
> m_inlineBox
->bidiLevel())
138 return RenderedPosition();
140 InlineBox
* box
= m_inlineBox
;
142 InlineBox
* prev
= box
->prevLeafChildIgnoringLineBreak();
143 if (!prev
|| prev
->bidiLevel() < bidiLevelOfRun
)
144 return RenderedPosition(&box
->layoutObject(), box
, box
->caretLeftmostOffset());
148 ASSERT_NOT_REACHED();
149 return RenderedPosition();
152 RenderedPosition
RenderedPosition::rightBoundaryOfBidiRun(unsigned char bidiLevelOfRun
)
154 if (!m_inlineBox
|| bidiLevelOfRun
> m_inlineBox
->bidiLevel())
155 return RenderedPosition();
157 InlineBox
* box
= m_inlineBox
;
159 InlineBox
* next
= box
->nextLeafChildIgnoringLineBreak();
160 if (!next
|| next
->bidiLevel() < bidiLevelOfRun
)
161 return RenderedPosition(&box
->layoutObject(), box
, box
->caretRightmostOffset());
165 ASSERT_NOT_REACHED();
166 return RenderedPosition();
169 bool RenderedPosition::atLeftBoundaryOfBidiRun(ShouldMatchBidiLevel shouldMatchBidiLevel
, unsigned char bidiLevelOfRun
) const
174 if (atLeftmostOffsetInBox()) {
175 if (shouldMatchBidiLevel
== IgnoreBidiLevel
)
176 return !prevLeafChild() || prevLeafChild()->bidiLevel() < m_inlineBox
->bidiLevel();
177 return m_inlineBox
->bidiLevel() >= bidiLevelOfRun
&& (!prevLeafChild() || prevLeafChild()->bidiLevel() < bidiLevelOfRun
);
180 if (atRightmostOffsetInBox()) {
181 if (shouldMatchBidiLevel
== IgnoreBidiLevel
)
182 return nextLeafChild() && m_inlineBox
->bidiLevel() < nextLeafChild()->bidiLevel();
183 return nextLeafChild() && m_inlineBox
->bidiLevel() < bidiLevelOfRun
&& nextLeafChild()->bidiLevel() >= bidiLevelOfRun
;
189 bool RenderedPosition::atRightBoundaryOfBidiRun(ShouldMatchBidiLevel shouldMatchBidiLevel
, unsigned char bidiLevelOfRun
) const
194 if (atRightmostOffsetInBox()) {
195 if (shouldMatchBidiLevel
== IgnoreBidiLevel
)
196 return !nextLeafChild() || nextLeafChild()->bidiLevel() < m_inlineBox
->bidiLevel();
197 return m_inlineBox
->bidiLevel() >= bidiLevelOfRun
&& (!nextLeafChild() || nextLeafChild()->bidiLevel() < bidiLevelOfRun
);
200 if (atLeftmostOffsetInBox()) {
201 if (shouldMatchBidiLevel
== IgnoreBidiLevel
)
202 return prevLeafChild() && m_inlineBox
->bidiLevel() < prevLeafChild()->bidiLevel();
203 return prevLeafChild() && m_inlineBox
->bidiLevel() < bidiLevelOfRun
&& prevLeafChild()->bidiLevel() >= bidiLevelOfRun
;
209 Position
RenderedPosition::positionAtLeftBoundaryOfBiDiRun() const
211 ASSERT(atLeftBoundaryOfBidiRun());
213 if (atLeftmostOffsetInBox())
214 return Position::editingPositionOf(m_layoutObject
->node(), m_offset
);
216 return Position::editingPositionOf(nextLeafChild()->layoutObject().node(), nextLeafChild()->caretLeftmostOffset());
219 Position
RenderedPosition::positionAtRightBoundaryOfBiDiRun() const
221 ASSERT(atRightBoundaryOfBidiRun());
223 if (atRightmostOffsetInBox())
224 return Position::editingPositionOf(m_layoutObject
->node(), m_offset
);
226 return Position::editingPositionOf(prevLeafChild()->layoutObject().node(), prevLeafChild()->caretRightmostOffset());
229 IntRect
RenderedPosition::absoluteRect(LayoutUnit
* extraWidthToEndOfLine
) const
234 IntRect localRect
= pixelSnappedIntRect(m_layoutObject
->localCaretRect(m_inlineBox
, m_offset
, extraWidthToEndOfLine
));
235 return localRect
== IntRect() ? IntRect() : m_layoutObject
->localToAbsoluteQuad(FloatRect(localRect
)).enclosingBoundingBox();
238 void RenderedPosition::positionInGraphicsLayerBacking(CompositedSelectionBound
& bound
) const
240 bound
.layer
= nullptr;
241 bound
.edgeTopInLayer
= bound
.edgeBottomInLayer
= FloatPoint();
246 LayoutRect rect
= m_layoutObject
->localCaretRect(m_inlineBox
, m_offset
);
247 DeprecatedPaintLayer
* layer
= nullptr;
248 bound
.edgeTopInLayer
= m_layoutObject
->localToInvalidationBackingPoint(rect
.minXMinYCorner(), &layer
);
249 bound
.edgeBottomInLayer
= m_layoutObject
->localToInvalidationBackingPoint(rect
.minXMaxYCorner(), nullptr);
250 bound
.layer
= layer
? layer
->graphicsLayerBacking() : nullptr;
253 bool layoutObjectContainsPosition(LayoutObject
* target
, const Position
& position
)
255 for (LayoutObject
* layoutObject
= layoutObjectFromPosition(position
); layoutObject
&& layoutObject
->node(); layoutObject
= layoutObject
->parent()) {
256 if (layoutObject
== target
)