Commit e1c1a77e authored by jpu@apple.com's avatar jpu@apple.com

Mark text with text alternative with blue underline.

https://bugs.webkit.org/show_bug.cgi?id=83047

Reviewed by Enrica Casucci.

Tests: platform/mac/editing/input/edit-dictated-text-with-alternative.html
       platform/mac/editing/input/insert-dictated-text.html

This patch implements visual indication on dictated text with alternatives, and provides UI
to show alternative text on OS X. Majority of the changes is for generalizing existing AlternativeTextController
class to handle dictation alternatives. The two new classes, AlternativeTextUIController and
TextAlternativeWithRange, are used by both WebKit and WK2. So WebCore seems to be the natural place
for them.

* WebCore.exp.in:
* WebCore.xcodeproj/project.pbxproj:
* editing/AlternativeTextController.cpp: Expanded exising class interface to support dictation alternatives.
(DictationAlternativeDetails): Marker detail class for dictation alternative mark.
(WebCore::DictationAlternativeDetails::create):
(WebCore::DictationAlternativeDetails::dictationContext):
(WebCore::DictationAlternativeDetails::DictationAlternativeDetails):
(WebCore::markerTypesForAppliedDictationAlternative):
(WebCore::AlternativeTextController::applyAlternativeTextToRange): Generalized existing applyAlternativeTextToRange() to handle dictation alternatives.
(WebCore::AlternativeTextController::timerFired): Expanded existing code to handle dictation alternatives.
(WebCore::AlternativeTextController::handleAlternativeTextUIResult): Expanded existing code to handle dictation alternatives.
(WebCore::AlternativeTextController::respondToChangedSelection): Moved part of the function into respondToMarkerAtEndOfWord() to improve readability.
(WebCore::AlternativeTextController::shouldStartTimerFor):
(WebCore::AlternativeTextController::respondToMarkerAtEndOfWord):
(WebCore::AlternativeTextController::markerDescriptionForAppliedAlternativeText):
(WebCore::AlternativeTextController::removeDictationAlternativesForMarker):
(WebCore::AlternativeTextController::dictationAlternativesForMarker):
(WebCore::AlternativeTextController::applyDictationAlternative):
* editing/AlternativeTextController.h:
* editing/Editor.cpp:
(WebCore::Editor::notifyComponentsOnChangedSelection): Renamed existing respondToChangedSelection() function to avoid naming collision.
(WebCore::Editor::appliedEditing):
(WebCore::Editor::unappliedEditing):
(WebCore::Editor::reappliedEditing):
(WebCore::Editor::updateMarkersForWordsAffectedByEditing):
(WebCore::Editor::changeSelectionAfterCommand):
(WebCore::Editor::respondToChangedSelection):
(WebCore::Editor::dictationAlternativesForMarker):
(WebCore::Editor::applyDictationAlternativelternative):
* editing/Editor.h:
* editing/FrameSelection.h:
* editing/mac/AlternativeTextUIController.h: Added. WK1 and WK2 use this class to keep track of text alternatives objects.
(AlternativeTextUIController):
(WebCore::AlternativeTextUIController::AlternativeTextUIController):
(AlernativeTextContextController):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::AlernativeTextContextController):
* editing/mac/AlternativeTextUIController.mm: Added.
(WebCore::AlternativeTextUIController::AlernativeTextContextController::addAlternatives):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::alternativesForContext):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::removeAlternativesForContext):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::clear):
(WebCore::AlternativeTextUIController::addAlternatives):
(WebCore::AlternativeTextUIController::alternativesForContext):
(WebCore::AlternativeTextUIController::clear):
(WebCore::AlternativeTextUIController::showAlternatives):
(WebCore::AlternativeTextUIController::handleAcceptedAlternative):
(WebCore::AlternativeTextUIController::dismissAlternatives):
(WebCore::AlternativeTextUIController::removeAlternatives):
* editing/mac/TextAlternativeWithRange.h: Added.  A simple struct to make it easier to pass around a pair of text alternatives object and range.
* editing/mac/TextAlternativeWithRange.mm: Added.
(WebCore::TextAlternativeWithRange::TextAlternativeWithRange):
(WebCore::collectDictationTextAlternatives):
* page/AlternativeTextClient.h:
* page/ContextMenuController.cpp: Added code to show alternative dictated text in context menu.
(WebCore::ContextMenuController::contextMenuItemSelected):
(WebCore::ContextMenuController::populate):
(WebCore::ContextMenuController::checkOrEnableIfNeeded):
* platform/ContextMenuItem.h:
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::dictationAlternatives):
* rendering/HitTestResult.h:
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paintDocumentMarker):

