~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebKit2/UIProcess/mac/TextCheckerMac.mm

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 
23
 * THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
 
 
26
#import "config.h"
 
27
#import "TextChecker.h"
 
28
 
 
29
#import "TextCheckerState.h"
 
30
#import <WebCore/NotImplemented.h>
 
31
#import <wtf/RetainPtr.h>
 
32
 
 
33
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
 
34
@interface NSSpellChecker (WebNSSpellCheckerDetails)
 
35
- (NSString *)languageForWordRange:(NSRange)range inString:(NSString *)string orthography:(NSOrthography *)orthography;
 
36
@end
 
37
#endif
 
38
 
 
39
static NSString* const WebAutomaticSpellingCorrectionEnabled = @"WebAutomaticSpellingCorrectionEnabled";
 
40
static NSString* const WebContinuousSpellCheckingEnabled = @"WebContinuousSpellCheckingEnabled";
 
41
static NSString* const WebGrammarCheckingEnabled = @"WebGrammarCheckingEnabled";
 
42
static NSString* const WebSmartInsertDeleteEnabled = @"WebSmartInsertDeleteEnabled";
 
43
static NSString* const WebAutomaticQuoteSubstitutionEnabled = @"WebAutomaticQuoteSubstitutionEnabled";
 
44
static NSString* const WebAutomaticDashSubstitutionEnabled = @"WebAutomaticDashSubstitutionEnabled";
 
45
static NSString* const WebAutomaticLinkDetectionEnabled = @"WebAutomaticLinkDetectionEnabled";
 
46
static NSString* const WebAutomaticTextReplacementEnabled = @"WebAutomaticTextReplacementEnabled";
 
47
 
 
48
using namespace WebCore;
 
49
 
 
50
namespace WebKit {
 
51
 
 
52
TextCheckerState textCheckerState;
 
53
 
 
54
static void initializeState()
 
55
{
 
56
    static bool didInitializeState;
 
57
    if (didInitializeState)
 
58
        return;
 
59
 
 
60
    textCheckerState.isContinuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled] && TextChecker::isContinuousSpellCheckingAllowed();
 
61
    textCheckerState.isGrammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled];
 
62
    textCheckerState.isAutomaticSpellingCorrectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticSpellingCorrectionEnabled];
 
63
    textCheckerState.isAutomaticQuoteSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticQuoteSubstitutionEnabled];
 
64
    textCheckerState.isAutomaticDashSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticDashSubstitutionEnabled];
 
65
    textCheckerState.isAutomaticLinkDetectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticLinkDetectionEnabled];
 
66
    textCheckerState.isAutomaticTextReplacementEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticTextReplacementEnabled];
 
67
 
 
68
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
 
69
    if (![[NSUserDefaults standardUserDefaults] objectForKey:WebAutomaticSpellingCorrectionEnabled])
 
70
        textCheckerState.isAutomaticSpellingCorrectionEnabled = [NSSpellChecker isAutomaticSpellingCorrectionEnabled];
 
71
#endif
 
72
 
 
73
    didInitializeState = true;
 
74
}
 
75
 
 
76
const TextCheckerState& TextChecker::state()
 
77
{
 
78
    initializeState();
 
79
    return textCheckerState;
 
80
}
 
81
 
 
82
bool TextChecker::isContinuousSpellCheckingAllowed()
 
83
{
 
84
    static bool allowContinuousSpellChecking = true;
 
85
    static bool readAllowContinuousSpellCheckingDefault = false;
 
86
 
 
87
    if (!readAllowContinuousSpellCheckingDefault) {
 
88
        if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"])
 
89
            allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"];
 
90
 
 
91
        readAllowContinuousSpellCheckingDefault = true;
 
92
    }
 
93
 
 
94
    return allowContinuousSpellChecking;
 
95
}
 
96
 
 
97
void TextChecker::setContinuousSpellCheckingEnabled(bool isContinuousSpellCheckingEnabled)
 
98
{
 
99
    if (state().isContinuousSpellCheckingEnabled == isContinuousSpellCheckingEnabled)
 
100
        return;
 
101
                                                                                      
 
102
    textCheckerState.isContinuousSpellCheckingEnabled = isContinuousSpellCheckingEnabled;
 
103
    [[NSUserDefaults standardUserDefaults] setBool:isContinuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled];
 
104
 
 
105
    // FIXME: preflight the spell checker.
 
106
}
 
