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 38 namespace WebCore { 39 40 static 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 67 RenderedPosition::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 83 RenderedPosition::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 99 InlineBox* RenderedPosition::prevLeafChild() const 100 { 101 if (m_prevLeafChild == uncachedInlineBox()) 102 m_prevLeafChild = m_inlineBox->prevLeafChildIgnoringLineBreak(); 103 return m_prevLeafChild; 104 } 105 106 InlineBox* RenderedPosition::nextLeafChild() const 107 { 108 if (m_nextLeafChild == uncachedInlineBox()) 109 m_nextLeafChild = m_inlineBox->nextLeafChildIgnoringLineBreak(); 110 return m_nextLeafChild; 111 } 112 113 bool 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 120 unsigned char RenderedPosition::bidiLevelOnLeft() const 121 { 122 InlineBox* box = atLeftmostOffsetInBox() ? prevLeafChild() : m_inlineBox; 123 return box ? box->bidiLevel() : 0; 124 } 125 126 unsigned char RenderedPosition::bidiLevelOnRight() const 127 { 128 InlineBox* box = atRightmostOffsetInBox() ? nextLeafChild() : m_inlineBox; 129 return box ? box->bidiLevel() : 0; 130 } 131 132 RenderedPosition 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 149 RenderedPosition 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 166 bool 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 186 bool 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 206 Position 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 216 Position 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 226 IntRect 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 235 bool 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