Changes in WebKit include implementation of new functions declared in AlternativeTextClient,
and logic for calling Editor::insertDictatedText() instead of Editor::insertText() when there's
alternatives attached to the input string.

* WebCoreSupport/CorrectionPanel.mm:
(correctionIndicatorType):
(CorrectionPanel::handleAcceptedReplacement):
* WebCoreSupport/WebAlternativeTextClient.h:
(WebAlternativeTextClient):
* WebCoreSupport/WebAlternativeTextClient.mm:
(WebAlternativeTextClient::showCorrectionAlternative):
(WebAlternativeTextClient::dismissAlternative):
(WebAlternativeTextClient::dismissAlternativeSoon):
(WebAlternativeTextClient::recordAutocorrectionResponse):
(WebAlternativeTextClient::removeDictationAlternatives):
(WebAlternativeTextClient::showDictationAlternativeUI):
(WebAlternativeTextClient::dismissDictationAlternativeUI):
(WebAlternativeTextClient::dictationAlternatives):
* WebView/WebHTMLView.mm:
(-[WebHTMLView validAttributesForMarkedText]):
(-[WebHTMLView insertText:]):
* WebView/WebView.mm:
(-[WebView handleAcceptedAlternativeText:]):
(-[WebView _getWebCoreDictationAlternatives:fromTextAlternatives:]):
(-[WebView _showDictationAlternativeUI:WebCore::forDictationContext:]):
(-[WebView _dismissDictationAlternativeUI]):
(-[WebView _removeDictationAlternatives:]):
(-[WebView _dictationAlternatives:]):
* WebView/WebViewData.h:
* WebView/WebViewData.mm:
(-[WebViewPrivate init]):
* WebView/WebViewInternal.h:
* WebView/WebViewPrivate.h:

Changes in WebKit2 include implementation of new functions declared in AlternativeTextClient,
and logic for calling Editor::insertDictatedText() instead of Editor::insertText() when there's
alternatives attached to the input string.

* Shared/API/c/WKContextMenuItemTypes.h:
* Shared/API/c/WKSharedAPICast.h:
* Shared/WebCoreArgumentCoders.cpp:
* Shared/WebCoreArgumentCoders.h:
* UIProcess/API/mac/PageClientImpl.h:
* UIProcess/API/mac/PageClientImpl.mm:
(WebKit::PageClientImpl::PageClientImpl):
(WebKit::PageClientImpl::pageClosed):
(WebKit::PageClientImpl::addDictationAlternatives):
(WebKit::PageClientImpl::removeDictationAlternatives):
(WebKit::PageClientImpl::showDictationAlternativeUI):
(WebKit::PageClientImpl::dictationAlternatives):
(WebKit::PageClientImpl::dismissDictationAlternativeUI):
* UIProcess/API/mac/WKView.mm:
(-[WKView insertText:replacementRange:]):
(-[WKView validAttributesForMarkedText]):
(-[WKView handleAcceptedAlternativeText:]):
* UIProcess/API/mac/WKViewInternal.h:
* UIProcess/PageClient.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::showDictationAlternativeUI):
(WebKit::WebPageProxy::dismissDictationAlternativeUI):
(WebKit::WebPageProxy::removeDictationAlternatives):
(WebKit::WebPageProxy::dictationAlternatives):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/mac/CorrectionPanel.mm:
(correctionIndicatorType):
(WebKit::CorrectionPanel::handleAcceptedReplacement):
* UIProcess/mac/WebPageProxyMac.mm:
(WebKit::WebPageProxy::insertDictatedText):
* WebProcess/WebCoreSupport/WebAlternativeTextClient.h:
(WebAlternativeTextClient):
* WebProcess/WebCoreSupport/mac/WebAlternativeTextClient.cpp:
(WebKit::WebAlternativeTextClient::showCorrectionAlternative):
(WebKit::WebAlternativeTextClient::dismissAlternative):
(WebKit::WebAlternativeTextClient::dismissAlternativeSoon):
(WebKit::WebAlternativeTextClient::recordAutocorrectionResponse):
(WebKit::WebAlternativeTextClient::removeDictationAlternatives):
(WebKit::WebAlternativeTextClient::showDictationAlternativeUI):
(WebKit::WebAlternativeTextClient::dismissDictationAlternativeUI):
(WebKit::WebAlternativeTextClient::dictationAlternatives):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::insertDictatedText):

* platform/mac-lion/Skipped:
* platform/mac-snowleopard/Skipped:
* platform/mac/editing/input/edit-dictated-text-with-alternative-expected.txt: Added.
* platform/mac/editing/input/edit-dictated-text-with-alternative.html: Added.
* platform/mac/editing/input/insert-dictated-text-expected.txt: Added.
* platform/mac/editing/input/insert-dictated-text.html: Added.

