Home | History | Annotate | Download | only in editing
      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 
     39 namespace blink {
     40 
     41 static 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 
     68 RenderedPosition::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 
     84 RenderedPosition::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 
    100 InlineBox* RenderedPosition::prevLeafChild() const
    101 {
    102     if (m_prevLeafChild == uncachedInlineBox())
    103         m_prevLeafChild = m_inlineBox->prevLeafChildIgnoringLineBreak();
    104     return m_prevLeafChild;
    105 }
    106 
    107 InlineBox* RenderedPosition::nextLeafChild() const
    108 {
    109     if (m_nextLeafChild == uncachedInlineBox())
    110         m_nextLeafChild = m_inlineBox->nextLeafChildIgnoringLineBreak();
    111     return m_nextLeafChild;
    112 }
    113 
    114 bool 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 
    121 unsigned char RenderedPosition::bidiLevelOnLeft() const
    122 {
    123     InlineBox* box = atLeftmostOffsetInBox() ? prevLeafChild() : m_inlineBox;
    124     return box ? box->bidiLevel() : 0;
    125 }
    126 
    127 unsigned char RenderedPosition::bidiLevelOnRight() const
    128 {
    129     InlineBox* box = atRightmostOffsetInBox() ? nextLeafChild() : m_inlineBox;
    130     return box ? box->bidiLevel() : 0;
    131 }
    132 
    133 RenderedPosition 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 
    150 RenderedPosition 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 
    167 bool 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 
    187 bool 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 
    207 Position 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 
    217 Position 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 
    227 IntRect 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 
    236 void 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 
    251 bool 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