blob: 8d1ad9dbd007768d2f3207bf8de2efef9a856474 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
2 * (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
5 * (C) 2001 Peter Kelly (pmk@post.com)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
7 * Copyright (C) 2011 Motorola Mobility. All rights reserved.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#include "config.h"
26#include "core/dom/Range.h"
27
Ben Murdochdf957042013-08-06 11:01:27 +010028#include "bindings/v8/ExceptionState.h"
29#include "bindings/v8/ExceptionStatePlaceholder.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010030#include "core/dom/ClientRect.h"
31#include "core/dom/ClientRectList.h"
32#include "core/dom/DocumentFragment.h"
33#include "core/dom/ExceptionCode.h"
34#include "core/dom/Node.h"
35#include "core/dom/NodeTraversal.h"
36#include "core/dom/NodeWithIndex.h"
37#include "core/dom/ProcessingInstruction.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010038#include "core/dom/ScopedEventQueue.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010039#include "core/dom/Text.h"
40#include "core/editing/TextIterator.h"
41#include "core/editing/VisiblePosition.h"
42#include "core/editing/VisibleUnits.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043#include "core/editing/markup.h"
44#include "core/html/HTMLElement.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045#include "core/platform/graphics/FloatQuad.h"
46#include "core/rendering/RenderBoxModelObject.h"
47#include "core/rendering/RenderText.h"
Ben Murdoche69819b2013-07-17 14:56:49 +010048#include "wtf/RefCountedLeakCounter.h"
49#include "wtf/Vector.h"
50#include "wtf/text/CString.h"
51#include "wtf/text/StringBuilder.h"
Ben Murdochdf957042013-08-06 11:01:27 +010052#include <stdio.h>
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010053
54namespace WebCore {
55
56using namespace std;
57using namespace HTMLNames;
58
59DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, rangeCounter, ("Range"));
60
61inline Range::Range(PassRefPtr<Document> ownerDocument)
62 : m_ownerDocument(ownerDocument)
63 , m_start(m_ownerDocument)
64 , m_end(m_ownerDocument)
65{
66#ifndef NDEBUG
67 rangeCounter.increment();
68#endif
69
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010070 ScriptWrappable::init(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010071 m_ownerDocument->attachRange(this);
72}
73
74PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument)
75{
76 return adoptRef(new Range(ownerDocument));
77}
78
79inline Range::Range(PassRefPtr<Document> ownerDocument, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset)
80 : m_ownerDocument(ownerDocument)
81 , m_start(m_ownerDocument)
82 , m_end(m_ownerDocument)
83{
84#ifndef NDEBUG
85 rangeCounter.increment();
86#endif
87
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010088 ScriptWrappable::init(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010089 m_ownerDocument->attachRange(this);
90
91 // Simply setting the containers and offsets directly would not do any of the checking
92 // that setStart and setEnd do, so we call those functions.
93 setStart(startContainer, startOffset);
94 setEnd(endContainer, endOffset);
95}
96
97PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset)
98{
99 return adoptRef(new Range(ownerDocument, startContainer, startOffset, endContainer, endOffset));
100}
101
102PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, const Position& start, const Position& end)
103{
104 return adoptRef(new Range(ownerDocument, start.containerNode(), start.computeOffsetInContainerNode(), end.containerNode(), end.computeOffsetInContainerNode()));
105}
106
107Range::~Range()
108{
109 // Always detach (even if we've already detached) to fix https://bugs.webkit.org/show_bug.cgi?id=26044
110 m_ownerDocument->detachRange(this);
111
112#ifndef NDEBUG
113 rangeCounter.decrement();
114#endif
115}
116
117void Range::setDocument(Document* document)
118{
119 ASSERT(m_ownerDocument != document);
120 if (m_ownerDocument)
121 m_ownerDocument->detachRange(this);
122 m_ownerDocument = document;
123 m_start.setToStartOfNode(document);
124 m_end.setToStartOfNode(document);
125 m_ownerDocument->attachRange(this);
126}
127
Ben Murdochdf957042013-08-06 11:01:27 +0100128Node* Range::startContainer(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100129{
130 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100131 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100132 return 0;
133 }
134
135 return m_start.container();
136}
137
Ben Murdochdf957042013-08-06 11:01:27 +0100138int Range::startOffset(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100139{
140 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100141 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100142 return 0;
143 }
144
145 return m_start.offset();
146}
147
Ben Murdochdf957042013-08-06 11:01:27 +0100148Node* Range::endContainer(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100149{
150 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100151 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100152 return 0;
153 }
154
155 return m_end.container();
156}
157
Ben Murdochdf957042013-08-06 11:01:27 +0100158int Range::endOffset(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100159{
160 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100161 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100162 return 0;
163 }
164
165 return m_end.offset();
166}
167
Ben Murdochdf957042013-08-06 11:01:27 +0100168Node* Range::commonAncestorContainer(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100169{
170 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100171 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100172 return 0;
173 }
174
175 return commonAncestorContainer(m_start.container(), m_end.container());
176}
177
178Node* Range::commonAncestorContainer(Node* containerA, Node* containerB)
179{
180 for (Node* parentA = containerA; parentA; parentA = parentA->parentNode()) {
181 for (Node* parentB = containerB; parentB; parentB = parentB->parentNode()) {
182 if (parentA == parentB)
183 return parentA;
184 }
185 }
186 return 0;
187}
188
Ben Murdochdf957042013-08-06 11:01:27 +0100189bool Range::collapsed(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100190{
191 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100192 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100193 return 0;
194 }
195
196 return m_start == m_end;
197}
198
199static inline bool checkForDifferentRootContainer(const RangeBoundaryPoint& start, const RangeBoundaryPoint& end)
200{
201 Node* endRootContainer = end.container();
202 while (endRootContainer->parentNode())
203 endRootContainer = endRootContainer->parentNode();
204 Node* startRootContainer = start.container();
205 while (startRootContainer->parentNode())
206 startRootContainer = startRootContainer->parentNode();
207
Ben Murdoch1fad5ca2013-08-07 11:05:11 +0100208 return startRootContainer != endRootContainer || (Range::compareBoundaryPoints(start, end, ASSERT_NO_EXCEPTION) > 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100209}
210
Ben Murdochdf957042013-08-06 11:01:27 +0100211void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100212{
213 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100214 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100215 return;
216 }
217
218 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100219 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100220 return;
221 }
222
223 bool didMoveDocument = false;
224 if (refNode->document() != m_ownerDocument) {
225 setDocument(refNode->document());
226 didMoveDocument = true;
227 }
228
Ben Murdochdf957042013-08-06 11:01:27 +0100229 Node* childNode = checkNodeWOffset(refNode.get(), offset, es);
230 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100231 return;
232
233 m_start.set(refNode, offset, childNode);
234
235 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
Ben Murdochdf957042013-08-06 11:01:27 +0100236 collapse(true, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100237}
238
Ben Murdochdf957042013-08-06 11:01:27 +0100239void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100240{
241 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100242 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100243 return;
244 }
245
246 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100247 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100248 return;
249 }
250
251 bool didMoveDocument = false;
252 if (refNode->document() != m_ownerDocument) {
253 setDocument(refNode->document());
254 didMoveDocument = true;
255 }
256
Ben Murdochdf957042013-08-06 11:01:27 +0100257 Node* childNode = checkNodeWOffset(refNode.get(), offset, es);
258 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100259 return;
260
261 m_end.set(refNode, offset, childNode);
262
263 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
Ben Murdochdf957042013-08-06 11:01:27 +0100264 collapse(false, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100265}
266
Ben Murdochdf957042013-08-06 11:01:27 +0100267void Range::setStart(const Position& start, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100268{
269 Position parentAnchored = start.parentAnchoredEquivalent();
Ben Murdochdf957042013-08-06 11:01:27 +0100270 setStart(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100271}
272
Ben Murdochdf957042013-08-06 11:01:27 +0100273void Range::setEnd(const Position& end, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100274{
275 Position parentAnchored = end.parentAnchoredEquivalent();
Ben Murdochdf957042013-08-06 11:01:27 +0100276 setEnd(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100277}
278
Ben Murdochdf957042013-08-06 11:01:27 +0100279void Range::collapse(bool toStart, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100280{
281 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100282 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100283 return;
284 }
285
286 if (toStart)
287 m_end = m_start;
288 else
289 m_start = m_end;
290}
291
Ben Murdochdf957042013-08-06 11:01:27 +0100292bool Range::isPointInRange(Node* refNode, int offset, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100293{
294 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100295 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100296 return false;
297 }
298
299 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100300 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100301 return false;
302 }
303
304 if (!refNode->attached() || refNode->document() != m_ownerDocument) {
305 return false;
306 }
307
Ben Murdochdf957042013-08-06 11:01:27 +0100308 checkNodeWOffset(refNode, offset, es);
309 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100310 return false;
311
Ben Murdochdf957042013-08-06 11:01:27 +0100312 return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), es) >= 0 && !es.hadException()
313 && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), es) <= 0 && !es.hadException();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100314}
315
Ben Murdochdf957042013-08-06 11:01:27 +0100316short Range::comparePoint(Node* refNode, int offset, ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100317{
318 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
Ben Murdoch02772c62013-07-26 10:21:05 +0100319 // This method returns -1, 0 or 1 depending on if the point described by the
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100320 // refNode node and an offset within the node is before, same as, or after the range respectively.
321
322 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100323 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100324 return 0;
325 }
326
327 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100328 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100329 return 0;
330 }
331
332 if (!refNode->attached() || refNode->document() != m_ownerDocument) {
Ben Murdochdf957042013-08-06 11:01:27 +0100333 es.throwDOMException(WrongDocumentError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100334 return 0;
335 }
336
Ben Murdochdf957042013-08-06 11:01:27 +0100337 checkNodeWOffset(refNode, offset, es);
338 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100339 return 0;
340
341 // compare to start, and point comes before
Ben Murdochdf957042013-08-06 11:01:27 +0100342 if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), es) < 0)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100343 return -1;
344
Ben Murdochdf957042013-08-06 11:01:27 +0100345 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100346 return 0;
347
348 // compare to end, and point comes after
Ben Murdochdf957042013-08-06 11:01:27 +0100349 if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), es) > 0 && !es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100350 return 1;
351
352 // point is in the middle of this range, or on the boundary points
353 return 0;
354}
355
Ben Murdochdf957042013-08-06 11:01:27 +0100356Range::CompareResults Range::compareNode(Node* refNode, ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100357{
358 // http://developer.mozilla.org/en/docs/DOM:range.compareNode
359 // This method returns 0, 1, 2, or 3 based on if the node is before, after,
360 // before and after(surrounds), or inside the range, respectively
361
362 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100363 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100364 return NODE_BEFORE;
365 }
Ben Murdoch02772c62013-07-26 10:21:05 +0100366
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100367 if (!m_start.container() && refNode->attached()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100368 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100369 return NODE_BEFORE;
370 }
371
372 if (m_start.container() && !refNode->attached()) {
373 // Firefox doesn't throw an exception for this case; it returns 0.
374 return NODE_BEFORE;
375 }
376
377 if (refNode->document() != m_ownerDocument) {
378 // Firefox doesn't throw an exception for this case; it returns 0.
379 return NODE_BEFORE;
380 }
381
382 ContainerNode* parentNode = refNode->parentNode();
383 int nodeIndex = refNode->nodeIndex();
Ben Murdoch02772c62013-07-26 10:21:05 +0100384
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100385 if (!parentNode) {
386 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
387 // but we throw to match firefox behavior
Ben Murdochdf957042013-08-06 11:01:27 +0100388 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100389 return NODE_BEFORE;
390 }
391
Ben Murdochdf957042013-08-06 11:01:27 +0100392 if (comparePoint(parentNode, nodeIndex, es) < 0) { // starts before
393 if (comparePoint(parentNode, nodeIndex + 1, es) > 0) // ends after the range
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100394 return NODE_BEFORE_AND_AFTER;
395 return NODE_BEFORE; // ends before or in the range
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100396 }
Ben Murdochdf957042013-08-06 11:01:27 +0100397 // starts at or after the range start
398 if (comparePoint(parentNode, nodeIndex + 1, es) > 0) // ends after the range
399 return NODE_AFTER;
400 return NODE_INSIDE; // ends inside the range
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100401}
402
Ben Murdochdf957042013-08-06 11:01:27 +0100403short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100404{
405 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100406 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100407 return 0;
408 }
409
410 if (!sourceRange) {
Ben Murdochdf957042013-08-06 11:01:27 +0100411 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100412 return 0;
413 }
414
Ben Murdochdf957042013-08-06 11:01:27 +0100415 Node* thisCont = commonAncestorContainer(es);
416 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100417 return 0;
Ben Murdochdf957042013-08-06 11:01:27 +0100418 Node* sourceCont = sourceRange->commonAncestorContainer(es);
419 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100420 return 0;
421
422 if (thisCont->document() != sourceCont->document()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100423 es.throwDOMException(WrongDocumentError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100424 return 0;
425 }
426
427 Node* thisTop = thisCont;
428 Node* sourceTop = sourceCont;
429 while (thisTop->parentNode())
430 thisTop = thisTop->parentNode();
431 while (sourceTop->parentNode())
432 sourceTop = sourceTop->parentNode();
433 if (thisTop != sourceTop) { // in different DocumentFragments
Ben Murdochdf957042013-08-06 11:01:27 +0100434 es.throwDOMException(WrongDocumentError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100435 return 0;
436 }
437
438 switch (how) {
439 case START_TO_START:
Ben Murdochdf957042013-08-06 11:01:27 +0100440 return compareBoundaryPoints(m_start, sourceRange->m_start, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100441 case START_TO_END:
Ben Murdochdf957042013-08-06 11:01:27 +0100442 return compareBoundaryPoints(m_end, sourceRange->m_start, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100443 case END_TO_END:
Ben Murdochdf957042013-08-06 11:01:27 +0100444 return compareBoundaryPoints(m_end, sourceRange->m_end, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100445 case END_TO_START:
Ben Murdochdf957042013-08-06 11:01:27 +0100446 return compareBoundaryPoints(m_start, sourceRange->m_end, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100447 }
448
Ben Murdochdf957042013-08-06 11:01:27 +0100449 es.throwDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100450 return 0;
451}
452
Ben Murdochdf957042013-08-06 11:01:27 +0100453short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100454{
455 ASSERT(containerA);
456 ASSERT(containerB);
457
458 if (!containerA)
459 return -1;
460 if (!containerB)
461 return 1;
462
463 // see DOM2 traversal & range section 2.5
464
465 // case 1: both points have the same container
466 if (containerA == containerB) {
467 if (offsetA == offsetB)
468 return 0; // A is equal to B
469 if (offsetA < offsetB)
470 return -1; // A is before B
471 else
472 return 1; // A is after B
473 }
474
475 // case 2: node C (container B or an ancestor) is a child node of A
476 Node* c = containerB;
477 while (c && c->parentNode() != containerA)
478 c = c->parentNode();
479 if (c) {
480 int offsetC = 0;
481 Node* n = containerA->firstChild();
482 while (n != c && offsetC < offsetA) {
483 offsetC++;
484 n = n->nextSibling();
485 }
486
487 if (offsetA <= offsetC)
488 return -1; // A is before B
489 else
490 return 1; // A is after B
491 }
492
493 // case 3: node C (container A or an ancestor) is a child node of B
494 c = containerA;
495 while (c && c->parentNode() != containerB)
496 c = c->parentNode();
497 if (c) {
498 int offsetC = 0;
499 Node* n = containerB->firstChild();
500 while (n != c && offsetC < offsetB) {
501 offsetC++;
502 n = n->nextSibling();
503 }
504
505 if (offsetC < offsetB)
506 return -1; // A is before B
507 else
508 return 1; // A is after B
509 }
510
511 // case 4: containers A & B are siblings, or children of siblings
512 // ### we need to do a traversal here instead
513 Node* commonAncestor = commonAncestorContainer(containerA, containerB);
514 if (!commonAncestor) {
Ben Murdochdf957042013-08-06 11:01:27 +0100515 es.throwDOMException(WrongDocumentError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100516 return 0;
517 }
518 Node* childA = containerA;
519 while (childA && childA->parentNode() != commonAncestor)
520 childA = childA->parentNode();
521 if (!childA)
522 childA = commonAncestor;
523 Node* childB = containerB;
524 while (childB && childB->parentNode() != commonAncestor)
525 childB = childB->parentNode();
526 if (!childB)
527 childB = commonAncestor;
528
529 if (childA == childB)
530 return 0; // A is equal to B
531
532 Node* n = commonAncestor->firstChild();
533 while (n) {
534 if (n == childA)
535 return -1; // A is before B
536 if (n == childB)
537 return 1; // A is after B
538 n = n->nextSibling();
539 }
540
541 // Should never reach this point.
542 ASSERT_NOT_REACHED();
543 return 0;
544}
545
Ben Murdochdf957042013-08-06 11:01:27 +0100546short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100547{
Ben Murdochdf957042013-08-06 11:01:27 +0100548 return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100549}
550
551bool Range::boundaryPointsValid() const
552{
Ben Murdochdf957042013-08-06 11:01:27 +0100553 TrackExceptionState es;
554 return m_start.container() && compareBoundaryPoints(m_start, m_end, es) <= 0 && !es.hadException();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100555}
556
Ben Murdochdf957042013-08-06 11:01:27 +0100557void Range::deleteContents(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100558{
Ben Murdochdf957042013-08-06 11:01:27 +0100559 checkDeleteExtract(es);
560 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100561 return;
562
Ben Murdochdf957042013-08-06 11:01:27 +0100563 processContents(DELETE_CONTENTS, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100564}
565
Ben Murdochdf957042013-08-06 11:01:27 +0100566bool Range::intersectsNode(Node* refNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100567{
568 // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
569 // Returns a bool if the node intersects the range.
570
571 // Throw exception if the range is already detached.
572 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100573 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100574 return false;
575 }
576 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100577 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100578 return false;
579 }
580
581 if (!refNode->attached() || refNode->document() != m_ownerDocument) {
582 // Firefox doesn't throw an exception for these cases; it returns false.
583 return false;
584 }
585
586 ContainerNode* parentNode = refNode->parentNode();
587 int nodeIndex = refNode->nodeIndex();
Ben Murdoch02772c62013-07-26 10:21:05 +0100588
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100589 if (!parentNode) {
590 // if the node is the top document we should return NODE_BEFORE_AND_AFTER
591 // but we throw to match firefox behavior
Ben Murdochdf957042013-08-06 11:01:27 +0100592 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100593 return false;
594 }
595
Ben Murdochdf957042013-08-06 11:01:27 +0100596 if (comparePoint(parentNode, nodeIndex, es) < 0 // starts before start
597 && comparePoint(parentNode, nodeIndex + 1, es) < 0) { // ends before start
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100598 return false;
Ben Murdochdf957042013-08-06 11:01:27 +0100599 }
600
601 if (comparePoint(parentNode, nodeIndex, es) > 0 // starts after end
602 && comparePoint(parentNode, nodeIndex + 1, es) > 0) { // ends after end
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100603 return false;
604 }
Ben Murdoch02772c62013-07-26 10:21:05 +0100605
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100606 return true; // all other cases
607}
608
609static inline Node* highestAncestorUnderCommonRoot(Node* node, Node* commonRoot)
610{
611 if (node == commonRoot)
612 return 0;
613
614 ASSERT(commonRoot->contains(node));
615
616 while (node->parentNode() != commonRoot)
617 node = node->parentNode();
618
619 return node;
620}
621
622static inline Node* childOfCommonRootBeforeOffset(Node* container, unsigned offset, Node* commonRoot)
623{
624 ASSERT(container);
625 ASSERT(commonRoot);
Ben Murdoch02772c62013-07-26 10:21:05 +0100626
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100627 if (!commonRoot->contains(container))
628 return 0;
629
630 if (container == commonRoot) {
631 container = container->firstChild();
632 for (unsigned i = 0; container && i < offset; i++)
633 container = container->nextSibling();
634 } else {
635 while (container->parentNode() != commonRoot)
636 container = container->parentNode();
637 }
638
639 return container;
640}
641
642static inline unsigned lengthOfContentsInNode(Node* node)
643{
644 // This switch statement must be consistent with that of Range::processContentsBetweenOffsets.
645 switch (node->nodeType()) {
646 case Node::TEXT_NODE:
647 case Node::CDATA_SECTION_NODE:
648 case Node::COMMENT_NODE:
649 return static_cast<CharacterData*>(node)->length();
650 case Node::PROCESSING_INSTRUCTION_NODE:
651 return static_cast<ProcessingInstruction*>(node)->data().length();
652 case Node::ELEMENT_NODE:
653 case Node::ATTRIBUTE_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100654 case Node::ENTITY_NODE:
655 case Node::DOCUMENT_NODE:
656 case Node::DOCUMENT_TYPE_NODE:
657 case Node::DOCUMENT_FRAGMENT_NODE:
658 case Node::NOTATION_NODE:
659 case Node::XPATH_NAMESPACE_NODE:
660 return node->childNodeCount();
661 }
662 ASSERT_NOT_REACHED();
663 return 0;
664}
665
Ben Murdochdf957042013-08-06 11:01:27 +0100666PassRefPtr<DocumentFragment> Range::processContents(ActionType action, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100667{
668 typedef Vector<RefPtr<Node> > NodeVector;
669
670 RefPtr<DocumentFragment> fragment;
671 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
672 fragment = DocumentFragment::create(m_ownerDocument.get());
673
Ben Murdochdf957042013-08-06 11:01:27 +0100674 if (collapsed(es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100675 return fragment.release();
Ben Murdochdf957042013-08-06 11:01:27 +0100676 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100677 return 0;
678
Ben Murdochdf957042013-08-06 11:01:27 +0100679 RefPtr<Node> commonRoot = commonAncestorContainer(es);
680 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100681 return 0;
682 ASSERT(commonRoot);
683
684 if (m_start.container() == m_end.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100685 processContentsBetweenOffsets(action, fragment, m_start.container(), m_start.offset(), m_end.offset(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100686 return fragment;
687 }
688
Ben Murdoch591b9582013-07-10 11:41:44 +0100689 // Since mutation observers can modify the range during the process, the boundary points need to be saved.
690 RangeBoundaryPoint originalStart(m_start);
691 RangeBoundaryPoint originalEnd(m_end);
692
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100693 // what is the highest node that partially selects the start / end of the range?
Ben Murdoch591b9582013-07-10 11:41:44 +0100694 RefPtr<Node> partialStart = highestAncestorUnderCommonRoot(originalStart.container(), commonRoot.get());
695 RefPtr<Node> partialEnd = highestAncestorUnderCommonRoot(originalEnd.container(), commonRoot.get());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100696
697 // Start and end containers are different.
698 // There are three possibilities here:
699 // 1. Start container == commonRoot (End container must be a descendant)
700 // 2. End container == commonRoot (Start container must be a descendant)
701 // 3. Neither is commonRoot, they are both descendants
702 //
703 // In case 3, we grab everything after the start (up until a direct child
704 // of commonRoot) into leftContents, and everything before the end (up until
705 // a direct child of commonRoot) into rightContents. Then we process all
706 // commonRoot children between leftContents and rightContents
707 //
708 // In case 1 or 2, we skip either processing of leftContents or rightContents,
709 // in which case the last lot of nodes either goes from the first or last
710 // child of commonRoot.
711 //
712 // These are deleted, cloned, or extracted (i.e. both) depending on action.
713
714 // Note that we are verifying that our common root hierarchy is still intact
715 // after any DOM mutation event, at various stages below. See webkit bug 60350.
716
717 RefPtr<Node> leftContents;
Ben Murdoch591b9582013-07-10 11:41:44 +0100718 if (originalStart.container() != commonRoot && commonRoot->contains(originalStart.container())) {
Ben Murdochdf957042013-08-06 11:01:27 +0100719 leftContents = processContentsBetweenOffsets(action, 0, originalStart.container(), originalStart.offset(), lengthOfContentsInNode(originalStart.container()), es);
720 leftContents = processAncestorsAndTheirSiblings(action, originalStart.container(), ProcessContentsForward, leftContents, commonRoot.get(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100721 }
722
723 RefPtr<Node> rightContents;
Ben Murdoch591b9582013-07-10 11:41:44 +0100724 if (m_end.container() != commonRoot && commonRoot->contains(originalEnd.container())) {
Ben Murdochdf957042013-08-06 11:01:27 +0100725 rightContents = processContentsBetweenOffsets(action, 0, originalEnd.container(), 0, originalEnd.offset(), es);
726 rightContents = processAncestorsAndTheirSiblings(action, originalEnd.container(), ProcessContentsBackward, rightContents, commonRoot.get(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100727 }
728
729 // delete all children of commonRoot between the start and end container
Ben Murdoch591b9582013-07-10 11:41:44 +0100730 RefPtr<Node> processStart = childOfCommonRootBeforeOffset(originalStart.container(), originalStart.offset(), commonRoot.get());
731 if (processStart && originalStart.container() != commonRoot) // processStart contains nodes before m_start.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100732 processStart = processStart->nextSibling();
Ben Murdoch591b9582013-07-10 11:41:44 +0100733 RefPtr<Node> processEnd = childOfCommonRootBeforeOffset(originalEnd.container(), originalEnd.offset(), commonRoot.get());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100734
735 // Collapse the range, making sure that the result is not within a node that was partially selected.
736 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
Ben Murdoch1fad5ca2013-08-07 11:05:11 +0100737 if (partialStart && commonRoot->contains(partialStart.get())) {
738 // FIXME: We should not continue if we have an earlier error.
739 es.clearException();
Ben Murdochdf957042013-08-06 11:01:27 +0100740 setStart(partialStart->parentNode(), partialStart->nodeIndex() + 1, es);
Ben Murdoch1fad5ca2013-08-07 11:05:11 +0100741 } else if (partialEnd && commonRoot->contains(partialEnd.get())) {
742 // FIXME: We should not continue if we have an earlier error.
743 es.clearException();
Ben Murdochdf957042013-08-06 11:01:27 +0100744 setStart(partialEnd->parentNode(), partialEnd->nodeIndex(), es);
Ben Murdoch1fad5ca2013-08-07 11:05:11 +0100745 }
Ben Murdochdf957042013-08-06 11:01:27 +0100746 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100747 return 0;
748 m_end = m_start;
749 }
750
Ben Murdoch591b9582013-07-10 11:41:44 +0100751 originalStart.clear();
752 originalEnd.clear();
753
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100754 // Now add leftContents, stuff in between, and rightContents to the fragment
755 // (or just delete the stuff in between)
756
757 if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && leftContents)
Ben Murdochdf957042013-08-06 11:01:27 +0100758 fragment->appendChild(leftContents, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100759
760 if (processStart) {
761 NodeVector nodes;
762 for (Node* n = processStart.get(); n && n != processEnd; n = n->nextSibling())
763 nodes.append(n);
Ben Murdochdf957042013-08-06 11:01:27 +0100764 processNodes(action, nodes, commonRoot, fragment, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100765 }
766
767 if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && rightContents)
Ben Murdochdf957042013-08-06 11:01:27 +0100768 fragment->appendChild(rightContents, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100769
770 return fragment.release();
771}
772
Ben Murdochdf957042013-08-06 11:01:27 +0100773static inline void deleteCharacterData(PassRefPtr<CharacterData> data, unsigned startOffset, unsigned endOffset, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100774{
775 if (data->length() - endOffset)
Ben Murdochdf957042013-08-06 11:01:27 +0100776 data->deleteData(endOffset, data->length() - endOffset, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100777 if (startOffset)
Ben Murdochdf957042013-08-06 11:01:27 +0100778 data->deleteData(0, startOffset, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100779}
780
781PassRefPtr<Node> Range::processContentsBetweenOffsets(ActionType action, PassRefPtr<DocumentFragment> fragment,
Ben Murdochdf957042013-08-06 11:01:27 +0100782 Node* container, unsigned startOffset, unsigned endOffset, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100783{
784 ASSERT(container);
785 ASSERT(startOffset <= endOffset);
786
787 // This switch statement must be consistent with that of lengthOfContentsInNode.
Ben Murdoch02772c62013-07-26 10:21:05 +0100788 RefPtr<Node> result;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100789 switch (container->nodeType()) {
790 case Node::TEXT_NODE:
791 case Node::CDATA_SECTION_NODE:
792 case Node::COMMENT_NODE:
793 ASSERT(endOffset <= static_cast<CharacterData*>(container)->length());
794 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
795 RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(container->cloneNode(true));
Ben Murdochdf957042013-08-06 11:01:27 +0100796 deleteCharacterData(c, startOffset, endOffset, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100797 if (fragment) {
798 result = fragment;
Ben Murdochdf957042013-08-06 11:01:27 +0100799 result->appendChild(c.release(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100800 } else
801 result = c.release();
802 }
803 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
Ben Murdochdf957042013-08-06 11:01:27 +0100804 static_cast<CharacterData*>(container)->deleteData(startOffset, endOffset - startOffset, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100805 break;
806 case Node::PROCESSING_INSTRUCTION_NODE:
807 ASSERT(endOffset <= static_cast<ProcessingInstruction*>(container)->data().length());
808 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
809 RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(container->cloneNode(true));
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100810 c->setData(c->data().substring(startOffset, endOffset - startOffset));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100811 if (fragment) {
812 result = fragment;
Ben Murdochdf957042013-08-06 11:01:27 +0100813 result->appendChild(c.release(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100814 } else
815 result = c.release();
816 }
817 if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
818 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(container);
819 String data(pi->data());
820 data.remove(startOffset, endOffset - startOffset);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100821 pi->setData(data);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100822 }
823 break;
824 case Node::ELEMENT_NODE:
825 case Node::ATTRIBUTE_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100826 case Node::ENTITY_NODE:
827 case Node::DOCUMENT_NODE:
828 case Node::DOCUMENT_TYPE_NODE:
829 case Node::DOCUMENT_FRAGMENT_NODE:
830 case Node::NOTATION_NODE:
831 case Node::XPATH_NAMESPACE_NODE:
832 // FIXME: Should we assert that some nodes never appear here?
833 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
834 if (fragment)
835 result = fragment;
836 else
837 result = container->cloneNode(false);
838 }
839
840 Node* n = container->firstChild();
841 Vector<RefPtr<Node> > nodes;
842 for (unsigned i = startOffset; n && i; i--)
843 n = n->nextSibling();
844 for (unsigned i = startOffset; n && i < endOffset; i++, n = n->nextSibling())
845 nodes.append(n);
846
Ben Murdochdf957042013-08-06 11:01:27 +0100847 processNodes(action, nodes, container, result, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100848 break;
849 }
850
851 return result.release();
852}
853
Ben Murdochdf957042013-08-06 11:01:27 +0100854void Range::processNodes(ActionType action, Vector<RefPtr<Node> >& nodes, PassRefPtr<Node> oldContainer, PassRefPtr<Node> newContainer, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100855{
856 for (unsigned i = 0; i < nodes.size(); i++) {
857 switch (action) {
858 case DELETE_CONTENTS:
Ben Murdochdf957042013-08-06 11:01:27 +0100859 oldContainer->removeChild(nodes[i].get(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100860 break;
861 case EXTRACT_CONTENTS:
Ben Murdochdf957042013-08-06 11:01:27 +0100862 newContainer->appendChild(nodes[i].release(), es); // will remove n from its parent
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100863 break;
864 case CLONE_CONTENTS:
Ben Murdochdf957042013-08-06 11:01:27 +0100865 newContainer->appendChild(nodes[i]->cloneNode(true), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100866 break;
867 }
868 }
869}
870
Ben Murdochdf957042013-08-06 11:01:27 +0100871PassRefPtr<Node> Range::processAncestorsAndTheirSiblings(ActionType action, Node* container, ContentsProcessDirection direction, PassRefPtr<Node> passedClonedContainer, Node* commonRoot, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100872{
873 typedef Vector<RefPtr<Node> > NodeVector;
874
875 RefPtr<Node> clonedContainer = passedClonedContainer;
876 Vector<RefPtr<Node> > ancestors;
877 for (ContainerNode* n = container->parentNode(); n && n != commonRoot; n = n->parentNode())
878 ancestors.append(n);
879
880 RefPtr<Node> firstChildInAncestorToProcess = direction == ProcessContentsForward ? container->nextSibling() : container->previousSibling();
881 for (Vector<RefPtr<Node> >::const_iterator it = ancestors.begin(); it != ancestors.end(); it++) {
882 RefPtr<Node> ancestor = *it;
883 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
884 if (RefPtr<Node> clonedAncestor = ancestor->cloneNode(false)) { // Might have been removed already during mutation event.
Ben Murdochdf957042013-08-06 11:01:27 +0100885 clonedAncestor->appendChild(clonedContainer, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100886 clonedContainer = clonedAncestor;
887 }
888 }
889
890 // Copy siblings of an ancestor of start/end containers
891 // FIXME: This assertion may fail if DOM is modified during mutation event
892 // FIXME: Share code with Range::processNodes
893 ASSERT(!firstChildInAncestorToProcess || firstChildInAncestorToProcess->parentNode() == ancestor);
Ben Murdoch02772c62013-07-26 10:21:05 +0100894
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100895 NodeVector nodes;
896 for (Node* child = firstChildInAncestorToProcess.get(); child;
897 child = (direction == ProcessContentsForward) ? child->nextSibling() : child->previousSibling())
898 nodes.append(child);
899
900 for (NodeVector::const_iterator it = nodes.begin(); it != nodes.end(); it++) {
901 Node* child = it->get();
902 switch (action) {
903 case DELETE_CONTENTS:
Ben Murdochdf957042013-08-06 11:01:27 +0100904 ancestor->removeChild(child, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100905 break;
906 case EXTRACT_CONTENTS: // will remove child from ancestor
907 if (direction == ProcessContentsForward)
Ben Murdochdf957042013-08-06 11:01:27 +0100908 clonedContainer->appendChild(child, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100909 else
Ben Murdochdf957042013-08-06 11:01:27 +0100910 clonedContainer->insertBefore(child, clonedContainer->firstChild(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100911 break;
912 case CLONE_CONTENTS:
913 if (direction == ProcessContentsForward)
Ben Murdochdf957042013-08-06 11:01:27 +0100914 clonedContainer->appendChild(child->cloneNode(true), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100915 else
Ben Murdochdf957042013-08-06 11:01:27 +0100916 clonedContainer->insertBefore(child->cloneNode(true), clonedContainer->firstChild(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100917 break;
918 }
919 }
920 firstChildInAncestorToProcess = direction == ProcessContentsForward ? ancestor->nextSibling() : ancestor->previousSibling();
921 }
922
923 return clonedContainer.release();
924}
925
Ben Murdochdf957042013-08-06 11:01:27 +0100926PassRefPtr<DocumentFragment> Range::extractContents(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100927{
Ben Murdochdf957042013-08-06 11:01:27 +0100928 checkDeleteExtract(es);
929 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100930 return 0;
931
Ben Murdochdf957042013-08-06 11:01:27 +0100932 return processContents(EXTRACT_CONTENTS, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100933}
934
Ben Murdochdf957042013-08-06 11:01:27 +0100935PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100936{
937 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100938 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100939 return 0;
940 }
941
Ben Murdochdf957042013-08-06 11:01:27 +0100942 return processContents(CLONE_CONTENTS, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100943}
944
Ben Murdochdf957042013-08-06 11:01:27 +0100945void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100946{
947 RefPtr<Node> newNode = prpNewNode;
948
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100949 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100950 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100951 return;
952 }
953
954 if (!newNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100955 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100956 return;
957 }
958
Ben Murdoche69819b2013-07-17 14:56:49 +0100959 // HierarchyRequestError: Raised if the container of the start of the Range is of a type that
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100960 // does not allow children of the type of newNode or if newNode is an ancestor of the container.
961
962 // an extra one here - if a text node is going to split, it must have a parent to insert into
963 bool startIsText = m_start.container()->isTextNode();
964 if (startIsText && !m_start.container()->parentNode()) {
Ben Murdochdf957042013-08-06 11:01:27 +0100965 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100966 return;
967 }
968
969 // In the case where the container is a text node, we check against the container's parent, because
970 // text nodes get split up upon insertion.
971 Node* checkAgainst;
972 if (startIsText)
973 checkAgainst = m_start.container()->parentNode();
974 else
975 checkAgainst = m_start.container();
976
977 Node::NodeType newNodeType = newNode->nodeType();
978 int numNewChildren;
979 if (newNodeType == Node::DOCUMENT_FRAGMENT_NODE && !newNode->isShadowRoot()) {
980 // check each child node, not the DocumentFragment itself
981 numNewChildren = 0;
982 for (Node* c = newNode->firstChild(); c; c = c->nextSibling()) {
983 if (!checkAgainst->childTypeAllowed(c->nodeType())) {
Ben Murdochdf957042013-08-06 11:01:27 +0100984 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100985 return;
986 }
987 ++numNewChildren;
988 }
989 } else {
990 numNewChildren = 1;
991 if (!checkAgainst->childTypeAllowed(newNodeType)) {
Ben Murdochdf957042013-08-06 11:01:27 +0100992 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100993 return;
994 }
995 }
996
997 for (Node* n = m_start.container(); n; n = n->parentNode()) {
998 if (n == newNode) {
Ben Murdochdf957042013-08-06 11:01:27 +0100999 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001000 return;
1001 }
1002 }
1003
Ben Murdoche69819b2013-07-17 14:56:49 +01001004 // InvalidNodeTypeError: Raised if newNode is an Attr, Entity, Notation, ShadowRoot or Document node.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001005 switch (newNodeType) {
1006 case Node::ATTRIBUTE_NODE:
1007 case Node::ENTITY_NODE:
1008 case Node::NOTATION_NODE:
1009 case Node::DOCUMENT_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001010 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001011 return;
1012 default:
1013 if (newNode->isShadowRoot()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001014 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001015 return;
1016 }
1017 break;
1018 }
1019
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001020 EventQueueScope scope;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001021 bool collapsed = m_start == m_end;
1022 RefPtr<Node> container;
1023 if (startIsText) {
1024 container = m_start.container();
Ben Murdochdf957042013-08-06 11:01:27 +01001025 RefPtr<Text> newText = toText(container.get())->splitText(m_start.offset(), es);
1026 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001027 return;
Ben Murdoch02772c62013-07-26 10:21:05 +01001028
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001029 container = m_start.container();
Ben Murdochdf957042013-08-06 11:01:27 +01001030 container->parentNode()->insertBefore(newNode.release(), newText.get(), es);
1031 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001032 return;
1033
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001034 if (collapsed)
1035 m_end.setToBeforeChild(newText.get());
1036 } else {
1037 RefPtr<Node> lastChild;
1038 if (collapsed)
1039 lastChild = (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) ? newNode->lastChild() : newNode;
1040
1041 int startOffset = m_start.offset();
1042 container = m_start.container();
Ben Murdochdf957042013-08-06 11:01:27 +01001043 container->insertBefore(newNode.release(), container->childNode(startOffset), es);
1044 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001045 return;
1046
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001047 if (collapsed && numNewChildren)
1048 m_end.set(m_start.container(), startOffset + numNewChildren, lastChild.get());
1049 }
1050}
1051
Ben Murdochdf957042013-08-06 11:01:27 +01001052String Range::toString(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001053{
1054 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001055 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001056 return String();
1057 }
1058
1059 StringBuilder builder;
1060
1061 Node* pastLast = pastLastNode();
1062 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(n)) {
1063 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE) {
1064 String data = static_cast<CharacterData*>(n)->data();
1065 int length = data.length();
1066 int start = (n == m_start.container()) ? min(max(0, m_start.offset()), length) : 0;
1067 int end = (n == m_end.container()) ? min(max(start, m_end.offset()), length) : length;
Ben Murdoch591b9582013-07-10 11:41:44 +01001068 builder.append(data, start, end - start);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001069 }
1070 }
1071
1072 return builder.toString();
1073}
1074
1075String Range::toHTML() const
1076{
1077 return createMarkup(this);
1078}
1079
1080String Range::text() const
1081{
1082 if (!m_start.container())
1083 return String();
1084
1085 // We need to update layout, since plainText uses line boxes in the render tree.
1086 // FIXME: As with innerText, we'd like this to work even if there are no render objects.
1087 m_start.container()->document()->updateLayout();
1088
1089 return plainText(this);
1090}
1091
Ben Murdochdf957042013-08-06 11:01:27 +01001092PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& markup, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001093{
1094 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001095 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001096 return 0;
1097 }
1098
1099 Node* element = m_start.container()->isElementNode() ? m_start.container() : m_start.container()->parentNode();
1100 if (!element || !element->isHTMLElement()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001101 es.throwDOMException(NotSupportedError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001102 return 0;
1103 }
1104
Ben Murdochdf957042013-08-06 11:01:27 +01001105 RefPtr<DocumentFragment> fragment = WebCore::createContextualFragment(markup, toHTMLElement(element), AllowScriptingContentAndDoNotMarkAlreadyStarted, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001106 if (!fragment)
1107 return 0;
1108
1109 return fragment.release();
1110}
1111
1112
Ben Murdochdf957042013-08-06 11:01:27 +01001113void Range::detach(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001114{
1115 // Check first to see if we've already detached:
1116 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001117 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001118 return;
1119 }
1120
1121 m_ownerDocument->detachRange(this);
1122
1123 m_start.clear();
1124 m_end.clear();
1125}
1126
Ben Murdochdf957042013-08-06 11:01:27 +01001127Node* Range::checkNodeWOffset(Node* n, int offset, ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001128{
1129 switch (n->nodeType()) {
1130 case Node::DOCUMENT_TYPE_NODE:
1131 case Node::ENTITY_NODE:
1132 case Node::NOTATION_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001133 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001134 return 0;
1135 case Node::CDATA_SECTION_NODE:
1136 case Node::COMMENT_NODE:
1137 case Node::TEXT_NODE:
1138 if (static_cast<unsigned>(offset) > static_cast<CharacterData*>(n)->length())
Ben Murdochdf957042013-08-06 11:01:27 +01001139 es.throwDOMException(IndexSizeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001140 return 0;
1141 case Node::PROCESSING_INSTRUCTION_NODE:
1142 if (static_cast<unsigned>(offset) > static_cast<ProcessingInstruction*>(n)->data().length())
Ben Murdochdf957042013-08-06 11:01:27 +01001143 es.throwDOMException(IndexSizeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001144 return 0;
1145 case Node::ATTRIBUTE_NODE:
1146 case Node::DOCUMENT_FRAGMENT_NODE:
1147 case Node::DOCUMENT_NODE:
1148 case Node::ELEMENT_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001149 case Node::XPATH_NAMESPACE_NODE: {
1150 if (!offset)
1151 return 0;
1152 Node* childBefore = n->childNode(offset - 1);
1153 if (!childBefore)
Ben Murdochdf957042013-08-06 11:01:27 +01001154 es.throwDOMException(IndexSizeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001155 return childBefore;
1156 }
1157 }
1158 ASSERT_NOT_REACHED();
1159 return 0;
1160}
1161
Ben Murdochdf957042013-08-06 11:01:27 +01001162void Range::checkNodeBA(Node* n, ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001163{
Ben Murdoche69819b2013-07-17 14:56:49 +01001164 // InvalidNodeTypeError: Raised if the root container of refNode is not an
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001165 // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG shadow DOM tree,
1166 // or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation node.
1167
1168 switch (n->nodeType()) {
1169 case Node::ATTRIBUTE_NODE:
1170 case Node::DOCUMENT_FRAGMENT_NODE:
1171 case Node::DOCUMENT_NODE:
1172 case Node::ENTITY_NODE:
1173 case Node::NOTATION_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001174 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001175 return;
1176 case Node::CDATA_SECTION_NODE:
1177 case Node::COMMENT_NODE:
1178 case Node::DOCUMENT_TYPE_NODE:
1179 case Node::ELEMENT_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001180 case Node::PROCESSING_INSTRUCTION_NODE:
1181 case Node::TEXT_NODE:
1182 case Node::XPATH_NAMESPACE_NODE:
1183 break;
1184 }
1185
1186 Node* root = n;
1187 while (ContainerNode* parent = root->parentNode())
1188 root = parent;
1189
1190 switch (root->nodeType()) {
1191 case Node::ATTRIBUTE_NODE:
1192 case Node::DOCUMENT_NODE:
1193 case Node::DOCUMENT_FRAGMENT_NODE:
1194 break;
1195 case Node::CDATA_SECTION_NODE:
1196 case Node::COMMENT_NODE:
1197 case Node::DOCUMENT_TYPE_NODE:
1198 case Node::ELEMENT_NODE:
1199 case Node::ENTITY_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001200 case Node::NOTATION_NODE:
1201 case Node::PROCESSING_INSTRUCTION_NODE:
1202 case Node::TEXT_NODE:
1203 case Node::XPATH_NAMESPACE_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001204 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001205 return;
1206 }
1207}
1208
Ben Murdochdf957042013-08-06 11:01:27 +01001209PassRefPtr<Range> Range::cloneRange(ExceptionState& es) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001210{
1211 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001212 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001213 return 0;
1214 }
1215
1216 return Range::create(m_ownerDocument, m_start.container(), m_start.offset(), m_end.container(), m_end.offset());
1217}
1218
Ben Murdochdf957042013-08-06 11:01:27 +01001219void Range::setStartAfter(Node* refNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001220{
1221 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001222 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001223 return;
1224 }
1225
1226 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +01001227 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001228 return;
1229 }
1230
Ben Murdochdf957042013-08-06 11:01:27 +01001231 checkNodeBA(refNode, es);
1232 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001233 return;
1234
Ben Murdochdf957042013-08-06 11:01:27 +01001235 setStart(refNode->parentNode(), refNode->nodeIndex() + 1, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001236}
1237
Ben Murdochdf957042013-08-06 11:01:27 +01001238void Range::setEndBefore(Node* refNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001239{
1240 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001241 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001242 return;
1243 }
1244
1245 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +01001246 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001247 return;
1248 }
1249
Ben Murdochdf957042013-08-06 11:01:27 +01001250 checkNodeBA(refNode, es);
1251 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001252 return;
1253
Ben Murdochdf957042013-08-06 11:01:27 +01001254 setEnd(refNode->parentNode(), refNode->nodeIndex(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001255}
1256
Ben Murdochdf957042013-08-06 11:01:27 +01001257void Range::setEndAfter(Node* refNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001258{
1259 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001260 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001261 return;
1262 }
1263
1264 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +01001265 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001266 return;
1267 }
1268
Ben Murdochdf957042013-08-06 11:01:27 +01001269 checkNodeBA(refNode, es);
1270 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001271 return;
1272
Ben Murdochdf957042013-08-06 11:01:27 +01001273 setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001274}
1275
Ben Murdochdf957042013-08-06 11:01:27 +01001276void Range::selectNode(Node* refNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001277{
1278 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001279 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001280 return;
1281 }
1282
1283 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +01001284 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001285 return;
1286 }
1287
Ben Murdoche69819b2013-07-17 14:56:49 +01001288 // InvalidNodeTypeError: Raised if an ancestor of refNode is an Entity, Notation or
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001289 // DocumentType node or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation
1290 // node.
1291 for (ContainerNode* anc = refNode->parentNode(); anc; anc = anc->parentNode()) {
1292 switch (anc->nodeType()) {
1293 case Node::ATTRIBUTE_NODE:
1294 case Node::CDATA_SECTION_NODE:
1295 case Node::COMMENT_NODE:
1296 case Node::DOCUMENT_FRAGMENT_NODE:
1297 case Node::DOCUMENT_NODE:
1298 case Node::ELEMENT_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001299 case Node::PROCESSING_INSTRUCTION_NODE:
1300 case Node::TEXT_NODE:
1301 case Node::XPATH_NAMESPACE_NODE:
1302 break;
1303 case Node::DOCUMENT_TYPE_NODE:
1304 case Node::ENTITY_NODE:
1305 case Node::NOTATION_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001306 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001307 return;
1308 }
1309 }
1310
1311 switch (refNode->nodeType()) {
1312 case Node::CDATA_SECTION_NODE:
1313 case Node::COMMENT_NODE:
1314 case Node::DOCUMENT_TYPE_NODE:
1315 case Node::ELEMENT_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001316 case Node::PROCESSING_INSTRUCTION_NODE:
1317 case Node::TEXT_NODE:
1318 case Node::XPATH_NAMESPACE_NODE:
1319 break;
1320 case Node::ATTRIBUTE_NODE:
1321 case Node::DOCUMENT_FRAGMENT_NODE:
1322 case Node::DOCUMENT_NODE:
1323 case Node::ENTITY_NODE:
1324 case Node::NOTATION_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001325 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001326 return;
1327 }
1328
1329 if (m_ownerDocument != refNode->document())
1330 setDocument(refNode->document());
1331
Ben Murdochdf957042013-08-06 11:01:27 +01001332 setStartBefore(refNode, es);
1333 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001334 return;
Ben Murdochdf957042013-08-06 11:01:27 +01001335 setEndAfter(refNode, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001336}
1337
Ben Murdochdf957042013-08-06 11:01:27 +01001338void Range::selectNodeContents(Node* refNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001339{
1340 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001341 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001342 return;
1343 }
1344
1345 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +01001346 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001347 return;
1348 }
1349
Ben Murdoche69819b2013-07-17 14:56:49 +01001350 // InvalidNodeTypeError: Raised if refNode or an ancestor of refNode is an Entity, Notation
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001351 // or DocumentType node.
1352 for (Node* n = refNode; n; n = n->parentNode()) {
1353 switch (n->nodeType()) {
1354 case Node::ATTRIBUTE_NODE:
1355 case Node::CDATA_SECTION_NODE:
1356 case Node::COMMENT_NODE:
1357 case Node::DOCUMENT_FRAGMENT_NODE:
1358 case Node::DOCUMENT_NODE:
1359 case Node::ELEMENT_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001360 case Node::PROCESSING_INSTRUCTION_NODE:
1361 case Node::TEXT_NODE:
1362 case Node::XPATH_NAMESPACE_NODE:
1363 break;
1364 case Node::DOCUMENT_TYPE_NODE:
1365 case Node::ENTITY_NODE:
1366 case Node::NOTATION_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001367 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001368 return;
1369 }
1370 }
1371
1372 if (m_ownerDocument != refNode->document())
1373 setDocument(refNode->document());
1374
1375 m_start.setToStartOfNode(refNode);
1376 m_end.setToEndOfNode(refNode);
1377}
1378
Ben Murdochdf957042013-08-06 11:01:27 +01001379void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001380{
1381 RefPtr<Node> newParent = passNewParent;
1382
1383 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001384 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001385 return;
1386 }
1387
1388 if (!newParent) {
Ben Murdochdf957042013-08-06 11:01:27 +01001389 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001390 return;
1391 }
1392
Ben Murdoche69819b2013-07-17 14:56:49 +01001393 // InvalidNodeTypeError: Raised if node is an Attr, Entity, DocumentType, Notation,
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001394 // Document, or DocumentFragment node.
1395 switch (newParent->nodeType()) {
1396 case Node::ATTRIBUTE_NODE:
1397 case Node::DOCUMENT_FRAGMENT_NODE:
1398 case Node::DOCUMENT_NODE:
1399 case Node::DOCUMENT_TYPE_NODE:
1400 case Node::ENTITY_NODE:
1401 case Node::NOTATION_NODE:
Ben Murdochdf957042013-08-06 11:01:27 +01001402 es.throwDOMException(InvalidNodeTypeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001403 return;
1404 case Node::CDATA_SECTION_NODE:
1405 case Node::COMMENT_NODE:
1406 case Node::ELEMENT_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001407 case Node::PROCESSING_INSTRUCTION_NODE:
1408 case Node::TEXT_NODE:
1409 case Node::XPATH_NAMESPACE_NODE:
1410 break;
1411 }
1412
Ben Murdoche69819b2013-07-17 14:56:49 +01001413 // Raise a HierarchyRequestError if m_start.container() doesn't accept children like newParent.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001414 Node* parentOfNewParent = m_start.container();
1415
Ben Murdoch02772c62013-07-26 10:21:05 +01001416 // If m_start.container() is a character data node, it will be split and it will be its parent that will
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001417 // need to accept newParent (or in the case of a comment, it logically "would" be inserted into the parent,
1418 // although this will fail below for another reason).
1419 if (parentOfNewParent->isCharacterDataNode())
1420 parentOfNewParent = parentOfNewParent->parentNode();
1421 if (!parentOfNewParent || !parentOfNewParent->childTypeAllowed(newParent->nodeType())) {
Ben Murdochdf957042013-08-06 11:01:27 +01001422 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001423 return;
1424 }
Ben Murdoch02772c62013-07-26 10:21:05 +01001425
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001426 if (newParent->contains(m_start.container())) {
Ben Murdochdf957042013-08-06 11:01:27 +01001427 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001428 return;
1429 }
1430
1431 // FIXME: Do we need a check if the node would end up with a child node of a type not
1432 // allowed by the type of node?
1433
1434 // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
1435 Node* startNonTextContainer = m_start.container();
1436 if (startNonTextContainer->nodeType() == Node::TEXT_NODE)
1437 startNonTextContainer = startNonTextContainer->parentNode();
1438 Node* endNonTextContainer = m_end.container();
1439 if (endNonTextContainer->nodeType() == Node::TEXT_NODE)
1440 endNonTextContainer = endNonTextContainer->parentNode();
1441 if (startNonTextContainer != endNonTextContainer) {
Ben Murdochdf957042013-08-06 11:01:27 +01001442 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001443 return;
1444 }
1445
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001446 while (Node* n = newParent->firstChild()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001447 toContainerNode(newParent.get())->removeChild(n, es);
1448 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001449 return;
1450 }
Ben Murdochdf957042013-08-06 11:01:27 +01001451 RefPtr<DocumentFragment> fragment = extractContents(es);
1452 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001453 return;
Ben Murdochdf957042013-08-06 11:01:27 +01001454 insertNode(newParent, es);
1455 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001456 return;
Ben Murdochdf957042013-08-06 11:01:27 +01001457 newParent->appendChild(fragment.release(), es);
1458 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001459 return;
Ben Murdochdf957042013-08-06 11:01:27 +01001460 selectNode(newParent.get(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001461}
1462
Ben Murdochdf957042013-08-06 11:01:27 +01001463void Range::setStartBefore(Node* refNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001464{
1465 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001466 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001467 return;
1468 }
1469
1470 if (!refNode) {
Ben Murdochdf957042013-08-06 11:01:27 +01001471 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001472 return;
1473 }
1474
Ben Murdochdf957042013-08-06 11:01:27 +01001475 checkNodeBA(refNode, es);
1476 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001477 return;
1478
Ben Murdochdf957042013-08-06 11:01:27 +01001479 setStart(refNode->parentNode(), refNode->nodeIndex(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001480}
1481
Ben Murdochdf957042013-08-06 11:01:27 +01001482void Range::checkDeleteExtract(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001483{
1484 if (!m_start.container()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001485 es.throwDOMException(InvalidStateError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001486 return;
1487 }
1488
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01001489 if (!commonAncestorContainer(es) || es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001490 return;
Ben Murdoch02772c62013-07-26 10:21:05 +01001491
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001492 Node* pastLast = pastLastNode();
1493 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(n)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001494 if (n->nodeType() == Node::DOCUMENT_TYPE_NODE) {
Ben Murdochdf957042013-08-06 11:01:27 +01001495 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001496 return;
1497 }
1498 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001499}
1500
1501Node* Range::firstNode() const
1502{
1503 if (!m_start.container())
1504 return 0;
1505 if (m_start.container()->offsetInCharacters())
1506 return m_start.container();
1507 if (Node* child = m_start.container()->childNode(m_start.offset()))
1508 return child;
1509 if (!m_start.offset())
1510 return m_start.container();
1511 return NodeTraversal::nextSkippingChildren(m_start.container());
1512}
1513
1514ShadowRoot* Range::shadowRoot() const
1515{
1516 return startContainer() ? startContainer()->containingShadowRoot() : 0;
1517}
1518
1519Node* Range::pastLastNode() const
1520{
1521 if (!m_start.container() || !m_end.container())
1522 return 0;
1523 if (m_end.container()->offsetInCharacters())
1524 return NodeTraversal::nextSkippingChildren(m_end.container());
1525 if (Node* child = m_end.container()->childNode(m_end.offset()))
1526 return child;
1527 return NodeTraversal::nextSkippingChildren(m_end.container());
1528}
1529
1530IntRect Range::boundingBox() const
1531{
1532 IntRect result;
1533 Vector<IntRect> rects;
1534 textRects(rects);
1535 const size_t n = rects.size();
1536 for (size_t i = 0; i < n; ++i)
1537 result.unite(rects[i]);
1538 return result;
1539}
1540
1541void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight, RangeInFixedPosition* inFixed) const
1542{
1543 Node* startContainer = m_start.container();
1544 Node* endContainer = m_end.container();
1545
1546 if (!startContainer || !endContainer) {
1547 if (inFixed)
1548 *inFixed = NotFixedPosition;
1549 return;
1550 }
1551
1552 bool allFixed = true;
1553 bool someFixed = false;
1554
1555 Node* stopNode = pastLastNode();
1556 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1557 RenderObject* r = node->renderer();
1558 if (!r || !r->isText())
1559 continue;
1560 RenderText* renderText = toRenderText(r);
1561 int startOffset = node == startContainer ? m_start.offset() : 0;
1562 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<int>::max();
1563 bool isFixed = false;
1564 renderText->absoluteRectsForRange(rects, startOffset, endOffset, useSelectionHeight, &isFixed);
1565 allFixed &= isFixed;
1566 someFixed |= isFixed;
1567 }
Ben Murdoch02772c62013-07-26 10:21:05 +01001568
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001569 if (inFixed)
1570 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixedPosition : NotFixedPosition);
1571}
1572
1573void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight, RangeInFixedPosition* inFixed) const
1574{
1575 Node* startContainer = m_start.container();
1576 Node* endContainer = m_end.container();
1577
1578 if (!startContainer || !endContainer) {
1579 if (inFixed)
1580 *inFixed = NotFixedPosition;
1581 return;
1582 }
1583
1584 bool allFixed = true;
1585 bool someFixed = false;
1586
1587 Node* stopNode = pastLastNode();
1588 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1589 RenderObject* r = node->renderer();
1590 if (!r || !r->isText())
1591 continue;
1592 RenderText* renderText = toRenderText(r);
1593 int startOffset = node == startContainer ? m_start.offset() : 0;
1594 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<int>::max();
1595 bool isFixed = false;
1596 renderText->absoluteQuadsForRange(quads, startOffset, endOffset, useSelectionHeight, &isFixed);
1597 allFixed &= isFixed;
1598 someFixed |= isFixed;
1599 }
1600
1601 if (inFixed)
1602 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixedPosition : NotFixedPosition);
1603}
1604
1605#ifndef NDEBUG
1606void Range::formatForDebugger(char* buffer, unsigned length) const
1607{
1608 StringBuilder result;
1609 String s;
1610
1611 if (!m_start.container() || !m_end.container())
1612 result.appendLiteral("<empty>");
1613 else {
1614 const int FormatBufferSize = 1024;
1615 char s[FormatBufferSize];
1616 result.appendLiteral("from offset ");
1617 result.appendNumber(m_start.offset());
1618 result.appendLiteral(" of ");
1619 m_start.container()->formatForDebugger(s, FormatBufferSize);
1620 result.append(s);
1621 result.appendLiteral(" to offset ");
1622 result.appendNumber(m_end.offset());
1623 result.appendLiteral(" of ");
1624 m_end.container()->formatForDebugger(s, FormatBufferSize);
1625 result.append(s);
1626 }
1627
1628 strncpy(buffer, result.toString().utf8().data(), length - 1);
1629}
1630#endif
1631
1632bool areRangesEqual(const Range* a, const Range* b)
1633{
1634 if (a == b)
1635 return true;
1636 if (!a || !b)
1637 return false;
1638 return a->startPosition() == b->startPosition() && a->endPosition() == b->endPosition();
1639}
1640
1641PassRefPtr<Range> rangeOfContents(Node* node)
1642{
1643 ASSERT(node);
1644 RefPtr<Range> range = Range::create(node->document());
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01001645 range->selectNodeContents(node, IGNORE_EXCEPTION);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001646 return range.release();
1647}
1648
1649int Range::maxStartOffset() const
1650{
1651 if (!m_start.container())
1652 return 0;
1653 if (!m_start.container()->offsetInCharacters())
1654 return m_start.container()->childNodeCount();
1655 return m_start.container()->maxCharacterOffset();
1656}
1657
1658int Range::maxEndOffset() const
1659{
1660 if (!m_end.container())
1661 return 0;
1662 if (!m_end.container()->offsetInCharacters())
1663 return m_end.container()->childNodeCount();
1664 return m_end.container()->maxCharacterOffset();
1665}
1666
1667static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint& boundary, ContainerNode* container)
1668{
1669 if (!boundary.childBefore())
1670 return;
1671 if (boundary.container() != container)
1672 return;
1673 boundary.invalidateOffset();
1674}
1675
1676void Range::nodeChildrenChanged(ContainerNode* container)
1677{
1678 ASSERT(container);
1679 ASSERT(container->document() == m_ownerDocument);
1680 boundaryNodeChildrenChanged(m_start, container);
1681 boundaryNodeChildrenChanged(m_end, container);
1682}
1683
1684static inline void boundaryNodeChildrenWillBeRemoved(RangeBoundaryPoint& boundary, ContainerNode* container)
1685{
1686 for (Node* nodeToBeRemoved = container->firstChild(); nodeToBeRemoved; nodeToBeRemoved = nodeToBeRemoved->nextSibling()) {
1687 if (boundary.childBefore() == nodeToBeRemoved) {
1688 boundary.setToStartOfNode(container);
1689 return;
1690 }
1691
1692 for (Node* n = boundary.container(); n; n = n->parentNode()) {
1693 if (n == nodeToBeRemoved) {
1694 boundary.setToStartOfNode(container);
1695 return;
1696 }
1697 }
1698 }
1699}
1700
1701void Range::nodeChildrenWillBeRemoved(ContainerNode* container)
1702{
1703 ASSERT(container);
1704 ASSERT(container->document() == m_ownerDocument);
1705 boundaryNodeChildrenWillBeRemoved(m_start, container);
1706 boundaryNodeChildrenWillBeRemoved(m_end, container);
1707}
1708
1709static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, Node* nodeToBeRemoved)
1710{
1711 if (boundary.childBefore() == nodeToBeRemoved) {
1712 boundary.childBeforeWillBeRemoved();
1713 return;
1714 }
1715
1716 for (Node* n = boundary.container(); n; n = n->parentNode()) {
1717 if (n == nodeToBeRemoved) {
1718 boundary.setToBeforeChild(nodeToBeRemoved);
1719 return;
1720 }
1721 }
1722}
1723
1724void Range::nodeWillBeRemoved(Node* node)
1725{
1726 ASSERT(node);
1727 ASSERT(node->document() == m_ownerDocument);
1728 ASSERT(node != m_ownerDocument);
1729 ASSERT(node->parentNode());
1730 boundaryNodeWillBeRemoved(m_start, node);
1731 boundaryNodeWillBeRemoved(m_end, node);
1732}
1733
1734static inline void boundaryTextInserted(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
1735{
1736 if (boundary.container() != text)
1737 return;
1738 unsigned boundaryOffset = boundary.offset();
1739 if (offset >= boundaryOffset)
1740 return;
1741 boundary.setOffset(boundaryOffset + length);
1742}
1743
1744void Range::textInserted(Node* text, unsigned offset, unsigned length)
1745{
1746 ASSERT(text);
1747 ASSERT(text->document() == m_ownerDocument);
1748 boundaryTextInserted(m_start, text, offset, length);
1749 boundaryTextInserted(m_end, text, offset, length);
1750}
1751
1752static inline void boundaryTextRemoved(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
1753{
1754 if (boundary.container() != text)
1755 return;
1756 unsigned boundaryOffset = boundary.offset();
1757 if (offset >= boundaryOffset)
1758 return;
1759 if (offset + length >= boundaryOffset)
1760 boundary.setOffset(offset);
1761 else
1762 boundary.setOffset(boundaryOffset - length);
1763}
1764
1765void Range::textRemoved(Node* text, unsigned offset, unsigned length)
1766{
1767 ASSERT(text);
1768 ASSERT(text->document() == m_ownerDocument);
1769 boundaryTextRemoved(m_start, text, offset, length);
1770 boundaryTextRemoved(m_end, text, offset, length);
1771}
1772
1773static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, NodeWithIndex& oldNode, unsigned offset)
1774{
1775 if (boundary.container() == oldNode.node())
1776 boundary.set(oldNode.node()->previousSibling(), boundary.offset() + offset, 0);
1777 else if (boundary.container() == oldNode.node()->parentNode() && boundary.offset() == oldNode.index())
1778 boundary.set(oldNode.node()->previousSibling(), offset, 0);
1779}
1780
1781void Range::textNodesMerged(NodeWithIndex& oldNode, unsigned offset)
1782{
1783 ASSERT(oldNode.node());
1784 ASSERT(oldNode.node()->document() == m_ownerDocument);
1785 ASSERT(oldNode.node()->parentNode());
1786 ASSERT(oldNode.node()->isTextNode());
1787 ASSERT(oldNode.node()->previousSibling());
1788 ASSERT(oldNode.node()->previousSibling()->isTextNode());
1789 boundaryTextNodesMerged(m_start, oldNode, offset);
1790 boundaryTextNodesMerged(m_end, oldNode, offset);
1791}
1792
1793static inline void boundaryTextNodesSplit(RangeBoundaryPoint& boundary, Text* oldNode)
1794{
1795 if (boundary.container() != oldNode)
1796 return;
1797 unsigned boundaryOffset = boundary.offset();
1798 if (boundaryOffset <= oldNode->length())
1799 return;
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001800 boundary.set(oldNode->nextSibling(), boundaryOffset - oldNode->length(), 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001801}
1802
1803void Range::textNodeSplit(Text* oldNode)
1804{
1805 ASSERT(oldNode);
1806 ASSERT(oldNode->document() == m_ownerDocument);
1807 ASSERT(oldNode->parentNode());
1808 ASSERT(oldNode->isTextNode());
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001809 ASSERT(oldNode->nextSibling());
1810 ASSERT(oldNode->nextSibling()->isTextNode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001811 boundaryTextNodesSplit(m_start, oldNode);
1812 boundaryTextNodesSplit(m_end, oldNode);
1813}
1814
Ben Murdochdf957042013-08-06 11:01:27 +01001815void Range::expand(const String& unit, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001816{
1817 VisiblePosition start(startPosition());
1818 VisiblePosition end(endPosition());
1819 if (unit == "word") {
1820 start = startOfWord(start);
1821 end = endOfWord(end);
1822 } else if (unit == "sentence") {
1823 start = startOfSentence(start);
1824 end = endOfSentence(end);
1825 } else if (unit == "block") {
1826 start = startOfParagraph(start);
1827 end = endOfParagraph(end);
1828 } else if (unit == "document") {
1829 start = startOfDocument(start);
1830 end = endOfDocument(end);
1831 } else
1832 return;
Ben Murdochdf957042013-08-06 11:01:27 +01001833 setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().computeOffsetInContainerNode(), es);
1834 setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOffsetInContainerNode(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001835}
1836
1837PassRefPtr<ClientRectList> Range::getClientRects() const
1838{
1839 if (!m_start.container())
1840 return ClientRectList::create();
1841
1842 m_ownerDocument->updateLayoutIgnorePendingStylesheets();
1843
1844 Vector<FloatQuad> quads;
1845 getBorderAndTextQuads(quads);
1846
1847 return ClientRectList::create(quads);
1848}
1849
1850PassRefPtr<ClientRect> Range::getBoundingClientRect() const
1851{
1852 return ClientRect::create(boundingRect());
1853}
1854
1855void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const
1856{
1857 Node* startContainer = m_start.container();
1858 Node* endContainer = m_end.container();
1859 Node* stopNode = pastLastNode();
1860
1861 HashSet<Node*> nodeSet;
1862 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1863 if (node->isElementNode())
1864 nodeSet.add(node);
1865 }
1866
1867 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next(node)) {
1868 if (node->isElementNode()) {
1869 if (!nodeSet.contains(node->parentNode())) {
1870 if (RenderBoxModelObject* renderBoxModelObject = toElement(node)->renderBoxModelObject()) {
1871 Vector<FloatQuad> elementQuads;
1872 renderBoxModelObject->absoluteQuads(elementQuads);
1873 m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoom(elementQuads, renderBoxModelObject);
1874
1875 quads.append(elementQuads);
1876 }
1877 }
1878 } else if (node->isTextNode()) {
1879 if (RenderObject* renderer = toText(node)->renderer()) {
1880 RenderText* renderText = toRenderText(renderer);
1881 int startOffset = (node == startContainer) ? m_start.offset() : 0;
1882 int endOffset = (node == endContainer) ? m_end.offset() : INT_MAX;
Ben Murdoch02772c62013-07-26 10:21:05 +01001883
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001884 Vector<FloatQuad> textQuads;
1885 renderText->absoluteQuadsForRange(textQuads, startOffset, endOffset);
1886 m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoom(textQuads, renderText);
1887
1888 quads.append(textQuads);
1889 }
1890 }
1891 }
1892}
1893
1894FloatRect Range::boundingRect() const
1895{
1896 if (!m_start.container())
1897 return FloatRect();
1898
1899 m_ownerDocument->updateLayoutIgnorePendingStylesheets();
1900
1901 Vector<FloatQuad> quads;
1902 getBorderAndTextQuads(quads);
1903 if (quads.isEmpty())
1904 return FloatRect();
1905
1906 FloatRect result;
1907 for (size_t i = 0; i < quads.size(); ++i)
1908 result.unite(quads[i].boundingBox());
1909
1910 return result;
1911}
1912
1913} // namespace WebCore
1914
1915#ifndef NDEBUG
1916
1917void showTree(const WebCore::Range* range)
1918{
1919 if (range && range->boundaryPointsValid()) {
1920 range->startContainer()->showTreeAndMark(range->startContainer(), "S", range->endContainer(), "E");
1921 fprintf(stderr, "start offset: %d, end offset: %d\n", range->startOffset(), range->endOffset());
1922 }
1923}
1924
1925#endif