AX: new lines in content editable elements don't notify accessibility
https://bugs.webkit.org/show_bug.cgi?id=153361
Reviewed by Ryosuke Niwa.
Relocate accessibility edit notification logic into higher level logic.
Typing notifications relocated into TypingCommand.
Cut & Paste notifications relocated into Editor.
Undo relocated into EditCommandComposition.
Tests: accessibility/mac/value-change/value-change-user-info-contenteditable.html
accessibility/mac/value-change/value-change-user-info-textarea.html
accessibility/mac/value-change/value-change-user-info-textfield.html
* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
* accessibility/AXObjectCache.cpp:
(WebCore::AccessibilityReplacedText::AccessibilityReplacedText):
(WebCore::AccessibilityReplacedText::postTextStateChangeNotification):
(WebCore::AXObjectCache::postTextStateChangeNotification):
(WebCore::AXObjectCache::postTextReplacementNotification):
* accessibility/AXObjectCache.h:
(WebCore::VisiblePositionIndexRange::isNull):
(WebCore::AccessibilityReplacedText::AccessibilityReplacedText):
(WebCore::AccessibilityReplacedText::replacedRange):
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::listMarkerTextForNodeAndPosition):
(WebCore::AccessibilityObject::stringForVisiblePositionRange):
* accessibility/AccessibilityObject.h:
(WebCore::VisiblePositionRange::VisiblePositionRange):
* accessibility/mac/AXObjectCacheMac.mm:
(WebCore::AXObjectCache::postTextStateChangePlatformNotification):
(WebCore::AXObjectCache::postTextReplacementPlatformNotification):
* editing/AppendNodeCommand.cpp:
(WebCore::AppendNodeCommand::doApply): Deleted.
(WebCore::AppendNodeCommand::doUnapply): Deleted.
* editing/CompositeEditCommand.cpp:
(WebCore::AccessibilityUndoReplacedText::indexForVisiblePosition):
(WebCore::AccessibilityUndoReplacedText::confgureTextToBeDeletedByUnapplyIndexesWithEditCommandEndingSelection):
(WebCore::AccessibilityUndoReplacedText::confgureTextToBeDeletedByUnapplyStartIndexWithEditCommandStartingSelection):
(WebCore::AccessibilityUndoReplacedText::setTextInsertedByUnapplyRange):
(WebCore::AccessibilityUndoReplacedText::captureTextToBeDeletedByUnapply):
(WebCore::AccessibilityUndoReplacedText::captureTextToBeDeletedByReapply):
(WebCore::stringForVisiblePositionIndexRange):
(WebCore::AccessibilityUndoReplacedText::textInsertedByUnapply):
(WebCore::AccessibilityUndoReplacedText::textInsertedByReapply):
(WebCore::postTextStateChangeNotification):
(WebCore::AccessibilityUndoReplacedText::postTextStateChangeNotificationForUnapply):
(WebCore::AccessibilityUndoReplacedText::postTextStateChangeNotificationForReapply):
(WebCore::EditCommandComposition::EditCommandComposition):
(WebCore::EditCommandComposition::unapply):
(WebCore::EditCommandComposition::reapply):
(WebCore::EditCommandComposition::setStartingSelection):
(WebCore::EditCommandComposition::setEndingSelection):
(WebCore::EditCommandComposition::setTextInsertedByUnapplyRange):
(WebCore::CompositeEditCommand::removeNode):
(WebCore::CompositeEditCommand::replaceTextInNode):
(WebCore::deleteSelectionEditingActionForEditingAction):
(WebCore::CompositeEditCommand::deleteSelection):
(WebCore::CompositeEditCommand::applyStyle): Deleted.
(WebCore::CompositeEditCommand::updatePositionForNodeRemovalPreservingChildren): Deleted.
(WebCore::CompositeEditCommand::inputText): Deleted.
* editing/CompositeEditCommand.h:
(WebCore::AccessibilityUndoReplacedText::AccessibilityUndoReplacedText):
* editing/DeleteFromTextNodeCommand.cpp:
(WebCore::DeleteFromTextNodeCommand::doApply): Deleted.
(WebCore::DeleteFromTextNodeCommand::getNodesInCommand): Deleted.
* editing/DeleteFromTextNodeCommand.h:
* editing/DictationCommand.cpp:
(WebCore::DictationCommand::doApply):
* editing/EditCommand.cpp:
(WebCore::EditCommand::postTextStateChangeNotification):
(WebCore::SimpleEditCommand::SimpleEditCommand): Deleted.
(WebCore::SimpleEditCommand::doReapply): Deleted.
(WebCore::SimpleEditCommand::addNodeAndDescendants): Deleted.
* editing/EditCommand.h:
* editing/EditingAllInOne.cpp:
* editing/Editor.cpp:
(WebCore::Editor::replaceSelectionWithFragment):
(WebCore::Editor::appliedEditing):
(WebCore::Editor::unappliedEditing):
(WebCore::Editor::postTextStateChangeNotificationForCut):
(WebCore::Editor::performCutOrCopy):
(WebCore::Editor::changeSelectionAfterCommand):
(WebCore::dispatchEditableContentChangedEvents): Deleted.
(WebCore::Editor::addTextToKillRing): Deleted.
* editing/Editor.h:
* editing/InsertIntoTextNodeCommand.cpp:
(WebCore::InsertIntoTextNodeCommand::doApply): Deleted.
(WebCore::InsertIntoTextNodeCommand::getNodesInCommand): Deleted.
* editing/InsertNodeBeforeCommand.cpp:
(WebCore::InsertNodeBeforeCommand::doApply): Deleted.
(WebCore::InsertNodeBeforeCommand::doUnapply): Deleted.
(WebCore::InsertNodeBeforeCommand::getNodesInCommand): Deleted.
* editing/RemoveNodeCommand.cpp:
(WebCore::RemoveNodeCommand::RemoveNodeCommand):
* editing/RemoveNodeCommand.h:
(WebCore::RemoveNodeCommand::create):
* editing/ReplaceDeleteFromTextNodeCommand.cpp: Removed.
* editing/ReplaceDeleteFromTextNodeCommand.h: Removed.
* editing/ReplaceInsertIntoTextNodeCommand.cpp: Removed.
* editing/ReplaceInsertIntoTextNodeCommand.h: Removed.
* editing/ReplaceSelectionCommand.cpp:
(WebCore::ReplaceSelectionCommand::doApply):
(WebCore::ReplaceSelectionCommand::completeHTMLReplacement):
(WebCore::ReplaceSelectionCommand::performTrivialReplace):
* editing/ReplaceSelectionCommand.h:
(WebCore::ReplaceSelectionCommand::visibleSelectionForInsertedText):
* editing/TextInsertionBaseCommand.cpp:
(WebCore::TextInsertionBaseCommand::TextInsertionBaseCommand):
* editing/TextInsertionBaseCommand.h:
* editing/TypingCommand.cpp:
(WebCore::TypingCommand::TypingCommand):
(WebCore::TypingCommand::insertText):
(WebCore::TypingCommand::insertLineBreak):
(WebCore::TypingCommand::insertParagraphSeparatorInQuotedContent):
(WebCore::TypingCommand::insertParagraphSeparator):
(WebCore::TypingCommand::postTextStateChangeNotificationForDeletion):
(WebCore::TypingCommand::doApply):
(WebCore::TypingCommand::insertTextAndNotifyAccessibility):
(WebCore::TypingCommand::insertLineBreakAndNotifyAccessibility):
(WebCore::TypingCommand::insertParagraphSeparatorAndNotifyAccessibility):
(WebCore::TypingCommand::insertParagraphSeparatorInQuotedContentAndNotifyAccessibility):
(WebCore::TypingCommand::deleteKeyPressed):
(WebCore::TypingCommand::forwardDeleteKeyPressed):
* editing/TypingCommand.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@199030 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp
index 15b4f85..2198907 100644
--- a/Source/WebCore/editing/TypingCommand.cpp
+++ b/Source/WebCore/editing/TypingCommand.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "TypingCommand.h"
+#include "AXObjectCache.h"
#include "BreakBlockquoteCommand.h"
#include "DeleteSelectionCommand.h"
#include "Document.h"
@@ -75,7 +76,7 @@
};
TypingCommand::TypingCommand(Document& document, ETypingCommand commandType, const String &textToInsert, Options options, TextGranularity granularity, TextCompositionType compositionType)
- : TextInsertionBaseCommand(document)
+ : TextInsertionBaseCommand(document, EditActionTyping)
, m_commandType(commandType)
, m_textToInsert(textToInsert)
, m_openForMoreTyping(true)
@@ -182,7 +183,7 @@
lastTypingCommand->setCompositionType(compositionType);
lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
- lastTypingCommand->insertText(newText, options & SelectInsertedText);
+ lastTypingCommand->insertTextAndNotifyAccessibility(newText, options & SelectInsertedText);
return;
}
@@ -194,7 +195,7 @@
{
if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(*document.frame())) {
lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
- lastTypingCommand->insertLineBreak();
+ lastTypingCommand->insertLineBreakAndNotifyAccessibility();
return;
}
@@ -204,7 +205,7 @@
void TypingCommand::insertParagraphSeparatorInQuotedContent(Document& document)
{
if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(*document.frame())) {
- lastTypingCommand->insertParagraphSeparatorInQuotedContent();
+ lastTypingCommand->insertParagraphSeparatorInQuotedContentAndNotifyAccessibility();
return;
}
@@ -215,7 +216,7 @@
{
if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(*document.frame())) {
lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
- lastTypingCommand->insertParagraphSeparator();
+ lastTypingCommand->insertParagraphSeparatorAndNotifyAccessibility();
return;
}
@@ -247,6 +248,17 @@
}
#endif
+void TypingCommand::postTextStateChangeNotificationForDeletion(const VisibleSelection& selection)
+{
+ if (!AXObjectCache::accessibilityEnabled())
+ return;
+ postTextStateChangeNotification(AXTextEditTypeDelete, AccessibilityObject::stringForVisiblePositionRange(selection), selection.start());
+ VisiblePositionIndexRange range;
+ range.startIndex.value = indexForVisiblePosition(selection.start(), range.startIndex.scope);
+ range.endIndex.value = indexForVisiblePosition(selection.end(), range.endIndex.scope);
+ composition()->setTextInsertedByUnapplyRange(range);
+}
+
void TypingCommand::doApply()
{
if (!endingSelection().isNonOrphanedCaretOrRange())
@@ -267,27 +279,22 @@
forwardDeleteKeyPressed(m_granularity, m_shouldAddToKillRing);
return;
case InsertLineBreak:
- insertLineBreak();
+ insertLineBreakAndNotifyAccessibility();
return;
case InsertParagraphSeparator:
- insertParagraphSeparator();
+ insertParagraphSeparatorAndNotifyAccessibility();
return;
case InsertParagraphSeparatorInQuotedContent:
- insertParagraphSeparatorInQuotedContent();
+ insertParagraphSeparatorInQuotedContentAndNotifyAccessibility();
return;
case InsertText:
- insertText(m_textToInsert, m_selectInsertedText);
+ insertTextAndNotifyAccessibility(m_textToInsert, m_selectInsertedText);
return;
}
ASSERT_NOT_REACHED();
}
-EditAction TypingCommand::editingAction() const
-{
- return EditActionTyping;
-}
-
void TypingCommand::markMisspellingsAfterTyping(ETypingCommand commandType)
{
Frame& frame = this->frame();
@@ -371,6 +378,14 @@
forEachLineInString(text, operation);
}
+void TypingCommand::insertTextAndNotifyAccessibility(const String &text, bool selectInsertedText)
+{
+ AccessibilityReplacedText replacedText(frame().selection().selection());
+ insertText(text, selectInsertedText);
+ replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, text, frame().selection().selection());
+ composition()->setTextInsertedByUnapplyRange(replacedText.replacedRange());
+}
+
void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool selectInsertedText)
{
RefPtr<InsertTextCommand> command = InsertTextCommand::create(document(), text, selectInsertedText,
@@ -390,6 +405,14 @@
typingAddedToOpenCommand(InsertLineBreak);
}
+void TypingCommand::insertLineBreakAndNotifyAccessibility()
+{
+ AccessibilityReplacedText replacedText(frame().selection().selection());
+ insertLineBreak();
+ replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, "\n", frame().selection().selection());
+ composition()->setTextInsertedByUnapplyRange(replacedText.replacedRange());
+}
+
void TypingCommand::insertParagraphSeparator()
{
if (!canAppendNewLineFeedToSelection(endingSelection()))
@@ -399,6 +422,14 @@
typingAddedToOpenCommand(InsertParagraphSeparator);
}
+void TypingCommand::insertParagraphSeparatorAndNotifyAccessibility()
+{
+ AccessibilityReplacedText replacedText(frame().selection().selection());
+ insertParagraphSeparator();
+ replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, "\n", frame().selection().selection());
+ composition()->setTextInsertedByUnapplyRange(replacedText.replacedRange());
+}
+
void TypingCommand::insertParagraphSeparatorInQuotedContent()
{
// If the selection starts inside a table, just insert the paragraph separator normally
@@ -412,6 +443,14 @@
typingAddedToOpenCommand(InsertParagraphSeparatorInQuotedContent);
}
+void TypingCommand::insertParagraphSeparatorInQuotedContentAndNotifyAccessibility()
+{
+ AccessibilityReplacedText replacedText(frame().selection().selection());
+ insertParagraphSeparatorInQuotedContent();
+ replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, "\n", frame().selection().selection());
+ composition()->setTextInsertedByUnapplyRange(replacedText.replacedRange());
+}
+
bool TypingCommand::makeEditableRootEmpty()
{
Element* root = endingSelection().rootEditableElement();
@@ -532,6 +571,10 @@
if (shouldAddToKillRing)
frame.editor().addRangeToKillRing(*selectionToDelete.toNormalizedRange().get(), Editor::KillRingInsertionMode::PrependText);
+
+ // Post the accessibility notification before actually deleting the content while selectionToDelete is still valid
+ postTextStateChangeNotificationForDeletion(selectionToDelete);
+
// Make undo select everything that has been deleted, unless an undo will undo more than just this deletion.
// FIXME: This behaves like TextEdit except for the case where you open with text insertion and then delete
// more text than you insert. In that case all of the text that was around originally should be selected.
@@ -628,6 +671,9 @@
if (selectionToDelete.isCaret() || !frame.selection().shouldDeleteSelection(selectionToDelete))
return;
+ // Post the accessibility notification before actually deleting the content while selectionToDelete is still valid
+ postTextStateChangeNotificationForDeletion(selectionToDelete);
+
if (shouldAddToKillRing)
frame.editor().addRangeToKillRing(*selectionToDelete.toNormalizedRange().get(), Editor::KillRingInsertionMode::AppendText);
// make undo select what was deleted