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 blink {
     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.createRange();
     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     m_startOffsetInContent = Range::create(*document, backwardsIterator.endPosition(), startPosition)->text().length();
     91     m_endOffsetInContent = Range::create(*document, backwardsIterator.endPosition(), endPosition)->text().length();
     92     m_contentRange = Range::create(*document, backwardsIterator.endPosition(), forwardRange->startPosition());
     93     ASSERT(m_contentRange);
     94 }
     95 
     96 PassRefPtrWillBeRawPtr<Range> SurroundingText::rangeFromContentOffsets(unsigned startOffsetInContent, unsigned endOffsetInContent)
     97 {
     98     if (startOffsetInContent >= endOffsetInContent || endOffsetInContent > content().length())
     99         return nullptr;
    100 
    101     CharacterIterator iterator(m_contentRange.get());
    102 
    103     ASSERT(!iterator.atEnd());
    104     iterator.advance(startOffsetInContent);
    105 
    106     Position start = iterator.startPosition();
    107 
    108     ASSERT(!iterator.atEnd());
    109     iterator.advance(endOffsetInContent - startOffsetInContent);
    110 
    111     Position end = iterator.startPosition();
    112 
    113     ASSERT(start.document());
    114     return Range::create(*start.document(), start, end);
    115 }
    116 
    117 String SurroundingText::content() const
    118 {
    119     if (m_contentRange)
    120         return m_contentRange->text();
    121     return String();
    122 }
    123 
    124 unsigned SurroundingText::startOffsetInContent() const
    125 {
    126     return m_startOffsetInContent;
    127 }
    128 
    129 unsigned SurroundingText::endOffsetInContent() const
    130 {
    131     return m_endOffsetInContent;
    132 }
    133 
    134 } // namespace blink
    135