Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2012 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/SurroundingText.h"
     33 
     34 #include "core/dom/Document.h"
     35 #include "core/dom/Element.h"
     36 #include "core/dom/Position.h"
     37 #include "core/dom/Range.h"
     38 #include "core/editing/TextIterator.h"
     39 
     40 namespace WebCore {
     41 
     42 SurroundingText::SurroundingText(const Range& range, unsigned maxLength)
     43     : m_startOffsetInContent(0)
     44     , m_endOffsetInContent(0)
     45 {
     46     initialize(range.startPosition(), range.endPosition(), maxLength);
     47 }
     48 
     49 SurroundingText::SurroundingText(const Position& position, unsigned maxLength)
     50     : m_startOffsetInContent(0)
     51     , m_endOffsetInContent(0)
     52 {
     53     initialize(position, position, maxLength);
     54 }
     55 
     56 void SurroundingText::initialize(const Position& startPosition, const Position& endPosition, unsigned maxLength)
     57 {
     58     ASSERT(startPosition.document() == endPosition.document());
     59 
     60     const unsigned halfMaxLength = maxLength / 2;
     61 
     62     Document* document = startPosition.document();
     63     // The position will have no document if it is null (as in no position).
     64     if (!document)
     65         return;
     66 
     67     // The forward range starts at the selection end and ends at the document's
     68     // end. It will then be updated to only contain the text in the text in the
     69     // right range around the selection.
     70     RefPtrWillBeRawPtr<Range> forwardRange = Range::create(*document, endPosition, lastPositionInNode(document->documentElement()).parentAnchoredEquivalent());
     71     CharacterIterator forwardIterator(forwardRange.get(), TextIteratorStopsOnFormControls);
     72     // FIXME: why do we stop going trough the text if we were not able to select something on the right?
     73     if (!forwardIterator.atEnd())
     74         forwardIterator.advance(maxLength - halfMaxLength);
     75 
     76     forwardRange = forwardIterator.range();
     77     if (!forwardRange || !Range::create(*document, endPosition, forwardRange->startPosition())->text().length()) {
     78         ASSERT(forwardRange);
     79         return;
     80     }
     81 
     82     // Same as with the forward range but with the backward range. The range
     83     // starts at the document's start and ends at the selection start and will
     84     // be updated.
     85     RefPtrWillBeRawPtr<Range> backwardsRange = Range::create(*document, firstPositionInNode(document->documentElement()).parentAnchoredEquivalent(), startPosition);
     86     BackwardsCharacterIterator backwardsIterator(backwardsRange.get(), TextIteratorStopsOnFormControls);
     87     if (!backwardsIterator.atEnd())
     88         backwardsIterator.advance(halfMaxLength);
     89 
     90     backwardsRange = backwardsIterator.range();
     91     if (!backwardsRange) {
     92         ASSERT(backwardsRange);
     93         return;
     94     }
     95 
     96     m_startOffsetInContent = Range::create(*document, backwardsRange->endPosition(), startPosition)->text().length();
     97     m_endOffsetInContent = Range::create(*document, backwardsRange->endPosition(), endPosition)->text().length();
     98     m_contentRange = Range::create(*document, backwardsRange->endPosition(), forwardRange->startPosition());
     99     ASSERT(m_contentRange);
    100 }
    101 
    102 PassRefPtrWillBeRawPtr<Range> SurroundingText::rangeFromContentOffsets(unsigned startOffsetInContent, unsigned endOffsetInContent)
    103 {
    104     if (startOffsetInContent >= endOffsetInContent || endOffsetInContent > content().length())
    105         return nullptr;
    106 
    107     CharacterIterator iterator(m_contentRange.get());
    108 
    109     ASSERT(!iterator.atEnd());
    110     iterator.advance(startOffsetInContent);
    111 
    112     ASSERT(iterator.range());
    113     Position start = iterator.range()->startPosition();
    114 
    115     ASSERT(!iterator.atEnd());
    116     iterator.advance(endOffsetInContent - startOffsetInContent);
    117 
    118     ASSERT(iterator.range());
    119     Position end = iterator.range()->startPosition();
    120 
    121     ASSERT(start.document());
    122     return Range::create(*start.document(), start, end);
    123 }
    124 
    125 String SurroundingText::content() const
    126 {
    127     if (m_contentRange)
    128         return m_contentRange->text();
    129     return String();
    130 }
    131 
    132 unsigned SurroundingText::startOffsetInContent() const
    133 {
    134     return m_startOffsetInContent;
    135 }
    136 
    137 unsigned SurroundingText::endOffsetInContent() const
    138 {
    139     return m_endOffsetInContent;
    140 }
    141 
    142 } // namespace WebCore
    143