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