Crash in CompositeEditCommand::ensureComposition
https://bugs.webkit.org/show_bug.cgi?id=76207

Reviewed by Chang Shu.

Source/WebCore: 

The crash was caused by TypingCommand not kept alive when new editing commands are executed
during adding more typings to the open last typing command since m_lastEditCommand is replaced
by the new command. Fixed the bug by keeping them alive a little longer with RefPtr.

Test: editing/execCommand/editing-command-while-executing-typing-command-crash.html

* editing/FrameSelection.cpp:
(WebCore::shouldStopBlinkingDueToTypingCommand):
(WebCore::FrameSelection::updateAppearance):
* editing/TypingCommand.cpp:
(WebCore::TypingCommand::deleteSelection):
(WebCore::TypingCommand::deleteKeyPressed):
(WebCore::TypingCommand::forwardDeleteKeyPressed):
(WebCore::TypingCommand::insertText):
(WebCore::TypingCommand::insertLineBreak):
(WebCore::TypingCommand::insertParagraphSeparatorInQuotedContent):
(WebCore::TypingCommand::insertParagraphSeparator):
(WebCore::TypingCommand::lastTypingCommandIfStillOpenForTyping):
(WebCore::TypingCommand::closeTyping):
* editing/TypingCommand.h:

LayoutTests: 

Add a regression test.

* editing/execCommand/editing-command-while-executing-typing-command-crash-expected.txt: Added.
* editing/execCommand/editing-command-while-executing-typing-command-crash.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@105441 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp
index 1ee0033..4101ecf 100644
--- a/Source/WebCore/editing/TypingCommand.cpp
+++ b/Source/WebCore/editing/TypingCommand.cpp
@@ -87,7 +87,7 @@
     if (!frame->selection()->isRange())
         return;
 
-    if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame)) {
+    if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame)) {
         lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
         lastTypingCommand->deleteSelection(options & SmartDelete);
         return;
@@ -100,8 +100,8 @@
 {
     ASSERT(document);
     if (granularity == CharacterGranularity) {
-        if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
-            updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand, document->frame());
+        if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
+            updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand.get(), document->frame());
             lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
             lastTypingCommand->deleteKeyPressed(granularity, options & KillRing);
             return;
@@ -117,8 +117,8 @@
     ASSERT(document);
     Frame* frame = document->frame();
     if (granularity == CharacterGranularity) {
-        if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame)) {
-            updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand, frame);
+        if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame)) {
+            updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand.get(), frame);
             lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
             lastTypingCommand->forwardDeleteKeyPressed(granularity, options & KillRing);
             return;
@@ -176,7 +176,7 @@
     // Set the starting and ending selection appropriately if we are using a selection
     // that is different from the current selection.  In the future, we should change EditCommand
     // to deal with custom selections in a general way that can be used by all of the commands.
-    if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame.get())) {
+    if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame.get())) {
         if (lastTypingCommand->endingSelection() != selectionForInsertion) {
             lastTypingCommand->setStartingSelection(selectionForInsertion);
             lastTypingCommand->setEndingSelection(selectionForInsertion);
@@ -204,7 +204,7 @@
 void TypingCommand::insertLineBreak(Document *document, Options options)
 {
     ASSERT(document);
-    if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
+    if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
         lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
         lastTypingCommand->insertLineBreak();
         return;
@@ -216,7 +216,7 @@
 void TypingCommand::insertParagraphSeparatorInQuotedContent(Document *document)
 {
     ASSERT(document);
-    if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
+    if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
         lastTypingCommand->insertParagraphSeparatorInQuotedContent();
         return;
     }
@@ -227,7 +227,7 @@
 void TypingCommand::insertParagraphSeparator(Document *document, Options options)
 {
     ASSERT(document);
-    if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
+    if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document->frame())) {
         lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
         lastTypingCommand->insertParagraphSeparator();
         return;
@@ -236,20 +236,20 @@
     applyCommand(TypingCommand::create(document, InsertParagraphSeparator, "", options));
 }
 
-TypingCommand* TypingCommand::lastTypingCommandIfStillOpenForTyping(Frame* frame)
+PassRefPtr<TypingCommand> TypingCommand::lastTypingCommandIfStillOpenForTyping(Frame* frame)
 {
     ASSERT(frame);
 
-    CompositeEditCommand* lastEditCommand = frame->editor()->lastEditCommand();
-    if (!lastEditCommand || !lastEditCommand->isTypingCommand() || !static_cast<TypingCommand*>(lastEditCommand)->isOpenForMoreTyping())
+    RefPtr<CompositeEditCommand> lastEditCommand = frame->editor()->lastEditCommand();
+    if (!lastEditCommand || !lastEditCommand->isTypingCommand() || !static_cast<TypingCommand*>(lastEditCommand.get())->isOpenForMoreTyping())
         return 0;
 
-    return static_cast<TypingCommand*>(lastEditCommand);
+    return static_cast<TypingCommand*>(lastEditCommand.get());
 }
 
 void TypingCommand::closeTyping(Frame* frame)
 {
-    if (TypingCommand* lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame))
+    if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(frame))
         lastTypingCommand->closeTyping();
 }