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