| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 SetSelectionOptions options, | 336 SetSelectionOptions options, |
| 337 CursorAlignOnScroll align, | 337 CursorAlignOnScroll align, |
| 338 TextGranularity granularity) { | 338 TextGranularity granularity) { |
| 339 setSelection( | 339 setSelection( |
| 340 SelectionInFlatTree::Builder(newSelection.asSelection()) | 340 SelectionInFlatTree::Builder(newSelection.asSelection()) |
| 341 .setIsHandleVisible(handleVisibility == HandleVisibility::Visible) | 341 .setIsHandleVisible(handleVisibility == HandleVisibility::Visible) |
| 342 .build(), | 342 .build(), |
| 343 options, align, granularity); | 343 options, align, granularity); |
| 344 } | 344 } |
| 345 | 345 |
| 346 // TODO(yosin): We should move |computePositionForChildrenRemoval()| to | |
| 347 // "SelectionEditor.cpp" since it used only in | |
| 348 // |SelectionEditor::nodeChildrenWillBeRemoved()|. | |
| 349 static Position computePositionForChildrenRemoval(const Position& position, | |
| 350 ContainerNode& container) { | |
| 351 Node* node = position.computeContainerNode(); | |
| 352 if (container.containsIncludingHostElements(*node)) | |
| 353 return Position::firstPositionInNode(&container); | |
| 354 return position; | |
| 355 } | |
| 356 | |
| 357 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) { | 346 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) { |
| 358 if (!container.inActiveDocument()) | 347 if (!container.inActiveDocument()) |
| 359 return; | 348 return; |
| 360 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to | 349 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
| 361 // |Editor| class. | 350 // |Editor| class. |
| 362 if (!document().isRunningExecCommand()) | 351 if (!document().isRunningExecCommand()) |
| 363 TypingCommand::closeTyping(m_frame); | 352 TypingCommand::closeTyping(m_frame); |
| 364 } | 353 } |
| 365 | 354 |
| 366 // TODO(yosin): We should move |SelectionEditor::nodeChildrenWillBeRemoved()| | |
| 367 // to "SelectionEditor.cpp". | |
| 368 void SelectionEditor::nodeChildrenWillBeRemoved(ContainerNode& container) { | |
| 369 if (m_selection.isNone()) | |
| 370 return; | |
| 371 const Position oldBase = m_selection.m_base; | |
| 372 const Position oldExtent = m_selection.m_extent; | |
| 373 const Position& newBase = | |
| 374 computePositionForChildrenRemoval(oldBase, container); | |
| 375 const Position& newExtent = | |
| 376 computePositionForChildrenRemoval(oldExtent, container); | |
| 377 if (newBase == oldBase && newExtent == oldExtent) | |
| 378 return; | |
| 379 m_selection = SelectionInDOMTree::Builder() | |
| 380 .setBaseAndExtent(newBase, newExtent) | |
| 381 .build(); | |
| 382 markCacheDirty(); | |
| 383 } | |
| 384 | |
| 385 // TODO(yosin): We should move |computePositionForChildrenRemoval()| with | |
| 386 // |nodeWillBeRemoved()| to "SelectionEditor.cpp". | |
| 387 static Position computePositionForNodeRemoval(const Position& position, | |
| 388 Node& nodeToBeRemoved) { | |
| 389 Position result = position; | |
| 390 // TODO(yosin): We should rename |updatePositionForNodeRemoval()| | |
| 391 // to |computePositionForNodeRemoval()| to avoid using output parameter. | |
| 392 updatePositionForNodeRemoval(result, nodeToBeRemoved); | |
| 393 return result; | |
| 394 } | |
| 395 | |
| 396 // TODO(yosin): We should move |nodeWillBeRemoved()| to | |
| 397 // "SelectionEditor.cpp". | |
| 398 void SelectionEditor::nodeWillBeRemoved(Node& nodeToBeRemoved) { | |
| 399 if (m_selection.isNone()) | |
| 400 return; | |
| 401 const Position oldBase = m_selection.m_base; | |
| 402 const Position oldExtent = m_selection.m_extent; | |
| 403 const Position& newBase = | |
| 404 computePositionForNodeRemoval(oldBase, nodeToBeRemoved); | |
| 405 const Position& newExtent = | |
| 406 computePositionForNodeRemoval(oldExtent, nodeToBeRemoved); | |
| 407 if (newBase == oldBase && newExtent == oldExtent) | |
| 408 return; | |
| 409 m_selection = SelectionInDOMTree::Builder() | |
| 410 .setBaseAndExtent(newBase, newExtent) | |
| 411 .build(); | |
| 412 markCacheDirty(); | |
| 413 } | |
| 414 | |
| 415 void FrameSelection::nodeWillBeRemoved(Node& node) { | 355 void FrameSelection::nodeWillBeRemoved(Node& node) { |
| 416 // There can't be a selection inside a fragment, so if a fragment's node is | 356 // There can't be a selection inside a fragment, so if a fragment's node is |
| 417 // being removed, the selection in the document that created the fragment | 357 // being removed, the selection in the document that created the fragment |
| 418 // needs no adjustment. | 358 // needs no adjustment. |
| 419 if (!node.inActiveDocument()) | 359 if (!node.inActiveDocument()) |
| 420 return; | 360 return; |
| 421 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to | 361 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
| 422 // |Editor| class. | 362 // |Editor| class. |
| 423 if (!document().isRunningExecCommand()) | 363 if (!document().isRunningExecCommand()) |
| 424 TypingCommand::closeTyping(m_frame); | 364 TypingCommand::closeTyping(m_frame); |
| 425 } | 365 } |
| 426 | 366 |
| 427 // TODO(yosin): We should move |updatePositionAfterAdoptingTextReplacement()| | |
| 428 // to "SelectionEditor.cpp" since it used only in | |
| 429 // |SelectionEditor::didUpdateCharacterData()|. | |
| 430 static Position updatePositionAfterAdoptingTextReplacement( | |
| 431 const Position& position, | |
| 432 CharacterData* node, | |
| 433 unsigned offset, | |
| 434 unsigned oldLength, | |
| 435 unsigned newLength) { | |
| 436 if (position.anchorNode() != node) | |
| 437 return position; | |
| 438 | |
| 439 if (position.isBeforeAnchor()) { | |
| 440 return updatePositionAfterAdoptingTextReplacement( | |
| 441 Position(node, 0), node, offset, oldLength, newLength); | |
| 442 } | |
| 443 if (position.isAfterAnchor()) { | |
| 444 return updatePositionAfterAdoptingTextReplacement( | |
| 445 Position(node, oldLength), node, offset, oldLength, newLength); | |
| 446 } | |
| 447 | |
| 448 // See: | |
| 449 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation | |
| 450 DCHECK_GE(position.offsetInContainerNode(), 0); | |
| 451 unsigned positionOffset = | |
| 452 static_cast<unsigned>(position.offsetInContainerNode()); | |
| 453 // Replacing text can be viewed as a deletion followed by insertion. | |
| 454 if (positionOffset >= offset && positionOffset <= offset + oldLength) | |
| 455 positionOffset = offset; | |
| 456 | |
| 457 // Adjust the offset if the position is after the end of the deleted contents | |
| 458 // (positionOffset > offset + oldLength) to avoid having a stale offset. | |
| 459 if (positionOffset > offset + oldLength) | |
| 460 positionOffset = positionOffset - oldLength + newLength; | |
| 461 | |
| 462 // Due to case folding | |
| 463 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText | |
| 464 // length may be different from Text length. A correct implementation would | |
| 465 // translate the LayoutText offset to a Text offset; this is just a safety | |
| 466 // precaution to avoid offset values that run off the end of the Text. | |
| 467 if (positionOffset > node->length()) | |
| 468 positionOffset = node->length(); | |
| 469 | |
| 470 return Position(node, positionOffset); | |
| 471 } | |
| 472 | |
| 473 // TODO(yosin): We should move |didUpdateCharacterData()| to | |
| 474 // "SelectionEditor.cpp". | |
| 475 void SelectionEditor::didUpdateCharacterData(CharacterData* node, | |
| 476 unsigned offset, | |
| 477 unsigned oldLength, | |
| 478 unsigned newLength) { | |
| 479 // The fragment check is a performance optimization. See | |
| 480 // http://trac.webkit.org/changeset/30062. | |
| 481 if (m_selection.isNone() || !node || !node->isConnected()) { | |
| 482 didFinishDOMMutation(); | |
| 483 return; | |
| 484 } | |
| 485 const Position& newBase = updatePositionAfterAdoptingTextReplacement( | |
| 486 m_selection.m_base, node, offset, oldLength, newLength); | |
| 487 const Position& newExtent = updatePositionAfterAdoptingTextReplacement( | |
| 488 m_selection.m_extent, node, offset, oldLength, newLength); | |
| 489 didFinishTextChange(newBase, newExtent); | |
| 490 } | |
| 491 | |
| 492 // TODO(yosin): We should move |updatePostionAfterAdoptingTextNodesMerged()| | |
| 493 // to "SelectionEditor.cpp" since it used only in | |
| 494 // |SelectionEditor::didMergeTextNodes()|. | |
| 495 // TODO(yosin): We should introduce |Position(const Text&, int)| to avoid | |
| 496 // |const_cast<Text*>|. | |
| 497 static Position updatePostionAfterAdoptingTextNodesMerged( | |
| 498 const Position& position, | |
| 499 const Text& mergedNode, | |
| 500 const NodeWithIndex& nodeToBeRemovedWithIndex, | |
| 501 unsigned oldLength) { | |
| 502 Node* const anchorNode = position.anchorNode(); | |
| 503 const Node& nodeToBeRemoved = nodeToBeRemovedWithIndex.node(); | |
| 504 switch (position.anchorType()) { | |
| 505 case PositionAnchorType::BeforeChildren: | |
| 506 case PositionAnchorType::AfterChildren: | |
| 507 return position; | |
| 508 case PositionAnchorType::BeforeAnchor: | |
| 509 if (anchorNode == nodeToBeRemoved) | |
| 510 return Position(const_cast<Text*>(&mergedNode), mergedNode.length()); | |
| 511 return position; | |
| 512 case PositionAnchorType::AfterAnchor: | |
| 513 if (anchorNode == nodeToBeRemoved) | |
| 514 return Position(const_cast<Text*>(&mergedNode), mergedNode.length()); | |
| 515 if (anchorNode == mergedNode) | |
| 516 return Position(const_cast<Text*>(&mergedNode), oldLength); | |
| 517 return position; | |
| 518 case PositionAnchorType::OffsetInAnchor: { | |
| 519 const int offset = position.offsetInContainerNode(); | |
| 520 if (anchorNode == nodeToBeRemoved) | |
| 521 return Position(const_cast<Text*>(&mergedNode), oldLength + offset); | |
| 522 if (anchorNode == nodeToBeRemoved.parentNode() && | |
| 523 offset == nodeToBeRemovedWithIndex.index()) { | |
| 524 return Position(const_cast<Text*>(&mergedNode), oldLength); | |
| 525 } | |
| 526 return position; | |
| 527 } | |
| 528 } | |
| 529 NOTREACHED() << position; | |
| 530 return position; | |
| 531 } | |
| 532 | |
| 533 // TODO(yosin): We should move |SelectionEditor::didMergeTextNodes()| to | |
| 534 // "SelectionEditor.cpp". | |
| 535 void SelectionEditor::didMergeTextNodes( | |
| 536 const Text& mergedNode, | |
| 537 const NodeWithIndex& nodeToBeRemovedWithIndex, | |
| 538 unsigned oldLength) { | |
| 539 if (m_selection.isNone()) { | |
| 540 didFinishDOMMutation(); | |
| 541 return; | |
| 542 } | |
| 543 const Position& newBase = updatePostionAfterAdoptingTextNodesMerged( | |
| 544 m_selection.m_base, mergedNode, nodeToBeRemovedWithIndex, oldLength); | |
| 545 const Position& newExtent = updatePostionAfterAdoptingTextNodesMerged( | |
| 546 m_selection.m_extent, mergedNode, nodeToBeRemovedWithIndex, oldLength); | |
| 547 didFinishTextChange(newBase, newExtent); | |
| 548 } | |
| 549 | |
| 550 // TODO(yosin): We should move |updatePostionAfterAdoptingTextNodeSplit()| | |
| 551 // to "SelectionEditor.cpp" since it used only in | |
| 552 // |SelectionEditor::didSplitTextNode()|. | |
| 553 static Position updatePostionAfterAdoptingTextNodeSplit( | |
| 554 const Position& position, | |
| 555 const Text& oldNode) { | |
| 556 if (!position.anchorNode() || position.anchorNode() != &oldNode || | |
| 557 !position.isOffsetInAnchor()) | |
| 558 return position; | |
| 559 // See: | |
| 560 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation | |
| 561 DCHECK_GE(position.offsetInContainerNode(), 0); | |
| 562 unsigned positionOffset = | |
| 563 static_cast<unsigned>(position.offsetInContainerNode()); | |
| 564 unsigned oldLength = oldNode.length(); | |
| 565 if (positionOffset <= oldLength) | |
| 566 return position; | |
| 567 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength); | |
| 568 } | |
| 569 | |
| 570 // TODO(yosin): We should move |SelectionEditor::didSplitTextNode()| to | |
| 571 // "SelectionEditor.cpp". | |
| 572 void SelectionEditor::didSplitTextNode(const Text& oldNode) { | |
| 573 if (m_selection.isNone() || !oldNode.isConnected()) { | |
| 574 didFinishDOMMutation(); | |
| 575 return; | |
| 576 } | |
| 577 const Position& newBase = | |
| 578 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_base, oldNode); | |
| 579 const Position& newExtent = | |
| 580 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_extent, oldNode); | |
| 581 didFinishTextChange(newBase, newExtent); | |
| 582 } | |
| 583 | |
| 584 void FrameSelection::didChangeFocus() { | 367 void FrameSelection::didChangeFocus() { |
| 585 // Hits in | 368 // Hits in |
| 586 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable
d.html | 369 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable
d.html |
| 587 DisableCompositingQueryAsserts disabler; | 370 DisableCompositingQueryAsserts disabler; |
| 588 updateAppearance(); | 371 updateAppearance(); |
| 589 } | 372 } |
| 590 | 373 |
| 591 static DispatchEventResult dispatchSelectStart( | 374 static DispatchEventResult dispatchSelectStart( |
| 592 const VisibleSelection& selection) { | 375 const VisibleSelection& selection) { |
| 593 Node* selectStartTarget = selection.extent().computeContainerNode(); | 376 Node* selectStartTarget = selection.extent().computeContainerNode(); |
| (...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1404 } | 1187 } |
| 1405 | 1188 |
| 1406 void showTree(const blink::FrameSelection* sel) { | 1189 void showTree(const blink::FrameSelection* sel) { |
| 1407 if (sel) | 1190 if (sel) |
| 1408 sel->showTreeForThis(); | 1191 sel->showTreeForThis(); |
| 1409 else | 1192 else |
| 1410 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; | 1193 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; |
| 1411 } | 1194 } |
| 1412 | 1195 |
| 1413 #endif | 1196 #endif |
| OLD | NEW |