Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: Source/core/editing/TypingCommand.cpp

Issue 1294543005: Move execCommand related files in core/editing/ related files into core/editing/commands/ (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: 2015-08-18T14:20:58 Rebase for merging code style fixes Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "core/editing/TypingCommand.h"
28
29 #include "core/HTMLNames.h"
30 #include "core/dom/Document.h"
31 #include "core/dom/Element.h"
32 #include "core/dom/ElementTraversal.h"
33 #include "core/editing/BreakBlockquoteCommand.h"
34 #include "core/editing/EditingUtilities.h"
35 #include "core/editing/Editor.h"
36 #include "core/editing/FrameSelection.h"
37 #include "core/editing/InsertLineBreakCommand.h"
38 #include "core/editing/InsertParagraphSeparatorCommand.h"
39 #include "core/editing/InsertTextCommand.h"
40 #include "core/editing/VisiblePosition.h"
41 #include "core/editing/VisibleUnits.h"
42 #include "core/editing/spellcheck/SpellChecker.h"
43 #include "core/frame/LocalFrame.h"
44 #include "core/html/HTMLBRElement.h"
45 #include "core/layout/LayoutObject.h"
46
47 namespace blink {
48
49 using namespace HTMLNames;
50
51 class TypingCommandLineOperation {
52 STACK_ALLOCATED();
53 public:
54 TypingCommandLineOperation(TypingCommand* typingCommand, bool selectInserted Text, const String& text)
55 : m_typingCommand(typingCommand)
56 , m_selectInsertedText(selectInsertedText)
57 , m_text(text)
58 { }
59
60 void operator()(size_t lineOffset, size_t lineLength, bool isLastLine) const
61 {
62 if (isLastLine) {
63 if (!lineOffset || lineLength > 0)
64 m_typingCommand->insertTextRunWithoutNewlines(m_text.substring(l ineOffset, lineLength), m_selectInsertedText);
65 } else {
66 if (lineLength > 0)
67 m_typingCommand->insertTextRunWithoutNewlines(m_text.substring(l ineOffset, lineLength), false);
68 m_typingCommand->insertParagraphSeparator();
69 }
70 }
71
72 private:
73 RawPtrWillBeMember<TypingCommand> m_typingCommand;
74 bool m_selectInsertedText;
75 const String& m_text;
76 };
77
78 TypingCommand::TypingCommand(Document& document, ETypingCommand commandType, con st String &textToInsert, Options options, TextGranularity granularity, TextCompo sitionType compositionType)
79 : TextInsertionBaseCommand(document)
80 , m_commandType(commandType)
81 , m_textToInsert(textToInsert)
82 , m_openForMoreTyping(true)
83 , m_selectInsertedText(options & SelectInsertedText)
84 , m_smartDelete(options & SmartDelete)
85 , m_granularity(granularity)
86 , m_compositionType(compositionType)
87 , m_killRing(options & KillRing)
88 , m_openedByBackwardDelete(false)
89 , m_shouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndica tor)
90 , m_shouldPreventSpellChecking(options & PreventSpellChecking)
91 {
92 updatePreservesTypingStyle(m_commandType);
93 }
94
95 void TypingCommand::deleteSelection(Document& document, Options options)
96 {
97 LocalFrame* frame = document.frame();
98 ASSERT(frame);
99
100 if (!frame->selection().isRange())
101 return;
102
103 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandI fStillOpenForTyping(frame)) {
104 lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellC hecking);
105 lastTypingCommand->deleteSelection(options & SmartDelete);
106 return;
107 }
108
109 TypingCommand::create(document, DeleteSelection, "", options)->apply();
110 }
111
112 void TypingCommand::deleteKeyPressed(Document& document, Options options, TextGr anularity granularity)
113 {
114 if (granularity == CharacterGranularity) {
115 LocalFrame* frame = document.frame();
116 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingComm andIfStillOpenForTyping(frame)) {
117 // If the last typing command is not Delete, open a new typing comma nd.
118 // We need to group continuous delete commands alone in a single typ ing command.
119 if (lastTypingCommand->commandTypeOfOpenCommand() == DeleteKey) {
120 updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand .get(), frame);
121 lastTypingCommand->setShouldPreventSpellChecking(options & Preve ntSpellChecking);
122 lastTypingCommand->deleteKeyPressed(granularity, options & KillR ing);
123 return;
124 }
125 }
126 }
127
128 TypingCommand::create(document, DeleteKey, "", options, granularity)->apply( );
129 }
130
131 void TypingCommand::forwardDeleteKeyPressed(Document& document, Options options, TextGranularity granularity)
132 {
133 // FIXME: Forward delete in TextEdit appears to open and close a new typing command.
134 if (granularity == CharacterGranularity) {
135 LocalFrame* frame = document.frame();
136 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingComm andIfStillOpenForTyping(frame)) {
137 updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand.get (), frame);
138 lastTypingCommand->setShouldPreventSpellChecking(options & PreventSp ellChecking);
139 lastTypingCommand->forwardDeleteKeyPressed(granularity, options & Ki llRing);
140 return;
141 }
142 }
143
144 TypingCommand::create(document, ForwardDeleteKey, "", options, granularity)- >apply();
145 }
146
147 void TypingCommand::updateSelectionIfDifferentFromCurrentSelection(TypingCommand * typingCommand, LocalFrame* frame)
148 {
149 ASSERT(frame);
150 VisibleSelection currentSelection = frame->selection().selection();
151 if (VisibleSelection::InDOMTree::equalSelections(currentSelection, typingCom mand->endingSelection()))
152 return;
153
154 typingCommand->setStartingSelection(currentSelection);
155 typingCommand->setEndingSelection(currentSelection);
156 }
157
158 void TypingCommand::insertText(Document& document, const String& text, Options o ptions, TextCompositionType composition)
159 {
160 LocalFrame* frame = document.frame();
161 ASSERT(frame);
162
163 if (!text.isEmpty())
164 document.frame()->spellChecker().updateMarkersForWordsAffectedByEditing( isSpaceOrNewline(text[0]));
165
166 insertText(document, text, frame->selection().selection(), options, composit ion);
167 }
168
169 // FIXME: We shouldn't need to take selectionForInsertion. It should be identica l to FrameSelection's current selection.
170 void TypingCommand::insertText(Document& document, const String& text, const Vis ibleSelection& selectionForInsertion, Options options, TextCompositionType compo sitionType)
171 {
172 RefPtrWillBeRawPtr<LocalFrame> frame = document.frame();
173 ASSERT(frame);
174
175 VisibleSelection currentSelection = frame->selection().selection();
176
177 String newText = dispatchBeforeTextInsertedEvent(text, selectionForInsertion , compositionType == TextCompositionUpdate);
178
179 // Set the starting and ending selection appropriately if we are using a sel ection
180 // that is different from the current selection. In the future, we should c hange EditCommand
181 // to deal with custom selections in a general way that can be used by all o f the commands.
182 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandI fStillOpenForTyping(frame.get())) {
183 if (!VisibleSelection::InDOMTree::equalSelections(lastTypingCommand->end ingSelection(), selectionForInsertion)) {
184 lastTypingCommand->setStartingSelection(selectionForInsertion);
185 lastTypingCommand->setEndingSelection(selectionForInsertion);
186 }
187
188 lastTypingCommand->setCompositionType(compositionType);
189 lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & Reta inAutocorrectionIndicator);
190 lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellC hecking);
191 lastTypingCommand->insertText(newText, options & SelectInsertedText);
192 return;
193 }
194
195 RefPtrWillBeRawPtr<TypingCommand> cmd = TypingCommand::create(document, Inse rtText, newText, options, compositionType);
196 applyTextInsertionCommand(frame.get(), cmd, selectionForInsertion, currentSe lection);
197 }
198
199 void TypingCommand::insertLineBreak(Document& document, Options options)
200 {
201 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandI fStillOpenForTyping(document.frame())) {
202 lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & Reta inAutocorrectionIndicator);
203 lastTypingCommand->insertLineBreak();
204 return;
205 }
206
207 TypingCommand::create(document, InsertLineBreak, "", options)->apply();
208 }
209
210 void TypingCommand::insertParagraphSeparatorInQuotedContent(Document& document)
211 {
212 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandI fStillOpenForTyping(document.frame())) {
213 lastTypingCommand->insertParagraphSeparatorInQuotedContent();
214 return;
215 }
216
217 TypingCommand::create(document, InsertParagraphSeparatorInQuotedContent)->ap ply();
218 }
219
220 void TypingCommand::insertParagraphSeparator(Document& document, Options options )
221 {
222 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandI fStillOpenForTyping(document.frame())) {
223 lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & Reta inAutocorrectionIndicator);
224 lastTypingCommand->insertParagraphSeparator();
225 return;
226 }
227
228 TypingCommand::create(document, InsertParagraphSeparator, "", options)->appl y();
229 }
230
231 PassRefPtrWillBeRawPtr<TypingCommand> TypingCommand::lastTypingCommandIfStillOpe nForTyping(LocalFrame* frame)
232 {
233 ASSERT(frame);
234
235 RefPtrWillBeRawPtr<CompositeEditCommand> lastEditCommand = frame->editor().l astEditCommand();
236 if (!lastEditCommand || !lastEditCommand->isTypingCommand() || !static_cast< TypingCommand*>(lastEditCommand.get())->isOpenForMoreTyping())
237 return nullptr;
238
239 return static_cast<TypingCommand*>(lastEditCommand.get());
240 }
241
242 void TypingCommand::closeTyping(LocalFrame* frame)
243 {
244 if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandI fStillOpenForTyping(frame))
245 lastTypingCommand->closeTyping();
246 }
247
248 void TypingCommand::doApply()
249 {
250 if (!endingSelection().isNonOrphanedCaretOrRange())
251 return;
252
253 if (m_commandType == DeleteKey) {
254 if (m_commands.isEmpty())
255 m_openedByBackwardDelete = true;
256 }
257
258 switch (m_commandType) {
259 case DeleteSelection:
260 deleteSelection(m_smartDelete);
261 return;
262 case DeleteKey:
263 deleteKeyPressed(m_granularity, m_killRing);
264 return;
265 case ForwardDeleteKey:
266 forwardDeleteKeyPressed(m_granularity, m_killRing);
267 return;
268 case InsertLineBreak:
269 insertLineBreak();
270 return;
271 case InsertParagraphSeparator:
272 insertParagraphSeparator();
273 return;
274 case InsertParagraphSeparatorInQuotedContent:
275 insertParagraphSeparatorInQuotedContent();
276 return;
277 case InsertText:
278 insertText(m_textToInsert, m_selectInsertedText);
279 return;
280 }
281
282 ASSERT_NOT_REACHED();
283 }
284
285 EditAction TypingCommand::editingAction() const
286 {
287 return EditActionTyping;
288 }
289
290 void TypingCommand::markMisspellingsAfterTyping(ETypingCommand commandType)
291 {
292 LocalFrame* frame = document().frame();
293 if (!frame)
294 return;
295
296 if (!frame->spellChecker().isContinuousSpellCheckingEnabled())
297 return;
298
299 frame->spellChecker().cancelCheck();
300
301 // Take a look at the selection that results after typing and determine whet her we need to spellcheck.
302 // Since the word containing the current selection is never marked, this doe s a check to
303 // see if typing made a new word that is not in the current selection. Basic ally, you
304 // get this by being at the end of a word and typing a space.
305 VisiblePosition start(endingSelection().start(), endingSelection().affinity( ));
306 VisiblePosition previous = start.previous();
307
308 VisiblePosition p1 = startOfWord(previous, LeftWordIfOnBoundary);
309
310 if (commandType == InsertParagraphSeparator) {
311 VisiblePosition p2 = nextWordPosition(start);
312 VisibleSelection words(p1, endOfWord(p2));
313 frame->spellChecker().markMisspellingsAfterLineBreak(words);
314 } else if (previous.isNotNull()) {
315 VisiblePosition p2 = startOfWord(start, LeftWordIfOnBoundary);
316 if (p1.deepEquivalent() != p2.deepEquivalent())
317 frame->spellChecker().markMisspellingsAfterTypingToWord(p1, endingSe lection());
318 }
319 }
320
321 void TypingCommand::typingAddedToOpenCommand(ETypingCommand commandTypeForAddedT yping)
322 {
323 LocalFrame* frame = document().frame();
324 if (!frame)
325 return;
326
327 updatePreservesTypingStyle(commandTypeForAddedTyping);
328 updateCommandTypeOfOpenCommand(commandTypeForAddedTyping);
329
330 // The old spellchecking code requires that checking be done first, to preve nt issues like that in 6864072, where <doesn't> is marked as misspelled.
331 markMisspellingsAfterTyping(commandTypeForAddedTyping);
332 frame->editor().appliedEditing(this);
333 }
334
335 void TypingCommand::insertText(const String &text, bool selectInsertedText)
336 {
337 // FIXME: Need to implement selectInsertedText for cases where more than one insert is involved.
338 // This requires support from insertTextRunWithoutNewlines and insertParagra phSeparator for extending
339 // an existing selection; at the moment they can either put the caret after what's inserted or
340 // select what's inserted, but there's no way to "extend selection" to inclu de both an old selection
341 // that ends just before where we want to insert text and the newly inserted text.
342 TypingCommandLineOperation operation(this, selectInsertedText, text);
343 forEachLineInString(text, operation);
344 }
345
346 void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool select InsertedText)
347 {
348 RefPtrWillBeRawPtr<InsertTextCommand> command = InsertTextCommand::create(do cument(), text, selectInsertedText,
349 m_compositionType == TextCompositionNone ? InsertTextCommand::RebalanceL eadingAndTrailingWhitespaces : InsertTextCommand::RebalanceAllWhitespaces);
350
351 applyCommandToComposite(command, endingSelection());
352
353 typingAddedToOpenCommand(InsertText);
354 }
355
356 void TypingCommand::insertLineBreak()
357 {
358 if (!canAppendNewLineFeedToSelection(endingSelection()))
359 return;
360
361 applyCommandToComposite(InsertLineBreakCommand::create(document()));
362 typingAddedToOpenCommand(InsertLineBreak);
363 }
364
365 void TypingCommand::insertParagraphSeparator()
366 {
367 if (!canAppendNewLineFeedToSelection(endingSelection()))
368 return;
369
370 applyCommandToComposite(InsertParagraphSeparatorCommand::create(document())) ;
371 typingAddedToOpenCommand(InsertParagraphSeparator);
372 }
373
374 void TypingCommand::insertParagraphSeparatorInQuotedContent()
375 {
376 // If the selection starts inside a table, just insert the paragraph separat or normally
377 // Breaking the blockquote would also break apart the table, which is uneces sary when inserting a newline
378 if (enclosingNodeOfType(endingSelection().start(), &isTableStructureNode)) {
379 insertParagraphSeparator();
380 return;
381 }
382
383 applyCommandToComposite(BreakBlockquoteCommand::create(document()));
384 typingAddedToOpenCommand(InsertParagraphSeparatorInQuotedContent);
385 }
386
387 bool TypingCommand::makeEditableRootEmpty()
388 {
389 Element* root = endingSelection().rootEditableElement();
390 if (!root || !root->hasChildren())
391 return false;
392
393 if (root->firstChild() == root->lastChild()) {
394 if (isHTMLBRElement(root->firstChild())) {
395 // If there is a single child and it could be a placeholder, leave i t alone.
396 if (root->layoutObject() && root->layoutObject()->isLayoutBlockFlow( ))
397 return false;
398 }
399 }
400
401 while (Node* child = root->firstChild())
402 removeNode(child);
403
404 addBlockPlaceholderIfNeeded(root);
405 setEndingSelection(VisibleSelection(firstPositionInNode(root), DOWNSTREAM, e ndingSelection().isDirectional()));
406
407 return true;
408 }
409
410 void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
411 {
412 LocalFrame* frame = document().frame();
413 if (!frame)
414 return;
415
416 frame->spellChecker().updateMarkersForWordsAffectedByEditing(false);
417
418 VisibleSelection selectionToDelete;
419 VisibleSelection selectionAfterUndo;
420
421 switch (endingSelection().selectionType()) {
422 case RangeSelection:
423 selectionToDelete = endingSelection();
424 selectionAfterUndo = selectionToDelete;
425 break;
426 case CaretSelection: {
427 // After breaking out of an empty mail blockquote, we still want continu e with the deletion
428 // so actual content will get deleted, and not just the quote style.
429 if (breakOutOfEmptyMailBlockquotedParagraph())
430 typingAddedToOpenCommand(DeleteKey);
431
432 m_smartDelete = false;
433
434 OwnPtrWillBeRawPtr<FrameSelection> selection = FrameSelection::create();
435 selection->setSelection(endingSelection());
436 selection->modify(FrameSelection::AlterationExtend, DirectionBackward, g ranularity);
437 if (killRing && selection->isCaret() && granularity != CharacterGranular ity)
438 selection->modify(FrameSelection::AlterationExtend, DirectionBackwar d, CharacterGranularity);
439
440 VisiblePosition visibleStart(endingSelection().visibleStart());
441 if (visibleStart.previous(CannotCrossEditingBoundary).isNull()) {
442 // When the caret is at the start of the editable area in an empty l ist item, break out of the list item.
443 if (breakOutOfEmptyListItem()) {
444 typingAddedToOpenCommand(DeleteKey);
445 return;
446 }
447 // When there are no visible positions in the editing root, delete i ts entire contents.
448 if (visibleStart.next(CannotCrossEditingBoundary).isNull() && makeEd itableRootEmpty()) {
449 typingAddedToOpenCommand(DeleteKey);
450 return;
451 }
452 }
453
454 // If we have a caret selection at the beginning of a cell, we have noth ing to do.
455 Node* enclosingTableCell = enclosingNodeOfType(visibleStart.deepEquivale nt(), &isTableCell);
456 if (enclosingTableCell && visibleStart.deepEquivalent() == VisiblePositi on(firstPositionInNode(enclosingTableCell)).deepEquivalent())
457 return;
458
459 // If the caret is at the start of a paragraph after a table, move conte nt into the last table cell.
460 if (isStartOfParagraph(visibleStart) && isFirstPositionAfterTable(visibl eStart.previous(CannotCrossEditingBoundary))) {
461 // Unless the caret is just before a table. We don't want to move a table into the last table cell.
462 if (isLastPositionBeforeTable(visibleStart))
463 return;
464 // Extend the selection backward into the last cell, then deletion w ill handle the move.
465 selection->modify(FrameSelection::AlterationExtend, DirectionBackwar d, granularity);
466 // If the caret is just after a table, select the table and don't delete anything.
467 } else if (Element* table = isFirstPositionAfterTable(visibleStart)) {
468 setEndingSelection(VisibleSelection(positionBeforeNode(table), endin gSelection().start(), DOWNSTREAM, endingSelection().isDirectional()));
469 typingAddedToOpenCommand(DeleteKey);
470 return;
471 }
472
473 selectionToDelete = selection->selection();
474
475 if (granularity == CharacterGranularity && selectionToDelete.end().compu teContainerNode() == selectionToDelete.start().computeContainerNode()
476 && selectionToDelete.end().computeOffsetInContainerNode() - selectio nToDelete.start().computeOffsetInContainerNode() > 1) {
477 // If there are multiple Unicode code points to be deleted, adjust t he range to match platform conventions.
478 selectionToDelete.setWithoutValidation(selectionToDelete.end(), sele ctionToDelete.end().previous(BackwardDeletion));
479 }
480
481 if (!startingSelection().isRange() || selectionToDelete.base() != starti ngSelection().start()) {
482 selectionAfterUndo = selectionToDelete;
483 } else {
484 // It's a little tricky to compute what the starting selection would have been in the original document.
485 // We can't let the VisibleSelection class's validation kick in or i t'll adjust for us based on
486 // the current state of the document and we'll get the wrong result.
487 selectionAfterUndo.setWithoutValidation(startingSelection().end(), s electionToDelete.extent());
488 }
489 break;
490 }
491 case NoSelection:
492 ASSERT_NOT_REACHED();
493 break;
494 }
495
496 ASSERT(!selectionToDelete.isNone());
497 if (selectionToDelete.isNone())
498 return;
499
500 if (selectionToDelete.isCaret())
501 return;
502
503 if (killRing)
504 frame->editor().addToKillRing(selectionToDelete.toNormalizedEphemeralRan ge());
505 // On Mac, make undo select everything that has been deleted, unless an undo will undo more than just this deletion.
506 // FIXME: This behaves like TextEdit except for the case where you open with text insertion and then delete
507 // more text than you insert. In that case all of the text that was around originally should be selected.
508 if (frame->editor().behavior().shouldUndoOfDeleteSelectText() && m_openedByB ackwardDelete)
509 setStartingSelection(selectionAfterUndo);
510 CompositeEditCommand::deleteSelection(selectionToDelete, m_smartDelete);
511 setSmartDelete(false);
512 typingAddedToOpenCommand(DeleteKey);
513 }
514
515 void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool ki llRing)
516 {
517 LocalFrame* frame = document().frame();
518 if (!frame)
519 return;
520
521 frame->spellChecker().updateMarkersForWordsAffectedByEditing(false);
522
523 VisibleSelection selectionToDelete;
524 VisibleSelection selectionAfterUndo;
525
526 switch (endingSelection().selectionType()) {
527 case RangeSelection:
528 selectionToDelete = endingSelection();
529 selectionAfterUndo = selectionToDelete;
530 break;
531 case CaretSelection: {
532 m_smartDelete = false;
533
534 // Handle delete at beginning-of-block case.
535 // Do nothing in the case that the caret is at the start of a
536 // root editable element or at the start of a document.
537 OwnPtrWillBeRawPtr<FrameSelection> selection = FrameSelection::create();
538 selection->setSelection(endingSelection());
539 selection->modify(FrameSelection::AlterationExtend, DirectionForward, gr anularity);
540 if (killRing && selection->isCaret() && granularity != CharacterGranular ity)
541 selection->modify(FrameSelection::AlterationExtend, DirectionForward , CharacterGranularity);
542
543 Position downstreamEnd = endingSelection().end().downstream();
544 VisiblePosition visibleEnd = endingSelection().visibleEnd();
545 Node* enclosingTableCell = enclosingNodeOfType(visibleEnd.deepEquivalent (), &isTableCell);
546 if (enclosingTableCell && visibleEnd.deepEquivalent() == VisiblePosition (lastPositionInNode(enclosingTableCell)).deepEquivalent())
547 return;
548 if (visibleEnd.deepEquivalent() == endOfParagraph(visibleEnd).deepEquiva lent())
549 downstreamEnd = visibleEnd.next(CannotCrossEditingBoundary).deepEqui valent().downstream();
550 // When deleting tables: Select the table first, then perform the deleti on
551 if (isRenderedTableElement(downstreamEnd.computeContainerNode()) && down streamEnd.computeOffsetInContainerNode() <= caretMinOffset(downstreamEnd.compute ContainerNode())) {
552 setEndingSelection(VisibleSelection(endingSelection().end(), positio nAfterNode(downstreamEnd.computeContainerNode()), DOWNSTREAM, endingSelection(). isDirectional()));
553 typingAddedToOpenCommand(ForwardDeleteKey);
554 return;
555 }
556
557 // deleting to end of paragraph when at end of paragraph needs to merge the next paragraph (if any)
558 if (granularity == ParagraphBoundary && selection->selection().isCaret() && isEndOfParagraph(selection->selection().visibleEnd()))
559 selection->modify(FrameSelection::AlterationExtend, DirectionForward , CharacterGranularity);
560
561 selectionToDelete = selection->selection();
562 if (!startingSelection().isRange() || selectionToDelete.base() != starti ngSelection().start()) {
563 selectionAfterUndo = selectionToDelete;
564 } else {
565 // It's a little tricky to compute what the starting selection would have been in the original document.
566 // We can't let the VisibleSelection class's validation kick in or i t'll adjust for us based on
567 // the current state of the document and we'll get the wrong result.
568 Position extent = startingSelection().end();
569 if (extent.computeContainerNode() != selectionToDelete.end().compute ContainerNode()) {
570 extent = selectionToDelete.extent();
571 } else {
572 int extraCharacters;
573 if (selectionToDelete.start().computeContainerNode() == selectio nToDelete.end().computeContainerNode())
574 extraCharacters = selectionToDelete.end().computeOffsetInCon tainerNode() - selectionToDelete.start().computeOffsetInContainerNode();
575 else
576 extraCharacters = selectionToDelete.end().computeOffsetInCon tainerNode();
577 extent = Position(extent.computeContainerNode(), extent.computeO ffsetInContainerNode() + extraCharacters);
578 }
579 selectionAfterUndo.setWithoutValidation(startingSelection().start(), extent);
580 }
581 break;
582 }
583 case NoSelection:
584 ASSERT_NOT_REACHED();
585 break;
586 }
587
588 ASSERT(!selectionToDelete.isNone());
589 if (selectionToDelete.isNone())
590 return;
591
592 if (selectionToDelete.isCaret())
593 return;
594
595 if (killRing)
596 frame->editor().addToKillRing(selectionToDelete.toNormalizedEphemeralRan ge());
597 // Make undo select what was deleted on Mac alone
598 if (frame->editor().behavior().shouldUndoOfDeleteSelectText())
599 setStartingSelection(selectionAfterUndo);
600 CompositeEditCommand::deleteSelection(selectionToDelete, m_smartDelete);
601 setSmartDelete(false);
602 typingAddedToOpenCommand(ForwardDeleteKey);
603 }
604
605 void TypingCommand::deleteSelection(bool smartDelete)
606 {
607 CompositeEditCommand::deleteSelection(smartDelete);
608 typingAddedToOpenCommand(DeleteSelection);
609 }
610
611 void TypingCommand::updatePreservesTypingStyle(ETypingCommand commandType)
612 {
613 switch (commandType) {
614 case DeleteSelection:
615 case DeleteKey:
616 case ForwardDeleteKey:
617 case InsertParagraphSeparator:
618 case InsertLineBreak:
619 m_preservesTypingStyle = true;
620 return;
621 case InsertParagraphSeparatorInQuotedContent:
622 case InsertText:
623 m_preservesTypingStyle = false;
624 return;
625 }
626 ASSERT_NOT_REACHED();
627 m_preservesTypingStyle = false;
628 }
629
630 bool TypingCommand::isTypingCommand() const
631 {
632 return true;
633 }
634
635 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698