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 WebCore { 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 }; 244