Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / editing / PlainTextRange.cpp
blobb69bd0ece0d5a12a48dd249906328b3bbf2b5f03
1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
3 * Copyright (C) 2005 Alexey Proskuryakov.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "config.h"
28 #include "core/editing/PlainTextRange.h"
30 #include "core/dom/ContainerNode.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/Range.h"
33 #include "core/editing/EphemeralRange.h"
34 #include "core/editing/VisiblePosition.h"
35 #include "core/editing/VisibleUnits.h"
36 #include "core/editing/iterators/TextIterator.h"
38 namespace blink {
40 PlainTextRange::PlainTextRange()
41 : m_start(kNotFound)
42 , m_end(kNotFound)
46 PlainTextRange::PlainTextRange(int location)
47 : m_start(location)
48 , m_end(location)
50 ASSERT(location >= 0);
53 PlainTextRange::PlainTextRange(int start, int end)
54 : m_start(start)
55 , m_end(end)
57 ASSERT(start >= 0);
58 ASSERT(end >= 0);
59 ASSERT(start <= end);
62 EphemeralRange PlainTextRange::createRange(const ContainerNode& scope) const
64 return createRangeFor(scope, ForGeneric);
67 EphemeralRange PlainTextRange::createRangeForSelection(const ContainerNode& scope) const
69 return createRangeFor(scope, ForSelection);
72 EphemeralRange PlainTextRange::createRangeFor(const ContainerNode& scope, GetRangeFor getRangeFor) const
74 ASSERT(isNotNull());
76 size_t docTextPosition = 0;
77 bool startRangeFound = false;
79 Position textRunStartPosition;
80 Position textRunEndPosition;
82 TextIteratorBehaviorFlags behaviorFlags = TextIteratorEmitsObjectReplacementCharacter;
83 if (getRangeFor == ForSelection)
84 behaviorFlags |= TextIteratorEmitsCharactersBetweenAllVisiblePositions;
85 auto range = EphemeralRange::rangeOfContents(scope);
86 TextIterator it(range.startPosition(), range.endPosition(), behaviorFlags);
88 // FIXME: the atEnd() check shouldn't be necessary, workaround for
89 // <http://bugs.webkit.org/show_bug.cgi?id=6289>.
90 if (!start() && !length() && it.atEnd())
91 return EphemeralRange(Position(it.currentContainer(), 0));
93 Position resultStart = Position(&scope.document(), 0);
94 Position resultEnd = resultStart;
96 for (; !it.atEnd(); it.advance()) {
97 int len = it.length();
99 textRunStartPosition = it.startPositionInCurrentContainer();
100 textRunEndPosition = it.endPositionInCurrentContainer();
102 bool foundStart = start() >= docTextPosition && start() <= docTextPosition + len;
103 bool foundEnd = end() >= docTextPosition && end() <= docTextPosition + len;
105 // Fix textRunRange->endPosition(), but only if foundStart || foundEnd, because it is only
106 // in those cases that textRunRange is used.
107 if (foundEnd) {
108 // FIXME: This is a workaround for the fact that the end of a run
109 // is often at the wrong position for emitted '\n's or if the
110 // layoutObject of the current node is a replaced element.
111 if (len == 1 && (it.text().characterAt(0) == '\n' || it.isInsideReplacedElement())) {
112 it.advance();
113 if (!it.atEnd()) {
114 textRunEndPosition = it.startPositionInCurrentContainer();
115 } else {
116 Position runEnd = nextPositionOf(createVisiblePosition(textRunStartPosition)).deepEquivalent();
117 if (runEnd.isNotNull())
118 textRunEndPosition = runEnd;
123 if (foundStart) {
124 startRangeFound = true;
125 if (textRunStartPosition.computeContainerNode()->isTextNode()) {
126 int offset = start() - docTextPosition;
127 resultStart = Position(textRunStartPosition.computeContainerNode(), offset + textRunStartPosition.offsetInContainerNode());
128 } else {
129 if (start() == docTextPosition)
130 resultStart = textRunStartPosition;
131 else
132 resultStart = textRunEndPosition;
136 if (foundEnd) {
137 if (textRunStartPosition.computeContainerNode()->isTextNode()) {
138 int offset = end() - docTextPosition;
139 resultEnd = Position(textRunStartPosition.computeContainerNode(), offset + textRunStartPosition.offsetInContainerNode());
140 } else {
141 if (end() == docTextPosition)
142 resultEnd = textRunStartPosition;
143 else
144 resultEnd = textRunEndPosition;
146 docTextPosition += len;
147 break;
149 docTextPosition += len;
152 if (!startRangeFound)
153 return EphemeralRange();
155 if (length() && end() > docTextPosition) { // end() is out of bounds
156 resultEnd = textRunEndPosition;
159 return EphemeralRange(resultStart.toOffsetInAnchor(), resultEnd.toOffsetInAnchor());
162 PlainTextRange PlainTextRange::create(const ContainerNode& scope, const EphemeralRange& range)
164 if (range.isNull())
165 return PlainTextRange();
167 // The critical assumption is that this only gets called with ranges that
168 // concentrate on a given area containing the selection root. This is done
169 // because of text fields and textareas. The DOM for those is not
170 // directly in the document DOM, so ensure that the range does not cross a
171 // boundary of one of those.
172 Node* startContainer = range.startPosition().computeContainerNode();
173 if (startContainer != &scope && !startContainer->isDescendantOf(&scope))
174 return PlainTextRange();
175 Node* endContainer = range.endPosition().computeContainerNode();
176 if (endContainer != scope && !endContainer->isDescendantOf(&scope))
177 return PlainTextRange();
179 size_t start = TextIterator::rangeLength(Position(&const_cast<ContainerNode&>(scope), 0), range.startPosition());
180 size_t end = TextIterator::rangeLength(Position(&const_cast<ContainerNode&>(scope), 0), range.endPosition());
182 return PlainTextRange(start, end);
185 PlainTextRange PlainTextRange::create(const ContainerNode& scope, const Range& range)
187 return create(scope, EphemeralRange(&range));