diff options
Diffstat (limited to 'WebKit/mac/WebCoreSupport/WebEditorClient.mm')
-rw-r--r-- | WebKit/mac/WebCoreSupport/WebEditorClient.mm | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/WebKit/mac/WebCoreSupport/WebEditorClient.mm b/WebKit/mac/WebCoreSupport/WebEditorClient.mm new file mode 100644 index 0000000..f2ed480 --- /dev/null +++ b/WebKit/mac/WebCoreSupport/WebEditorClient.mm @@ -0,0 +1,624 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "WebEditorClient.h" + +#import "DOMHTMLInputElementInternal.h" +#import "DOMHTMLTextAreaElementInternal.h" +#import "DOMRangeInternal.h" +#import "WebArchive.h" +#import "WebDataSourceInternal.h" +#import "WebDocument.h" +#import "WebEditingDelegatePrivate.h" +#import "WebFormDelegate.h" +#import "WebFrameInternal.h" +#import "WebHTMLView.h" +#import "WebHTMLViewInternal.h" +#import "WebKitLogging.h" +#import "WebKitVersionChecks.h" +#import "WebLocalizableStrings.h" +#import "WebNSURLExtras.h" +#import "WebViewInternal.h" +#import <WebCore/Document.h> +#import <WebCore/EditAction.h> +#import <WebCore/EditCommand.h> +#import <WebCore/KeyboardEvent.h> +#import <WebCore/LegacyWebArchive.h> +#import <WebCore/PlatformKeyboardEvent.h> +#import <WebCore/PlatformString.h> +#import <WebCore/WebCoreObjCExtras.h> +#import <wtf/PassRefPtr.h> + +using namespace WebCore; +using namespace WTF; + +EditorInsertAction core(WebViewInsertAction); +WebViewInsertAction kit(EditorInsertAction); + +EditorInsertAction core(WebViewInsertAction kitAction) +{ + return static_cast<EditorInsertAction>(kitAction); +} + +WebViewInsertAction kit(EditorInsertAction coreAction) +{ + return static_cast<WebViewInsertAction>(coreAction); +} + +#ifdef BUILDING_ON_TIGER +@interface NSSpellChecker (NotYetPublicMethods) +- (void)learnWord:(NSString *)word; +@end +#endif + +@interface WebEditCommand : NSObject +{ + EditCommand *m_command; +} + ++ (WebEditCommand *)commandWithEditCommand:(PassRefPtr<EditCommand>)command; +- (EditCommand *)command; + +@end + +@implementation WebEditCommand + +#ifndef BUILDING_ON_TIGER ++ (void)initialize +{ + WebCoreObjCFinalizeOnMainThread(self); +} +#endif + +- (id)initWithEditCommand:(PassRefPtr<EditCommand>)command +{ + ASSERT(command); + [super init]; + m_command = command.releaseRef(); + return self; +} + +- (void)dealloc +{ + if (WebCoreObjCScheduleDeallocateOnMainThread([WebEditCommand class], self)) + return; + + m_command->deref(); + [super dealloc]; +} + +- (void)finalize +{ + ASSERT_MAIN_THREAD(); + m_command->deref(); + [super finalize]; +} + ++ (WebEditCommand *)commandWithEditCommand:(PassRefPtr<EditCommand>)command +{ + return [[[WebEditCommand alloc] initWithEditCommand:command] autorelease]; +} + +- (EditCommand *)command; +{ + return m_command; +} + +@end + +@interface WebEditorUndoTarget : NSObject +{ +} + +- (void)undoEditing:(id)arg; +- (void)redoEditing:(id)arg; + +@end + +@implementation WebEditorUndoTarget + +- (void)undoEditing:(id)arg +{ + ASSERT([arg isKindOfClass:[WebEditCommand class]]); + [arg command]->unapply(); +} + +- (void)redoEditing:(id)arg +{ + ASSERT([arg isKindOfClass:[WebEditCommand class]]); + [arg command]->reapply(); +} + +@end + +void WebEditorClient::pageDestroyed() +{ + delete this; +} + +WebEditorClient::WebEditorClient(WebView *webView) + : m_webView(webView) + , m_undoTarget([[[WebEditorUndoTarget alloc] init] autorelease]) + , m_haveUndoRedoOperations(false) +{ +} + +bool WebEditorClient::isContinuousSpellCheckingEnabled() +{ + return [m_webView isContinuousSpellCheckingEnabled]; +} + +void WebEditorClient::toggleContinuousSpellChecking() +{ + [m_webView toggleContinuousSpellChecking:nil]; +} + +bool WebEditorClient::isGrammarCheckingEnabled() +{ +#ifdef BUILDING_ON_TIGER + return false; +#else + return [m_webView isGrammarCheckingEnabled]; +#endif +} + +void WebEditorClient::toggleGrammarChecking() +{ +#ifndef BUILDING_ON_TIGER + [m_webView toggleGrammarChecking:nil]; +#endif +} + +int WebEditorClient::spellCheckerDocumentTag() +{ + return [m_webView spellCheckerDocumentTag]; +} + +bool WebEditorClient::isEditable() +{ + return [m_webView isEditable]; +} + +bool WebEditorClient::shouldDeleteRange(Range* range) +{ + return [[m_webView _editingDelegateForwarder] webView:m_webView + shouldDeleteDOMRange:kit(range)]; +} + +bool WebEditorClient::shouldShowDeleteInterface(HTMLElement* element) +{ + return [[m_webView _editingDelegateForwarder] webView:m_webView + shouldShowDeleteInterfaceForElement:kit(element)]; +} + +bool WebEditorClient::smartInsertDeleteEnabled() +{ + return [m_webView smartInsertDeleteEnabled]; +} + +bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* style, Range* range) +{ + return [[m_webView _editingDelegateForwarder] webView:m_webView + shouldApplyStyle:kit(style) toElementsInDOMRange:kit(range)]; +} + +bool WebEditorClient::shouldMoveRangeAfterDelete(Range* range, Range* rangeToBeReplaced) +{ + return [[m_webView _editingDelegateForwarder] webView:m_webView + shouldMoveRangeAfterDelete:kit(range) replacingRange:kit(rangeToBeReplaced)]; +} + +bool WebEditorClient::shouldBeginEditing(Range* range) +{ + return [[m_webView _editingDelegateForwarder] webView:m_webView + shouldBeginEditingInDOMRange:kit(range)]; + + return false; +} + +bool WebEditorClient::shouldEndEditing(Range* range) +{ + return [[m_webView _editingDelegateForwarder] webView:m_webView + shouldEndEditingInDOMRange:kit(range)]; +} + +bool WebEditorClient::shouldInsertText(const String& text, Range* range, EditorInsertAction action) +{ + WebView* webView = m_webView; + return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:text replacingDOMRange:kit(range) givenAction:kit(action)]; +} + +bool WebEditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity selectionAffinity, bool stillSelecting) +{ + return [m_webView _shouldChangeSelectedDOMRange:kit(fromRange) toDOMRange:kit(toRange) affinity:kit(selectionAffinity) stillSelecting:stillSelecting]; +} + +void WebEditorClient::didBeginEditing() +{ + [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidBeginEditingNotification object:m_webView]; +} + +void WebEditorClient::respondToChangedContents() +{ + NSView <WebDocumentView> *view = [[[m_webView selectedFrame] frameView] documentView]; + if ([view isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)view _updateFontPanel]; + [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidChangeNotification object:m_webView]; +} + +void WebEditorClient::respondToChangedSelection() +{ + NSView <WebDocumentView> *view = [[[m_webView selectedFrame] frameView] documentView]; + if ([view isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)view _selectionChanged]; + + // FIXME: This quirk is needed due to <rdar://problem/5009625> - We can phase it out once Aperture can adopt the new behavior on their end + if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"]) + return; + + [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidChangeSelectionNotification object:m_webView]; +} + +void WebEditorClient::didEndEditing() +{ + [[NSNotificationCenter defaultCenter] postNotificationName:WebViewDidEndEditingNotification object:m_webView]; +} + +void WebEditorClient::didWriteSelectionToPasteboard() +{ + [[m_webView _editingDelegateForwarder] webView:m_webView didWriteSelectionToPasteboard:[NSPasteboard generalPasteboard]]; +} + +void WebEditorClient::didSetSelectionTypesForPasteboard() +{ + [[m_webView _editingDelegateForwarder] webView:m_webView didSetSelectionTypesForPasteboard:[NSPasteboard generalPasteboard]]; +} + +NSString* WebEditorClient::userVisibleString(NSURL *URL) +{ + return [URL _web_userVisibleString]; +} + +#ifdef BUILDING_ON_TIGER +NSArray* WebEditorClient::pasteboardTypesForSelection(Frame* selectedFrame) +{ + WebFrame* frame = kit(selectedFrame); + return [[[frame frameView] documentView] pasteboardTypesForSelection]; +} +#endif + +bool WebEditorClient::shouldInsertNode(Node *node, Range* replacingRange, EditorInsertAction givenAction) +{ + return [[m_webView _editingDelegateForwarder] webView:m_webView shouldInsertNode:kit(node) replacingDOMRange:kit(replacingRange) givenAction:(WebViewInsertAction)givenAction]; +} + +static NSString* undoNameForEditAction(EditAction editAction) +{ + switch (editAction) { + case EditActionUnspecified: return nil; + case EditActionSetColor: return UI_STRING_KEY("Set Color", "Set Color (Undo action name)", "Undo action name"); + case EditActionSetBackgroundColor: return UI_STRING_KEY("Set Background Color", "Set Background Color (Undo action name)", "Undo action name"); + case EditActionTurnOffKerning: return UI_STRING_KEY("Turn Off Kerning", "Turn Off Kerning (Undo action name)", "Undo action name"); + case EditActionTightenKerning: return UI_STRING_KEY("Tighten Kerning", "Tighten Kerning (Undo action name)", "Undo action name"); + case EditActionLoosenKerning: return UI_STRING_KEY("Loosen Kerning", "Loosen Kerning (Undo action name)", "Undo action name"); + case EditActionUseStandardKerning: return UI_STRING_KEY("Use Standard Kerning", "Use Standard Kerning (Undo action name)", "Undo action name"); + case EditActionTurnOffLigatures: return UI_STRING_KEY("Turn Off Ligatures", "Turn Off Ligatures (Undo action name)", "Undo action name"); + case EditActionUseStandardLigatures: return UI_STRING_KEY("Use Standard Ligatures", "Use Standard Ligatures (Undo action name)", "Undo action name"); + case EditActionUseAllLigatures: return UI_STRING_KEY("Use All Ligatures", "Use All Ligatures (Undo action name)", "Undo action name"); + case EditActionRaiseBaseline: return UI_STRING_KEY("Raise Baseline", "Raise Baseline (Undo action name)", "Undo action name"); + case EditActionLowerBaseline: return UI_STRING_KEY("Lower Baseline", "Lower Baseline (Undo action name)", "Undo action name"); + case EditActionSetTraditionalCharacterShape: return UI_STRING_KEY("Set Traditional Character Shape", "Set Traditional Character Shape (Undo action name)", "Undo action name"); + case EditActionSetFont: return UI_STRING_KEY("Set Font", "Set Font (Undo action name)", "Undo action name"); + case EditActionChangeAttributes: return UI_STRING_KEY("Change Attributes", "Change Attributes (Undo action name)", "Undo action name"); + case EditActionAlignLeft: return UI_STRING_KEY("Align Left", "Align Left (Undo action name)", "Undo action name"); + case EditActionAlignRight: return UI_STRING_KEY("Align Right", "Align Right (Undo action name)", "Undo action name"); + case EditActionCenter: return UI_STRING_KEY("Center", "Center (Undo action name)", "Undo action name"); + case EditActionJustify: return UI_STRING_KEY("Justify", "Justify (Undo action name)", "Undo action name"); + case EditActionSetWritingDirection: return UI_STRING_KEY("Set Writing Direction", "Set Writing Direction (Undo action name)", "Undo action name"); + case EditActionSubscript: return UI_STRING_KEY("Subscript", "Subscript (Undo action name)", "Undo action name"); + case EditActionSuperscript: return UI_STRING_KEY("Superscript", "Superscript (Undo action name)", "Undo action name"); + case EditActionUnderline: return UI_STRING_KEY("Underline", "Underline (Undo action name)", "Undo action name"); + case EditActionOutline: return UI_STRING_KEY("Outline", "Outline (Undo action name)", "Undo action name"); + case EditActionUnscript: return UI_STRING_KEY("Unscript", "Unscript (Undo action name)", "Undo action name"); + case EditActionDrag: return UI_STRING_KEY("Drag", "Drag (Undo action name)", "Undo action name"); + case EditActionCut: return UI_STRING_KEY("Cut", "Cut (Undo action name)", "Undo action name"); + case EditActionPaste: return UI_STRING_KEY("Paste", "Paste (Undo action name)", "Undo action name"); + case EditActionPasteFont: return UI_STRING_KEY("Paste Font", "Paste Font (Undo action name)", "Undo action name"); + case EditActionPasteRuler: return UI_STRING_KEY("Paste Ruler", "Paste Ruler (Undo action name)", "Undo action name"); + case EditActionTyping: return UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name"); + case EditActionCreateLink: return UI_STRING_KEY("Create Link", "Create Link (Undo action name)", "Undo action name"); + case EditActionUnlink: return UI_STRING_KEY("Unlink", "Unlink (Undo action name)", "Undo action name"); + case EditActionInsertList: return UI_STRING_KEY("Insert List", "Insert List (Undo action name)", "Undo action name"); + case EditActionFormatBlock: return UI_STRING_KEY("Formatting", "Format Block (Undo action name)", "Undo action name"); + case EditActionIndent: return UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name"); + case EditActionOutdent: return UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name"); + } + return nil; +} + +void WebEditorClient::registerCommandForUndoOrRedo(PassRefPtr<EditCommand> cmd, bool isRedo) +{ + ASSERT(cmd); + + NSUndoManager *undoManager = [m_webView undoManager]; + NSString *actionName = undoNameForEditAction(cmd->editingAction()); + WebEditCommand *command = [WebEditCommand commandWithEditCommand:cmd]; + [undoManager registerUndoWithTarget:m_undoTarget.get() selector:(isRedo ? @selector(redoEditing:) : @selector(undoEditing:)) object:command]; + if (actionName) + [undoManager setActionName:actionName]; + m_haveUndoRedoOperations = YES; +} + +void WebEditorClient::registerCommandForUndo(PassRefPtr<EditCommand> cmd) +{ + registerCommandForUndoOrRedo(cmd, false); +} + +void WebEditorClient::registerCommandForRedo(PassRefPtr<EditCommand> cmd) +{ + registerCommandForUndoOrRedo(cmd, true); +} + +void WebEditorClient::clearUndoRedoOperations() +{ + if (m_haveUndoRedoOperations) { + // workaround for <rdar://problem/4645507> NSUndoManager dies + // with uncaught exception when undo items cleared while + // groups are open + NSUndoManager *undoManager = [m_webView undoManager]; + int groupingLevel = [undoManager groupingLevel]; + for (int i = 0; i < groupingLevel; ++i) + [undoManager endUndoGrouping]; + + [undoManager removeAllActionsWithTarget:m_undoTarget.get()]; + + for (int i = 0; i < groupingLevel; ++i) + [undoManager beginUndoGrouping]; + + m_haveUndoRedoOperations = NO; + } +} + +bool WebEditorClient::canUndo() const +{ + return [[m_webView undoManager] canUndo]; +} + +bool WebEditorClient::canRedo() const +{ + return [[m_webView undoManager] canRedo]; +} + +void WebEditorClient::undo() +{ + if (canUndo()) + [[m_webView undoManager] undo]; +} + +void WebEditorClient::redo() +{ + if (canRedo()) + [[m_webView undoManager] redo]; +} + +void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event) +{ + Frame* frame = event->target()->toNode()->document()->frame(); + WebHTMLView *webHTMLView = [[kit(frame) frameView] documentView]; + if ([webHTMLView _interceptEditingKeyEvent:event shouldSaveCommand:NO]) + event->setDefaultHandled(); +} + +void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event) +{ + Frame* frame = event->target()->toNode()->document()->frame(); + WebHTMLView *webHTMLView = [[kit(frame) frameView] documentView]; + if ([webHTMLView _interceptEditingKeyEvent:event shouldSaveCommand:YES]) + event->setDefaultHandled(); +} + +#define FormDelegateLog(ctrl) LOG(FormDelegate, "control=%@", ctrl) + +void WebEditorClient::textFieldDidBeginEditing(Element* element) +{ + DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element]; + FormDelegateLog(inputElement); + CallFormDelegate(m_webView, @selector(textFieldDidBeginEditing:inFrame:), inputElement, kit(element->document()->frame())); +} + +void WebEditorClient::textFieldDidEndEditing(Element* element) +{ + DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element]; + FormDelegateLog(inputElement); + CallFormDelegate(m_webView, @selector(textFieldDidEndEditing:inFrame:), inputElement, kit(element->document()->frame())); +} + +void WebEditorClient::textDidChangeInTextField(Element* element) +{ + DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element]; + FormDelegateLog(inputElement); + CallFormDelegate(m_webView, @selector(textDidChangeInTextField:inFrame:), inputElement, kit(element->document()->frame())); +} + +static SEL selectorForKeyEvent(KeyboardEvent* event) +{ + // FIXME: This helper function is for the auto-fill code so we can pass a selector to the form delegate. + // Eventually, we should move all of the auto-fill code down to WebKit and remove the need for this function by + // not relying on the selector in the new implementation. + // The key identifiers are from <http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set> + String key = event->keyIdentifier(); + if (key == "Up") + return @selector(moveUp:); + if (key == "Down") + return @selector(moveDown:); + if (key == "U+001B") + return @selector(cancel:); + if (key == "U+0009") { + if (event->shiftKey()) + return @selector(insertBacktab:); + return @selector(insertTab:); + } + if (key == "Enter") + return @selector(insertNewline:); + return 0; +} + +bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event) +{ + DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element]; + FormDelegateLog(inputElement); + if (SEL commandSelector = selectorForKeyEvent(event)) + return CallFormDelegateReturningBoolean(NO, m_webView, @selector(textField:doCommandBySelector:inFrame:), inputElement, commandSelector, kit(element->document()->frame())); + return NO; +} + +void WebEditorClient::textWillBeDeletedInTextField(Element* element) +{ + DOMHTMLInputElement* inputElement = [DOMHTMLInputElement _wrapHTMLInputElement:(HTMLInputElement*)element]; + FormDelegateLog(inputElement); + // We're using the deleteBackward selector for all deletion operations since the autofill code treats all deletions the same way. + CallFormDelegateReturningBoolean(NO, m_webView, @selector(textField:doCommandBySelector:inFrame:), inputElement, @selector(deleteBackward:), kit(element->document()->frame())); +} + +void WebEditorClient::textDidChangeInTextArea(Element* element) +{ + DOMHTMLTextAreaElement* textAreaElement = [DOMHTMLTextAreaElement _wrapHTMLTextAreaElement:(HTMLTextAreaElement*)element]; + FormDelegateLog(textAreaElement); + CallFormDelegate(m_webView, @selector(textDidChangeInTextArea:inFrame:), textAreaElement, kit(element->document()->frame())); +} + +void WebEditorClient::ignoreWordInSpellDocument(const String& text) +{ + [[NSSpellChecker sharedSpellChecker] ignoreWord:text + inSpellDocumentWithTag:spellCheckerDocumentTag()]; +} + +void WebEditorClient::learnWord(const String& text) +{ + [[NSSpellChecker sharedSpellChecker] learnWord:text]; +} + +void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength) +{ + NSString* textString = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(text) length:length freeWhenDone:NO]; + NSRange range = [[NSSpellChecker sharedSpellChecker] checkSpellingOfString:textString startingAt:0 language:nil wrap:NO inSpellDocumentWithTag:spellCheckerDocumentTag() wordCount:NULL]; + [textString release]; + if (misspellingLocation) { + // WebCore expects -1 to represent "not found" + if (range.location == NSNotFound) + *misspellingLocation = -1; + else + *misspellingLocation = range.location; + } + + if (misspellingLength) + *misspellingLength = range.length; +} + +void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength) +{ +#ifndef BUILDING_ON_TIGER + NSArray *grammarDetails; + NSString* textString = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(text) length:length freeWhenDone:NO]; + NSRange range = [[NSSpellChecker sharedSpellChecker] checkGrammarOfString:textString startingAt:0 language:nil wrap:NO inSpellDocumentWithTag:spellCheckerDocumentTag() details:&grammarDetails]; + [textString release]; + if (badGrammarLocation) + // WebCore expects -1 to represent "not found" + *badGrammarLocation = (range.location == NSNotFound) ? -1 : range.location; + if (badGrammarLength) + *badGrammarLength = range.length; + for (NSDictionary *detail in grammarDetails) { + ASSERT(detail); + GrammarDetail grammarDetail; + NSValue *detailRangeAsNSValue = [detail objectForKey:NSGrammarRange]; + ASSERT(detailRangeAsNSValue); + NSRange detailNSRange = [detailRangeAsNSValue rangeValue]; + ASSERT(detailNSRange.location != NSNotFound && detailNSRange.length > 0); + grammarDetail.location = detailNSRange.location; + grammarDetail.length = detailNSRange.length; + grammarDetail.userDescription = [detail objectForKey:NSGrammarUserDescription]; + NSArray *guesses = [detail objectForKey:NSGrammarCorrections]; + for (NSString *guess in guesses) + grammarDetail.guesses.append(String(guess)); + details.append(grammarDetail); + } +#endif +} + +void WebEditorClient::updateSpellingUIWithGrammarString(const String& badGrammarPhrase, const GrammarDetail& grammarDetail) +{ +#ifndef BUILDING_ON_TIGER + NSMutableArray* corrections = [NSMutableArray array]; + for (unsigned i = 0; i < grammarDetail.guesses.size(); i++) { + NSString* guess = grammarDetail.guesses[i]; + [corrections addObject:guess]; + } + NSRange grammarRange = NSMakeRange(grammarDetail.location, grammarDetail.length); + NSString* grammarUserDescription = grammarDetail.userDescription; + NSMutableDictionary* grammarDetailDict = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithRange:grammarRange], NSGrammarRange, grammarUserDescription, NSGrammarUserDescription, corrections, NSGrammarCorrections, nil]; + + [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithGrammarString:badGrammarPhrase detail:grammarDetailDict]; +#endif +} + +void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& misspelledWord) +{ + [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithMisspelledWord:misspelledWord]; +} + +void WebEditorClient::showSpellingUI(bool show) +{ + NSPanel *spellingPanel = [[NSSpellChecker sharedSpellChecker] spellingPanel]; + if (show) + [spellingPanel orderFront:nil]; + else + [spellingPanel orderOut:nil]; +} + +bool WebEditorClient::spellingUIIsShowing() +{ + return [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible]; +} + +void WebEditorClient::getGuessesForWord(const String& word, WTF::Vector<String>& guesses) +{ + NSArray* stringsArray = [[NSSpellChecker sharedSpellChecker] guessesForWord:word]; + unsigned count = [stringsArray count]; + guesses.clear(); + if (count > 0) { + NSEnumerator* enumerator = [stringsArray objectEnumerator]; + NSString* string; + while ((string = [enumerator nextObject]) != nil) + guesses.append(string); + } +} + +void WebEditorClient::setInputMethodState(bool) +{ +} |