107
 
 
108
void TextChecker::setGrammarCheckingEnabled(bool isGrammarCheckingEnabled)
 
109
{
 
110
    if (state().isGrammarCheckingEnabled == isGrammarCheckingEnabled)
 
111
        return;
 
112
 
 
113
    textCheckerState.isGrammarCheckingEnabled = isGrammarCheckingEnabled;
 
114
    [[NSUserDefaults standardUserDefaults] setBool:isGrammarCheckingEnabled forKey:WebGrammarCheckingEnabled];    
 
115
    [[NSSpellChecker sharedSpellChecker] updatePanels];
 
116
    
 
117
    // We call preflightSpellChecker() when turning continuous spell checking on, but we don't need to do that here
 
118
    // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
 
119
}
 
120
 
 
121
void TextChecker::setAutomaticSpellingCorrectionEnabled(bool isAutomaticSpellingCorrectionEnabled)
 
122
{
 
123
    if (state().isAutomaticSpellingCorrectionEnabled == isAutomaticSpellingCorrectionEnabled)
 
124
        return;
 
125
 
 
126
    textCheckerState.isAutomaticSpellingCorrectionEnabled = isAutomaticSpellingCorrectionEnabled;
 
127
    [[NSUserDefaults standardUserDefaults] setBool:isAutomaticSpellingCorrectionEnabled forKey:WebAutomaticSpellingCorrectionEnabled];    
 
128
 
 
129
    [[NSSpellChecker sharedSpellChecker] updatePanels];
 
130
}
 
131
 
 
132
void TextChecker::setAutomaticQuoteSubstitutionEnabled(bool isAutomaticQuoteSubstitutionEnabled)
 
133
{
 
134
    if (state().isAutomaticQuoteSubstitutionEnabled == isAutomaticQuoteSubstitutionEnabled)
 
135
        return;
 
136
 
 
137
    textCheckerState.isAutomaticQuoteSubstitutionEnabled = isAutomaticQuoteSubstitutionEnabled;
 
138
    [[NSUserDefaults standardUserDefaults] setBool:isAutomaticQuoteSubstitutionEnabled forKey:WebAutomaticQuoteSubstitutionEnabled];    
 
139
    
 
140
    [[NSSpellChecker sharedSpellChecker] updatePanels];
 
141
}
 
142
 
 
143
void TextChecker::setAutomaticDashSubstitutionEnabled(bool isAutomaticDashSubstitutionEnabled)
 
144
{
 
145
    if (state().isAutomaticDashSubstitutionEnabled == isAutomaticDashSubstitutionEnabled)
 
146
        return;
 
147
 
 
148
    textCheckerState.isAutomaticDashSubstitutionEnabled = isAutomaticDashSubstitutionEnabled;
 
149
    [[NSUserDefaults standardUserDefaults] setBool:isAutomaticDashSubstitutionEnabled forKey:WebAutomaticDashSubstitutionEnabled];
 
150
 
 
151
    [[NSSpellChecker sharedSpellChecker] updatePanels];
 
152
}
 
153
 
 
154
void TextChecker::setAutomaticLinkDetectionEnabled(bool isAutomaticLinkDetectionEnabled)
 
155
{
 
156
    if (state().isAutomaticLinkDetectionEnabled == isAutomaticLinkDetectionEnabled)
 
157
        return;
 
158
    
 
159
    textCheckerState.isAutomaticLinkDetectionEnabled = isAutomaticLinkDetectionEnabled;
 
160
    [[NSUserDefaults standardUserDefaults] setBool:isAutomaticLinkDetectionEnabled forKey:WebAutomaticLinkDetectionEnabled];
 
161
    
 
162
    [[NSSpellChecker sharedSpellChecker] updatePanels];
 
163
}
 
164
 
 
165
void TextChecker::setAutomaticTextReplacementEnabled(bool isAutomaticTextReplacementEnabled)
 
