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