OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. |
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) | 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
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 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 } | 157 } |
158 } | 158 } |
159 | 159 |
160 // When an event handler has moved the selection outside of a text control | 160 // When an event handler has moved the selection outside of a text control |
161 // we should use the target control's selection for this editing operation. | 161 // we should use the target control's selection for this editing operation. |
162 VisibleSelection Editor::selectionForCommand(Event* event) { | 162 VisibleSelection Editor::selectionForCommand(Event* event) { |
163 frame().selection().updateIfNeeded(); | 163 frame().selection().updateIfNeeded(); |
164 VisibleSelection selection = frame().selection().selection(); | 164 VisibleSelection selection = frame().selection().selection(); |
165 if (!event) | 165 if (!event) |
166 return selection; | 166 return selection; |
167 // If the target is a text control, and the current selection is outside of it
s shadow tree, | 167 // If the target is a text control, and the current selection is outside of |
168 // then use the saved selection for that text control. | 168 // its shadow tree, then use the saved selection for that text control. |
169 HTMLTextFormControlElement* textFormControlOfSelectionStart = | 169 HTMLTextFormControlElement* textFormControlOfSelectionStart = |
170 enclosingTextFormControl(selection.start()); | 170 enclosingTextFormControl(selection.start()); |
171 HTMLTextFormControlElement* textFromControlOfTarget = | 171 HTMLTextFormControlElement* textFromControlOfTarget = |
172 isHTMLTextFormControlElement(*event->target()->toNode()) | 172 isHTMLTextFormControlElement(*event->target()->toNode()) |
173 ? toHTMLTextFormControlElement(event->target()->toNode()) | 173 ? toHTMLTextFormControlElement(event->target()->toNode()) |
174 : 0; | 174 : 0; |
175 if (textFromControlOfTarget && | 175 if (textFromControlOfTarget && |
176 (selection.start().isNull() || | 176 (selection.start().isNull() || |
177 textFromControlOfTarget != textFormControlOfSelectionStart)) { | 177 textFromControlOfTarget != textFormControlOfSelectionStart)) { |
178 if (Range* range = textFromControlOfTarget->selection()) { | 178 if (Range* range = textFromControlOfTarget->selection()) { |
179 return createVisibleSelection(EphemeralRange(range), | 179 return createVisibleSelection(EphemeralRange(range), |
180 TextAffinity::Downstream, | 180 TextAffinity::Downstream, |
181 selection.isDirectional()); | 181 selection.isDirectional()); |
182 } | 182 } |
183 } | 183 } |
184 return selection; | 184 return selection; |
185 } | 185 } |
186 | 186 |
187 // Function considers Mac editing behavior a fallback when Page or Settings is n
ot available. | 187 // Function considers Mac editing behavior a fallback when Page or Settings is |
| 188 // not available. |
188 EditingBehavior Editor::behavior() const { | 189 EditingBehavior Editor::behavior() const { |
189 if (!frame().settings()) | 190 if (!frame().settings()) |
190 return EditingBehavior(EditingMacBehavior); | 191 return EditingBehavior(EditingMacBehavior); |
191 | 192 |
192 return EditingBehavior(frame().settings()->editingBehaviorType()); | 193 return EditingBehavior(frame().settings()->editingBehaviorType()); |
193 } | 194 } |
194 | 195 |
195 static EditorClient& emptyEditorClient() { | 196 static EditorClient& emptyEditorClient() { |
196 DEFINE_STATIC_LOCAL(EmptyEditorClient, client, ()); | 197 DEFINE_STATIC_LOCAL(EmptyEditorClient, client, ()); |
197 return client; | 198 return client; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 } | 236 } |
236 | 237 |
237 bool Editor::canEdit() const { | 238 bool Editor::canEdit() const { |
238 return frame().selection().rootEditableElement(); | 239 return frame().selection().rootEditableElement(); |
239 } | 240 } |
240 | 241 |
241 bool Editor::canEditRichly() const { | 242 bool Editor::canEditRichly() const { |
242 return frame().selection().isContentRichlyEditable(); | 243 return frame().selection().isContentRichlyEditable(); |
243 } | 244 } |
244 | 245 |
245 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu it
ems. They | 246 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu |
246 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the me
nu items. | 247 // items. They also send onbeforecopy, apparently for symmetry, but it doesn't |
247 // We need to use onbeforecopy as a real menu enabler because we allow elements
that are not | 248 // affect the menu items. We need to use onbeforecopy as a real menu enabler |
248 // normally selectable to implement copy/paste (like divs, or a document body). | 249 // because we allow elements that are not normally selectable to implement |
| 250 // copy/paste (like divs, or a document body). |
249 | 251 |
250 bool Editor::canDHTMLCut() { | 252 bool Editor::canDHTMLCut() { |
251 return !frame().selection().isInPasswordField() && | 253 return !frame().selection().isInPasswordField() && |
252 !dispatchCPPEvent(EventTypeNames::beforecut, DataTransferNumb); | 254 !dispatchCPPEvent(EventTypeNames::beforecut, DataTransferNumb); |
253 } | 255 } |
254 | 256 |
255 bool Editor::canDHTMLCopy() { | 257 bool Editor::canDHTMLCopy() { |
256 return !frame().selection().isInPasswordField() && | 258 return !frame().selection().isInPasswordField() && |
257 !dispatchCPPEvent(EventTypeNames::beforecopy, DataTransferNumb); | 259 !dispatchCPPEvent(EventTypeNames::beforecopy, DataTransferNumb); |
258 } | 260 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 case DeleteDirection::Backward: | 352 case DeleteDirection::Backward: |
351 DCHECK(frame().document()); | 353 DCHECK(frame().document()); |
352 TypingCommand::deleteKeyPressed(*frame().document(), options, | 354 TypingCommand::deleteKeyPressed(*frame().document(), options, |
353 granularity); | 355 granularity); |
354 break; | 356 break; |
355 } | 357 } |
356 revealSelectionAfterEditingOperation(); | 358 revealSelectionAfterEditingOperation(); |
357 } | 359 } |
358 | 360 |
359 // FIXME: We should to move this down into deleteKeyPressed. | 361 // FIXME: We should to move this down into deleteKeyPressed. |
360 // clear the "start new kill ring sequence" setting, because it was set to tru
e | 362 // clear the "start new kill ring sequence" setting, because it was set to |
361 // when the selection was updated by deleting the range | 363 // true when the selection was updated by deleting the range |
362 if (killRing) | 364 if (killRing) |
363 setStartNewKillRingSequence(false); | 365 setStartNewKillRingSequence(false); |
364 | 366 |
365 return true; | 367 return true; |
366 } | 368 } |
367 | 369 |
368 void Editor::deleteSelectionWithSmartDelete( | 370 void Editor::deleteSelectionWithSmartDelete( |
369 DeleteMode deleteMode, | 371 DeleteMode deleteMode, |
370 InputEvent::InputType inputType, | 372 InputEvent::InputType inputType, |
371 const Position& referenceMovePosition) { | 373 const Position& referenceMovePosition) { |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 static void writeImageNodeToPasteboard(Pasteboard* pasteboard, | 495 static void writeImageNodeToPasteboard(Pasteboard* pasteboard, |
494 Node* node, | 496 Node* node, |
495 const String& title) { | 497 const String& title) { |
496 DCHECK(pasteboard); | 498 DCHECK(pasteboard); |
497 DCHECK(node); | 499 DCHECK(node); |
498 | 500 |
499 RefPtr<Image> image = imageFromNode(*node); | 501 RefPtr<Image> image = imageFromNode(*node); |
500 if (!image.get()) | 502 if (!image.get()) |
501 return; | 503 return; |
502 | 504 |
503 // FIXME: This should probably be reconciled with HitTestResult::absoluteImage
URL. | 505 // FIXME: This should probably be reconciled with |
| 506 // HitTestResult::absoluteImageURL. |
504 AtomicString urlString; | 507 AtomicString urlString; |
505 if (isHTMLImageElement(*node) || isHTMLInputElement(*node)) | 508 if (isHTMLImageElement(*node) || isHTMLInputElement(*node)) |
506 urlString = toHTMLElement(node)->getAttribute(srcAttr); | 509 urlString = toHTMLElement(node)->getAttribute(srcAttr); |
507 else if (isSVGImageElement(*node)) | 510 else if (isSVGImageElement(*node)) |
508 urlString = toSVGElement(node)->imageSourceURL(); | 511 urlString = toSVGElement(node)->imageSourceURL(); |
509 else if (isHTMLEmbedElement(*node) || isHTMLObjectElement(*node) || | 512 else if (isHTMLEmbedElement(*node) || isHTMLObjectElement(*node) || |
510 isHTMLCanvasElement(*node)) | 513 isHTMLCanvasElement(*node)) |
511 urlString = toHTMLElement(node)->imageSourceURL(); | 514 urlString = toHTMLElement(node)->imageSourceURL(); |
512 KURL url = urlString.isEmpty() | 515 KURL url = urlString.isEmpty() |
513 ? KURL() | 516 ? KURL() |
514 : node->document().completeURL( | 517 : node->document().completeURL( |
515 stripLeadingAndTrailingHTMLSpaces(urlString)); | 518 stripLeadingAndTrailingHTMLSpaces(urlString)); |
516 | 519 |
517 pasteboard->writeImage(image.get(), url, title); | 520 pasteboard->writeImage(image.get(), url, title); |
518 } | 521 } |
519 | 522 |
520 // Returns whether caller should continue with "the default processing", which i
s the same as | 523 // Returns whether caller should continue with "the default processing", which |
521 // the event handler NOT setting the return value to false | 524 // is the same as the event handler NOT setting the return value to false |
522 bool Editor::dispatchCPPEvent(const AtomicString& eventType, | 525 bool Editor::dispatchCPPEvent(const AtomicString& eventType, |
523 DataTransferAccessPolicy policy, | 526 DataTransferAccessPolicy policy, |
524 PasteMode pasteMode) { | 527 PasteMode pasteMode) { |
525 Element* target = findEventTargetFromSelection(); | 528 Element* target = findEventTargetFromSelection(); |
526 if (!target) | 529 if (!target) |
527 return true; | 530 return true; |
528 | 531 |
529 DataTransfer* dataTransfer = | 532 DataTransfer* dataTransfer = |
530 DataTransfer::create(DataTransfer::CopyAndPaste, policy, | 533 DataTransfer::create(DataTransfer::CopyAndPaste, policy, |
531 policy == DataTransferWritable | 534 policy == DataTransferWritable |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 DeleteMode deleteMode, | 606 DeleteMode deleteMode, |
604 const Position& referenceMovePosition) { | 607 const Position& referenceMovePosition) { |
605 if (!dragSource || !dragSource->isConnected()) | 608 if (!dragSource || !dragSource->isConnected()) |
606 return true; | 609 return true; |
607 | 610 |
608 // Dispatch 'beforeinput'. | 611 // Dispatch 'beforeinput'. |
609 const bool shouldDelete = dispatchBeforeInputEditorCommand( | 612 const bool shouldDelete = dispatchBeforeInputEditorCommand( |
610 dragSource, InputEvent::InputType::DeleteByDrag, | 613 dragSource, InputEvent::InputType::DeleteByDrag, |
611 nullptr) == DispatchEventResult::NotCanceled; | 614 nullptr) == DispatchEventResult::NotCanceled; |
612 | 615 |
613 // 'beforeinput' event handler may destroy frame, return false to cancel remai
ning actions; | 616 // 'beforeinput' event handler may destroy frame, return false to cancel |
| 617 // remaining actions; |
614 if (m_frame->document()->frame() != m_frame) | 618 if (m_frame->document()->frame() != m_frame) |
615 return false; | 619 return false; |
616 | 620 |
617 if (shouldDelete && dragSource->isConnected()) { | 621 if (shouldDelete && dragSource->isConnected()) { |
618 deleteSelectionWithSmartDelete( | 622 deleteSelectionWithSmartDelete( |
619 deleteMode, InputEvent::InputType::DeleteByDrag, referenceMovePosition); | 623 deleteMode, InputEvent::InputType::DeleteByDrag, referenceMovePosition); |
620 } | 624 } |
621 | 625 |
622 return true; | 626 return true; |
623 } | 627 } |
(...skipping 11 matching lines...) Expand all Loading... |
635 // Dispatch 'beforeinput'. | 639 // Dispatch 'beforeinput'. |
636 DataTransfer* dataTransfer = | 640 DataTransfer* dataTransfer = |
637 DataTransfer::create(DataTransfer::DragAndDrop, DataTransferReadable, | 641 DataTransfer::create(DataTransfer::DragAndDrop, DataTransferReadable, |
638 dragData->platformData()); | 642 dragData->platformData()); |
639 dataTransfer->setSourceOperation(dragData->draggingSourceOperationMask()); | 643 dataTransfer->setSourceOperation(dragData->draggingSourceOperationMask()); |
640 const bool shouldInsert = | 644 const bool shouldInsert = |
641 dispatchBeforeInputDataTransfer( | 645 dispatchBeforeInputDataTransfer( |
642 dropTarget, InputEvent::InputType::InsertFromDrop, dataTransfer, | 646 dropTarget, InputEvent::InputType::InsertFromDrop, dataTransfer, |
643 nullptr) == DispatchEventResult::NotCanceled; | 647 nullptr) == DispatchEventResult::NotCanceled; |
644 | 648 |
645 // 'beforeinput' event handler may destroy frame, return false to cancel remai
ning actions; | 649 // 'beforeinput' event handler may destroy frame, return false to cancel |
| 650 // remaining actions; |
646 if (m_frame->document()->frame() != m_frame) | 651 if (m_frame->document()->frame() != m_frame) |
647 return false; | 652 return false; |
648 | 653 |
649 if (shouldInsert && dropTarget->isConnected()) | 654 if (shouldInsert && dropTarget->isConnected()) |
650 replaceSelectionAfterDragging(fragment, insertMode, dragSourceType); | 655 replaceSelectionAfterDragging(fragment, insertMode, dragSourceType); |
651 | 656 |
652 return true; | 657 return true; |
653 } | 658 } |
654 | 659 |
655 EphemeralRange Editor::selectedRange() { | 660 EphemeralRange Editor::selectedRange() { |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
807 dispatchEditableContentChangedEvents( | 812 dispatchEditableContentChangedEvents( |
808 composition->startingRootEditableElement(), | 813 composition->startingRootEditableElement(), |
809 composition->endingRootEditableElement()); | 814 composition->endingRootEditableElement()); |
810 // TODO(chongz): Filter empty InputType after spec is finalized. | 815 // TODO(chongz): Filter empty InputType after spec is finalized. |
811 dispatchInputEventEditableContentChanged( | 816 dispatchInputEventEditableContentChanged( |
812 composition->startingRootEditableElement(), | 817 composition->startingRootEditableElement(), |
813 composition->endingRootEditableElement(), cmd->inputType(), | 818 composition->endingRootEditableElement(), cmd->inputType(), |
814 cmd->textDataForInputEvent(), isComposingFromCommand(cmd)); | 819 cmd->textDataForInputEvent(), isComposingFromCommand(cmd)); |
815 VisibleSelection newSelection(cmd->endingSelection()); | 820 VisibleSelection newSelection(cmd->endingSelection()); |
816 | 821 |
817 // Don't clear the typing style with this selection change. We do those things
elsewhere if necessary. | 822 // Don't clear the typing style with this selection change. We do those things |
| 823 // elsewhere if necessary. |
818 changeSelectionAfterCommand(newSelection, 0); | 824 changeSelectionAfterCommand(newSelection, 0); |
819 | 825 |
820 if (!cmd->preservesTypingStyle()) | 826 if (!cmd->preservesTypingStyle()) |
821 frame().selection().clearTypingStyle(); | 827 frame().selection().clearTypingStyle(); |
822 | 828 |
823 // Command will be equal to last edit command only in the case of typing | 829 // Command will be equal to last edit command only in the case of typing |
824 if (m_lastEditCommand.get() == cmd) { | 830 if (m_lastEditCommand.get() == cmd) { |
825 DCHECK(cmd->isTypingCommand()); | 831 DCHECK(cmd->isTypingCommand()); |
826 } else if (m_lastEditCommand && m_lastEditCommand->isDragAndDropCommand() && | 832 } else if (m_lastEditCommand && m_lastEditCommand->isDragAndDropCommand() && |
827 (cmd->inputType() == InputEvent::InputType::DeleteByDrag || | 833 (cmd->inputType() == InputEvent::InputType::DeleteByDrag || |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 | 899 |
894 Editor* Editor::create(LocalFrame& frame) { | 900 Editor* Editor::create(LocalFrame& frame) { |
895 return new Editor(frame); | 901 return new Editor(frame); |
896 } | 902 } |
897 | 903 |
898 Editor::Editor(LocalFrame& frame) | 904 Editor::Editor(LocalFrame& frame) |
899 : m_frame(&frame), | 905 : m_frame(&frame), |
900 m_undoStack(UndoStack::create()), | 906 m_undoStack(UndoStack::create()), |
901 m_preventRevealSelection(0), | 907 m_preventRevealSelection(0), |
902 m_shouldStartNewKillRingSequence(false), | 908 m_shouldStartNewKillRingSequence(false), |
903 // This is off by default, since most editors want this behavior (this mat
ches IE but not FF). | 909 // This is off by default, since most editors want this behavior (this |
| 910 // matches IE but not FF). |
904 m_shouldStyleWithCSS(false), | 911 m_shouldStyleWithCSS(false), |
905 m_killRing(wrapUnique(new KillRing)), | 912 m_killRing(wrapUnique(new KillRing)), |
906 m_areMarkedTextMatchesHighlighted(false), | 913 m_areMarkedTextMatchesHighlighted(false), |
907 m_defaultParagraphSeparator(EditorParagraphSeparatorIsDiv), | 914 m_defaultParagraphSeparator(EditorParagraphSeparatorIsDiv), |
908 m_overwriteModeEnabled(false) {} | 915 m_overwriteModeEnabled(false) {} |
909 | 916 |
910 Editor::~Editor() {} | 917 Editor::~Editor() {} |
911 | 918 |
912 void Editor::clear() { | 919 void Editor::clear() { |
913 frame().inputMethodController().clear(); | 920 frame().inputMethodController().clear(); |
(...skipping 26 matching lines...) Expand all Loading... |
940 triggeringEvent && triggeringEvent->isComposition() | 947 triggeringEvent && triggeringEvent->isComposition() |
941 ? TypingCommand::TextCompositionConfirm | 948 ? TypingCommand::TextCompositionConfirm |
942 : TypingCommand::TextCompositionNone); | 949 : TypingCommand::TextCompositionNone); |
943 | 950 |
944 // Reveal the current selection | 951 // Reveal the current selection |
945 if (LocalFrame* editedFrame = selection.start().document()->frame()) { | 952 if (LocalFrame* editedFrame = selection.start().document()->frame()) { |
946 if (Page* page = editedFrame->page()) { | 953 if (Page* page = editedFrame->page()) { |
947 LocalFrame* focusedOrMainFrame = | 954 LocalFrame* focusedOrMainFrame = |
948 toLocalFrame(page->focusController().focusedOrMainFrame()); | 955 toLocalFrame(page->focusController().focusedOrMainFrame()); |
949 | 956 |
950 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStyleshee
ts | 957 // TODO(xiaochengh): The use of |
| 958 // updateStyleAndLayoutIgnorePendingStylesheets |
951 // needs to be audited. See http://crbug.com/590369 for more details. | 959 // needs to be audited. See http://crbug.com/590369 for more details. |
952 focusedOrMainFrame->document() | 960 focusedOrMainFrame->document() |
953 ->updateStyleAndLayoutIgnorePendingStylesheets(); | 961 ->updateStyleAndLayoutIgnorePendingStylesheets(); |
954 | 962 |
955 focusedOrMainFrame->selection().revealSelection( | 963 focusedOrMainFrame->selection().revealSelection( |
956 ScrollAlignment::alignCenterIfNeeded); | 964 ScrollAlignment::alignCenterIfNeeded); |
957 } | 965 } |
958 } | 966 } |
959 | 967 |
960 return true; | 968 return true; |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1097 void Editor::performDelete() { | 1105 void Editor::performDelete() { |
1098 if (!canDelete()) | 1106 if (!canDelete()) |
1099 return; | 1107 return; |
1100 addToKillRing(selectedRange()); | 1108 addToKillRing(selectedRange()); |
1101 // TODO(chongz): |Editor::performDelete()| has no direction. | 1109 // TODO(chongz): |Editor::performDelete()| has no direction. |
1102 // https://github.com/w3c/editing/issues/130 | 1110 // https://github.com/w3c/editing/issues/130 |
1103 deleteSelectionWithSmartDelete( | 1111 deleteSelectionWithSmartDelete( |
1104 canSmartCopyOrDelete() ? DeleteMode::Smart : DeleteMode::Simple, | 1112 canSmartCopyOrDelete() ? DeleteMode::Smart : DeleteMode::Simple, |
1105 InputEvent::InputType::DeleteContentBackward); | 1113 InputEvent::InputType::DeleteContentBackward); |
1106 | 1114 |
1107 // clear the "start new kill ring sequence" setting, because it was set to tru
e | 1115 // clear the "start new kill ring sequence" setting, because it was set to |
1108 // when the selection was updated by deleting the range | 1116 // true when the selection was updated by deleting the range |
1109 setStartNewKillRingSequence(false); | 1117 setStartNewKillRingSequence(false); |
1110 } | 1118 } |
1111 | 1119 |
1112 static void countEditingEvent(ExecutionContext* executionContext, | 1120 static void countEditingEvent(ExecutionContext* executionContext, |
1113 const Event* event, | 1121 const Event* event, |
1114 UseCounter::Feature featureOnInput, | 1122 UseCounter::Feature featureOnInput, |
1115 UseCounter::Feature featureOnTextArea, | 1123 UseCounter::Feature featureOnTextArea, |
1116 UseCounter::Feature featureOnContentEditable, | 1124 UseCounter::Feature featureOnContentEditable, |
1117 UseCounter::Feature featureOnNonNode) { | 1125 UseCounter::Feature featureOnNonNode) { |
1118 EventTarget* eventTarget = event->target(); | 1126 EventTarget* eventTarget = event->target(); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1284 m_shouldStartNewKillRingSequence = false; | 1292 m_shouldStartNewKillRingSequence = false; |
1285 } | 1293 } |
1286 | 1294 |
1287 void Editor::changeSelectionAfterCommand( | 1295 void Editor::changeSelectionAfterCommand( |
1288 const VisibleSelection& newSelection, | 1296 const VisibleSelection& newSelection, |
1289 FrameSelection::SetSelectionOptions options) { | 1297 FrameSelection::SetSelectionOptions options) { |
1290 // If the new selection is orphaned, then don't update the selection. | 1298 // If the new selection is orphaned, then don't update the selection. |
1291 if (newSelection.start().isOrphan() || newSelection.end().isOrphan()) | 1299 if (newSelection.start().isOrphan() || newSelection.end().isOrphan()) |
1292 return; | 1300 return; |
1293 | 1301 |
1294 // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Rang
es for selections that are no longer valid | 1302 // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain |
| 1303 // Ranges for selections that are no longer valid |
1295 bool selectionDidNotChangeDOMPosition = | 1304 bool selectionDidNotChangeDOMPosition = |
1296 newSelection == frame().selection().selection(); | 1305 newSelection == frame().selection().selection(); |
1297 frame().selection().setSelection(newSelection, options); | 1306 frame().selection().setSelection(newSelection, options); |
1298 | 1307 |
1299 // Some editing operations change the selection visually without affecting its
position within the DOM. | 1308 // Some editing operations change the selection visually without affecting its |
1300 // For example when you press return in the following (the caret is marked by
^): | 1309 // position within the DOM. For example when you press return in the following |
| 1310 // (the caret is marked by ^): |
1301 // <div contentEditable="true"><div>^Hello</div></div> | 1311 // <div contentEditable="true"><div>^Hello</div></div> |
1302 // WebCore inserts <div><br></div> *before* the current block, which correctly
moves the paragraph down but which doesn't | 1312 // WebCore inserts <div><br></div> *before* the current block, which correctly |
1303 // change the caret's DOM position (["hello", 0]). In these situations the abo
ve FrameSelection::setSelection call | 1313 // moves the paragraph down but which doesn't change the caret's DOM position |
1304 // does not call EditorClient::respondToChangedSelection(), which, on the Mac,
sends selection change notifications and | 1314 // (["hello", 0]). In these situations the above FrameSelection::setSelection |
1305 // starts a new kill ring sequence, but we want to do these things (matches Ap
pKit). | 1315 // call does not call EditorClient::respondToChangedSelection(), which, on the |
| 1316 // Mac, sends selection change notifications and starts a new kill ring |
| 1317 // sequence, but we want to do these things (matches AppKit). |
1306 if (selectionDidNotChangeDOMPosition) | 1318 if (selectionDidNotChangeDOMPosition) |
1307 client().respondToChangedSelection(m_frame, | 1319 client().respondToChangedSelection(m_frame, |
1308 frame().selection().getSelectionType()); | 1320 frame().selection().getSelectionType()); |
1309 } | 1321 } |
1310 | 1322 |
1311 IntRect Editor::firstRectForRange(const EphemeralRange& range) const { | 1323 IntRect Editor::firstRectForRange(const EphemeralRange& range) const { |
1312 DCHECK(!frame().document()->needsLayoutTreeUpdate()); | 1324 DCHECK(!frame().document()->needsLayoutTreeUpdate()); |
1313 DocumentLifecycle::DisallowTransitionScope disallowTransition( | 1325 DocumentLifecycle::DisallowTransitionScope disallowTransition( |
1314 frame().document()->lifecycle()); | 1326 frame().document()->lifecycle()); |
1315 | 1327 |
(...skipping 17 matching lines...) Expand all Loading... |
1333 return IntRect(); | 1345 return IntRect(); |
1334 | 1346 |
1335 if (startCaretRect.y() == endCaretRect.y()) { | 1347 if (startCaretRect.y() == endCaretRect.y()) { |
1336 // start and end are on the same line | 1348 // start and end are on the same line |
1337 return IntRect(std::min(startCaretRect.x(), endCaretRect.x()), | 1349 return IntRect(std::min(startCaretRect.x(), endCaretRect.x()), |
1338 startCaretRect.y(), | 1350 startCaretRect.y(), |
1339 abs(endCaretRect.x() - startCaretRect.x()), | 1351 abs(endCaretRect.x() - startCaretRect.x()), |
1340 std::max(startCaretRect.height(), endCaretRect.height())); | 1352 std::max(startCaretRect.height(), endCaretRect.height())); |
1341 } | 1353 } |
1342 | 1354 |
1343 // start and end aren't on the same line, so go from start to the end of its l
ine | 1355 // start and end aren't on the same line, so go from start to the end of its |
| 1356 // line |
1344 return IntRect(startCaretRect.x(), startCaretRect.y(), | 1357 return IntRect(startCaretRect.x(), startCaretRect.y(), |
1345 (startCaretRect.width() + extraWidthToEndOfLine).toInt(), | 1358 (startCaretRect.width() + extraWidthToEndOfLine).toInt(), |
1346 startCaretRect.height()); | 1359 startCaretRect.height()); |
1347 } | 1360 } |
1348 | 1361 |
1349 void Editor::computeAndSetTypingStyle(StylePropertySet* style, | 1362 void Editor::computeAndSetTypingStyle(StylePropertySet* style, |
1350 InputEvent::InputType inputType) { | 1363 InputEvent::InputType inputType) { |
1351 if (!style || style->isEmpty()) { | 1364 if (!style || style->isEmpty()) { |
1352 frame().selection().clearTypingStyle(); | 1365 frame().selection().clearTypingStyle(); |
1353 return; | 1366 return; |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1611 } | 1624 } |
1612 | 1625 |
1613 DEFINE_TRACE(Editor) { | 1626 DEFINE_TRACE(Editor) { |
1614 visitor->trace(m_frame); | 1627 visitor->trace(m_frame); |
1615 visitor->trace(m_lastEditCommand); | 1628 visitor->trace(m_lastEditCommand); |
1616 visitor->trace(m_undoStack); | 1629 visitor->trace(m_undoStack); |
1617 visitor->trace(m_mark); | 1630 visitor->trace(m_mark); |
1618 } | 1631 } |
1619 | 1632 |
1620 } // namespace blink | 1633 } // namespace blink |
OLD | NEW |