166
{
 
167
    if (state().isAutomaticTextReplacementEnabled == isAutomaticTextReplacementEnabled)
 
168
        return;
 
169
    
 
170
    textCheckerState.isAutomaticTextReplacementEnabled = isAutomaticTextReplacementEnabled;
 
171
    [[NSUserDefaults standardUserDefaults] setBool:isAutomaticTextReplacementEnabled forKey:WebAutomaticTextReplacementEnabled];
 
172
 
 
173
    [[NSSpellChecker sharedSpellChecker] updatePanels];
 
174
}
 
175
 
 
176
static bool smartInsertDeleteEnabled;
 
177
    
 
178
bool TextChecker::isSmartInsertDeleteEnabled()
 
179
{
 
180
    static bool readSmartInsertDeleteEnabledDefault;
 
181
 
 
182
    if (!readSmartInsertDeleteEnabledDefault) {
 
183
        smartInsertDeleteEnabled = ![[NSUserDefaults standardUserDefaults] objectForKey:WebSmartInsertDeleteEnabled] || [[NSUserDefaults standardUserDefaults] boolForKey:WebSmartInsertDeleteEnabled];
 
184
 
 
185
        readSmartInsertDeleteEnabledDefault = true;
 
186
    }
 
187
 
 
188
    return smartInsertDeleteEnabled;
 
189
}
 
190
 
 
191
void TextChecker::setSmartInsertDeleteEnabled(bool flag)
 
192
{
 
193
    if (flag == isSmartInsertDeleteEnabled())
 
194
        return;
 
195
 
 
196
    smartInsertDeleteEnabled = flag;
 
197
 
 
198
    [[NSUserDefaults standardUserDefaults] setBool:flag forKey:WebSmartInsertDeleteEnabled];
 
199
}
 
200
 
 
201
bool TextChecker::substitutionsPanelIsShowing()
 
