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