OLD | NEW |
---|---|
1 /* | 1 /* |
2 * (C) 1999 Lars Knoll (knoll@kde.org) | 2 * (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no) | 3 * (C) 2000 Gunnstein Lye (gunnstein@netcom.no) |
4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no) | 4 * (C) 2000 Frederik Holljen (frederik.holljen@hig.no) |
5 * (C) 2001 Peter Kelly (pmk@post.com) | 5 * (C) 2001 Peter Kelly (pmk@post.com) |
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ights reserved. | 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ights reserved. |
7 * Copyright (C) 2011 Motorola Mobility. All rights reserved. | 7 * Copyright (C) 2011 Motorola Mobility. All rights reserved. |
8 * | 8 * |
9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
(...skipping 22 matching lines...) Expand all Loading... | |
33 #include "core/dom/Node.h" | 33 #include "core/dom/Node.h" |
34 #include "core/dom/NodeTraversal.h" | 34 #include "core/dom/NodeTraversal.h" |
35 #include "core/dom/NodeWithIndex.h" | 35 #include "core/dom/NodeWithIndex.h" |
36 #include "core/dom/ProcessingInstruction.h" | 36 #include "core/dom/ProcessingInstruction.h" |
37 #include "core/events/ScopedEventQueue.h" | 37 #include "core/events/ScopedEventQueue.h" |
38 #include "core/dom/Text.h" | 38 #include "core/dom/Text.h" |
39 #include "core/editing/TextIterator.h" | 39 #include "core/editing/TextIterator.h" |
40 #include "core/editing/VisiblePosition.h" | 40 #include "core/editing/VisiblePosition.h" |
41 #include "core/editing/VisibleUnits.h" | 41 #include "core/editing/VisibleUnits.h" |
42 #include "core/editing/markup.h" | 42 #include "core/editing/markup.h" |
43 #include "core/frame/UseCounter.h" | |
43 #include "core/html/HTMLElement.h" | 44 #include "core/html/HTMLElement.h" |
44 #include "core/rendering/RenderBoxModelObject.h" | 45 #include "core/rendering/RenderBoxModelObject.h" |
45 #include "core/rendering/RenderText.h" | 46 #include "core/rendering/RenderText.h" |
46 #include "platform/geometry/FloatQuad.h" | 47 #include "platform/geometry/FloatQuad.h" |
47 #include "wtf/RefCountedLeakCounter.h" | 48 #include "wtf/RefCountedLeakCounter.h" |
48 #include "wtf/text/CString.h" | 49 #include "wtf/text/CString.h" |
49 #include "wtf/text/StringBuilder.h" | 50 #include "wtf/text/StringBuilder.h" |
50 #ifndef NDEBUG | 51 #ifndef NDEBUG |
51 #include <stdio.h> | 52 #include <stdio.h> |
52 #endif | 53 #endif |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 { | 119 { |
119 ASSERT(m_ownerDocument != document); | 120 ASSERT(m_ownerDocument != document); |
120 ASSERT(m_ownerDocument); | 121 ASSERT(m_ownerDocument); |
121 m_ownerDocument->detachRange(this); | 122 m_ownerDocument->detachRange(this); |
122 m_ownerDocument = &document; | 123 m_ownerDocument = &document; |
123 m_start.setToStartOfNode(document); | 124 m_start.setToStartOfNode(document); |
124 m_end.setToStartOfNode(document); | 125 m_end.setToStartOfNode(document); |
125 m_ownerDocument->attachRange(this); | 126 m_ownerDocument->attachRange(this); |
126 } | 127 } |
127 | 128 |
128 Node* Range::startContainer(ExceptionState& exceptionState) const | 129 Node* Range::commonAncestorContainer() const |
129 { | 130 { |
130 if (!m_start.container()) { | |
131 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
132 return 0; | |
133 } | |
134 | |
135 return m_start.container(); | |
136 } | |
137 | |
138 int Range::startOffset(ExceptionState& exceptionState) const | |
139 { | |
140 if (!m_start.container()) { | |
141 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
142 return 0; | |
143 } | |
144 | |
145 return m_start.offset(); | |
146 } | |
147 | |
148 Node* Range::endContainer(ExceptionState& exceptionState) const | |
149 { | |
150 if (!m_start.container()) { | |
151 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
152 return 0; | |
153 } | |
154 | |
155 return m_end.container(); | |
156 } | |
157 | |
158 int Range::endOffset(ExceptionState& exceptionState) const | |
159 { | |
160 if (!m_start.container()) { | |
161 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
162 return 0; | |
163 } | |
164 | |
165 return m_end.offset(); | |
166 } | |
167 | |
168 Node* Range::commonAncestorContainer(ExceptionState& exceptionState) const | |
169 { | |
170 if (!m_start.container()) { | |
171 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
172 return 0; | |
173 } | |
174 | |
175 return commonAncestorContainer(m_start.container(), m_end.container()); | 131 return commonAncestorContainer(m_start.container(), m_end.container()); |
176 } | 132 } |
177 | 133 |
178 Node* Range::commonAncestorContainer(Node* containerA, Node* containerB) | 134 Node* Range::commonAncestorContainer(Node* containerA, Node* containerB) |
179 { | 135 { |
180 for (Node* parentA = containerA; parentA; parentA = parentA->parentNode()) { | 136 for (Node* parentA = containerA; parentA; parentA = parentA->parentNode()) { |
181 for (Node* parentB = containerB; parentB; parentB = parentB->parentNode( )) { | 137 for (Node* parentB = containerB; parentB; parentB = parentB->parentNode( )) { |
182 if (parentA == parentB) | 138 if (parentA == parentB) |
183 return parentA; | 139 return parentA; |
184 } | 140 } |
185 } | 141 } |
186 return 0; | 142 return 0; |
187 } | 143 } |
188 | 144 |
189 bool Range::collapsed(ExceptionState& exceptionState) const | |
190 { | |
191 if (!m_start.container()) { | |
192 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
193 return 0; | |
194 } | |
195 | |
196 return m_start == m_end; | |
197 } | |
198 | |
199 static inline bool checkForDifferentRootContainer(const RangeBoundaryPoint& star t, const RangeBoundaryPoint& end) | 145 static inline bool checkForDifferentRootContainer(const RangeBoundaryPoint& star t, const RangeBoundaryPoint& end) |
200 { | 146 { |
201 Node* endRootContainer = end.container(); | 147 Node* endRootContainer = end.container(); |
202 while (endRootContainer->parentNode()) | 148 while (endRootContainer->parentNode()) |
203 endRootContainer = endRootContainer->parentNode(); | 149 endRootContainer = endRootContainer->parentNode(); |
204 Node* startRootContainer = start.container(); | 150 Node* startRootContainer = start.container(); |
205 while (startRootContainer->parentNode()) | 151 while (startRootContainer->parentNode()) |
206 startRootContainer = startRootContainer->parentNode(); | 152 startRootContainer = startRootContainer->parentNode(); |
207 | 153 |
208 return startRootContainer != endRootContainer || (Range::compareBoundaryPoin ts(start, end, ASSERT_NO_EXCEPTION) > 0); | 154 return startRootContainer != endRootContainer || (Range::compareBoundaryPoin ts(start, end, ASSERT_NO_EXCEPTION) > 0); |
209 } | 155 } |
210 | 156 |
211 void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionState& excep tionState) | 157 void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionState& excep tionState) |
212 { | 158 { |
213 if (!m_start.container()) { | |
214 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
215 return; | |
216 } | |
217 | |
218 if (!refNode) { | 159 if (!refNode) { |
219 exceptionState.throwDOMException(NotFoundError, "The node provided was n ull."); | 160 exceptionState.throwDOMException(NotFoundError, "The node provided was n ull."); |
220 return; | 161 return; |
221 } | 162 } |
222 | 163 |
223 bool didMoveDocument = false; | 164 bool didMoveDocument = false; |
224 if (refNode->document() != m_ownerDocument) { | 165 if (refNode->document() != m_ownerDocument) { |
225 setDocument(refNode->document()); | 166 setDocument(refNode->document()); |
226 didMoveDocument = true; | 167 didMoveDocument = true; |
227 } | 168 } |
228 | 169 |
229 Node* childNode = checkNodeWOffset(refNode.get(), offset, exceptionState); | 170 Node* childNode = checkNodeWOffset(refNode.get(), offset, exceptionState); |
230 if (exceptionState.hadException()) | 171 if (exceptionState.hadException()) |
231 return; | 172 return; |
232 | 173 |
233 m_start.set(refNode, offset, childNode); | 174 m_start.set(refNode, offset, childNode); |
234 | 175 |
235 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 176 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) |
236 collapse(true, exceptionState); | 177 collapse(true); |
237 } | 178 } |
238 | 179 |
239 void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionState& excepti onState) | 180 void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionState& excepti onState) |
240 { | 181 { |
241 if (!m_start.container()) { | |
242 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
243 return; | |
244 } | |
245 | |
246 if (!refNode) { | 182 if (!refNode) { |
247 exceptionState.throwDOMException(NotFoundError, "The node provided was n ull."); | 183 exceptionState.throwDOMException(NotFoundError, "The node provided was n ull."); |
248 return; | 184 return; |
249 } | 185 } |
250 | 186 |
251 bool didMoveDocument = false; | 187 bool didMoveDocument = false; |
252 if (refNode->document() != m_ownerDocument) { | 188 if (refNode->document() != m_ownerDocument) { |
253 setDocument(refNode->document()); | 189 setDocument(refNode->document()); |
254 didMoveDocument = true; | 190 didMoveDocument = true; |
255 } | 191 } |
256 | 192 |
257 Node* childNode = checkNodeWOffset(refNode.get(), offset, exceptionState); | 193 Node* childNode = checkNodeWOffset(refNode.get(), offset, exceptionState); |
258 if (exceptionState.hadException()) | 194 if (exceptionState.hadException()) |
259 return; | 195 return; |
260 | 196 |
261 m_end.set(refNode, offset, childNode); | 197 m_end.set(refNode, offset, childNode); |
262 | 198 |
263 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) | 199 if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) |
264 collapse(false, exceptionState); | 200 collapse(false); |
265 } | 201 } |
266 | 202 |
267 void Range::setStart(const Position& start, ExceptionState& exceptionState) | 203 void Range::setStart(const Position& start, ExceptionState& exceptionState) |
268 { | 204 { |
269 Position parentAnchored = start.parentAnchoredEquivalent(); | 205 Position parentAnchored = start.parentAnchoredEquivalent(); |
270 setStart(parentAnchored.containerNode(), parentAnchored.offsetInContainerNod e(), exceptionState); | 206 setStart(parentAnchored.containerNode(), parentAnchored.offsetInContainerNod e(), exceptionState); |
271 } | 207 } |
272 | 208 |
273 void Range::setEnd(const Position& end, ExceptionState& exceptionState) | 209 void Range::setEnd(const Position& end, ExceptionState& exceptionState) |
274 { | 210 { |
275 Position parentAnchored = end.parentAnchoredEquivalent(); | 211 Position parentAnchored = end.parentAnchoredEquivalent(); |
276 setEnd(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode( ), exceptionState); | 212 setEnd(parentAnchored.containerNode(), parentAnchored.offsetInContainerNode( ), exceptionState); |
277 } | 213 } |
278 | 214 |
279 void Range::collapse(bool toStart, ExceptionState& exceptionState) | 215 void Range::collapse(bool toStart) |
280 { | 216 { |
281 if (!m_start.container()) { | |
282 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
283 return; | |
284 } | |
285 | |
286 if (toStart) | 217 if (toStart) |
287 m_end = m_start; | 218 m_end = m_start; |
288 else | 219 else |
289 m_start = m_end; | 220 m_start = m_end; |
290 } | 221 } |
291 | 222 |
292 bool Range::isPointInRange(Node* refNode, int offset, ExceptionState& exceptionS tate) | 223 bool Range::isPointInRange(Node* refNode, int offset, ExceptionState& exceptionS tate) |
293 { | 224 { |
294 if (!m_start.container()) { | |
295 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
296 return false; | |
297 } | |
298 | |
299 if (!refNode) { | 225 if (!refNode) { |
300 exceptionState.throwDOMException(HierarchyRequestError, "The node provid ed was null."); | 226 exceptionState.throwDOMException(HierarchyRequestError, "The node provid ed was null."); |
301 return false; | 227 return false; |
302 } | 228 } |
303 | 229 |
304 if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) { | 230 if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) { |
305 return false; | 231 return false; |
306 } | 232 } |
307 | 233 |
308 checkNodeWOffset(refNode, offset, exceptionState); | 234 checkNodeWOffset(refNode, offset, exceptionState); |
309 if (exceptionState.hadException()) | 235 if (exceptionState.hadException()) |
310 return false; | 236 return false; |
311 | 237 |
312 return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.o ffset(), exceptionState) >= 0 && !exceptionState.hadException() | 238 return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.o ffset(), exceptionState) >= 0 && !exceptionState.hadException() |
313 && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offse t(), exceptionState) <= 0 && !exceptionState.hadException(); | 239 && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offse t(), exceptionState) <= 0 && !exceptionState.hadException(); |
314 } | 240 } |
315 | 241 |
316 short Range::comparePoint(Node* refNode, int offset, ExceptionState& exceptionSt ate) const | 242 short Range::comparePoint(Node* refNode, int offset, ExceptionState& exceptionSt ate) const |
317 { | 243 { |
318 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint | 244 // http://developer.mozilla.org/en/docs/DOM:range.comparePoint |
319 // This method returns -1, 0 or 1 depending on if the point described by the | 245 // This method returns -1, 0 or 1 depending on if the point described by the |
320 // refNode node and an offset within the node is before, same as, or after t he range respectively. | 246 // refNode node and an offset within the node is before, same as, or after t he range respectively. |
321 | 247 |
322 if (!m_start.container()) { | |
323 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
324 return 0; | |
325 } | |
326 | |
327 if (!refNode) { | 248 if (!refNode) { |
328 exceptionState.throwDOMException(HierarchyRequestError, "The node provid ed was null."); | 249 exceptionState.throwDOMException(HierarchyRequestError, "The node provid ed was null."); |
329 return 0; | 250 return 0; |
330 } | 251 } |
331 | 252 |
332 if (!refNode->inActiveDocument()) { | 253 if (!refNode->inActiveDocument()) { |
333 exceptionState.throwDOMException(WrongDocumentError, "The node provided is not in an active document."); | 254 exceptionState.throwDOMException(WrongDocumentError, "The node provided is not in an active document."); |
334 return 0; | 255 return 0; |
335 } | 256 } |
336 | 257 |
(...skipping 25 matching lines...) Expand all Loading... | |
362 { | 283 { |
363 // http://developer.mozilla.org/en/docs/DOM:range.compareNode | 284 // http://developer.mozilla.org/en/docs/DOM:range.compareNode |
364 // This method returns 0, 1, 2, or 3 based on if the node is before, after, | 285 // This method returns 0, 1, 2, or 3 based on if the node is before, after, |
365 // before and after(surrounds), or inside the range, respectively | 286 // before and after(surrounds), or inside the range, respectively |
366 | 287 |
367 if (!refNode) { | 288 if (!refNode) { |
368 exceptionState.throwDOMException(NotFoundError, "The node provided was n ull."); | 289 exceptionState.throwDOMException(NotFoundError, "The node provided was n ull."); |
369 return NODE_BEFORE; | 290 return NODE_BEFORE; |
370 } | 291 } |
371 | 292 |
372 if (!m_start.container() && refNode->inActiveDocument()) { | 293 if (!refNode->inActiveDocument()) { |
373 exceptionState.throwDOMException(InvalidStateError, "This Range is detac hed, and the provided node is not."); | |
374 return NODE_BEFORE; | |
375 } | |
376 | |
377 if (m_start.container() && !refNode->inActiveDocument()) { | |
378 // Firefox doesn't throw an exception for this case; it returns 0. | 294 // Firefox doesn't throw an exception for this case; it returns 0. |
379 return NODE_BEFORE; | 295 return NODE_BEFORE; |
380 } | 296 } |
381 | 297 |
382 if (refNode->document() != m_ownerDocument) { | 298 if (refNode->document() != m_ownerDocument) { |
383 // Firefox doesn't throw an exception for this case; it returns 0. | 299 // Firefox doesn't throw an exception for this case; it returns 0. |
384 return NODE_BEFORE; | 300 return NODE_BEFORE; |
385 } | 301 } |
386 | 302 |
387 ContainerNode* parentNode = refNode->parentNode(); | 303 ContainerNode* parentNode = refNode->parentNode(); |
(...skipping 12 matching lines...) Expand all Loading... | |
400 return NODE_BEFORE; // ends before or in the range | 316 return NODE_BEFORE; // ends before or in the range |
401 } | 317 } |
402 // starts at or after the range start | 318 // starts at or after the range start |
403 if (comparePoint(parentNode, nodeIndex + 1, exceptionState) > 0) // ends aft er the range | 319 if (comparePoint(parentNode, nodeIndex + 1, exceptionState) > 0) // ends aft er the range |
404 return NODE_AFTER; | 320 return NODE_AFTER; |
405 return NODE_INSIDE; // ends inside the range | 321 return NODE_INSIDE; // ends inside the range |
406 } | 322 } |
407 | 323 |
408 short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, Exc eptionState& exceptionState) const | 324 short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, Exc eptionState& exceptionState) const |
409 { | 325 { |
410 if (!m_start.container()) { | |
411 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
412 return 0; | |
413 } | |
414 | |
415 if (!sourceRange) { | 326 if (!sourceRange) { |
416 exceptionState.throwDOMException(NotFoundError, "The source range provid ed was null."); | 327 exceptionState.throwDOMException(NotFoundError, "The source range provid ed was null."); |
417 return 0; | 328 return 0; |
418 } | 329 } |
419 | 330 |
420 Node* thisCont = commonAncestorContainer(exceptionState); | 331 Node* thisCont = commonAncestorContainer(); |
421 if (exceptionState.hadException()) | 332 Node* sourceCont = sourceRange->commonAncestorContainer(); |
422 return 0; | |
423 Node* sourceCont = sourceRange->commonAncestorContainer(exceptionState); | |
424 if (exceptionState.hadException()) | |
425 return 0; | |
426 | |
427 if (thisCont->document() != sourceCont->document()) { | 333 if (thisCont->document() != sourceCont->document()) { |
428 exceptionState.throwDOMException(WrongDocumentError, "The source range i s in a different document than this range."); | 334 exceptionState.throwDOMException(WrongDocumentError, "The source range i s in a different document than this range."); |
429 return 0; | 335 return 0; |
430 } | 336 } |
431 | 337 |
432 Node* thisTop = thisCont; | 338 Node* thisTop = thisCont; |
433 Node* sourceTop = sourceCont; | 339 Node* sourceTop = sourceCont; |
434 while (thisTop->parentNode()) | 340 while (thisTop->parentNode()) |
435 thisTop = thisTop->parentNode(); | 341 thisTop = thisTop->parentNode(); |
436 while (sourceTop->parentNode()) | 342 while (sourceTop->parentNode()) |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
549 } | 455 } |
550 | 456 |
551 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const Ra ngeBoundaryPoint& boundaryB, ExceptionState& exceptionState) | 457 short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const Ra ngeBoundaryPoint& boundaryB, ExceptionState& exceptionState) |
552 { | 458 { |
553 return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boun daryB.container(), boundaryB.offset(), exceptionState); | 459 return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boun daryB.container(), boundaryB.offset(), exceptionState); |
554 } | 460 } |
555 | 461 |
556 bool Range::boundaryPointsValid() const | 462 bool Range::boundaryPointsValid() const |
557 { | 463 { |
558 TrackExceptionState exceptionState; | 464 TrackExceptionState exceptionState; |
559 return m_start.container() && compareBoundaryPoints(m_start, m_end, exceptio nState) <= 0 && !exceptionState.hadException(); | 465 return compareBoundaryPoints(m_start, m_end, exceptionState) <= 0 && !except ionState.hadException(); |
560 } | 466 } |
561 | 467 |
562 void Range::deleteContents(ExceptionState& exceptionState) | 468 void Range::deleteContents(ExceptionState& exceptionState) |
563 { | 469 { |
564 checkDeleteExtract(exceptionState); | 470 checkDeleteExtract(exceptionState); |
565 if (exceptionState.hadException()) | 471 if (exceptionState.hadException()) |
566 return; | 472 return; |
567 | 473 |
568 processContents(DELETE_CONTENTS, exceptionState); | 474 processContents(DELETE_CONTENTS, exceptionState); |
569 } | 475 } |
570 | 476 |
571 bool Range::intersectsNode(Node* refNode, ExceptionState& exceptionState) | 477 bool Range::intersectsNode(Node* refNode, ExceptionState& exceptionState) |
572 { | 478 { |
573 // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode | 479 // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode |
574 // Returns a bool if the node intersects the range. | 480 // Returns a bool if the node intersects the range. |
575 | |
576 // Throw exception if the range is already detached. | |
577 if (!m_start.container()) { | |
578 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
579 return false; | |
580 } | |
581 if (!refNode) { | 481 if (!refNode) { |
582 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); | 482 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); |
583 return false; | 483 return false; |
584 } | 484 } |
585 | 485 |
586 if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) { | 486 if (!refNode->inActiveDocument() || refNode->document() != m_ownerDocument) { |
587 // Firefox doesn't throw an exception for these cases; it returns false. | 487 // Firefox doesn't throw an exception for these cases; it returns false. |
588 return false; | 488 return false; |
589 } | 489 } |
590 | 490 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
667 } | 567 } |
668 | 568 |
669 PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception State& exceptionState) | 569 PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception State& exceptionState) |
670 { | 570 { |
671 typedef Vector<RefPtr<Node> > NodeVector; | 571 typedef Vector<RefPtr<Node> > NodeVector; |
672 | 572 |
673 RefPtr<DocumentFragment> fragment; | 573 RefPtr<DocumentFragment> fragment; |
674 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) | 574 if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) |
675 fragment = DocumentFragment::create(*m_ownerDocument.get()); | 575 fragment = DocumentFragment::create(*m_ownerDocument.get()); |
676 | 576 |
677 if (collapsed(exceptionState)) | 577 if (collapsed()) |
678 return fragment.release(); | 578 return fragment.release(); |
679 if (exceptionState.hadException()) | |
680 return nullptr; | |
681 | 579 |
682 RefPtr<Node> commonRoot = commonAncestorContainer(exceptionState); | 580 RefPtr<Node> commonRoot = commonAncestorContainer(); |
683 if (exceptionState.hadException()) | |
684 return nullptr; | |
685 ASSERT(commonRoot); | 581 ASSERT(commonRoot); |
686 | 582 |
687 if (m_start.container() == m_end.container()) { | 583 if (m_start.container() == m_end.container()) { |
688 processContentsBetweenOffsets(action, fragment, m_start.container(), m_s tart.offset(), m_end.offset(), exceptionState); | 584 processContentsBetweenOffsets(action, fragment, m_start.container(), m_s tart.offset(), m_end.offset(), exceptionState); |
689 return fragment; | 585 return fragment; |
690 } | 586 } |
691 | 587 |
692 // Since mutation observers can modify the range during the process, the bou ndary points need to be saved. | 588 // Since mutation observers can modify the range during the process, the bou ndary points need to be saved. |
693 RangeBoundaryPoint originalStart(m_start); | 589 RangeBoundaryPoint originalStart(m_start); |
694 RangeBoundaryPoint originalEnd(m_end); | 590 RangeBoundaryPoint originalEnd(m_end); |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
930 { | 826 { |
931 checkDeleteExtract(exceptionState); | 827 checkDeleteExtract(exceptionState); |
932 if (exceptionState.hadException()) | 828 if (exceptionState.hadException()) |
933 return nullptr; | 829 return nullptr; |
934 | 830 |
935 return processContents(EXTRACT_CONTENTS, exceptionState); | 831 return processContents(EXTRACT_CONTENTS, exceptionState); |
936 } | 832 } |
937 | 833 |
938 PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionState& exceptionState ) | 834 PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionState& exceptionState ) |
939 { | 835 { |
940 if (!m_start.container()) { | |
941 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
942 return nullptr; | |
943 } | |
944 | |
945 return processContents(CLONE_CONTENTS, exceptionState); | 836 return processContents(CLONE_CONTENTS, exceptionState); |
946 } | 837 } |
947 | 838 |
948 void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionState& exceptionSta te) | 839 void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionState& exceptionSta te) |
949 { | 840 { |
950 RefPtr<Node> newNode = prpNewNode; | 841 RefPtr<Node> newNode = prpNewNode; |
951 | 842 |
952 if (!m_start.container()) { | |
953 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
954 return; | |
955 } | |
956 | |
957 if (!newNode) { | 843 if (!newNode) { |
958 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); | 844 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); |
959 return; | 845 return; |
960 } | 846 } |
961 | 847 |
962 // HierarchyRequestError: Raised if the container of the start of the Range is of a type that | 848 // HierarchyRequestError: Raised if the container of the start of the Range is of a type that |
963 // does not allow children of the type of newNode or if newNode is an ancest or of the container. | 849 // does not allow children of the type of newNode or if newNode is an ancest or of the container. |
964 | 850 |
965 // an extra one here - if a text node is going to split, it must have a pare nt to insert into | 851 // an extra one here - if a text node is going to split, it must have a pare nt to insert into |
966 bool startIsText = m_start.container()->isTextNode(); | 852 bool startIsText = m_start.container()->isTextNode(); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1050 if (exceptionState.hadException()) | 936 if (exceptionState.hadException()) |
1051 return; | 937 return; |
1052 | 938 |
1053 // Note that m_start.offset() may have changed as a result of container- >insertBefore, | 939 // Note that m_start.offset() may have changed as a result of container- >insertBefore, |
1054 // when the node we are inserting comes before the range in the same con tainer. | 940 // when the node we are inserting comes before the range in the same con tainer. |
1055 if (collapsed && numNewChildren) | 941 if (collapsed && numNewChildren) |
1056 m_end.set(m_start.container(), m_start.offset() + numNewChildren, la stChild.get()); | 942 m_end.set(m_start.container(), m_start.offset() + numNewChildren, la stChild.get()); |
1057 } | 943 } |
1058 } | 944 } |
1059 | 945 |
1060 String Range::toString(ExceptionState& exceptionState) const | 946 String Range::toString() const |
1061 { | 947 { |
1062 if (!m_start.container()) { | |
1063 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1064 return String(); | |
1065 } | |
1066 | |
1067 StringBuilder builder; | 948 StringBuilder builder; |
1068 | 949 |
1069 Node* pastLast = pastLastNode(); | 950 Node* pastLast = pastLastNode(); |
1070 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { | 951 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { |
1071 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SEC TION_NODE) { | 952 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SEC TION_NODE) { |
1072 String data = toCharacterData(n)->data(); | 953 String data = toCharacterData(n)->data(); |
1073 int length = data.length(); | 954 int length = data.length(); |
1074 int start = (n == m_start.container()) ? min(max(0, m_start.offset() ), length) : 0; | 955 int start = (n == m_start.container()) ? min(max(0, m_start.offset() ), length) : 0; |
1075 int end = (n == m_end.container()) ? min(max(start, m_end.offset()), length) : length; | 956 int end = (n == m_end.container()) ? min(max(start, m_end.offset()), length) : length; |
1076 builder.append(data, start, end - start); | 957 builder.append(data, start, end - start); |
1077 } | 958 } |
1078 } | 959 } |
1079 | 960 |
1080 return builder.toString(); | 961 return builder.toString(); |
1081 } | 962 } |
1082 | 963 |
1083 String Range::toHTML() const | 964 String Range::toHTML() const |
1084 { | 965 { |
1085 return createMarkup(this); | 966 return createMarkup(this); |
1086 } | 967 } |
1087 | 968 |
1088 String Range::text() const | 969 String Range::text() const |
1089 { | 970 { |
1090 if (!m_start.container()) | |
1091 return String(); | |
1092 | |
1093 // We need to update layout, since plainText uses line boxes in the render t ree. | 971 // We need to update layout, since plainText uses line boxes in the render t ree. |
1094 // FIXME: As with innerText, we'd like this to work even if there are no ren der objects. | 972 // FIXME: As with innerText, we'd like this to work even if there are no ren der objects. |
1095 m_start.container()->document().updateLayout(); | 973 m_start.container()->document().updateLayout(); |
1096 | 974 |
1097 return plainText(this); | 975 return plainText(this); |
1098 } | 976 } |
1099 | 977 |
1100 PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& marku p, ExceptionState& exceptionState) | 978 PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& marku p, ExceptionState& exceptionState) |
1101 { | 979 { |
1102 if (!m_start.container()) { | |
1103 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1104 return nullptr; | |
1105 } | |
1106 | |
1107 Node* element = m_start.container()->isElementNode() ? m_start.container() : m_start.container()->parentNode(); | 980 Node* element = m_start.container()->isElementNode() ? m_start.container() : m_start.container()->parentNode(); |
1108 if (!element || !element->isHTMLElement()) { | 981 if (!element || !element->isHTMLElement()) { |
1109 exceptionState.throwDOMException(NotSupportedError, "The range's contain er must be an HTML element."); | 982 exceptionState.throwDOMException(NotSupportedError, "The range's contain er must be an HTML element."); |
1110 return nullptr; | 983 return nullptr; |
1111 } | 984 } |
1112 | 985 |
1113 RefPtr<DocumentFragment> fragment = WebCore::createContextualFragment(markup , toHTMLElement(element), AllowScriptingContentAndDoNotMarkAlreadyStarted, excep tionState); | 986 RefPtr<DocumentFragment> fragment = WebCore::createContextualFragment(markup , toHTMLElement(element), AllowScriptingContentAndDoNotMarkAlreadyStarted, excep tionState); |
1114 if (!fragment) | 987 if (!fragment) |
1115 return nullptr; | 988 return nullptr; |
1116 | 989 |
1117 return fragment.release(); | 990 return fragment.release(); |
1118 } | 991 } |
1119 | 992 |
1120 | 993 |
1121 void Range::detach(ExceptionState& exceptionState) | 994 void Range::detach() |
1122 { | 995 { |
1123 // Check first to see if we've already detached: | 996 // This is now a no-op as per the DOM specification. |
1124 if (!m_start.container()) { | 997 UseCounter::countDeprecation(ownerDocument(), UseCounter::RangeDetach); |
Yuta Kitamura
2014/04/28 09:27:38
Why don't you use "DeprecateAs=" IDL attribute her
Inactive
2014/04/28 14:44:18
Done.
| |
1125 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1126 return; | |
1127 } | |
1128 | |
1129 m_ownerDocument->detachRange(this); | |
1130 | |
1131 m_start.clear(); | |
1132 m_end.clear(); | |
1133 } | 998 } |
1134 | 999 |
1135 Node* Range::checkNodeWOffset(Node* n, int offset, ExceptionState& exceptionStat e) const | 1000 Node* Range::checkNodeWOffset(Node* n, int offset, ExceptionState& exceptionStat e) const |
1136 { | 1001 { |
1137 switch (n->nodeType()) { | 1002 switch (n->nodeType()) { |
1138 case Node::DOCUMENT_TYPE_NODE: | 1003 case Node::DOCUMENT_TYPE_NODE: |
1139 exceptionState.throwDOMException(InvalidNodeTypeError, "The node pro vided is of type '" + n->nodeName() + "'."); | 1004 exceptionState.throwDOMException(InvalidNodeTypeError, "The node pro vided is of type '" + n->nodeName() + "'."); |
1140 return 0; | 1005 return 0; |
1141 case Node::CDATA_SECTION_NODE: | 1006 case Node::CDATA_SECTION_NODE: |
1142 case Node::COMMENT_NODE: | 1007 case Node::COMMENT_NODE: |
(...skipping 16 matching lines...) Expand all Loading... | |
1159 exceptionState.throwDOMException(IndexSizeError, "There is no ch ild at offset " + String::number(offset) + "."); | 1024 exceptionState.throwDOMException(IndexSizeError, "There is no ch ild at offset " + String::number(offset) + "."); |
1160 return childBefore; | 1025 return childBefore; |
1161 } | 1026 } |
1162 } | 1027 } |
1163 ASSERT_NOT_REACHED(); | 1028 ASSERT_NOT_REACHED(); |
1164 return 0; | 1029 return 0; |
1165 } | 1030 } |
1166 | 1031 |
1167 void Range::checkNodeBA(Node* n, ExceptionState& exceptionState) const | 1032 void Range::checkNodeBA(Node* n, ExceptionState& exceptionState) const |
1168 { | 1033 { |
1169 if (!m_start.container()) { | |
1170 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1171 return; | |
1172 } | |
1173 | |
1174 if (!n) { | 1034 if (!n) { |
1175 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); | 1035 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); |
1176 return; | 1036 return; |
1177 } | 1037 } |
1178 | 1038 |
1179 // InvalidNodeTypeError: Raised if the root container of refNode is not an | 1039 // InvalidNodeTypeError: Raised if the root container of refNode is not an |
1180 // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG sha dow DOM tree, | 1040 // Attr, Document, DocumentFragment or ShadowRoot node, or part of a SVG sha dow DOM tree, |
1181 // or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation node. | 1041 // or if refNode is a Document, DocumentFragment, ShadowRoot, Attr, Entity, or Notation node. |
1182 | 1042 |
1183 if (!n->parentNode()) { | 1043 if (!n->parentNode()) { |
(...skipping 29 matching lines...) Expand all Loading... | |
1213 case Node::CDATA_SECTION_NODE: | 1073 case Node::CDATA_SECTION_NODE: |
1214 case Node::COMMENT_NODE: | 1074 case Node::COMMENT_NODE: |
1215 case Node::DOCUMENT_TYPE_NODE: | 1075 case Node::DOCUMENT_TYPE_NODE: |
1216 case Node::PROCESSING_INSTRUCTION_NODE: | 1076 case Node::PROCESSING_INSTRUCTION_NODE: |
1217 case Node::TEXT_NODE: | 1077 case Node::TEXT_NODE: |
1218 exceptionState.throwDOMException(InvalidNodeTypeError, "The node pro vided is of type '" + n->nodeName() + "'."); | 1078 exceptionState.throwDOMException(InvalidNodeTypeError, "The node pro vided is of type '" + n->nodeName() + "'."); |
1219 return; | 1079 return; |
1220 } | 1080 } |
1221 } | 1081 } |
1222 | 1082 |
1223 PassRefPtrWillBeRawPtr<Range> Range::cloneRange(ExceptionState& exceptionState) const | 1083 PassRefPtrWillBeRawPtr<Range> Range::cloneRange() const |
1224 { | 1084 { |
1225 if (!m_start.container()) { | |
1226 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1227 return nullptr; | |
1228 } | |
1229 | |
1230 return Range::create(*m_ownerDocument.get(), m_start.container(), m_start.of fset(), m_end.container(), m_end.offset()); | 1085 return Range::create(*m_ownerDocument.get(), m_start.container(), m_start.of fset(), m_end.container(), m_end.offset()); |
1231 } | 1086 } |
1232 | 1087 |
1233 void Range::setStartAfter(Node* refNode, ExceptionState& exceptionState) | 1088 void Range::setStartAfter(Node* refNode, ExceptionState& exceptionState) |
1234 { | 1089 { |
1235 checkNodeBA(refNode, exceptionState); | 1090 checkNodeBA(refNode, exceptionState); |
1236 if (exceptionState.hadException()) | 1091 if (exceptionState.hadException()) |
1237 return; | 1092 return; |
1238 | 1093 |
1239 setStart(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState); | 1094 setStart(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState); |
(...skipping 12 matching lines...) Expand all Loading... | |
1252 { | 1107 { |
1253 checkNodeBA(refNode, exceptionState); | 1108 checkNodeBA(refNode, exceptionState); |
1254 if (exceptionState.hadException()) | 1109 if (exceptionState.hadException()) |
1255 return; | 1110 return; |
1256 | 1111 |
1257 setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState); | 1112 setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, exceptionState); |
1258 } | 1113 } |
1259 | 1114 |
1260 void Range::selectNode(Node* refNode, ExceptionState& exceptionState) | 1115 void Range::selectNode(Node* refNode, ExceptionState& exceptionState) |
1261 { | 1116 { |
1262 if (!m_start.container()) { | |
1263 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1264 return; | |
1265 } | |
1266 | |
1267 if (!refNode) { | 1117 if (!refNode) { |
1268 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); | 1118 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); |
1269 return; | 1119 return; |
1270 } | 1120 } |
1271 | 1121 |
1272 if (!refNode->parentNode()) { | 1122 if (!refNode->parentNode()) { |
1273 exceptionState.throwDOMException(InvalidNodeTypeError, "the given Node h as no parent."); | 1123 exceptionState.throwDOMException(InvalidNodeTypeError, "the given Node h as no parent."); |
1274 return; | 1124 return; |
1275 } | 1125 } |
1276 | 1126 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1311 | 1161 |
1312 if (m_ownerDocument != refNode->document()) | 1162 if (m_ownerDocument != refNode->document()) |
1313 setDocument(refNode->document()); | 1163 setDocument(refNode->document()); |
1314 | 1164 |
1315 setStartBefore(refNode); | 1165 setStartBefore(refNode); |
1316 setEndAfter(refNode); | 1166 setEndAfter(refNode); |
1317 } | 1167 } |
1318 | 1168 |
1319 void Range::selectNodeContents(Node* refNode, ExceptionState& exceptionState) | 1169 void Range::selectNodeContents(Node* refNode, ExceptionState& exceptionState) |
1320 { | 1170 { |
1321 if (!m_start.container()) { | |
1322 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1323 return; | |
1324 } | |
1325 | |
1326 if (!refNode) { | 1171 if (!refNode) { |
1327 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); | 1172 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); |
1328 return; | 1173 return; |
1329 } | 1174 } |
1330 | 1175 |
1331 // InvalidNodeTypeError: Raised if refNode or an ancestor of refNode is an E ntity, Notation | 1176 // InvalidNodeTypeError: Raised if refNode or an ancestor of refNode is an E ntity, Notation |
1332 // or DocumentType node. | 1177 // or DocumentType node. |
1333 for (Node* n = refNode; n; n = n->parentNode()) { | 1178 for (Node* n = refNode; n; n = n->parentNode()) { |
1334 switch (n->nodeType()) { | 1179 switch (n->nodeType()) { |
1335 case Node::ATTRIBUTE_NODE: | 1180 case Node::ATTRIBUTE_NODE: |
(...skipping 14 matching lines...) Expand all Loading... | |
1350 if (m_ownerDocument != refNode->document()) | 1195 if (m_ownerDocument != refNode->document()) |
1351 setDocument(refNode->document()); | 1196 setDocument(refNode->document()); |
1352 | 1197 |
1353 m_start.setToStartOfNode(*refNode); | 1198 m_start.setToStartOfNode(*refNode); |
1354 m_end.setToEndOfNode(*refNode); | 1199 m_end.setToEndOfNode(*refNode); |
1355 } | 1200 } |
1356 | 1201 |
1357 void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionState& exc eptionState) | 1202 void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionState& exc eptionState) |
1358 { | 1203 { |
1359 RefPtr<Node> newParent = passNewParent; | 1204 RefPtr<Node> newParent = passNewParent; |
1360 | |
1361 if (!m_start.container()) { | |
1362 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1363 return; | |
1364 } | |
1365 | |
1366 if (!newParent) { | 1205 if (!newParent) { |
1367 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); | 1206 exceptionState.throwDOMException(NotFoundError, "The node provided is nu ll."); |
1368 return; | 1207 return; |
1369 } | 1208 } |
1370 | 1209 |
1371 // InvalidNodeTypeError: Raised if node is an Attr, Entity, DocumentType, No tation, | 1210 // InvalidNodeTypeError: Raised if node is an Attr, Entity, DocumentType, No tation, |
1372 // Document, or DocumentFragment node. | 1211 // Document, or DocumentFragment node. |
1373 switch (newParent->nodeType()) { | 1212 switch (newParent->nodeType()) { |
1374 case Node::ATTRIBUTE_NODE: | 1213 case Node::ATTRIBUTE_NODE: |
1375 case Node::DOCUMENT_FRAGMENT_NODE: | 1214 case Node::DOCUMENT_FRAGMENT_NODE: |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1445 { | 1284 { |
1446 checkNodeBA(refNode, exceptionState); | 1285 checkNodeBA(refNode, exceptionState); |
1447 if (exceptionState.hadException()) | 1286 if (exceptionState.hadException()) |
1448 return; | 1287 return; |
1449 | 1288 |
1450 setStart(refNode->parentNode(), refNode->nodeIndex(), exceptionState); | 1289 setStart(refNode->parentNode(), refNode->nodeIndex(), exceptionState); |
1451 } | 1290 } |
1452 | 1291 |
1453 void Range::checkDeleteExtract(ExceptionState& exceptionState) | 1292 void Range::checkDeleteExtract(ExceptionState& exceptionState) |
1454 { | 1293 { |
1455 if (!m_start.container()) { | |
1456 exceptionState.throwDOMException(InvalidStateError, "The range has no co ntainer. Perhaps 'detach()' has been invoked on this object?"); | |
1457 return; | |
1458 } | |
1459 | |
1460 ASSERT(boundaryPointsValid()); | 1294 ASSERT(boundaryPointsValid()); |
1461 | 1295 |
1462 if (!commonAncestorContainer(exceptionState) || exceptionState.hadException( )) | 1296 if (!commonAncestorContainer()) |
1463 return; | 1297 return; |
1464 | 1298 |
1465 Node* pastLast = pastLastNode(); | 1299 Node* pastLast = pastLastNode(); |
1466 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { | 1300 for (Node* n = firstNode(); n != pastLast; n = NodeTraversal::next(*n)) { |
1467 if (n->isDocumentTypeNode()) { | 1301 if (n->isDocumentTypeNode()) { |
1468 exceptionState.throwDOMException(HierarchyRequestError, "The Range c ontains a doctype node."); | 1302 exceptionState.throwDOMException(HierarchyRequestError, "The Range c ontains a doctype node."); |
1469 return; | 1303 return; |
1470 } | 1304 } |
1471 } | 1305 } |
1472 } | 1306 } |
1473 | 1307 |
1474 Node* Range::firstNode() const | 1308 Node* Range::firstNode() const |
1475 { | 1309 { |
1476 if (!m_start.container()) | |
1477 return 0; | |
1478 if (m_start.container()->offsetInCharacters()) | 1310 if (m_start.container()->offsetInCharacters()) |
1479 return m_start.container(); | 1311 return m_start.container(); |
1480 if (Node* child = m_start.container()->traverseToChildAt(m_start.offset())) | 1312 if (Node* child = m_start.container()->traverseToChildAt(m_start.offset())) |
1481 return child; | 1313 return child; |
1482 if (!m_start.offset()) | 1314 if (!m_start.offset()) |
1483 return m_start.container(); | 1315 return m_start.container(); |
1484 return NodeTraversal::nextSkippingChildren(*m_start.container()); | 1316 return NodeTraversal::nextSkippingChildren(*m_start.container()); |
1485 } | 1317 } |
1486 | 1318 |
1487 ShadowRoot* Range::shadowRoot() const | 1319 ShadowRoot* Range::shadowRoot() const |
1488 { | 1320 { |
1489 return startContainer() ? startContainer()->containingShadowRoot() : 0; | 1321 return startContainer() ? startContainer()->containingShadowRoot() : 0; |
1490 } | 1322 } |
1491 | 1323 |
1492 Node* Range::pastLastNode() const | 1324 Node* Range::pastLastNode() const |
1493 { | 1325 { |
1494 if (!m_start.container() || !m_end.container()) | |
1495 return 0; | |
1496 if (m_end.container()->offsetInCharacters()) | 1326 if (m_end.container()->offsetInCharacters()) |
1497 return NodeTraversal::nextSkippingChildren(*m_end.container()); | 1327 return NodeTraversal::nextSkippingChildren(*m_end.container()); |
1498 if (Node* child = m_end.container()->traverseToChildAt(m_end.offset())) | 1328 if (Node* child = m_end.container()->traverseToChildAt(m_end.offset())) |
1499 return child; | 1329 return child; |
1500 return NodeTraversal::nextSkippingChildren(*m_end.container()); | 1330 return NodeTraversal::nextSkippingChildren(*m_end.container()); |
1501 } | 1331 } |
1502 | 1332 |
1503 IntRect Range::boundingBox() const | 1333 IntRect Range::boundingBox() const |
1504 { | 1334 { |
1505 IntRect result; | 1335 IntRect result; |
1506 Vector<IntRect> rects; | 1336 Vector<IntRect> rects; |
1507 textRects(rects); | 1337 textRects(rects); |
1508 const size_t n = rects.size(); | 1338 const size_t n = rects.size(); |
1509 for (size_t i = 0; i < n; ++i) | 1339 for (size_t i = 0; i < n; ++i) |
1510 result.unite(rects[i]); | 1340 result.unite(rects[i]); |
1511 return result; | 1341 return result; |
1512 } | 1342 } |
1513 | 1343 |
1514 void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight, RangeInFi xedPosition* inFixed) const | 1344 void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight, RangeInFi xedPosition* inFixed) const |
1515 { | 1345 { |
1516 Node* startContainer = m_start.container(); | 1346 Node* startContainer = m_start.container(); |
1347 ASSERT(startContainer); | |
1517 Node* endContainer = m_end.container(); | 1348 Node* endContainer = m_end.container(); |
1518 | 1349 ASSERT(endContainer); |
1519 if (!startContainer || !endContainer) { | |
1520 if (inFixed) | |
1521 *inFixed = NotFixedPosition; | |
1522 return; | |
1523 } | |
1524 | 1350 |
1525 bool allFixed = true; | 1351 bool allFixed = true; |
1526 bool someFixed = false; | 1352 bool someFixed = false; |
1527 | 1353 |
1528 Node* stopNode = pastLastNode(); | 1354 Node* stopNode = pastLastNode(); |
1529 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next( *node)) { | 1355 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next( *node)) { |
1530 RenderObject* r = node->renderer(); | 1356 RenderObject* r = node->renderer(); |
1531 if (!r || !r->isText()) | 1357 if (!r || !r->isText()) |
1532 continue; | 1358 continue; |
1533 RenderText* renderText = toRenderText(r); | 1359 RenderText* renderText = toRenderText(r); |
1534 int startOffset = node == startContainer ? m_start.offset() : 0; | 1360 int startOffset = node == startContainer ? m_start.offset() : 0; |
1535 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<i nt>::max(); | 1361 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<i nt>::max(); |
1536 bool isFixed = false; | 1362 bool isFixed = false; |
1537 renderText->absoluteRectsForRange(rects, startOffset, endOffset, useSele ctionHeight, &isFixed); | 1363 renderText->absoluteRectsForRange(rects, startOffset, endOffset, useSele ctionHeight, &isFixed); |
1538 allFixed &= isFixed; | 1364 allFixed &= isFixed; |
1539 someFixed |= isFixed; | 1365 someFixed |= isFixed; |
1540 } | 1366 } |
1541 | 1367 |
1542 if (inFixed) | 1368 if (inFixed) |
1543 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixe dPosition : NotFixedPosition); | 1369 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixe dPosition : NotFixedPosition); |
1544 } | 1370 } |
1545 | 1371 |
1546 void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight, RangeIn FixedPosition* inFixed) const | 1372 void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight, RangeIn FixedPosition* inFixed) const |
1547 { | 1373 { |
1548 Node* startContainer = m_start.container(); | 1374 Node* startContainer = m_start.container(); |
1375 ASSERT(startContainer); | |
1549 Node* endContainer = m_end.container(); | 1376 Node* endContainer = m_end.container(); |
1550 | 1377 ASSERT(endContainer); |
1551 if (!startContainer || !endContainer) { | |
1552 if (inFixed) | |
1553 *inFixed = NotFixedPosition; | |
1554 return; | |
1555 } | |
1556 | 1378 |
1557 bool allFixed = true; | 1379 bool allFixed = true; |
1558 bool someFixed = false; | 1380 bool someFixed = false; |
1559 | 1381 |
1560 Node* stopNode = pastLastNode(); | 1382 Node* stopNode = pastLastNode(); |
1561 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next( *node)) { | 1383 for (Node* node = firstNode(); node != stopNode; node = NodeTraversal::next( *node)) { |
1562 RenderObject* r = node->renderer(); | 1384 RenderObject* r = node->renderer(); |
1563 if (!r || !r->isText()) | 1385 if (!r || !r->isText()) |
1564 continue; | 1386 continue; |
1565 RenderText* renderText = toRenderText(r); | 1387 RenderText* renderText = toRenderText(r); |
1566 int startOffset = node == startContainer ? m_start.offset() : 0; | 1388 int startOffset = node == startContainer ? m_start.offset() : 0; |
1567 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<i nt>::max(); | 1389 int endOffset = node == endContainer ? m_end.offset() : numeric_limits<i nt>::max(); |
1568 bool isFixed = false; | 1390 bool isFixed = false; |
1569 renderText->absoluteQuadsForRange(quads, startOffset, endOffset, useSele ctionHeight, &isFixed); | 1391 renderText->absoluteQuadsForRange(quads, startOffset, endOffset, useSele ctionHeight, &isFixed); |
1570 allFixed &= isFixed; | 1392 allFixed &= isFixed; |
1571 someFixed |= isFixed; | 1393 someFixed |= isFixed; |
1572 } | 1394 } |
1573 | 1395 |
1574 if (inFixed) | 1396 if (inFixed) |
1575 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixe dPosition : NotFixedPosition); | 1397 *inFixed = allFixed ? EntirelyFixedPosition : (someFixed ? PartiallyFixe dPosition : NotFixedPosition); |
1576 } | 1398 } |
1577 | 1399 |
1578 #ifndef NDEBUG | 1400 #ifndef NDEBUG |
1579 void Range::formatForDebugger(char* buffer, unsigned length) const | 1401 void Range::formatForDebugger(char* buffer, unsigned length) const |
1580 { | 1402 { |
1581 StringBuilder result; | 1403 StringBuilder result; |
1582 String s; | |
1583 | 1404 |
1584 if (!m_start.container() || !m_end.container()) | 1405 const int FormatBufferSize = 1024; |
1585 result.appendLiteral("<empty>"); | 1406 char s[FormatBufferSize]; |
1586 else { | 1407 result.appendLiteral("from offset "); |
1587 const int FormatBufferSize = 1024; | 1408 result.appendNumber(m_start.offset()); |
1588 char s[FormatBufferSize]; | 1409 result.appendLiteral(" of "); |
1589 result.appendLiteral("from offset "); | 1410 m_start.container()->formatForDebugger(s, FormatBufferSize); |
1590 result.appendNumber(m_start.offset()); | 1411 result.append(s); |
1591 result.appendLiteral(" of "); | 1412 result.appendLiteral(" to offset "); |
1592 m_start.container()->formatForDebugger(s, FormatBufferSize); | 1413 result.appendNumber(m_end.offset()); |
1593 result.append(s); | 1414 result.appendLiteral(" of "); |
1594 result.appendLiteral(" to offset "); | 1415 m_end.container()->formatForDebugger(s, FormatBufferSize); |
1595 result.appendNumber(m_end.offset()); | 1416 result.append(s); |
1596 result.appendLiteral(" of "); | |
1597 m_end.container()->formatForDebugger(s, FormatBufferSize); | |
1598 result.append(s); | |
1599 } | |
1600 | 1417 |
1601 strncpy(buffer, result.toString().utf8().data(), length - 1); | 1418 strncpy(buffer, result.toString().utf8().data(), length - 1); |
1602 } | 1419 } |
1603 #endif | 1420 #endif |
1604 | 1421 |
1605 bool areRangesEqual(const Range* a, const Range* b) | 1422 bool areRangesEqual(const Range* a, const Range* b) |
1606 { | 1423 { |
1607 if (a == b) | 1424 if (a == b) |
1608 return true; | 1425 return true; |
1609 if (!a || !b) | 1426 if (!a || !b) |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1785 start = startOfDocument(start); | 1602 start = startOfDocument(start); |
1786 end = endOfDocument(end); | 1603 end = endOfDocument(end); |
1787 } else | 1604 } else |
1788 return; | 1605 return; |
1789 setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().comp uteOffsetInContainerNode(), exceptionState); | 1606 setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().comp uteOffsetInContainerNode(), exceptionState); |
1790 setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOff setInContainerNode(), exceptionState); | 1607 setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOff setInContainerNode(), exceptionState); |
1791 } | 1608 } |
1792 | 1609 |
1793 PassRefPtrWillBeRawPtr<ClientRectList> Range::getClientRects() const | 1610 PassRefPtrWillBeRawPtr<ClientRectList> Range::getClientRects() const |
1794 { | 1611 { |
1795 if (!m_start.container()) | |
1796 return ClientRectList::create(); | |
1797 | |
1798 m_ownerDocument->updateLayoutIgnorePendingStylesheets(); | 1612 m_ownerDocument->updateLayoutIgnorePendingStylesheets(); |
1799 | 1613 |
1800 Vector<FloatQuad> quads; | 1614 Vector<FloatQuad> quads; |
1801 getBorderAndTextQuads(quads); | 1615 getBorderAndTextQuads(quads); |
1802 | 1616 |
1803 return ClientRectList::create(quads); | 1617 return ClientRectList::create(quads); |
1804 } | 1618 } |
1805 | 1619 |
1806 PassRefPtrWillBeRawPtr<ClientRect> Range::getBoundingClientRect() const | 1620 PassRefPtrWillBeRawPtr<ClientRect> Range::getBoundingClientRect() const |
1807 { | 1621 { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1842 m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoom(textQu ads, renderText); | 1656 m_ownerDocument->adjustFloatQuadsForScrollAndAbsoluteZoom(textQu ads, renderText); |
1843 | 1657 |
1844 quads.appendVector(textQuads); | 1658 quads.appendVector(textQuads); |
1845 } | 1659 } |
1846 } | 1660 } |
1847 } | 1661 } |
1848 } | 1662 } |
1849 | 1663 |
1850 FloatRect Range::boundingRect() const | 1664 FloatRect Range::boundingRect() const |
1851 { | 1665 { |
1852 if (!m_start.container()) | |
1853 return FloatRect(); | |
1854 | |
1855 m_ownerDocument->updateLayoutIgnorePendingStylesheets(); | 1666 m_ownerDocument->updateLayoutIgnorePendingStylesheets(); |
1856 | 1667 |
1857 Vector<FloatQuad> quads; | 1668 Vector<FloatQuad> quads; |
1858 getBorderAndTextQuads(quads); | 1669 getBorderAndTextQuads(quads); |
1859 if (quads.isEmpty()) | 1670 if (quads.isEmpty()) |
1860 return FloatRect(); | 1671 return FloatRect(); |
1861 | 1672 |
1862 FloatRect result; | 1673 FloatRect result; |
1863 for (size_t i = 0; i < quads.size(); ++i) | 1674 for (size_t i = 0; i < quads.size(); ++i) |
1864 result.unite(quads[i].boundingBox()); | 1675 result.unite(quads[i].boundingBox()); |
(...skipping 11 matching lines...) Expand all Loading... | |
1876 | 1687 |
1877 void showTree(const WebCore::Range* range) | 1688 void showTree(const WebCore::Range* range) |
1878 { | 1689 { |
1879 if (range && range->boundaryPointsValid()) { | 1690 if (range && range->boundaryPointsValid()) { |
1880 range->startContainer()->showTreeAndMark(range->startContainer(), "S", r ange->endContainer(), "E"); | 1691 range->startContainer()->showTreeAndMark(range->startContainer(), "S", r ange->endContainer(), "E"); |
1881 fprintf(stderr, "start offset: %d, end offset: %d\n", range->startOffset (), range->endOffset()); | 1692 fprintf(stderr, "start offset: %d, end offset: %d\n", range->startOffset (), range->endOffset()); |
1882 } | 1693 } |
1883 } | 1694 } |
1884 | 1695 |
1885 #endif | 1696 #endif |
OLD | NEW |