Diff
Modified: trunk/LayoutTests/ChangeLog (233438 => 233439)
--- trunk/LayoutTests/ChangeLog 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/LayoutTests/ChangeLog 2018-07-02 22:04:51 UTC (rev 233439)
@@ -1,3 +1,27 @@
+2018-07-02 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [WK1] editing/spelling/markers.html is failing on recent builds of macOS Mojave
+ https://bugs.webkit.org/show_bug.cgi?id=187253
+
+ Reviewed by Tim Horton.
+
+ In recent builds of macOS Mojave, NSSpellChecker returns both grammar and spelling errors when asked to analyze
+ the string "I have a issue.". While arguably correct, the change causes this existing layout test to fail due
+ to one of the calls to `verifyUnexpectedMarkers` expecting either grammar markers and not spelling markers, or
+ vice versa.
+
+ To fix this, we can leverage the mechanism added in r233412 to simulate different results from the platform
+ spellchecker, such that the test now exercises all combinations of grammar and spelling corrections observed on
+ each macOS platform, regardless of the actual platform where the test is being run.
+
+ This patch also enhances the capabilities of `LayoutTestSpellChecker`. See `Tools/ChangeLog` for more details.
+
+ * editing/spelling/markers-expected.txt:
+ * editing/spelling/markers.html:
+ * editing/spelling/text-replacement-after-typing-to-word.html:
+
+ Adjusted for a renamed TestRunner method.
+
2018-07-02 Michael Catanzaro <mcatanz...@igalia.com>
Unreviewed GTK gardening
Modified: trunk/LayoutTests/editing/spelling/markers-expected.txt (233438 => 233439)
--- trunk/LayoutTests/editing/spelling/markers-expected.txt 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/LayoutTests/editing/spelling/markers-expected.txt 2018-07-02 22:04:51 UTC (rev 233439)
@@ -7,6 +7,18 @@
PASS internals.markerRangeForNode(element.firstChild, nextMisspellingData.marker, 0) became different from null
PASS range.toString() is "a"
+Checking for issue on 'I have a issue.'
+PASS internals.markerRangeForNode(element.firstChild, nextMisspellingData.marker, 0) became different from null
+PASS range.toString() is "a"
+
+Checking for issue on 'I have a issue.'
+PASS internals.markerRangeForNode(element.firstChild, nextMisspellingData.marker, 0) became different from null
+PASS range.toString() is "a"
+
+Checking for issue on 'I have a issue.'
+PASS internals.markerRangeForNode(element.firstChild, nextMisspellingData.marker, 0) became different from null
+PASS range.toString() is "a"
+
Checking for issue on 'zz.'
PASS internals.markerRangeForNode(element.firstChild, nextMisspellingData.marker, 0) became different from null
PASS range.toString() is "zz"
@@ -22,6 +34,9 @@
Checking for no other issues on 'I have a issue.'
PASS internals.markerCountForNode(element.firstChild, oppositeMarker) became 0
+Checking for no other issues on 'I have a issue.'
+PASS internals.markerCountForNode(element.firstChild, oppositeMarker) became 0
+
Checking for no other issues on 'zz.'
PASS internals.markerCountForNode(element.firstChild, oppositeMarker) became 0
Modified: trunk/LayoutTests/editing/spelling/markers.html (233438 => 233439)
--- trunk/LayoutTests/editing/spelling/markers.html 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/LayoutTests/editing/spelling/markers.html 2018-07-02 22:04:51 UTC (rev 233439)
@@ -25,9 +25,10 @@
internals.settings.setAsynchronousSpellCheckingEnabled(true);
}
-function createEditableElement(parent) {
+function createEditableElement(parent, textContent) {
var e = document.createElement('div');
e.setAttribute("contentEditable", "true");
+ e.textContent = textContent;
e.className = 'editing';
parent.appendChild(e);
@@ -36,52 +37,77 @@
function typeText(elem, text) {
elem.focus();
+ selectAllCommand();
+ deleteCommand();
for (var i = 0; i < text.length; ++i)
typeCharacterCommand(text[i]);
}
-var container = document.getElementById('container');
+const container = document.getElementById('container');
+const elementWithGrammarIssue = createEditableElement(container, "I have a issue.");
+const elementWithSpellingIssue = createEditableElement(container, "zz.");
+const elementWithGrammarAndSpellingIssue = createEditableElement(container, "orange,zz,apple.");
-var elementWithGrammarIssue = createEditableElement(container);
-typeText(elementWithGrammarIssue, 'I have a issue.');
-
-var elementWithSpellingIssue = createEditableElement(container);
-typeText(elementWithSpellingIssue, 'zz.');
-
-var elementWithGrammarAndSpellingIssue = createEditableElement(container);
-typeText(elementWithGrammarAndSpellingIssue, 'orange,zz,apple.');
-
-var misspellings = [
- { marker: internals.sentenceRetroCorrectionEnabled ? 'spelling' : 'grammar', issue: 'a' },
+const misspellings = [
+ { marker: 'spelling', issue: 'a' },
+ { marker: 'grammar', issue: 'a' },
+ { marker: 'grammar', issue: 'I have a issue.' },
{ marker: 'spelling', issue: 'zz' },
{ marker: 'grammar', issue: 'orange,zz,apple.' },
{ marker: 'spelling', issue: 'orange,zz,apple' },
];
+const results = [
+ { "type": "spelling", "from": 7, "to": 8 },
+ {
+ "type": "grammar",
+ "from": 7,
+ "to": 8,
+ "details": [{ "from": 0, "to": 1 }]
+ },
+ {
+ "type": "grammar",
+ "from": 0,
+ "to": 15,
+ "details": [{ "from": 7, "to": 8 }]
+ }
+];
+
var tests = [
- function() { verifyDesiredMarkers(elementWithGrammarIssue, misspellings.slice(0, 1)) },
- function() { verifyDesiredMarkers(elementWithSpellingIssue, misspellings.slice(1, 2)) },
- function() { verifyDesiredMarkers(elementWithGrammarAndSpellingIssue, misspellings.slice(2, 4)) },
+ function() { verifyDesiredMarkers(elementWithGrammarIssue, misspellings.slice(0, 1), results.slice(0, 1)) },
+ function() { verifyDesiredMarkers(elementWithGrammarIssue, misspellings.slice(1, 2), results.slice(1, 2)) },
+ function() { verifyDesiredMarkers(elementWithGrammarIssue, misspellings.slice(0, 2), results.slice(0, 2)) },
+ function() { verifyDesiredMarkers(elementWithSpellingIssue, misspellings.slice(3, 4)) },
+ function() { verifyDesiredMarkers(elementWithGrammarAndSpellingIssue, misspellings.slice(4, 6)) },
// Those expect to have only one kind of markers either spelling or grammar.
- function() { verifyUnexpectedMarkers(elementWithGrammarIssue, misspellings.slice(0, 1)) },
- function() { verifyUnexpectedMarkers(elementWithSpellingIssue, misspellings.slice(1, 2)) },
+ function() { verifyUnexpectedMarkers(elementWithGrammarIssue, misspellings.slice(0, 1)), results.slice(0, 1) },
+ function() { verifyUnexpectedMarkers(elementWithGrammarIssue, misspellings.slice(1, 2)), results.slice(1, 2) },
+ function() { verifyUnexpectedMarkers(elementWithSpellingIssue, misspellings.slice(3, 4)) },
];
var element;
var nextMisspellingData;
-function verifyDesiredMarkers(e, misspellings)
+function verifyDesiredMarkers(e, misspellings, overrideSpellCheckingResults)
{
if (!window.internals)
return done();
+ const textToCheck = e.firstChild.nodeValue;
+ const spellCheckerResults = { };
+ if (overrideSpellCheckingResults)
+ spellCheckerResults[textToCheck] = overrideSpellCheckingResults;
+ testRunner.setSpellCheckerResults(spellCheckerResults);
+
+ typeText(e, textToCheck);
+
element = e;
nextMisspellingData = misspellings.shift();
if (!nextMisspellingData)
return done();
- debug("Checking for issue on '" + element.firstChild.nodeValue + "'");
+ debug(`Checking for issue on '${textToCheck}'`);
shouldBecomeDifferent('internals.markerRangeForNode(element.firstChild, nextMisspellingData.marker, 0)', "null", function() {
range = internals.markerRangeForNode(element.firstChild, nextMisspellingData.marker, 0);
@@ -92,8 +118,16 @@
}
var oppositeMarker;
-function verifyUnexpectedMarkers(e, misspellings)
+function verifyUnexpectedMarkers(e, misspellings, overrideSpellCheckingResults)
{
+ const textToCheck = e.firstChild.nodeValue;
+ const spellCheckerResults = { };
+ if (overrideSpellCheckingResults)
+ spellCheckerResults[textToCheck] = overrideSpellCheckingResults;
+ testRunner.setSpellCheckerResults(spellCheckerResults);
+
+ typeText(e, textToCheck);
+
element = e;
nextMisspellingData = misspellings.shift();
@@ -102,7 +136,7 @@
else if (nextMisspellingData.marker == 'spelling')
oppositeMarker = 'grammar';
- debug("Checking for no other issues on '" + element.firstChild.nodeValue + "'");
+ debug(`Checking for no other issues on '${textToCheck}'`);
shouldBecomeEqual('internals.markerCountForNode(element.firstChild, oppositeMarker)', '0', function() {
debug("");
Modified: trunk/LayoutTests/editing/spelling/text-replacement-after-typing-to-word.html (233438 => 233439)
--- trunk/LayoutTests/editing/spelling/text-replacement-after-typing-to-word.html 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/LayoutTests/editing/spelling/text-replacement-after-typing-to-word.html 2018-07-02 22:04:51 UTC (rev 233439)
@@ -17,19 +17,23 @@
internals.settings.setAsynchronousSpellCheckingEnabled(false);
internals.setAutomaticTextReplacementEnabled(true);
internals.setAutomaticSpellingCorrectionEnabled(true);
- testRunner.setSpellCheckerTextReplacements({
- "YT?": {
- "replacement": "You there?",
- "type": "replacement",
- "from": 0,
- "to": 3
- },
- "YT?\n": {
- "replacement": "You there?",
- "type": "replacement",
- "from": 0,
- "to": 3
- }
+ testRunner.setSpellCheckerResults({
+ "YT?": [
+ {
+ "replacement": "You there?",
+ "type": "replacement",
+ "from": 0,
+ "to": 3
+ }
+ ],
+ "YT?\n": [
+ {
+ "replacement": "You there?",
+ "type": "replacement",
+ "from": 0,
+ "to": 3
+ }
+ ]
});
}
Modified: trunk/Tools/ChangeLog (233438 => 233439)
--- trunk/Tools/ChangeLog 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/Tools/ChangeLog 2018-07-02 22:04:51 UTC (rev 233439)
@@ -1,3 +1,51 @@
+2018-07-02 Wenson Hsieh <wenson_hs...@apple.com>
+
+ [WK1] editing/spelling/markers.html is failing on recent builds of macOS Mojave
+ https://bugs.webkit.org/show_bug.cgi?id=187253
+
+ Reviewed by Tim Horton.
+
+ Enhances and refactors LayoutTestSpellChecker, which was introduced in r233412.
+
+ * DumpRenderTree/TestRunner.cpp:
+ (setSpellCheckerResultsCallback):
+
+ Rename setSpellCheckerTextReplacements to setSpellCheckerResults.
+
+ (TestRunner::staticFunctions):
+ (setSpellCheckerTextReplacementsCallback): Deleted.
+ * DumpRenderTree/TestRunner.h:
+ * DumpRenderTree/mac/TestRunnerMac.mm:
+ (TestRunner::setSpellCheckerResults):
+ (TestRunner::setSpellCheckerTextReplacements): Deleted.
+ * DumpRenderTree/win/TestRunnerWin.cpp:
+ (TestRunner::setSpellCheckerResults):
+ (TestRunner::setSpellCheckerTextReplacements): Deleted.
+ * TestRunnerShared/cocoa/LayoutTestSpellChecker.h:
+ * TestRunnerShared/cocoa/LayoutTestSpellChecker.mm:
+ (-[LayoutTestTextCheckingResult initWithType:range:replacement:details:]):
+ (-[LayoutTestTextCheckingResult grammarDetails]):
+ (-[LayoutTestSpellChecker reset]):
+ (-[LayoutTestSpellChecker results]):
+ (-[LayoutTestSpellChecker setResults:]):
+ (-[LayoutTestSpellChecker setResultsFromJSObject:inContext:]):
+
+ Add support for passing in a list of grammar correction detail ranges. Necessary for simulating grammar errors.
+
+ (-[LayoutTestSpellChecker checkString:range:types:options:inSpellDocumentWithTag:orthography:wordCount:]):
+
+ Tweaked to always call the superclass method. This ensures that we set the `orthography` and `wordCount`
+ outpointers if applicable.
+
+ (-[LayoutTestSpellChecker requestCheckingOfString:range:types:options:inSpellDocumentWithTag:completionHandler:]):
+
+ Added support for simulating asynchronous spell checking.
+
+ (-[LayoutTestTextCheckingResult initWithType:range:replacement:]): Deleted.
+ (-[LayoutTestSpellChecker replacements]): Deleted.
+ (-[LayoutTestSpellChecker setReplacements:]): Deleted.
+ (-[LayoutTestSpellChecker setReplacementsFromJSObject:inContext:]): Deleted.
+
2018-07-02 Brady Eidson <beid...@apple.com>
Another unreviewed followup to:
Modified: trunk/Tools/DumpRenderTree/TestRunner.cpp (233438 => 233439)
--- trunk/Tools/DumpRenderTree/TestRunner.cpp 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/Tools/DumpRenderTree/TestRunner.cpp 2018-07-02 22:04:51 UTC (rev 233439)
@@ -1788,13 +1788,13 @@
return JSValueMakeUndefined(context);
}
-static JSValueRef setSpellCheckerTextReplacementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+static JSValueRef setSpellCheckerResultsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
if (argumentCount < 1)
return JSValueMakeUndefined(context);
auto* runner = static_cast<TestRunner*>(JSObjectGetPrivate(thisObject));
- runner->setSpellCheckerTextReplacements(context, JSValueToObject(context, arguments[0], nullptr));
+ runner->setSpellCheckerResults(context, JSValueToObject(context, arguments[0], nullptr));
return JSValueMakeUndefined(context);
}
@@ -2265,7 +2265,7 @@
{ "runUIScript", runUIScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "imageCountInGeneralPasteboard", imageCountInGeneralPasteboardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setSpellCheckerLoggingEnabled", setSpellCheckerLoggingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
- { "setSpellCheckerTextReplacements", setSpellCheckerTextReplacementsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setSpellCheckerResults", setSpellCheckerResultsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setOpenPanelFiles", setOpenPanelFilesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "forceImmediateCompletion", forceImmediateCompletionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
Modified: trunk/Tools/DumpRenderTree/TestRunner.h (233438 => 233439)
--- trunk/Tools/DumpRenderTree/TestRunner.h 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/Tools/DumpRenderTree/TestRunner.h 2018-07-02 22:04:51 UTC (rev 233439)
@@ -376,7 +376,7 @@
bool dumpJSConsoleLogInStdErr() const { return m_dumpJSConsoleLogInStdErr; }
void setSpellCheckerLoggingEnabled(bool);
- void setSpellCheckerTextReplacements(JSContextRef, JSObjectRef replacements);
+ void setSpellCheckerResults(JSContextRef, JSObjectRef results);
const std::vector<std::string>& openPanelFiles() const { return m_openPanelFiles; }
void setOpenPanelFiles(JSContextRef, JSValueRef);
Modified: trunk/Tools/DumpRenderTree/mac/TestRunnerMac.mm (233438 => 233439)
--- trunk/Tools/DumpRenderTree/mac/TestRunnerMac.mm 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/Tools/DumpRenderTree/mac/TestRunnerMac.mm 2018-07-02 22:04:51 UTC (rev 233439)
@@ -219,12 +219,12 @@
#endif
}
-void TestRunner::setSpellCheckerTextReplacements(JSContextRef context, JSObjectRef replacements)
+void TestRunner::setSpellCheckerResults(JSContextRef context, JSObjectRef results)
{
#if PLATFORM(MAC)
- [[LayoutTestSpellChecker checker] setReplacementsFromJSObject:replacements inContext:context];
+ [[LayoutTestSpellChecker checker] setResultsFromJSObject:results inContext:context];
#else
- UNUSED_PARAM(replacements);
+ UNUSED_PARAM(results);
UNUSED_PARAM(context);
#endif
}
Modified: trunk/Tools/DumpRenderTree/win/TestRunnerWin.cpp (233438 => 233439)
--- trunk/Tools/DumpRenderTree/win/TestRunnerWin.cpp 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/Tools/DumpRenderTree/win/TestRunnerWin.cpp 2018-07-02 22:04:51 UTC (rev 233439)
@@ -1407,7 +1407,7 @@
fprintf(testResult, "ERROR: TestRunner::setSpellCheckerLoggingEnabled() not implemented\n");
}
-void TestRunner::setSpellCheckerTextReplacements(JSContextRef, JSObjectRef)
+void TestRunner::setSpellCheckerResults(JSContextRef, JSObjectRef)
{
- fprintf(testResult, "ERROR: TestRunner::setSpellCheckerTextReplacements() not implemented\n");
+ fprintf(testResult, "ERROR: TestRunner::setSpellCheckerResults() not implemented\n");
}
Modified: trunk/Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.h (233438 => 233439)
--- trunk/Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.h 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.h 2018-07-02 22:04:51 UTC (rev 233439)
@@ -34,9 +34,11 @@
@class LayoutTestTextCheckingResult;
+using TextCheckingResultsDictionary = NSDictionary<NSString *, NSArray<LayoutTestTextCheckingResult *> *>;
+
@interface LayoutTestSpellChecker : NSSpellChecker {
@private
- RetainPtr<NSDictionary<NSString *, LayoutTestTextCheckingResult *>> _replacements;
+ RetainPtr<TextCheckingResultsDictionary> _results;
BOOL _spellCheckerLoggingEnabled;
}
@@ -43,8 +45,8 @@
+ (instancetype)checker;
+ (void)uninstallAndReset;
-- (void)setReplacementsFromJSObject:(JSObjectRef)replacements inContext:(JSContextRef)context;
-@property (nonatomic, copy) NSDictionary<NSString *, LayoutTestTextCheckingResult *> *replacements;
+- (void)setResultsFromJSObject:(JSObjectRef)resultsObject inContext:(JSContextRef)context;
+@property (nonatomic, copy) TextCheckingResultsDictionary *results;
@property (nonatomic) BOOL spellCheckerLoggingEnabled;
@end
Modified: trunk/Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.mm (233438 => 233439)
--- trunk/Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.mm 2018-07-02 22:02:30 UTC (rev 233438)
+++ trunk/Tools/TestRunnerShared/cocoa/LayoutTestSpellChecker.mm 2018-07-02 22:04:51 UTC (rev 233439)
@@ -29,9 +29,12 @@
#import <_javascript_Core/JSRetainPtr.h>
#import <objc/runtime.h>
#import <wtf/Assertions.h>
+#import <wtf/BlockPtr.h>
#if PLATFORM(MAC)
+using TextCheckingCompletionHandler = void(^)(NSInteger, NSArray<NSTextCheckingResult *> *, NSOrthography *, NSInteger);
+
static LayoutTestSpellChecker *globalSpellChecker = nil;
static BOOL hasSwizzledLayoutTestSpellChecker = NO;
static IMP globallySwizzledSharedSpellCheckerImplementation;
@@ -116,14 +119,15 @@
RetainPtr<NSString> _replacement;
NSTextCheckingType _type;
NSRange _range;
+ RetainPtr<NSArray<NSDictionary *>> _details;
}
-- (instancetype)initWithType:(NSTextCheckingType)type range:(NSRange)range replacement:(NSString *)replacement;
+- (instancetype)initWithType:(NSTextCheckingType)type range:(NSRange)range replacement:(NSString *)replacement details:(NSArray<NSDictionary<NSString *, id> *> *)details;
@end
@implementation LayoutTestTextCheckingResult
-- (instancetype)initWithType:(NSTextCheckingType)type range:(NSRange)range replacement:(NSString *)replacement
+- (instancetype)initWithType:(NSTextCheckingType)type range:(NSRange)range replacement:(NSString *)replacement details:(NSArray<NSDictionary<NSString *, id> *> *)details
{
if (!(self = [super init]))
return nil;
@@ -130,11 +134,17 @@
_type = type;
_range = range;
- _replacement = replacement;
+ _replacement = adoptNS(replacement.copy);
+ _details = adoptNS(details.copy);
return self;
}
+- (NSArray<NSDictionary<NSString *, id> *> *)grammarDetails
+{
+ return _details.get();
+}
+
- (NSRange)range
{
return _range;
@@ -185,55 +195,80 @@
- (void)reset
{
- self.replacements = nil;
+ self.results = nil;
self.spellCheckerLoggingEnabled = NO;
}
-- (NSDictionary<NSString *, LayoutTestTextCheckingResult *> *)replacements
+- (TextCheckingResultsDictionary *)results
{
- return _replacements.get();
+ return _results.get();
}
-- (void)setReplacements:(NSDictionary<NSString *, LayoutTestTextCheckingResult *> *)replacements
+- (void)setResults:(TextCheckingResultsDictionary *)results
{
- _replacements = adoptNS(replacements.copy);
+ _results = adoptNS(results.copy);
}
-- (void)setReplacementsFromJSObject:(JSObjectRef)replacements inContext:(JSContextRef)context
+- (void)setResultsFromJSObject:(JSObjectRef)resultsObject inContext:(JSContextRef)context
{
auto fromPropertyName = adopt(JSStringCreateWithUTF8CString("from"));
auto toPropertyName = adopt(JSStringCreateWithUTF8CString("to"));
auto typePropertyName = adopt(JSStringCreateWithUTF8CString("type"));
auto replacementPropertyName = adopt(JSStringCreateWithUTF8CString("replacement"));
- auto properties = JSObjectCopyPropertyNames(context, replacements);
- auto result = adoptNS([[NSMutableDictionary alloc] init]);
+ auto detailsPropertyName = adopt(JSStringCreateWithUTF8CString("details"));
+ auto results = adoptNS([[NSMutableDictionary alloc] init]);
+
+ // FIXME: Using the Objective-C API would make this logic easier to follow.
+ auto properties = JSObjectCopyPropertyNames(context, resultsObject);
for (size_t index = 0; index < JSPropertyNameArrayGetCount(properties); ++index) {
- JSStringRef wordToReplace = JSPropertyNameArrayGetNameAtIndex(properties, index);
- JSObjectRef replacement = JSValueToObject(context, JSObjectGetProperty(context, replacements, wordToReplace, nullptr), nullptr);
- long fromValue = lroundl(JSValueToNumber(context, JSObjectGetProperty(context, replacement, fromPropertyName.get(), nullptr), nullptr));
- long toValue = lroundl(JSValueToNumber(context, JSObjectGetProperty(context, replacement, toPropertyName.get(), nullptr), nullptr));
- auto typeValue = adopt(JSValueToStringCopy(context, JSObjectGetProperty(context, replacement, typePropertyName.get(), nullptr), nullptr));
- auto replacementValue = JSObjectGetProperty(context, replacement, replacementPropertyName.get(), nullptr);
- RetainPtr<CFStringRef> replacementText;
- if (!JSValueIsUndefined(context, replacementValue)) {
- auto replacementJSString = adopt(JSValueToStringCopy(context, replacementValue, nullptr));
- replacementText = adoptCF(JSStringCopyCFString(kCFAllocatorDefault, replacementJSString.get()));
+ JSStringRef textToCheck = JSPropertyNameArrayGetNameAtIndex(properties, index);
+ JSObjectRef resultsArray = JSValueToObject(context, JSObjectGetProperty(context, resultsObject, textToCheck, nullptr), nullptr);
+ auto resultsArrayPropertyNames = JSObjectCopyPropertyNames(context, resultsArray);
+ auto resultsForWord = adoptNS([[NSMutableArray alloc] init]);
+ for (size_t resultIndex = 0; resultIndex < JSPropertyNameArrayGetCount(resultsArrayPropertyNames); ++resultIndex) {
+ auto resultsObject = JSValueToObject(context, JSObjectGetPropertyAtIndex(context, resultsArray, resultIndex, nullptr), nullptr);
+ long fromValue = lroundl(JSValueToNumber(context, JSObjectGetProperty(context, resultsObject, fromPropertyName.get(), nullptr), nullptr));
+ long toValue = lroundl(JSValueToNumber(context, JSObjectGetProperty(context, resultsObject, toPropertyName.get(), nullptr), nullptr));
+ auto typeValue = adopt(JSValueToStringCopy(context, JSObjectGetProperty(context, resultsObject, typePropertyName.get(), nullptr), nullptr));
+ auto replacementValue = JSObjectGetProperty(context, resultsObject, replacementPropertyName.get(), nullptr);
+ RetainPtr<CFStringRef> replacementText;
+ if (!JSValueIsUndefined(context, replacementValue)) {
+ auto replacementJSString = adopt(JSValueToStringCopy(context, replacementValue, nullptr));
+ replacementText = adoptCF(JSStringCopyCFString(kCFAllocatorDefault, replacementJSString.get()));
+ }
+ auto details = adoptNS([[NSMutableArray alloc] init]);
+ auto detailsValue = JSObjectGetProperty(context, resultsObject, detailsPropertyName.get(), nullptr);
+ if (!JSValueIsUndefined(context, detailsValue)) {
+ auto detailsObject = JSValueToObject(context, detailsValue, nullptr);
+ auto detailsObjectProperties = JSObjectCopyPropertyNames(context, detailsObject);
+ for (size_t detailIndex = 0; detailIndex < JSPropertyNameArrayGetCount(detailsObjectProperties); ++detailIndex) {
+ auto detail = adoptNS([[NSMutableDictionary alloc] init]);
+ auto detailObject = JSValueToObject(context, JSObjectGetPropertyAtIndex(context, detailsObject, detailIndex, nullptr), nullptr);
+ long from = lroundl(JSValueToNumber(context, JSObjectGetProperty(context, detailObject, fromPropertyName.get(), nullptr), nullptr));
+ long to = lroundl(JSValueToNumber(context, JSObjectGetProperty(context, detailObject, toPropertyName.get(), nullptr), nullptr));
+ [detail setObject:[NSValue valueWithRange:NSMakeRange(from, to - from)] forKey:NSGrammarRange];
+ [details addObject:detail.get()];
+ }
+ JSPropertyNameArrayRelease(detailsObjectProperties);
+ }
+ [resultsForWord addObject:[[[LayoutTestTextCheckingResult alloc] initWithType:nsTextCheckingType(WTFMove(typeValue)) range:NSMakeRange(fromValue, toValue - fromValue) replacement:(NSString *)replacementText.get() details:details.get()] autorelease]];
}
- auto spellCheckResult = adoptNS([[LayoutTestTextCheckingResult alloc] initWithType:nsTextCheckingType(WTFMove(typeValue)) range:NSMakeRange(fromValue, toValue - fromValue) replacement:(NSString *)replacementText.get()]);
- auto cfWordToReplace = adoptCF(JSStringCopyCFString(kCFAllocatorDefault, wordToReplace));
- [result setObject:spellCheckResult.get() forKey:(NSString *)cfWordToReplace.get()];
+ auto cfTextToCheck = adoptCF(JSStringCopyCFString(kCFAllocatorDefault, textToCheck));
+ [results setObject:resultsForWord.get() forKey:(NSString *)cfTextToCheck.get()];
+ JSPropertyNameArrayRelease(resultsArrayPropertyNames);
}
JSPropertyNameArrayRelease(properties);
- _replacements = WTFMove(result);
+ _results = WTFMove(results);
}
- (NSArray<NSTextCheckingResult *> *)checkString:(NSString *)stringToCheck range:(NSRange)range types:(NSTextCheckingTypes)checkingTypes options:(NSDictionary<NSString *, id> *)options inSpellDocumentWithTag:(NSInteger)tag orthography:(NSOrthography **)orthography wordCount:(NSInteger *)wordCount
{
- if (auto *result = [_replacements objectForKey:stringToCheck])
- return @[ result ];
+ NSArray *result = [super checkString:stringToCheck range:range types:checkingTypes options:options inSpellDocumentWithTag:tag orthography:orthography wordCount:wordCount];
+ if (auto *overrideResult = [_results objectForKey:stringToCheck])
+ return overrideResult;
- return [super checkString:stringToCheck range:range types:checkingTypes options:options inSpellDocumentWithTag:tag orthography:orthography wordCount:wordCount];
+ return result;
}
- (void)recordResponse:(NSCorrectionResponse)response toCorrection:(NSString *)correction forWord:(NSString *)word language:(NSString *)language inSpellDocumentWithTag:(NSInteger)tag
@@ -244,6 +279,18 @@
[super recordResponse:response toCorrection:correction forWord:word language:language inSpellDocumentWithTag:tag];
}
+- (NSInteger)requestCheckingOfString:(NSString *)stringToCheck range:(NSRange)range types:(NSTextCheckingTypes)checkingTypes options:(NSDictionary<NSString *, id> *)options inSpellDocumentWithTag:(NSInteger)tag completionHandler:(TextCheckingCompletionHandler)completionHandler
+{
+ return [super requestCheckingOfString:stringToCheck range:range types:checkingTypes options:options inSpellDocumentWithTag:tag completionHandler:[overrideResult = retainPtr([_results objectForKey:stringToCheck]), completion = makeBlockPtr(completionHandler), stringToCheck = retainPtr(stringToCheck)] (NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *result, NSOrthography *orthography, NSInteger wordCount) {
+ if (overrideResult) {
+ completion(sequenceNumber, overrideResult.get(), orthography, wordCount);
+ return;
+ }
+
+ completion(sequenceNumber, result, orthography, wordCount);
+ }];
+}
+
@end
#endif // PLATFORM(MAC)