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 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 // "FocusIn", |m_frame| may associate to another document. | 322 // "FocusIn", |m_frame| may associate to another document. |
323 if (!isAvailable() || document() != currentDocument) { | 323 if (!isAvailable() || document() != currentDocument) { |
324 // Once we get test case to reach here, we should change this | 324 // Once we get test case to reach here, we should change this |
325 // if-statement to |DCHECK()|. | 325 // if-statement to |DCHECK()|. |
326 NOTREACHED(); | 326 NOTREACHED(); |
327 return; | 327 return; |
328 } | 328 } |
329 } | 329 } |
330 | 330 |
331 if (!(options & DoNotUpdateAppearance)) { | 331 if (!(options & DoNotUpdateAppearance)) { |
332 // Hits in compositing/overflow/do-not-paint-outline-into-composited-scrolli
ng-contents.html | 332 // Hits in |
| 333 // compositing/overflow/do-not-paint-outline-into-composited-scrolling-conte
nts.html |
333 DisableCompositingQueryAsserts disabler; | 334 DisableCompositingQueryAsserts disabler; |
334 m_frameCaret->stopCaretBlinkTimer(); | 335 m_frameCaret->stopCaretBlinkTimer(); |
335 updateAppearance(); | 336 updateAppearance(); |
336 } | 337 } |
337 | 338 |
338 // Always clear the x position used for vertical arrow navigation. | 339 // Always clear the x position used for vertical arrow navigation. |
339 // It will be restored by the vertical arrow navigation code if necessary. | 340 // It will be restored by the vertical arrow navigation code if necessary. |
340 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); | 341 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); |
341 // This may dispatch a synchronous focus-related events. | 342 // This may dispatch a synchronous focus-related events. |
342 selectFrameElementInParentIfFullySelected(); | 343 selectFrameElementInParentIfFullySelected(); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 m_selectionEditor->setWithoutValidation(newStart, newEnd); | 444 m_selectionEditor->setWithoutValidation(newStart, newEnd); |
444 else | 445 else |
445 m_selectionEditor->setWithoutValidation(newEnd, newStart); | 446 m_selectionEditor->setWithoutValidation(newEnd, newStart); |
446 m_frameCaret->setCaretRectNeedsUpdate(); | 447 m_frameCaret->setCaretRectNeedsUpdate(); |
447 if (document().isRunningExecCommand()) | 448 if (document().isRunningExecCommand()) |
448 return; | 449 return; |
449 TypingCommand::closeTyping(m_frame); | 450 TypingCommand::closeTyping(m_frame); |
450 } | 451 } |
451 | 452 |
452 void FrameSelection::nodeWillBeRemoved(Node& node) { | 453 void FrameSelection::nodeWillBeRemoved(Node& node) { |
453 // There can't be a selection inside a fragment, so if a fragment's node is be
ing removed, | 454 // There can't be a selection inside a fragment, so if a fragment's node is |
454 // the selection in the document that created the fragment needs no adjustment
. | 455 // being removed, the selection in the document that created the fragment |
| 456 // needs no adjustment. |
455 if (isNone() || !node.inActiveDocument()) | 457 if (isNone() || !node.inActiveDocument()) |
456 return; | 458 return; |
457 | 459 |
458 respondToNodeModification( | 460 respondToNodeModification( |
459 node, removingNodeRemovesPosition(node, selection().base()), | 461 node, removingNodeRemovesPosition(node, selection().base()), |
460 removingNodeRemovesPosition(node, selection().extent()), | 462 removingNodeRemovesPosition(node, selection().extent()), |
461 removingNodeRemovesPosition(node, selection().start()), | 463 removingNodeRemovesPosition(node, selection().start()), |
462 removingNodeRemovesPosition(node, selection().end())); | 464 removingNodeRemovesPosition(node, selection().end())); |
463 | 465 |
464 m_frameCaret->nodeWillBeRemoved(node); | 466 m_frameCaret->nodeWillBeRemoved(node); |
(...skipping 29 matching lines...) Expand all Loading... |
494 if (selection().isBaseFirst()) | 496 if (selection().isBaseFirst()) |
495 m_selectionEditor->setWithoutValidation(start, end); | 497 m_selectionEditor->setWithoutValidation(start, end); |
496 else | 498 else |
497 m_selectionEditor->setWithoutValidation(end, start); | 499 m_selectionEditor->setWithoutValidation(end, start); |
498 } else { | 500 } else { |
499 clearDOMTreeSelection = true; | 501 clearDOMTreeSelection = true; |
500 } | 502 } |
501 | 503 |
502 clearLayoutTreeSelection = true; | 504 clearLayoutTreeSelection = true; |
503 } else if (baseRemoved || extentRemoved) { | 505 } else if (baseRemoved || extentRemoved) { |
504 // The base and/or extent are about to be removed, but the start and end are
n't. | 506 // The base and/or extent are about to be removed, but the start and end |
505 // Change the base and extent to the start and end, but don't re-validate th
e | 507 // aren't. Change the base and extent to the start and end, but don't |
506 // selection, since doing so could move the start and end into the node | 508 // re-validate the selection, since doing so could move the start and end |
507 // that is about to be removed. | 509 // into the node that is about to be removed. |
508 if (selection().isBaseFirst()) | 510 if (selection().isBaseFirst()) |
509 m_selectionEditor->setWithoutValidation(selection().start(), | 511 m_selectionEditor->setWithoutValidation(selection().start(), |
510 selection().end()); | 512 selection().end()); |
511 else | 513 else |
512 m_selectionEditor->setWithoutValidation(selection().end(), | 514 m_selectionEditor->setWithoutValidation(selection().end(), |
513 selection().start()); | 515 selection().start()); |
514 } else if (selectionStateOf(node) != SelectionNone) { | 516 } else if (selectionStateOf(node) != SelectionNone) { |
515 // When node to be removed is part of selection, we invalidate | 517 // When node to be removed is part of selection, we invalidate |
516 // selection to paint again. | 518 // selection to paint again. |
517 // TODO(yosin): We should paint changed area only rather than whole | 519 // TODO(yosin): We should paint changed area only rather than whole |
(...skipping 17 matching lines...) Expand all Loading... |
535 static Position updatePositionAfterAdoptingTextReplacement( | 537 static Position updatePositionAfterAdoptingTextReplacement( |
536 const Position& position, | 538 const Position& position, |
537 CharacterData* node, | 539 CharacterData* node, |
538 unsigned offset, | 540 unsigned offset, |
539 unsigned oldLength, | 541 unsigned oldLength, |
540 unsigned newLength) { | 542 unsigned newLength) { |
541 if (!position.anchorNode() || position.anchorNode() != node || | 543 if (!position.anchorNode() || position.anchorNode() != node || |
542 !position.isOffsetInAnchor()) | 544 !position.isOffsetInAnchor()) |
543 return position; | 545 return position; |
544 | 546 |
545 // See: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-R
ange-Mutation | 547 // See: |
| 548 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation |
546 DCHECK_GE(position.offsetInContainerNode(), 0); | 549 DCHECK_GE(position.offsetInContainerNode(), 0); |
547 unsigned positionOffset = | 550 unsigned positionOffset = |
548 static_cast<unsigned>(position.offsetInContainerNode()); | 551 static_cast<unsigned>(position.offsetInContainerNode()); |
549 // Replacing text can be viewed as a deletion followed by insertion. | 552 // Replacing text can be viewed as a deletion followed by insertion. |
550 if (positionOffset >= offset && positionOffset <= offset + oldLength) | 553 if (positionOffset >= offset && positionOffset <= offset + oldLength) |
551 positionOffset = offset; | 554 positionOffset = offset; |
552 | 555 |
553 // Adjust the offset if the position is after the end of the deleted contents | 556 // Adjust the offset if the position is after the end of the deleted contents |
554 // (positionOffset > offset + oldLength) to avoid having a stale offset. | 557 // (positionOffset > offset + oldLength) to avoid having a stale offset. |
555 if (positionOffset > offset + oldLength) | 558 if (positionOffset > offset + oldLength) |
556 positionOffset = positionOffset - oldLength + newLength; | 559 positionOffset = positionOffset - oldLength + newLength; |
557 | 560 |
558 // Due to case folding (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.t
xt), | 561 // Due to case folding |
559 // LayoutText length may be different from Text length. A correct implementat
ion | 562 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText |
560 // would translate the LayoutText offset to a Text offset; this is just a safe
ty | 563 // length may be different from Text length. A correct implementation would |
| 564 // translate the LayoutText offset to a Text offset; this is just a safety |
561 // precaution to avoid offset values that run off the end of the Text. | 565 // precaution to avoid offset values that run off the end of the Text. |
562 if (positionOffset > node->length()) | 566 if (positionOffset > node->length()) |
563 positionOffset = node->length(); | 567 positionOffset = node->length(); |
564 | 568 |
565 // CharacterNode in VisibleSelection must be Text node, because Comment | 569 // CharacterNode in VisibleSelection must be Text node, because Comment |
566 // and ProcessingInstruction node aren't visible. | 570 // and ProcessingInstruction node aren't visible. |
567 return Position(toText(node), positionOffset); | 571 return Position(toText(node), positionOffset); |
568 } | 572 } |
569 | 573 |
570 void FrameSelection::didUpdateCharacterData(CharacterData* node, | 574 void FrameSelection::didUpdateCharacterData(CharacterData* node, |
571 unsigned offset, | 575 unsigned offset, |
572 unsigned oldLength, | 576 unsigned oldLength, |
573 unsigned newLength) { | 577 unsigned newLength) { |
574 // The fragment check is a performance optimization. See http://trac.webkit.or
g/changeset/30062. | 578 // The fragment check is a performance optimization. See |
| 579 // http://trac.webkit.org/changeset/30062. |
575 if (isNone() || !node || !node->isConnected()) | 580 if (isNone() || !node || !node->isConnected()) |
576 return; | 581 return; |
577 | 582 |
578 Position base = updatePositionAfterAdoptingTextReplacement( | 583 Position base = updatePositionAfterAdoptingTextReplacement( |
579 selection().base(), node, offset, oldLength, newLength); | 584 selection().base(), node, offset, oldLength, newLength); |
580 Position extent = updatePositionAfterAdoptingTextReplacement( | 585 Position extent = updatePositionAfterAdoptingTextReplacement( |
581 selection().extent(), node, offset, oldLength, newLength); | 586 selection().extent(), node, offset, oldLength, newLength); |
582 Position start = updatePositionAfterAdoptingTextReplacement( | 587 Position start = updatePositionAfterAdoptingTextReplacement( |
583 selection().start(), node, offset, oldLength, newLength); | 588 selection().start(), node, offset, oldLength, newLength); |
584 Position end = updatePositionAfterAdoptingTextReplacement( | 589 Position end = updatePositionAfterAdoptingTextReplacement( |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 oldNode, offset); | 624 oldNode, offset); |
620 updateSelectionIfNeeded(base, extent, start, end); | 625 updateSelectionIfNeeded(base, extent, start, end); |
621 } | 626 } |
622 | 627 |
623 static Position updatePostionAfterAdoptingTextNodeSplit( | 628 static Position updatePostionAfterAdoptingTextNodeSplit( |
624 const Position& position, | 629 const Position& position, |
625 const Text& oldNode) { | 630 const Text& oldNode) { |
626 if (!position.anchorNode() || position.anchorNode() != &oldNode || | 631 if (!position.anchorNode() || position.anchorNode() != &oldNode || |
627 !position.isOffsetInAnchor()) | 632 !position.isOffsetInAnchor()) |
628 return position; | 633 return position; |
629 // See: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-R
ange-Mutation | 634 // See: |
| 635 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation |
630 DCHECK_GE(position.offsetInContainerNode(), 0); | 636 DCHECK_GE(position.offsetInContainerNode(), 0); |
631 unsigned positionOffset = | 637 unsigned positionOffset = |
632 static_cast<unsigned>(position.offsetInContainerNode()); | 638 static_cast<unsigned>(position.offsetInContainerNode()); |
633 unsigned oldLength = oldNode.length(); | 639 unsigned oldLength = oldNode.length(); |
634 if (positionOffset <= oldLength) | 640 if (positionOffset <= oldLength) |
635 return position; | 641 return position; |
636 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength); | 642 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength); |
637 } | 643 } |
638 | 644 |
639 void FrameSelection::didSplitTextNode(const Text& oldNode) { | 645 void FrameSelection::didSplitTextNode(const Text& oldNode) { |
(...skipping 23 matching lines...) Expand all Loading... |
663 TypingCommand::closeTyping(m_frame); | 669 TypingCommand::closeTyping(m_frame); |
664 VisibleSelection newSelection; | 670 VisibleSelection newSelection; |
665 if (selection().isBaseFirst()) | 671 if (selection().isBaseFirst()) |
666 newSelection.setWithoutValidation(start, end); | 672 newSelection.setWithoutValidation(start, end); |
667 else | 673 else |
668 newSelection.setWithoutValidation(end, start); | 674 newSelection.setWithoutValidation(end, start); |
669 setSelection(newSelection, DoNotSetFocus); | 675 setSelection(newSelection, DoNotSetFocus); |
670 } | 676 } |
671 | 677 |
672 void FrameSelection::didChangeFocus() { | 678 void FrameSelection::didChangeFocus() { |
673 // Hits in virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove
-disabled.html | 679 // Hits in |
| 680 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable
d.html |
674 DisableCompositingQueryAsserts disabler; | 681 DisableCompositingQueryAsserts disabler; |
675 updateAppearance(); | 682 updateAppearance(); |
676 } | 683 } |
677 | 684 |
678 static DispatchEventResult dispatchSelectStart( | 685 static DispatchEventResult dispatchSelectStart( |
679 const VisibleSelection& selection) { | 686 const VisibleSelection& selection) { |
680 Node* selectStartTarget = selection.extent().computeContainerNode(); | 687 Node* selectStartTarget = selection.extent().computeContainerNode(); |
681 if (!selectStartTarget) | 688 if (!selectStartTarget) |
682 return DispatchEventResult::NotCanceled; | 689 return DispatchEventResult::NotCanceled; |
683 | 690 |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
837 if (visibleStart.isNull() || visibleEnd.isNull()) | 844 if (visibleStart.isNull() || visibleEnd.isNull()) |
838 return false; | 845 return false; |
839 | 846 |
840 const PositionInFlatTree& start = visibleStart.deepEquivalent(); | 847 const PositionInFlatTree& start = visibleStart.deepEquivalent(); |
841 const PositionInFlatTree& end = visibleEnd.deepEquivalent(); | 848 const PositionInFlatTree& end = visibleEnd.deepEquivalent(); |
842 const PositionInFlatTree& pos = visiblePos.deepEquivalent(); | 849 const PositionInFlatTree& pos = visiblePos.deepEquivalent(); |
843 return start.compareTo(pos) <= 0 && pos.compareTo(end) <= 0; | 850 return start.compareTo(pos) <= 0 && pos.compareTo(end) <= 0; |
844 } | 851 } |
845 | 852 |
846 // Workaround for the fact that it's hard to delete a frame. | 853 // Workaround for the fact that it's hard to delete a frame. |
847 // Call this after doing user-triggered selections to make it easy to delete the
frame you entirely selected. | 854 // Call this after doing user-triggered selections to make it easy to delete the |
848 // Can't do this implicitly as part of every setSelection call because in some c
ontexts it might not be good | 855 // frame you entirely selected. Can't do this implicitly as part of every |
849 // for the focus to move to another frame. So instead we call it from places whe
re we are selecting with the | 856 // setSelection call because in some contexts it might not be good for the focus |
850 // mouse or the keyboard after setting the selection. | 857 // to move to another frame. So instead we call it from places where we are |
| 858 // selecting with the mouse or the keyboard after setting the selection. |
851 void FrameSelection::selectFrameElementInParentIfFullySelected() { | 859 void FrameSelection::selectFrameElementInParentIfFullySelected() { |
852 // Find the parent frame; if there is none, then we have nothing to do. | 860 // Find the parent frame; if there is none, then we have nothing to do. |
853 Frame* parent = m_frame->tree().parent(); | 861 Frame* parent = m_frame->tree().parent(); |
854 if (!parent) | 862 if (!parent) |
855 return; | 863 return; |
856 Page* page = m_frame->page(); | 864 Page* page = m_frame->page(); |
857 if (!page) | 865 if (!page) |
858 return; | 866 return; |
859 | 867 |
860 // Check if the selection contains the entire frame contents; if not, then the
re is nothing to do. | 868 // Check if the selection contains the entire frame contents; if not, then |
| 869 // there is nothing to do. |
861 if (!isRange()) | 870 if (!isRange()) |
862 return; | 871 return; |
863 | 872 |
864 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 873 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
865 // needs to be audited. See http://crbug.com/590369 for more details. | 874 // needs to be audited. See http://crbug.com/590369 for more details. |
866 document().updateStyleAndLayoutIgnorePendingStylesheets(); | 875 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
867 | 876 |
868 if (!isStartOfDocument(selection().visibleStart())) | 877 if (!isStartOfDocument(selection().visibleStart())) |
869 return; | 878 return; |
870 if (!isEndOfDocument(selection().visibleEnd())) | 879 if (!isEndOfDocument(selection().visibleEnd())) |
871 return; | 880 return; |
872 | 881 |
873 // FIXME: This is not yet implemented for cross-process frame relationships. | 882 // FIXME: This is not yet implemented for cross-process frame relationships. |
874 if (!parent->isLocalFrame()) | 883 if (!parent->isLocalFrame()) |
875 return; | 884 return; |
876 | 885 |
877 // Get to the <iframe> or <frame> (or even <object>) element in the parent fra
me. | 886 // Get to the <iframe> or <frame> (or even <object>) element in the parent |
| 887 // frame. |
878 // FIXME: Doesn't work for OOPI. | 888 // FIXME: Doesn't work for OOPI. |
879 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); | 889 HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner(); |
880 if (!ownerElement) | 890 if (!ownerElement) |
881 return; | 891 return; |
882 ContainerNode* ownerElementParent = ownerElement->parentNode(); | 892 ContainerNode* ownerElementParent = ownerElement->parentNode(); |
883 if (!ownerElementParent) | 893 if (!ownerElementParent) |
884 return; | 894 return; |
885 | 895 |
886 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 896 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
887 // needs to be audited. See http://crbug.com/590369 for more details. | 897 // needs to be audited. See http://crbug.com/590369 for more details. |
888 ownerElementParent->document().updateStyleAndLayoutIgnorePendingStylesheets(); | 898 ownerElementParent->document().updateStyleAndLayoutIgnorePendingStylesheets(); |
889 | 899 |
890 // This method's purpose is it to make it easier to select iframes (in order t
o delete them). Don't do anything if the iframe isn't deletable. | 900 // This method's purpose is it to make it easier to select iframes (in order |
| 901 // to delete them). Don't do anything if the iframe isn't deletable. |
891 if (!blink::hasEditableStyle(*ownerElementParent)) | 902 if (!blink::hasEditableStyle(*ownerElementParent)) |
892 return; | 903 return; |
893 | 904 |
894 // Create compute positions before and after the element. | 905 // Create compute positions before and after the element. |
895 unsigned ownerElementNodeIndex = ownerElement->nodeIndex(); | 906 unsigned ownerElementNodeIndex = ownerElement->nodeIndex(); |
896 VisiblePosition beforeOwnerElement = createVisiblePosition( | 907 VisiblePosition beforeOwnerElement = createVisiblePosition( |
897 Position(ownerElementParent, ownerElementNodeIndex)); | 908 Position(ownerElementParent, ownerElementNodeIndex)); |
898 VisiblePosition afterOwnerElement = createVisiblePosition( | 909 VisiblePosition afterOwnerElement = createVisiblePosition( |
899 Position(ownerElementParent, ownerElementNodeIndex + 1), | 910 Position(ownerElementParent, ownerElementNodeIndex + 1), |
900 VP_UPSTREAM_IF_POSSIBLE); | 911 VP_UPSTREAM_IF_POSSIBLE); |
901 | 912 |
902 // Focus on the parent frame, and then select from before this element to afte
r. | 913 // Focus on the parent frame, and then select from before this element to |
| 914 // after. |
903 VisibleSelection newSelection = | 915 VisibleSelection newSelection = |
904 createVisibleSelection(beforeOwnerElement, afterOwnerElement); | 916 createVisibleSelection(beforeOwnerElement, afterOwnerElement); |
905 page->focusController().setFocusedFrame(parent); | 917 page->focusController().setFocusedFrame(parent); |
906 // setFocusedFrame can dispatch synchronous focus/blur events. The document | 918 // setFocusedFrame can dispatch synchronous focus/blur events. The document |
907 // tree might be modified. | 919 // tree might be modified. |
908 if (newSelection.isNonOrphanedCaretOrRange()) | 920 if (newSelection.isNonOrphanedCaretOrRange()) |
909 toLocalFrame(parent)->selection().setSelection(newSelection); | 921 toLocalFrame(parent)->selection().setSelection(newSelection); |
910 } | 922 } |
911 | 923 |
912 // Returns a shadow tree node for legacy shadow trees, a child of the | 924 // Returns a shadow tree node for legacy shadow trees, a child of the |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 m_pendingSelection->setHasPendingSelection(); | 1114 m_pendingSelection->setHasPendingSelection(); |
1103 } | 1115 } |
1104 | 1116 |
1105 void FrameSelection::notifyLayoutObjectOfSelectionChange( | 1117 void FrameSelection::notifyLayoutObjectOfSelectionChange( |
1106 EUserTriggered userTriggered) { | 1118 EUserTriggered userTriggered) { |
1107 if (HTMLTextFormControlElement* textControl = | 1119 if (HTMLTextFormControlElement* textControl = |
1108 enclosingTextFormControl(start())) | 1120 enclosingTextFormControl(start())) |
1109 textControl->selectionChanged(userTriggered == UserTriggered); | 1121 textControl->selectionChanged(userTriggered == UserTriggered); |
1110 } | 1122 } |
1111 | 1123 |
1112 // Helper function that tells whether a particular node is an element that has a
n entire | 1124 // Helper function that tells whether a particular node is an element that has |
1113 // LocalFrame and FrameView, a <frame>, <iframe>, or <object>. | 1125 // an entire LocalFrame and FrameView, a <frame>, <iframe>, or <object>. |
1114 static bool isFrameElement(const Node* n) { | 1126 static bool isFrameElement(const Node* n) { |
1115 if (!n) | 1127 if (!n) |
1116 return false; | 1128 return false; |
1117 LayoutObject* layoutObject = n->layoutObject(); | 1129 LayoutObject* layoutObject = n->layoutObject(); |
1118 if (!layoutObject || !layoutObject->isLayoutPart()) | 1130 if (!layoutObject || !layoutObject->isLayoutPart()) |
1119 return false; | 1131 return false; |
1120 Widget* widget = toLayoutPart(layoutObject)->widget(); | 1132 Widget* widget = toLayoutPart(layoutObject)->widget(); |
1121 return widget && widget->isFrameView(); | 1133 return widget && widget->isFrameView(); |
1122 } | 1134 } |
1123 | 1135 |
1124 void FrameSelection::setFocusedNodeIfNeeded() { | 1136 void FrameSelection::setFocusedNodeIfNeeded() { |
1125 if (isNone() || !isFocused()) | 1137 if (isNone() || !isFocused()) |
1126 return; | 1138 return; |
1127 | 1139 |
1128 bool caretBrowsing = | 1140 bool caretBrowsing = |
1129 m_frame->settings() && m_frame->settings()->caretBrowsingEnabled(); | 1141 m_frame->settings() && m_frame->settings()->caretBrowsingEnabled(); |
1130 if (caretBrowsing) { | 1142 if (caretBrowsing) { |
1131 if (Element* anchor = enclosingAnchorElement(base())) { | 1143 if (Element* anchor = enclosingAnchorElement(base())) { |
1132 m_frame->page()->focusController().setFocusedElement(anchor, m_frame); | 1144 m_frame->page()->focusController().setFocusedElement(anchor, m_frame); |
1133 return; | 1145 return; |
1134 } | 1146 } |
1135 } | 1147 } |
1136 | 1148 |
1137 if (Element* target = rootEditableElement()) { | 1149 if (Element* target = rootEditableElement()) { |
1138 // Walk up the DOM tree to search for a node to focus. | 1150 // Walk up the DOM tree to search for a node to focus. |
1139 document().updateStyleAndLayoutTreeIgnorePendingStylesheets(); | 1151 document().updateStyleAndLayoutTreeIgnorePendingStylesheets(); |
1140 while (target) { | 1152 while (target) { |
1141 // We don't want to set focus on a subframe when selecting in a parent fra
me, | 1153 // We don't want to set focus on a subframe when selecting in a parent |
1142 // so add the !isFrameElement check here. There's probably a better way to
make this | 1154 // frame, so add the !isFrameElement check here. There's probably a better |
1143 // work in the long term, but this is the safest fix at this time. | 1155 // way to make this work in the long term, but this is the safest fix at |
| 1156 // this time. |
1144 if (target->isMouseFocusable() && !isFrameElement(target)) { | 1157 if (target->isMouseFocusable() && !isFrameElement(target)) { |
1145 m_frame->page()->focusController().setFocusedElement(target, m_frame); | 1158 m_frame->page()->focusController().setFocusedElement(target, m_frame); |
1146 return; | 1159 return; |
1147 } | 1160 } |
1148 target = target->parentOrShadowHostElement(); | 1161 target = target->parentOrShadowHostElement(); |
1149 } | 1162 } |
1150 document().clearFocusedElement(); | 1163 document().clearFocusedElement(); |
1151 } | 1164 } |
1152 | 1165 |
1153 if (caretBrowsing) | 1166 if (caretBrowsing) |
1154 m_frame->page()->focusController().setFocusedElement(0, m_frame); | 1167 m_frame->page()->focusController().setFocusedElement(0, m_frame); |
1155 } | 1168 } |
1156 | 1169 |
1157 static String extractSelectedText(const FrameSelection& selection, | 1170 static String extractSelectedText(const FrameSelection& selection, |
1158 TextIteratorBehavior behavior) { | 1171 TextIteratorBehavior behavior) { |
1159 const VisibleSelectionInFlatTree& visibleSelection = | 1172 const VisibleSelectionInFlatTree& visibleSelection = |
1160 selection.visibleSelection<EditingInFlatTreeStrategy>(); | 1173 selection.visibleSelection<EditingInFlatTreeStrategy>(); |
1161 const EphemeralRangeInFlatTree& range = | 1174 const EphemeralRangeInFlatTree& range = |
1162 visibleSelection.toNormalizedEphemeralRange(); | 1175 visibleSelection.toNormalizedEphemeralRange(); |
1163 // We remove '\0' characters because they are not visibly rendered to the user
. | 1176 // We remove '\0' characters because they are not visibly rendered to the |
| 1177 // user. |
1164 return plainText(range, behavior).replace(0, ""); | 1178 return plainText(range, behavior).replace(0, ""); |
1165 } | 1179 } |
1166 | 1180 |
1167 String FrameSelection::selectedHTMLForClipboard() const { | 1181 String FrameSelection::selectedHTMLForClipboard() const { |
1168 const VisibleSelectionInFlatTree& visibleSelection = | 1182 const VisibleSelectionInFlatTree& visibleSelection = |
1169 this->visibleSelection<EditingInFlatTreeStrategy>(); | 1183 this->visibleSelection<EditingInFlatTreeStrategy>(); |
1170 const EphemeralRangeInFlatTree& range = | 1184 const EphemeralRangeInFlatTree& range = |
1171 visibleSelection.toNormalizedEphemeralRange(); | 1185 visibleSelection.toNormalizedEphemeralRange(); |
1172 return createMarkup(range.startPosition(), range.endPosition(), | 1186 return createMarkup(range.startPosition(), range.endPosition(), |
1173 AnnotateForInterchange, | 1187 AnnotateForInterchange, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1224 | 1238 |
1225 if (isHTMLFrameElementBase(element)) { | 1239 if (isHTMLFrameElementBase(element)) { |
1226 Node* childDocument = toHTMLFrameElementBase(element).contentDocument(); | 1240 Node* childDocument = toHTMLFrameElementBase(element).contentDocument(); |
1227 if (HTMLFormElement* frameResult = scanForForm(childDocument)) | 1241 if (HTMLFormElement* frameResult = scanForForm(childDocument)) |
1228 return frameResult; | 1242 return frameResult; |
1229 } | 1243 } |
1230 } | 1244 } |
1231 return 0; | 1245 return 0; |
1232 } | 1246 } |
1233 | 1247 |
1234 // We look for either the form containing the current focus, or for one immediat
ely after it | 1248 // We look for either the form containing the current focus, or for one |
| 1249 // immediately after it |
1235 HTMLFormElement* FrameSelection::currentForm() const { | 1250 HTMLFormElement* FrameSelection::currentForm() const { |
1236 // Start looking either at the active (first responder) node, or where the sel
ection is. | 1251 // Start looking either at the active (first responder) node, or where the |
| 1252 // selection is. |
1237 Node* start = document().focusedElement(); | 1253 Node* start = document().focusedElement(); |
1238 if (!start) | 1254 if (!start) |
1239 start = this->start().anchorNode(); | 1255 start = this->start().anchorNode(); |
1240 if (!start) | 1256 if (!start) |
1241 return 0; | 1257 return 0; |
1242 | 1258 |
1243 // Try walking up the node tree to find a form element. | 1259 // Try walking up the node tree to find a form element. |
1244 for (HTMLElement* element = | 1260 for (HTMLElement* element = |
1245 Traversal<HTMLElement>::firstAncestorOrSelf(*start); | 1261 Traversal<HTMLElement>::firstAncestorOrSelf(*start); |
1246 element; element = Traversal<HTMLElement>::firstAncestor(*element)) { | 1262 element; element = Traversal<HTMLElement>::firstAncestor(*element)) { |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1477 } | 1493 } |
1478 | 1494 |
1479 void showTree(const blink::FrameSelection* sel) { | 1495 void showTree(const blink::FrameSelection* sel) { |
1480 if (sel) | 1496 if (sel) |
1481 sel->showTreeForThis(); | 1497 sel->showTreeForThis(); |
1482 else | 1498 else |
1483 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; | 1499 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; |
1484 } | 1500 } |
1485 | 1501 |
1486 #endif | 1502 #endif |
OLD | NEW |