| 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 |