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 
     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