202
{
 
203
    return [[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible];
 
204
}
 
205
 
 
206
void TextChecker::toggleSubstitutionsPanelIsShowing()
 
207
{
 
208
    NSPanel *substitutionsPanel = [[NSSpellChecker sharedSpellChecker] substitutionsPanel];
 
209
    if ([substitutionsPanel isVisible]) {
 
210
        [substitutionsPanel orderOut:nil];
 
211
        return;
 
212
    }
 
213
    [substitutionsPanel orderFront:nil];
 
214
}
 
215
 
 
216
void TextChecker::continuousSpellCheckingEnabledStateChanged(bool enabled)
 
217
{
 
218
    textCheckerState.isContinuousSpellCheckingEnabled = enabled;
 
219
}
 
220
 
 
221
void TextChecker::grammarCheckingEnabledStateChanged(bool enabled)
 
222
{
 
223
    textCheckerState.isGrammarCheckingEnabled = enabled;
 
224
}
 
225
 
 
226
int64_t TextChecker::uniqueSpellDocumentTag(WebPageProxy*)
 
227
{
 
228
    return [NSSpellChecker uniqueSpellDocumentTag];
 
229
}
 
230
 
 
231
void TextChecker::closeSpellDocumentWithTag(int64_t tag)
 
232
{
 
233
    [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:tag];
 
234
}
 
235
 
 
236
#if USE(UNIFIED_TEXT_CHECKING)
 
237
 
 
238
Vector<TextCheckingResult> TextChecker::checkTextOfParagraph(int64_t spellDocumentTag, const UChar* text, int length, uint64_t checkingTypes)
 
239
{
 
240
    Vector<TextCheckingResult> results;
 
241
 
 
242
    RetainPtr<NSString> textString(AdoptNS, [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(text) length:length freeWhenDone:NO]);
 
243
    NSArray *incomingResults = [[NSSpellChecker sharedSpellChecker] checkString:textString .get()
 
244
                                                                          range:NSMakeRange(0, length)
 
245
                                                                          types:checkingTypes | NSTextCheckingTypeOrthography
 
246
                                                                        options:nil
 
247
                                                         inSpellDocumentWithTag:spellDocumentTag 
 
248
                                                                    orthography:NULL
 
249
                                                                      wordCount:NULL];
 
250
    for (NSTextCheckingResult *incomingResult in incomingResults) {
 
251
        NSRange resultRange = [incomingResult range];
 
252
        NSTextCheckingType resultType = [incomingResult resultType];
 
253
        ASSERT(resultRange.location != NSNotFound);
 
254
        ASSERT(resultRange.length > 0);
 
255
        if (resultType == NSTextCheckingTypeSpelling && (checkingTypes & NSTextCheckingTypeSpelling)) {
 
256
            TextCheckingResult result;
 
257
            result.type = TextCheckingTypeSpelling;
 
258
            result.location = resultRange.location;
 
259
            result.length = resultRange.length;
 
260
            results.append(result);
 
261
        } else if (resultType == NSTextCheckingTypeGrammar && (checkingTypes & NSTextCheckingTypeGrammar)) {
 
262
            TextCheckingResult result;
 
263
            NSArray *details = [incomingResult grammarDetails];
 
264
            result.type = TextCheckingTypeGrammar;
 
265
            result.location = resultRange.location;
 
266
            result.length = resultRange.length;
 
267
            for (NSDictionary *incomingDetail in details) {
 
268
                ASSERT(incomingDetail);
 
269
                GrammarDetail detail;
 
270
                NSValue *detailRangeAsNSValue = [incomingDetail objectForKey:NSGrammarRange];
 
271
                ASSERT(detailRangeAsNSValue);
 
272
                NSRange detailNSRange = [detailRangeAsNSValue rangeValue];
 
273
                ASSERT(detailNSRange.location != NSNotFound);
 
274
                ASSERT(detailNSRange.length > 0);
 
275
                detail.location = detailNSRange.location;
 
276
                detail.length = detailNSRange.length;
 
277
                detail.userDescription = [incomingDetail objectForKey:NSGrammarUserDescription];
 
278
                NSArray *guesses = [incomingDetail objectForKey:NSGrammarCorrections];
 
279
                for (NSString *guess in guesses)
 
280
                    detail.guesses.append(String(guess));
 
281
                result.details.append(detail);
 
282
            }
 
283
            results.append(result);
 
284
        } else if (resultType == NSTextCheckingTypeLink && (checkingTypes & NSTextCheckingTypeLink)) {
 
285
            TextCheckingResult result;
 
286
            result.type = TextCheckingTypeLink;
 
287
            result.location = resultRange.location;
 
288
            result.length = resultRange.length;
 
289
            result.replacement = [[incomingResult URL] absoluteString];
 
290
            results.append(result);
 
291
        } else if (resultType == NSTextCheckingTypeQuote && (checkingTypes & NSTextCheckingTypeQuote)) {
 
292
            TextCheckingResult result;
 
293
            result.type = TextCheckingTypeQuote;
 
294
            result.location = resultRange.location;
 
295
            result.length = resultRange.length;
 
296
            result.replacement = [incomingResult replacementString];
 
297
            results.append(result);
 
298
        } else if (resultType == NSTextCheckingTypeDash && (checkingTypes & NSTextCheckingTypeDash)) {
 
299
            TextCheckingResult result;
 
300
            result.type = TextCheckingTypeDash;
 
301
            result.location = resultRange.location;
 
302
            result.length = resultRange.length;
 
303
            result.replacement = [incomingResult replacementString];
 
304
            results.append(result);
 
305
        } else if (resultType == NSTextCheckingTypeReplacement && (checkingTypes & NSTextCheckingTypeReplacement)) {
 
306
            TextCheckingResult result;
 
307
            result.type = TextCheckingTypeReplacement;
 
308
            result.location = resultRange.location;
 
309
            result.length = resultRange.length;
 
310
            result.replacement = [incomingResult replacementString];
 
311
            results.append(result);
 
312
        } else if (resultType == NSTextCheckingTypeCorrection && (checkingTypes & NSTextCheckingTypeCorrection)) {
 
313
            TextCheckingResult result;
 
314
            result.type = TextCheckingTypeCorrection;
 
315
            result.location = resultRange.location;
 
316
            result.length = resultRange.length;
 
317
            result.replacement = [incomingResult replacementString];
 
318
            results.append(result);
 
319
        }
 
320
    }
 
321
 
 
322
    return results;
 
323
}
 
324
 
 
325
#endif
 
326
 
 
327
void TextChecker::checkSpellingOfString(int64_t, const UChar*, uint32_t, int32_t&, int32_t&)
 
328
{
 
329
    // Mac uses checkTextOfParagraph instead.
 
330
    notImplemented();
 
331
}
 
332
 
 
333
void TextChecker::checkGrammarOfString(int64_t, const UChar*, uint32_t, Vector<WebCore::GrammarDetail>&, int32_t&, int32_t&)
 
334
{
 
335
    // Mac uses checkTextOfParagraph instead.
 
336
    notImplemented();
 
337
}
 
338
 
 
339
bool TextChecker::spellingUIIsShowing()
 
340
{
 
341
    return [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible];
 
342
}
 
343
 
 
344
void TextChecker::toggleSpellingUIIsShowing()
 
345
{
 
346
    NSPanel *spellingPanel = [[NSSpellChecker sharedSpellChecker] spellingPanel];
 
347
    if ([spellingPanel isVisible])
 
348
        [spellingPanel orderOut:nil];
 
349
    else
 
350
        [spellingPanel orderFront:nil];
 
351
}
 
352
 
 
353
void TextChecker::updateSpellingUIWithMisspelledWord(int64_t, const String& misspelledWord)
 
354
{
 
355
    [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithMisspelledWord:misspelledWord];
 
356
}
 
357
 
 
358
void TextChecker::updateSpellingUIWithGrammarString(int64_t, const String& badGrammarPhrase, const GrammarDetail& grammarDetail)
 
359
{
 
360
    RetainPtr<NSMutableArray> corrections(AdoptNS, [[NSMutableArray alloc] init]);
 
361
    for (size_t i = 0; i < grammarDetail.guesses.size(); ++i) {
 
362
        NSString *guess = grammarDetail.guesses[i];
 
363
        [corrections.get() addObject:guess];
 
364
    }
 
365
 
 
366
    NSRange grammarRange = NSMakeRange(grammarDetail.location, grammarDetail.length);
 
367
    NSString *grammarUserDescription = grammarDetail.userDescription;
 
368
    RetainPtr<NSDictionary> grammarDetailDict(AdoptNS, [[NSDictionary alloc] initWithObjectsAndKeys:[NSValue valueWithRange:grammarRange], NSGrammarRange, grammarUserDescription, NSGrammarUserDescription, corrections.get(), NSGrammarCorrections, nil]);
 
369
 
 
370
    [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithGrammarString:badGrammarPhrase detail:grammarDetailDict.get()];
 
371
}
 
372
 
 
373
void TextChecker::getGuessesForWord(int64_t spellDocumentTag, const String& word, const String& context, Vector<String>& guesses)
 
374
{
 
375
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
 
376
    NSString* language = nil;
 
377
    NSOrthography* orthography = nil;
 
378
    NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
 
379
    if (context.length()) {
 
380
        [checker checkString:context range:NSMakeRange(0, context.length()) types:NSTextCheckingTypeOrthography options:0 inSpellDocumentWithTag:spellDocumentTag orthography:&orthography wordCount:0];
 
381
        language = [checker languageForWordRange:NSMakeRange(0, context.length()) inString:context orthography:orthography];
 
382
    }
 
383
    NSArray* stringsArray = [checker guessesForWordRange:NSMakeRange(0, word.length()) inString:word language:language inSpellDocumentWithTag:spellDocumentTag];
 
384
#else
 
385
    NSArray* stringsArray = [[NSSpellChecker sharedSpellChecker] guessesForWord:word];
 
386
#endif
 
387
 
 
388
    for (NSString *guess in stringsArray)
 
389
        guesses.append(guess);
 
390
}
 
391
 
 
392
void TextChecker::learnWord(int64_t, const String& word)
 
393
{
 
394
    [[NSSpellChecker sharedSpellChecker] learnWord:word];
 
395
}
 
396
 
 
397
void TextChecker::ignoreWord(int64_t spellDocumentTag, const String& word)
 
398
{
 
399
    [[NSSpellChecker sharedSpellChecker] ignoreWord:word inSpellDocumentWithTag:spellDocumentTag];
 
400
}
 
401
 
 
402
} // namespace WebKit