Skip to content

Commit

Permalink
Spell checking indicator shows when an inline prediction candidate fo…
Browse files Browse the repository at this point in the history
…r a proper noun is being shown

https://bugs.webkit.org/show_bug.cgi?id=258643
rdar://110196591

Reviewed by Wenson Hsieh.

Use the `m_isHandlingAcceptedCandidate` flag to indicate when an inline prediction candidate is
being offered.

Setting text via `setMarkedText` eventually gets into `Editor::markAllMisspellingsAndBadGrammarInRanges`,
so exit early in that method if the flag is set so that spelling and grammer checking does not get
erroneously applied.

* Source/WebCore/editing/Editor.cpp:
(WebCore::Editor::setComposition):
(WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges):
* Tools/TestWebKitAPI/Tests/mac/WKWebViewMacEditingTests.mm:
(TEST):

Canonical link: https://commits.webkit.org/265725@main
  • Loading branch information
rr-codes committed Jul 3, 2023
1 parent 17c12a1 commit 8521823
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Source/WebCore/editing/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,9 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
// We should send a compositionstart event only when the given text is not empty because this
// function doesn't create a composition node when the text is empty.
if (!text.isEmpty()) {
// When an inline predicition is being offered, there will be text and a non-zero amount of highlights.
m_isHandlingAcceptedCandidate = !highlights.isEmpty();

target->dispatchEvent(CompositionEvent::create(eventNames().compositionstartEvent, document().windowProxy(), originalText));
event = CompositionEvent::create(eventNames().compositionupdateEvent, document().windowProxy(), text);
}
Expand All @@ -2270,6 +2273,9 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
// If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
// will delete the old composition with an optimized replace operation.
if (text.isEmpty()) {
// The absence of text implies that there are currently no inline predicitions being offered.
m_isHandlingAcceptedCandidate = false;

TypingCommand::deleteSelection(document(), TypingCommand::Option::PreventSpellChecking, TypingCommand::TextCompositionType::Pending);
if (target)
target->dispatchEvent(CompositionEvent::create(eventNames().compositionendEvent, document().windowProxy(), text));
Expand Down Expand Up @@ -2868,6 +2874,10 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(OptionSet<TextCheckingType
if (!client() || !spellingRange || (shouldMarkGrammar && !grammarRange))
return;

// Do not mark spelling or grammer corrections when an inline prediction candidate is currently being offered.
if (m_isHandlingAcceptedCandidate)
return;

// If we're not in an editable node, bail.
Ref editableNode = spellingRange->startContainer();
if (!editableNode->hasEditableStyle())
Expand Down
43 changes: 43 additions & 0 deletions Tools/TestWebKitAPI/Tests/mac/WKWebViewMacEditingTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
#import "TestNavigationDelegate.h"
#import "TestProtocol.h"
#import "TestWKWebView.h"
#import "WKWebViewConfigurationExtras.h"
#import <WebKit/WKProcessPoolPrivate.h>
#import <WebKit/WKWebViewPrivateForTesting.h>
#import <WebKit/_WKProcessPoolConfiguration.h>
#import <pal/spi/mac/NSTextInputContextSPI.h>
#import <wtf/BlockPtr.h>
Expand Down Expand Up @@ -178,4 +180,45 @@ - (SlowTextInputContext *)_web_superInputContext
TestWebKitAPI::Util::run(&done);
}

#if HAVE(INLINE_PREDICTIONS)
TEST(WKWebViewMacEditingTests, InlinePredictionsShouldSurpressAutocorrection)
{
auto configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
auto webView = adoptNS([[TestWKWebView<NSTextInputClient, NSTextInputClient_Async> alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration]);
[webView _setContinuousSpellCheckingEnabledForTesting:YES];
[webView synchronouslyLoadHTMLString:@"<body id='p' contenteditable>Is it &nbsp;</body>"];
[webView stringByEvaluatingJavaScript:@"document.body.focus()"];
[webView _setEditable:YES];
[webView waitForNextPresentationUpdate];

NSString *modifySelectionJavascript = @""
"(() => {"
" const node = document.getElementById('p').firstChild;"
" const range = document.createRange();"
" range.setStart(node, 7);"
" range.setEnd(node, 7);"
" "
" var selection = window.getSelection();"
" selection.removeAllRanges();"
" selection.addRange(range);"
"})();";

[webView stringByEvaluatingJavaScript:modifySelectionJavascript];

auto typedString = adoptNS([[NSAttributedString alloc] initWithString:@"wedn"]);
auto predictedString = adoptNS([[NSAttributedString alloc] initWithString:@"esday" attributes:@{
NSForegroundColorAttributeName : NSColor.grayColor
}]);

auto string = adoptNS([[NSMutableAttributedString alloc] init]);
[string appendAttributedString:typedString.get()];
[string appendAttributedString:predictedString.get()];

[webView setMarkedText:string.get() selectedRange:NSMakeRange(4, 0) replacementRange:NSMakeRange(6, 4)];

NSString *hasSpellingMarker = [webView stringByEvaluatingJavaScript:@"internals.hasSpellingMarker(6, 9) ? 'true' : 'false'"];
EXPECT_STREQ("false", hasSpellingMarker.UTF8String);
}
#endif

#endif // PLATFORM(MAC)

0 comments on commit 8521823

Please sign in to comment.