* DumpRenderTree/mac/TextInputController.m:
(+[TextInputController isSelectorExcludedFromWebScript:]):
(+[TextInputController webScriptNameForSelector:]):
(-[TextInputController dictatedStringWithPrimaryString:alternative:alternativeOffset:alternativeLength:]):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@120357 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3627271f
2012-06-14 Jia Pu <jpu@apple.com>
Mark text with text alternative with blue underline.
https://bugs.webkit.org/show_bug.cgi?id=83047
Reviewed by Enrica Casucci.
* platform/mac-lion/Skipped:
* platform/mac-snowleopard/Skipped:
* platform/mac/editing/input/edit-dictated-text-with-alternative-expected.txt: Added.
* platform/mac/editing/input/edit-dictated-text-with-alternative.html: Added.
* platform/mac/editing/input/insert-dictated-text-expected.txt: Added.
* platform/mac/editing/input/insert-dictated-text.html: Added.
2012-06-14 Emil A Eklund <eae@chromium.org>
Change RenderTableSection::calcRowLogicalHeight to round rather than floor height
......
......@@ -35,6 +35,10 @@ editing/text-iterator/findString-selection-disabled.html
# Pasting replaces the three periods with an ellipsis on Lion
editing/pasteboard/5478250.html
# Mountain Lion functionalities
platform/mac/editing/input/edit-dictated-text-with-alternative.html
platform/mac/editing/input/insert-dictated-text.html
# --- Media ---
# These need investigation
......
......@@ -211,3 +211,7 @@ fast/sub-pixel/file-upload-control-at-fractional-offset.html
# Frame::findString does nothing on pages that prevent selection
# https://bugs.webkit.org/show_bug.cgi?id=40361
editing/text-iterator/findString-selection-disabled.html
# Dictated text input is not supported on this platform
platform/mac/editing/input/edit-dictated-text-with-alternative.html
platform/mac/editing/input/insert-dictated-text.html
Editing text that has DictationAlternatives marker whould cause the marker to be removed.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
this is a tex
PASS markedText is ""
TEST COMPLETE
<html>
<head>
<script src="../../../../fast/js/resources/js-test-pre.js"></script>
<style>
body { margin: 0; padding: 0 }
</style>
</head>
<body>
<pre id="description"></pre>
<div id="test" contenteditable></div>
<p id="console"></p>
<script type="text/javascript">
description("Editing text that has DictationAlternatives marker whould cause the marker to be removed.");
var console_messages = document.createElement("ol");
function log(message)
{
var item = document.createElement("li");
item.appendChild(document.createTextNode(message));
console_messages.appendChild(item);
}
if (window.layoutTestController) {
try {
layoutTestController.dumpAsText();
var testArea = document.getElementById("test");
testArea.focus();
var dictatedString = textInputController.makeDictatedString("this is a text", "test", 10, 4);
document.execCommand("SelectAll");
textInputController.insertText(dictatedString);
textInputController.doCommand("deleteBackward:");
var markedText = "";
if (window.internals) {
var testText = testArea.firstChild;
var marked = internals.markerRangeForNode(testText, "DictationAlternatives", 0);
if (marked)
markedText = marked.toString();
}
shouldBeEqualToString("markedText", "");
document.write("TEST COMPLETE");
} catch (ex) {
document.write("Exception: " + ex.description);
}
document.getElementById("console").appendChild(console_messages);
} else {
document.write("(cannot run interactively)");
}
</script>
</body>
</html>
When inserting dictated text, range of text that has alternative text is attached as DictationAlternatives marker.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
this is a text
PASS markedText is "text"
TEST COMPLETE
<html>
<head>
<script src="../../../../fast/js/resources/js-test-pre.js"></script>
<style>
body { margin: 0; padding: 0 }
</style>
</head>
<body>
<pre id="description"></pre>
<div id="test" contenteditable></div>
<p id="console"></p>
<script type="text/javascript">
description("When inserting dictated text, range of text that has alternative text is attached as DictationAlternatives marker.");
var console_messages = document.createElement("ol");
function log(message)
{
var item = document.createElement("li");
item.appendChild(document.createTextNode(message));
console_messages.appendChild(item);
}
if (window.layoutTestController) {
try {
layoutTestController.dumpAsText();
var testArea = document.getElementById("test");
testArea.focus();
var dictatedString = textInputController.makeDictatedString("this is a text", "test", 10, 4);
document.execCommand("SelectAll");
textInputController.insertText(dictatedString);
var markedText = "";
if (window.internals) {
var testText = testArea.firstChild;
var marked = internals.markerRangeForNode(testText, "DictationAlternatives", 0);
if (marked)
markedText = marked.toString();
}
shouldBeEqualToString("markedText", "text");
document.write("TEST COMPLETE");
} catch (ex) {
document.write("Exception: " + ex.description);
}
document.getElementById("console").appendChild(console_messages);
} else {
document.write("(cannot run interactively)");
}
</script>
</body>
</html>
2012-06-14 Jia Pu <jpu@apple.com>
Mark text with text alternative with blue underline.
https://bugs.webkit.org/show_bug.cgi?id=83047
Reviewed by Enrica Casucci.
Tests: platform/mac/editing/input/edit-dictated-text-with-alternative.html
platform/mac/editing/input/insert-dictated-text.html
This patch implements visual indication on dictated text with alternatives, and provides UI
to show alternative text on OS X. Majority of the changes is for generalizing existing AlternativeTextController
class to handle dictation alternatives. The two new classes, AlternativeTextUIController and
TextAlternativeWithRange, are used by both WebKit and WK2. So WebCore seems to be the natural place
for them.
* WebCore.exp.in:
* WebCore.xcodeproj/project.pbxproj:
* editing/AlternativeTextController.cpp: Expanded exising class interface to support dictation alternatives.
(DictationAlternativeDetails): Marker detail class for dictation alternative mark.
(WebCore::DictationAlternativeDetails::create):
(WebCore::DictationAlternativeDetails::dictationContext):
(WebCore::DictationAlternativeDetails::DictationAlternativeDetails):
(WebCore::markerTypesForAppliedDictationAlternative):
(WebCore::AlternativeTextController::applyAlternativeTextToRange): Generalized existing applyAlternativeTextToRange() to handle dictation alternatives.
(WebCore::AlternativeTextController::timerFired): Expanded existing code to handle dictation alternatives.
(WebCore::AlternativeTextController::handleAlternativeTextUIResult): Expanded existing code to handle dictation alternatives.
(WebCore::AlternativeTextController::respondToChangedSelection): Moved part of the function into respondToMarkerAtEndOfWord() to improve readability.
(WebCore::AlternativeTextController::shouldStartTimerFor):
(WebCore::AlternativeTextController::respondToMarkerAtEndOfWord):
(WebCore::AlternativeTextController::markerDescriptionForAppliedAlternativeText):
(WebCore::AlternativeTextController::removeDictationAlternativesForMarker):
(WebCore::AlternativeTextController::dictationAlternativesForMarker):
(WebCore::AlternativeTextController::applyDictationAlternative):
* editing/AlternativeTextController.h:
* editing/Editor.cpp:
(WebCore::Editor::notifyComponentsOnChangedSelection): Renamed existing respondToChangedSelection() function to avoid naming collision.
(WebCore::Editor::appliedEditing):
(WebCore::Editor::unappliedEditing):
(WebCore::Editor::reappliedEditing):
(WebCore::Editor::updateMarkersForWordsAffectedByEditing):
(WebCore::Editor::changeSelectionAfterCommand):
(WebCore::Editor::respondToChangedSelection):
(WebCore::Editor::dictationAlternativesForMarker):
(WebCore::Editor::applyDictationAlternativelternative):
* editing/Editor.h:
* editing/FrameSelection.h:
* editing/mac/AlternativeTextUIController.h: Added. WK1 and WK2 use this class to keep track of text alternatives objects.
(AlternativeTextUIController):
(WebCore::AlternativeTextUIController::AlternativeTextUIController):
(AlernativeTextContextController):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::AlernativeTextContextController):
* editing/mac/AlternativeTextUIController.mm: Added.
(WebCore::AlternativeTextUIController::AlernativeTextContextController::addAlternatives):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::alternativesForContext):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::removeAlternativesForContext):
(WebCore::AlternativeTextUIController::AlernativeTextContextController::clear):
(WebCore::AlternativeTextUIController::addAlternatives):
(WebCore::AlternativeTextUIController::alternativesForContext):
(WebCore::AlternativeTextUIController::clear):
(WebCore::AlternativeTextUIController::showAlternatives):
(WebCore::AlternativeTextUIController::handleAcceptedAlternative):
(WebCore::AlternativeTextUIController::dismissAlternatives):
(WebCore::AlternativeTextUIController::removeAlternatives):
* editing/mac/TextAlternativeWithRange.h: Added. A simple struct to make it easier to pass around a pair of text alternatives object and range.
* editing/mac/TextAlternativeWithRange.mm: Added.
(WebCore::TextAlternativeWithRange::TextAlternativeWithRange):
(WebCore::collectDictationTextAlternatives):
* page/AlternativeTextClient.h:
* page/ContextMenuController.cpp: Added code to show alternative dictated text in context menu.
(WebCore::ContextMenuController::contextMenuItemSelected):
(WebCore::ContextMenuController::populate):
(WebCore::ContextMenuController::checkOrEnableIfNeeded):
* platform/ContextMenuItem.h:
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::dictationAlternatives):
* rendering/HitTestResult.h:
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paintDocumentMarker):
2012-06-14 Emil A Eklund <eae@chromium.org>
Change RenderTableSection::calcRowLogicalHeight to round rather than floor height
......@@ -2526,3 +2526,14 @@ __ZNK7WebCore4KURL7isEmptyEv
__ZNK7WebCore4KURL7isValidEv
__ZNK7WebCore4KURL22protocolIsInHTTPFamilyEv
#endif
#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION)
__ZN7WebCore27AlternativeTextUIController15addAlternativesERKN3WTF9RetainPtrI18NSTextAlternativesEE
__ZN7WebCore27AlternativeTextUIController22alternativesForContextEy
__ZN7WebCore27AlternativeTextUIController5clearEv
__ZN7WebCore27AlternativeTextUIController19dismissAlternativesEv
__ZN7WebCore27AlternativeTextUIController18removeAlternativesEy
__ZN7WebCore27AlternativeTextUIController16showAlternativesEP6NSViewRKNS_9FloatRectEyU13block_pointerFvP8NSStringE
__ZN7WebCore24TextAlternativeWithRangeC1EP18NSTextAlternatives8_NSRange
__ZN7WebCore32collectDictationTextAlternativesEP18NSAttributedStringRN3WTF6VectorINS_24TextAlternativeWithRangeELm0EEE
#endif
......@@ -5791,6 +5791,10 @@
CE08C3D1152B599A0021B8C2 /* AlternativeTextController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE08C3CF152B599A0021B8C2 /* AlternativeTextController.cpp */; };
CE08C3D2152B599A0021B8C2 /* AlternativeTextController.h in Headers */ = {isa = PBXBuildFile; fileRef = CE08C3D0152B599A0021B8C2 /* AlternativeTextController.h */; settings = {ATTRIBUTES = (); }; };
CE54FD381016D9A6008B44C8 /* ScriptSourceProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = CE54FD371016D9A6008B44C8 /* ScriptSourceProvider.h */; settings = {ATTRIBUTES = (Private, ); }; };
CE7B2DB31586ABAD0098B3FA /* AlternativeTextUIController.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7B2DAF1586ABAD0098B3FA /* AlternativeTextUIController.h */; settings = {ATTRIBUTES = (Private, ); }; };
CE7B2DB41586ABAD0098B3FA /* AlternativeTextUIController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CE7B2DB01586ABAD0098B3FA /* AlternativeTextUIController.mm */; };
CE7B2DB51586ABAD0098B3FA /* TextAlternativeWithRange.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7B2DB11586ABAD0098B3FA /* TextAlternativeWithRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
CE7B2DB61586ABAD0098B3FA /* TextAlternativeWithRange.mm in Sources */ = {isa = PBXBuildFile; fileRef = CE7B2DB21586ABAD0098B3FA /* TextAlternativeWithRange.mm */; };
CEA3949C11D45CDA003094CF /* StaticHashSetNodeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEA3949A11D45CDA003094CF /* StaticHashSetNodeList.cpp */; };
CEA3949D11D45CDA003094CF /* StaticHashSetNodeList.h in Headers */ = {isa = PBXBuildFile; fileRef = CEA3949B11D45CDA003094CF /* StaticHashSetNodeList.h */; };
CECADFC6153778FF00E37068 /* DictationAlternative.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CECADFC2153778FF00E37068 /* DictationAlternative.cpp */; };
......@@ -12987,6 +12991,10 @@
CE08C3D0152B599A0021B8C2 /* AlternativeTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlternativeTextController.h; sourceTree = "<group>"; };
CE54FD371016D9A6008B44C8 /* ScriptSourceProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptSourceProvider.h; sourceTree = "<group>"; };
CE5CB1B314EDAB6F00BB2795 /* EventSender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventSender.h; sourceTree = "<group>"; };
CE7B2DAF1586ABAD0098B3FA /* AlternativeTextUIController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AlternativeTextUIController.h; path = mac/AlternativeTextUIController.h; sourceTree = "<group>"; };
CE7B2DB01586ABAD0098B3FA /* AlternativeTextUIController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AlternativeTextUIController.mm; path = mac/AlternativeTextUIController.mm; sourceTree = "<group>"; };
CE7B2DB11586ABAD0098B3FA /* TextAlternativeWithRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextAlternativeWithRange.h; path = mac/TextAlternativeWithRange.h; sourceTree = "<group>"; };
CE7B2DB21586ABAD0098B3FA /* TextAlternativeWithRange.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TextAlternativeWithRange.mm; path = mac/TextAlternativeWithRange.mm; sourceTree = "<group>"; };
CEA3949A11D45CDA003094CF /* StaticHashSetNodeList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticHashSetNodeList.cpp; sourceTree = "<group>"; };
CEA3949B11D45CDA003094CF /* StaticHashSetNodeList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticHashSetNodeList.h; sourceTree = "<group>"; };
CECADFC2153778FF00E37068 /* DictationAlternative.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DictationAlternative.cpp; sourceTree = "<group>"; };
......@@ -20693,8 +20701,12 @@
ED501DC90B249F3900AE18D9 /* mac */ = {
isa = PBXGroup;
children = (
CE7B2DB01586ABAD0098B3FA /* AlternativeTextUIController.mm */,
CE7B2DAF1586ABAD0098B3FA /* AlternativeTextUIController.h */,
ED501DC50B249F2900AE18D9 /* EditorMac.mm */,
4A8C96EA0BE69032004EEFF0 /* FrameSelectionMac.mm */,
CE7B2DB21586ABAD0098B3FA /* TextAlternativeWithRange.mm */,
CE7B2DB11586ABAD0098B3FA /* TextAlternativeWithRange.h */,
);
name = mac;
sourceTree = "<group>";
......@@ -25061,6 +25073,8 @@
E1BE512E0CF6C512002EA959 /* XSLTUnicodeSort.h in Headers */,
977E2E0F12F0FC9C00C13379 /* XSSAuditor.h in Headers */,
FD537353137B651800008DCE /* ZeroPole.h in Headers */,
CE7B2DB31586ABAD0098B3FA /* AlternativeTextUIController.h in Headers */,
CE7B2DB51586ABAD0098B3FA /* TextAlternativeWithRange.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -28102,6 +28116,8 @@
977E2E0E12F0FC9C00C13379 /* XSSAuditor.cpp in Sources */,
FD537352137B651800008DCE /* ZeroPole.cpp in Sources */,
9A1B6F97158869C80011A8C4 /* JSDOMStringListCustom.cpp in Sources */,
CE7B2DB41586ABAD0098B3FA /* AlternativeTextUIController.mm in Sources */,
CE7B2DB61586ABAD0098B3FA /* TextAlternativeWithRange.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -28,6 +28,7 @@
#include "AlternativeTextClient.h"
#include "DocumentMarker.h"
#include "FrameSelection.h"
#include "Range.h"
#include "TextChecking.h"
#include "Timer.h"
......@@ -108,7 +109,7 @@ public:
void respondToUnappliedSpellCorrection(const VisibleSelection&, const String& corrected, const String& correction) UNLESS_ENABLED({ UNUSED_PARAM(corrected); UNUSED_PARAM(correction); })
void respondToAppliedEditing(CompositeEditCommand*) UNLESS_ENABLED({ })
void respondToUnappliedEditing(EditCommandComposition*) UNLESS_ENABLED({ })
void respondToChangedSelection(const VisibleSelection& oldSelection) UNLESS_ENABLED({ UNUSED_PARAM(oldSelection); })
void respondToChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions) UNLESS_ENABLED({ UNUSED_PARAM(oldSelection); })
void stopPendingCorrection(const VisibleSelection& oldSelection) UNLESS_ENABLED({ UNUSED_PARAM(oldSelection); })
void applyPendingCorrection(const VisibleSelection& selectionAfterTyping) UNLESS_ENABLED({ UNUSED_PARAM(selectionAfterTyping); })
......@@ -130,20 +131,21 @@ public:
void deletedAutocorrectionAtPosition(const Position&, const String& originalString) UNLESS_ENABLED({ UNUSED_PARAM(originalString); })
bool insertDictatedText(const String&, const Vector<DictationAlternative>&, Event*);
void removeDictationAlternativesForMarker(const DocumentMarker*);
Vector<String> dictationAlternativesForMarker(const DocumentMarker*);
void applyDictationAlternative(const String& alternativeString);
private:
#if USE(AUTOCORRECTION_PANEL)
String dismissSoon(ReasonForDismissingAlternativeText);
void applyAlternativeText(const String& alternative, const Vector<DocumentMarker::MarkerType>&);
void applyAlternativeTextToRange(const Range*, const String& alternative, AlternativeTextType, const Vector<DocumentMarker::MarkerType>&);
void timerFired(Timer<AlternativeTextController>*);
void recordAutocorrectionResponseReversed(const String& replacedString, const String& replacementString);
void recordSpellcheckerResponseForModifiedCorrection(Range* rangeOfCorrection, const String& corrected, const String& correction);
String markerDescriptionForAppliedAlternativeText(AlternativeTextType, DocumentMarker::MarkerType);
bool shouldStartTimerFor(const DocumentMarker* marker, int endOffset) const
{
return (((marker->type() == DocumentMarker::Replacement && !marker->description().isNull())
|| marker->type() == DocumentMarker::Spelling) && static_cast<int>(marker->endOffset()) == endOffset);
}
bool shouldStartTimerFor(const DocumentMarker&, int endOffset) const;
bool respondToMarkerAtEndOfWord(const DocumentMarker&, const Position& endOfWordPosition, FrameSelection::SetSelectionOptions);
AlternativeTextClient* alternativeTextClient();
EditorClient* editorClient();
......
......@@ -480,13 +480,13 @@ bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
return client() && client()->shouldShowDeleteInterface(element);
}
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
void Editor::notifyComponentsOnChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions options)
{
if (client())
client()->respondToChangedSelection(m_frame);
setStartNewKillRingSequence(true);
m_deleteButtonController->respondToChangedSelection(oldSelection);
m_alternativeTextController->respondToChangedSelection(oldSelection);
m_alternativeTextController->respondToChangedSelection(oldSelection, options);
}
void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
......@@ -789,7 +789,8 @@ void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd)
m_alternativeTextController->respondToAppliedEditing(cmd.get());
// Don't clear the typing style with this selection change. We do those things elsewhere if necessary.
changeSelectionAfterCommand(newSelection, false, false);
FrameSelection::SetSelectionOptions options = cmd->isDictationCommand() ? FrameSelection::DictationTriggered : 0;
changeSelectionAfterCommand(newSelection, options);
if (!cmd->preservesTypingStyle())
m_frame->selection()->clearTypingStyle();
......@@ -815,7 +816,7 @@ void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd)
dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement());
VisibleSelection newSelection(cmd->startingSelection());
changeSelectionAfterCommand(newSelection, true, true);
changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
m_alternativeTextController->respondToUnappliedEditing(cmd.get());
m_lastEditCommand = 0;
......@@ -831,7 +832,7 @@ void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd)
dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement());
VisibleSelection newSelection(cmd->endingSelection());
changeSelectionAfterCommand(newSelection, true, true);
changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
m_lastEditCommand = 0;
if (client())
......@@ -2266,6 +2267,10 @@ void Editor::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionA
Document* document = m_frame->document();
RefPtr<Range> wordRange = Range::create(document, startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent());
Vector<DocumentMarker*> markers = document->markers()->markersInRange(wordRange.get(), DocumentMarker::DictationAlternatives);
for (size_t i = 0; i < markers.size(); ++i)
m_alternativeTextController->removeDictationAlternativesForMarker(markers[i]);
document->markers()->removeMarkers(wordRange.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator | DocumentMarker::SpellCheckingExemption | DocumentMarker::DictationAlternatives, DocumentMarkerController::RemovePartiallyOverlappingMarker);
document->markers()->clearDescriptionOnMarkersIntersectingRange(wordRange.get(), DocumentMarker::Replacement);
}
......@@ -2413,7 +2418,7 @@ void Editor::dismissCorrectionPanelAsIgnored()
m_alternativeTextController->dismiss(ReasonForDismissingAlternativeTextIgnored);
}
void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle)
void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, FrameSelection::SetSelectionOptions options)
{
// If the new selection is orphaned, then don't update the selection.
if (newSelection.start().isOrphan() || newSelection.end().isOrphan())
......@@ -2424,14 +2429,8 @@ void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, b
// The old selection can be invalid here and calling shouldChangeSelection can produce some strange calls.
// See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ranges for selections that are no longer valid
bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()->selection();
if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection)) {
FrameSelection::SetSelectionOptions options = 0;
if (closeTyping)
options |= FrameSelection::CloseTyping;
if (clearTypingStyle)
options |= FrameSelection::ClearTypingStyle;
if (selectionDidNotChangeDOMPosition || m_frame->selection()->shouldChangeSelection(newSelection))
m_frame->selection()->setSelection(newSelection, options);
}
// Some editing operations change the selection visually without affecting its position within the DOM.
// For example when you press return in the following (the caret is marked by ^):
......@@ -2826,7 +2825,7 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, Fra
if (!isContinuousGrammarCheckingEnabled)
m_frame->document()->markers()->removeMarkers(DocumentMarker::Grammar);
respondToChangedSelection(oldSelection);
notifyComponentsOnChangedSelection(oldSelection, options);
}
static Node* findFirstMarkable(Node* node)
......@@ -2917,4 +2916,14 @@ void Editor::willDetachPage()
editorClient->frameWillDetachPage(frame());
}
Vector<String> Editor::dictationAlternativesForMarker(const DocumentMarker* marker)
{
return m_alternativeTextController->dictationAlternativesForMarker(marker);
}
void Editor::applyDictationAlternativelternative(const String& alternativeString)
{
m_alternativeTextController->applyDictationAlternative(alternativeString);
}
} // namespace WebCore
......@@ -134,8 +134,7 @@ public:
bool shouldShowDeleteInterface(HTMLElement*) const;
bool shouldDeleteRange(Range*) const;
bool shouldApplyStyle(StylePropertySet*, Range*);
void respondToChangedSelection(const VisibleSelection& oldSelection);
void respondToChangedContents(const VisibleSelection& endingSelection);
bool selectionStartHasStyle(CSSPropertyID, const String& value) const;
......@@ -395,7 +394,8 @@ public:
EditorParagraphSeparator defaultParagraphSeparator() const { return m_defaultParagraphSeparator; }
void setDefaultParagraphSeparator(EditorParagraphSeparator separator) { m_defaultParagraphSeparator = separator; }
Vector<String> dictationAlternativesForMarker(const DocumentMarker*);
void applyDictationAlternativelternative(const String& alternativeString);
private:
virtual void willDetachPage() OVERRIDE;
......@@ -429,7 +429,8 @@ private:
enum SetCompositionMode { ConfirmComposition, CancelComposition };
void setComposition(const String&, SetCompositionMode);
void changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle);
void changeSelectionAfterCommand(const VisibleSelection& newSelection, FrameSelection::SetSelectionOptions);
void notifyComponentsOnChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions);
Node* findEventTargetFromSelection() const;
......
......@@ -118,6 +118,7 @@ public:
ClearTypingStyle = 1 << 2,
SpellCorrectionTriggered = 1 << 3,
DoNotSetFocus = 1 << 4,
DictationTriggered = 1 << 5
};
typedef unsigned SetSelectionOptions; // Union of values in SetSelectionOption and EUserTriggered
static inline EUserTriggered selectionOptionsToUserTriggered(SetSelectionOptions options)
......
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef AlternativeTextUIController_h
#define AlternativeTextUIController_h
#include "AlternativeTextClient.h"
#include "FloatRect.h"
#include <wtf/HashMap.h>
#include <wtf/RetainPtr.h>
#if USE(DICTATION_ALTERNATIVES)
OBJC_CLASS NSTextAlternatives;
OBJC_CLASS NSView;
namespace WebCore {
class AlternativeTextUIController {
public:
AlternativeTextUIController() { }
// Returns a context ID.
uint64_t addAlternatives(const RetainPtr<NSTextAlternatives>&);
void clear();
void showAlternatives(NSView*, const FloatRect& boundingBoxOfPrimaryString, uint64_t context, void(^acceptanceHandler)(NSString*));
void dismissAlternatives();
void removeAlternatives(uint64_t context);
Vector<String> alternativesForContext(uint64_t context);
private:
void handleAcceptedAlternative(NSString* acceptedAlternative, uint64_t context, NSTextAlternatives*);
class AlernativeTextContextController {
public:
AlernativeTextContextController() { }
uint64_t addAlternatives(const RetainPtr<NSTextAlternatives>&);
void clear();
NSTextAlternatives* alternativesForContext(uint64_t context);
void removeAlternativesForContext(uint64_t context);
static const uint64_t invalidContext = 0;
private:
typedef HashMap<uint64_t, RetainPtr<NSTextAlternatives> > HashMapType;
HashMapType m_alternativesObjectMap;
};
AlernativeTextContextController m_contextController;
RetainPtr<NSView> m_view;
};
} // namespace WebCore
#endif
#endif // AlternativeTextUIController_h
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "AlternativeTextUIController.h"
#if USE(DICTATION_ALTERNATIVES)
#import <AppKit/NSSpellChecker.h>
#import <AppKit/NSTextAlternatives.h>
#import <AppKit/NSView.h>
namespace WebCore {
uint64_t AlternativeTextUIController::AlernativeTextContextController::addAlternatives(const RetainPtr<NSTextAlternatives>& alternatives)
{
uint64_t context = reinterpret_cast<uint64_t>(alternatives.get());
if (!context)
return invalidContext;
if (alternativesForContext(context))
return context;
HashMapType::AddResult result = m_alternativesObjectMap.add(context, alternatives);
return result.isNewEntry ? context : invalidContext;
}