| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * | 8 * |
| 9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 #include "core/dom/Node.h" | 36 #include "core/dom/Node.h" |
| 37 #include "core/dom/Range.h" | 37 #include "core/dom/Range.h" |
| 38 #include "core/dom/TreeScope.h" | 38 #include "core/dom/TreeScope.h" |
| 39 #include "core/editing/EditingUtilities.h" | 39 #include "core/editing/EditingUtilities.h" |
| 40 #include "core/editing/FrameSelection.h" | 40 #include "core/editing/FrameSelection.h" |
| 41 #include "core/editing/iterators/TextIterator.h" | 41 #include "core/editing/iterators/TextIterator.h" |
| 42 #include "core/frame/Deprecation.h" | 42 #include "core/frame/Deprecation.h" |
| 43 #include "core/frame/LocalFrame.h" | 43 #include "core/frame/LocalFrame.h" |
| 44 #include "core/frame/UseCounter.h" | 44 #include "core/frame/UseCounter.h" |
| 45 #include "core/inspector/ConsoleMessage.h" | 45 #include "core/inspector/ConsoleMessage.h" |
| 46 #include "platform/EventDispatchForbiddenScope.h" |
| 46 #include "wtf/text/WTFString.h" | 47 #include "wtf/text/WTFString.h" |
| 47 | 48 |
| 48 namespace blink { | 49 namespace blink { |
| 49 | 50 |
| 51 const FrameSelection::SetSelectionOptions kSetSelectionOptions = |
| 52 FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | |
| 53 FrameSelection::DoNotSetFocus; |
| 54 |
| 50 static Node* selectionShadowAncestor(LocalFrame* frame) { | 55 static Node* selectionShadowAncestor(LocalFrame* frame) { |
| 51 Node* node = frame->selection() | 56 Node* node = frame->selection() |
| 52 .computeVisibleSelectionInDOMTreeDeprecated() | 57 .computeVisibleSelectionInDOMTreeDeprecated() |
| 53 .base() | 58 .base() |
| 54 .anchorNode(); | 59 .anchorNode(); |
| 55 if (!node) | 60 if (!node) |
| 56 return 0; | 61 return 0; |
| 57 | 62 |
| 58 if (!node->isInShadowTree()) | 63 if (!node->isInShadowTree()) |
| 59 return 0; | 64 return 0; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 | 249 |
| 245 // 5. Set ([DOM4]) the start and the end of newRange to (node, offset). | 250 // 5. Set ([DOM4]) the start and the end of newRange to (node, offset). |
| 246 newRange->setStart(node, offset, exceptionState); | 251 newRange->setStart(node, offset, exceptionState); |
| 247 if (exceptionState.hadException()) | 252 if (exceptionState.hadException()) |
| 248 return; | 253 return; |
| 249 newRange->setEnd(node, offset, exceptionState); | 254 newRange->setEnd(node, offset, exceptionState); |
| 250 if (exceptionState.hadException()) | 255 if (exceptionState.hadException()) |
| 251 return; | 256 return; |
| 252 | 257 |
| 253 // 6. Set the context object's range to newRange. | 258 // 6. Set the context object's range to newRange. |
| 259 EventDispatchForbiddenScope noEvents; |
| 254 frame()->selection().setSelection( | 260 frame()->selection().setSelection( |
| 255 SelectionInDOMTree::Builder() | 261 SelectionInDOMTree::Builder() |
| 256 .collapse(Position(node, offset)) | 262 .collapse(Position(node, offset)) |
| 257 .setIsDirectional(frame()->selection().isDirectional()) | 263 .setIsDirectional(frame()->selection().isDirectional()) |
| 258 .build()); | 264 .build(), |
| 265 kSetSelectionOptions); |
| 259 cacheRangeIfSelectionOfDocument(newRange); | 266 cacheRangeIfSelectionOfDocument(newRange); |
| 260 } | 267 } |
| 261 | 268 |
| 262 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetoend | 269 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetoend |
| 263 void DOMSelection::collapseToEnd(ExceptionState& exceptionState) { | 270 void DOMSelection::collapseToEnd(ExceptionState& exceptionState) { |
| 264 if (!isAvailable()) | 271 if (!isAvailable()) |
| 265 return; | 272 return; |
| 266 | 273 |
| 267 // The method must throw InvalidStateError exception if the context object is | 274 // The method must throw InvalidStateError exception if the context object is |
| 268 // empty. | 275 // empty. |
| 269 if (rangeCount() == 0) { | 276 if (rangeCount() == 0) { |
| 270 exceptionState.throwDOMException(InvalidStateError, | 277 exceptionState.throwDOMException(InvalidStateError, |
| 271 "there is no selection."); | 278 "there is no selection."); |
| 272 return; | 279 return; |
| 273 } | 280 } |
| 274 | 281 |
| 275 // Otherwise, it must create a new range, set both its start and end to the | 282 // Otherwise, it must create a new range, set both its start and end to the |
| 276 // end of the context object's range, | 283 // end of the context object's range, |
| 284 EventDispatchForbiddenScope noEvents; |
| 277 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange(); | 285 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange(); |
| 278 newRange->collapse(false); | 286 newRange->collapse(false); |
| 279 | 287 |
| 280 // and then set the context object's range to the newly-created range. | 288 // and then set the context object's range to the newly-created range. |
| 281 SelectionInDOMTree::Builder builder; | 289 SelectionInDOMTree::Builder builder; |
| 282 builder.collapse(newRange->endPosition()); | 290 builder.collapse(newRange->endPosition()); |
| 283 frame()->selection().setSelection(builder.build()); | 291 frame()->selection().setSelection(builder.build(), kSetSelectionOptions); |
| 284 cacheRangeIfSelectionOfDocument(newRange); | 292 cacheRangeIfSelectionOfDocument(newRange); |
| 285 } | 293 } |
| 286 | 294 |
| 287 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetostart | 295 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetostart |
| 288 void DOMSelection::collapseToStart(ExceptionState& exceptionState) { | 296 void DOMSelection::collapseToStart(ExceptionState& exceptionState) { |
| 289 if (!isAvailable()) | 297 if (!isAvailable()) |
| 290 return; | 298 return; |
| 291 | 299 |
| 292 // The method must throw InvalidStateError ([DOM4]) exception if the context | 300 // The method must throw InvalidStateError ([DOM4]) exception if the context |
| 293 // object is empty. | 301 // object is empty. |
| 294 if (rangeCount() == 0) { | 302 if (rangeCount() == 0) { |
| 295 exceptionState.throwDOMException(InvalidStateError, | 303 exceptionState.throwDOMException(InvalidStateError, |
| 296 "there is no selection."); | 304 "there is no selection."); |
| 297 return; | 305 return; |
| 298 } | 306 } |
| 299 | 307 |
| 300 // Otherwise, it must create a new range, set both its start and end to the | 308 // Otherwise, it must create a new range, set both its start and end to the |
| 301 // start of the context object's range, | 309 // start of the context object's range, |
| 310 EventDispatchForbiddenScope noEvents; |
| 302 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange(); | 311 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange(); |
| 303 newRange->collapse(true); | 312 newRange->collapse(true); |
| 304 | 313 |
| 305 // and then set the context object's range to the newly-created range. | 314 // and then set the context object's range to the newly-created range. |
| 306 SelectionInDOMTree::Builder builder; | 315 SelectionInDOMTree::Builder builder; |
| 307 builder.collapse(newRange->startPosition()); | 316 builder.collapse(newRange->startPosition()); |
| 308 frame()->selection().setSelection(builder.build()); | 317 frame()->selection().setSelection(builder.build(), kSetSelectionOptions); |
| 309 cacheRangeIfSelectionOfDocument(newRange); | 318 cacheRangeIfSelectionOfDocument(newRange); |
| 310 } | 319 } |
| 311 | 320 |
| 312 void DOMSelection::empty() { | 321 void DOMSelection::empty() { |
| 313 if (!isAvailable()) | 322 if (!isAvailable()) |
| 314 return; | 323 return; |
| 315 frame()->selection().clear(); | 324 frame()->selection().clear(); |
| 316 } | 325 } |
| 317 | 326 |
| 318 void DOMSelection::setBaseAndExtent(Node* baseNode, | 327 void DOMSelection::setBaseAndExtent(Node* baseNode, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 348 return; | 357 return; |
| 349 | 358 |
| 350 clearCachedRangeIfSelectionOfDocument(); | 359 clearCachedRangeIfSelectionOfDocument(); |
| 351 | 360 |
| 352 // TODO(editing-dev): Once SVG USE element doesn't modify DOM tree, we | 361 // TODO(editing-dev): Once SVG USE element doesn't modify DOM tree, we |
| 353 // should get rid of this update layout call. | 362 // should get rid of this update layout call. |
| 354 // See http://crbug.com/566281 | 363 // See http://crbug.com/566281 |
| 355 // See "svg/text/textpath-reference-crash.html" | 364 // See "svg/text/textpath-reference-crash.html" |
| 356 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 365 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 357 | 366 |
| 367 EventDispatchForbiddenScope noEvents; |
| 358 Position basePosition(baseNode, baseOffset); | 368 Position basePosition(baseNode, baseOffset); |
| 359 Position extentPosition(extentNode, extentOffset); | 369 Position extentPosition(extentNode, extentOffset); |
| 360 frame()->selection().setSelection( | 370 frame()->selection().setSelection( |
| 361 SelectionInDOMTree::Builder() | 371 SelectionInDOMTree::Builder() |
| 362 .setBaseAndExtentDeprecated(basePosition, extentPosition) | 372 .setBaseAndExtentDeprecated(basePosition, extentPosition) |
| 363 .setIsDirectional(true) | 373 .setIsDirectional(true) |
| 364 .build()); | 374 .build(), |
| 375 kSetSelectionOptions); |
| 365 | 376 |
| 366 Range* newRange = Range::create(baseNode->document()); | 377 Range* newRange = Range::create(baseNode->document()); |
| 367 if (extentPosition.isNull()) { | 378 if (extentPosition.isNull()) { |
| 368 newRange->setStart(baseNode, baseOffset); | 379 newRange->setStart(baseNode, baseOffset); |
| 369 newRange->setEnd(baseNode, baseOffset); | 380 newRange->setEnd(baseNode, baseOffset); |
| 370 } else if (basePosition < extentPosition) { | 381 } else if (basePosition < extentPosition) { |
| 371 newRange->setStart(baseNode, baseOffset); | 382 newRange->setStart(baseNode, baseOffset); |
| 372 newRange->setEnd(extentNode, extentOffset); | 383 newRange->setEnd(extentNode, extentOffset); |
| 373 } else { | 384 } else { |
| 374 newRange->setStart(extentNode, extentOffset); | 385 newRange->setStart(extentNode, extentOffset); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 granularity = LineBoundary; | 429 granularity = LineBoundary; |
| 419 else if (equalIgnoringCase(granularityString, "sentenceboundary")) | 430 else if (equalIgnoringCase(granularityString, "sentenceboundary")) |
| 420 granularity = SentenceBoundary; | 431 granularity = SentenceBoundary; |
| 421 else if (equalIgnoringCase(granularityString, "paragraphboundary")) | 432 else if (equalIgnoringCase(granularityString, "paragraphboundary")) |
| 422 granularity = ParagraphBoundary; | 433 granularity = ParagraphBoundary; |
| 423 else if (equalIgnoringCase(granularityString, "documentboundary")) | 434 else if (equalIgnoringCase(granularityString, "documentboundary")) |
| 424 granularity = DocumentBoundary; | 435 granularity = DocumentBoundary; |
| 425 else | 436 else |
| 426 return; | 437 return; |
| 427 | 438 |
| 428 frame()->selection().modify(alter, direction, granularity); | 439 EventDispatchForbiddenScope noEvents; |
| 440 frame()->selection().modify(alter, direction, granularity, |
| 441 EUserTriggered::NotUserTriggered, |
| 442 FrameSelection::DoNotSetFocus); |
| 429 } | 443 } |
| 430 | 444 |
| 431 // https://www.w3.org/TR/selection-api/#dom-selection-extend | 445 // https://www.w3.org/TR/selection-api/#dom-selection-extend |
| 432 void DOMSelection::extend(Node* node, | 446 void DOMSelection::extend(Node* node, |
| 433 unsigned offset, | 447 unsigned offset, |
| 434 ExceptionState& exceptionState) { | 448 ExceptionState& exceptionState) { |
| 435 DCHECK(node); | 449 DCHECK(node); |
| 436 if (!isAvailable()) | 450 if (!isAvailable()) |
| 437 return; | 451 return; |
| 438 | 452 |
| 439 // 1. If node's root is not the document associated with the context object, | 453 // 1. If node's root is not the document associated with the context object, |
| 440 // abort these steps. | 454 // abort these steps. |
| 441 if (!isValidForPosition(node)) | 455 if (!isValidForPosition(node)) |
| 442 return; | 456 return; |
| 443 | 457 |
| 444 // 2. If the context object is empty, throw an InvalidStateError exception and | 458 // 2. If the context object is empty, throw an InvalidStateError exception and |
| 445 // abort these steps. | 459 // abort these steps. |
| 446 if (rangeCount() == 0) { | 460 if (rangeCount() == 0) { |
| 447 exceptionState.throwDOMException( | 461 exceptionState.throwDOMException( |
| 448 InvalidStateError, "This Selection object doesn't have any Ranges."); | 462 InvalidStateError, "This Selection object doesn't have any Ranges."); |
| 449 return; | 463 return; |
| 450 } | 464 } |
| 451 | 465 |
| 452 Range::checkNodeWOffset(node, offset, exceptionState); | 466 Range::checkNodeWOffset(node, offset, exceptionState); |
| 453 if (exceptionState.hadException()) | 467 if (exceptionState.hadException()) |
| 454 return; | 468 return; |
| 455 | 469 |
| 470 EventDispatchForbiddenScope noEvents; |
| 456 // 3. Let oldAnchor and oldFocus be the context object's anchor and focus, and | 471 // 3. Let oldAnchor and oldFocus be the context object's anchor and focus, and |
| 457 // let newFocus be the boundary point (node, offset). | 472 // let newFocus be the boundary point (node, offset). |
| 458 const Position& oldAnchor = anchorPosition(); | 473 const Position& oldAnchor = anchorPosition(); |
| 459 // TODO(tkent): Diagnostic checks for crbug.com/693578. They should be | 474 // TODO(tkent): Diagnostic checks for crbug.com/693578. They should be |
| 460 // removed before M58 branch. | 475 // removed before M58 branch. |
| 461 if (oldAnchor.isNull()) { | 476 if (oldAnchor.isNull()) { |
| 462 if (Range* range = documentCachedRange()) { | 477 if (Range* range = documentCachedRange()) { |
| 463 LOG(FATAL) | 478 LOG(FATAL) |
| 464 << "Selection has a cached Range, but anchorPosition is null. start=" | 479 << "Selection has a cached Range, but anchorPosition is null. start=" |
| 465 << range->startContainer() << " end=" << range->endContainer(); | 480 << range->startContainer() << " end=" << range->endContainer(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 495 newRange->setStart(node, offset); | 510 newRange->setStart(node, offset); |
| 496 newRange->setEnd(oldAnchor.anchorNode(), oldAnchor.offsetInContainerNode()); | 511 newRange->setEnd(oldAnchor.anchorNode(), oldAnchor.offsetInContainerNode()); |
| 497 } | 512 } |
| 498 | 513 |
| 499 // 8. Set the context object's range to newRange. | 514 // 8. Set the context object's range to newRange. |
| 500 SelectionInDOMTree::Builder builder; | 515 SelectionInDOMTree::Builder builder; |
| 501 if (newRange->collapsed()) | 516 if (newRange->collapsed()) |
| 502 builder.collapse(newFocus); | 517 builder.collapse(newFocus); |
| 503 else | 518 else |
| 504 builder.collapse(oldAnchor).extend(newFocus); | 519 builder.collapse(oldAnchor).extend(newFocus); |
| 505 frame()->selection().setSelection(builder.setIsDirectional(true).build()); | 520 frame()->selection().setSelection(builder.setIsDirectional(true).build(), |
| 521 kSetSelectionOptions); |
| 506 cacheRangeIfSelectionOfDocument(newRange); | 522 cacheRangeIfSelectionOfDocument(newRange); |
| 507 } | 523 } |
| 508 | 524 |
| 509 Range* DOMSelection::getRangeAt(unsigned index, | 525 Range* DOMSelection::getRangeAt(unsigned index, |
| 510 ExceptionState& exceptionState) const { | 526 ExceptionState& exceptionState) const { |
| 511 if (!isAvailable()) | 527 if (!isAvailable()) |
| 512 return nullptr; | 528 return nullptr; |
| 513 | 529 |
| 514 if (index >= rangeCount()) { | 530 if (index >= rangeCount()) { |
| 515 exceptionState.throwDOMException( | 531 exceptionState.throwDOMException( |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 } | 611 } |
| 596 | 612 |
| 597 FrameSelection& selection = frame()->selection(); | 613 FrameSelection& selection = frame()->selection(); |
| 598 | 614 |
| 599 if (newRange->ownerDocument() != selection.document()) { | 615 if (newRange->ownerDocument() != selection.document()) { |
| 600 // "editing/selection/selection-in-iframe-removed-crash.html" goes here. | 616 // "editing/selection/selection-in-iframe-removed-crash.html" goes here. |
| 601 return; | 617 return; |
| 602 } | 618 } |
| 603 | 619 |
| 604 if (rangeCount() == 0) { | 620 if (rangeCount() == 0) { |
| 605 selection.setSelectedRange(EphemeralRange(newRange), VP_DEFAULT_AFFINITY); | 621 EventDispatchForbiddenScope noEvents; |
| 622 selection.setSelectedRange(EphemeralRange(newRange), VP_DEFAULT_AFFINITY, |
| 623 SelectionDirectionalMode::NonDirectional, |
| 624 kSetSelectionOptions); |
| 606 cacheRangeIfSelectionOfDocument(newRange); | 625 cacheRangeIfSelectionOfDocument(newRange); |
| 607 return; | 626 return; |
| 608 } | 627 } |
| 609 | 628 |
| 610 Range* originalRange = primaryRangeOrNull(); | 629 Range* originalRange = primaryRangeOrNull(); |
| 611 DCHECK(originalRange); | 630 DCHECK(originalRange); |
| 612 | 631 |
| 613 if (originalRange->startContainer()->treeScope() != | 632 if (originalRange->startContainer()->treeScope() != |
| 614 newRange->startContainer()->treeScope()) { | 633 newRange->startContainer()->treeScope()) { |
| 615 return; | 634 return; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 m_treeScope->document().addConsoleMessage( | 819 m_treeScope->document().addConsoleMessage( |
| 801 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message)); | 820 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message)); |
| 802 } | 821 } |
| 803 | 822 |
| 804 DEFINE_TRACE(DOMSelection) { | 823 DEFINE_TRACE(DOMSelection) { |
| 805 visitor->trace(m_treeScope); | 824 visitor->trace(m_treeScope); |
| 806 ContextClient::trace(visitor); | 825 ContextClient::trace(visitor); |
| 807 } | 826 } |
| 808 | 827 |
| 809 } // namespace blink | 828 } // namespace blink |
| OLD | NEW |