1 /* 2 * Copyright (C) 2006, 2010, 2011 Apple Computer, Inc. All rights reserved. 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #import "config.h" 31 #import "WebEditorClient.h" 32 33 #import "WebCoreArgumentCoders.h" 34 #import "WebPage.h" 35 #import "WebFrame.h" 36 #import "WebPageProxyMessages.h" 37 #import "WebProcess.h" 38 #import <WebCore/ArchiveResource.h> 39 #import <WebCore/DocumentFragment.h> 40 #import <WebCore/DOMDocumentFragmentInternal.h> 41 #import <WebCore/DOMDocumentInternal.h> 42 #import <WebCore/FocusController.h> 43 #import <WebCore/Frame.h> 44 #import <WebCore/KeyboardEvent.h> 45 #import <WebCore/NotImplemented.h> 46 #import <WebCore/Page.h> 47 #import <WebKit/WebResource.h> 48 #import <WebKit/WebNSURLExtras.h> 49 50 using namespace WebCore; 51 52 @interface NSAttributedString (WebNSAttributedStringDetails) 53 - (DOMDocumentFragment*)_documentFromRange:(NSRange)range document:(DOMDocument*)document documentAttributes:(NSDictionary *)dict subresources:(NSArray **)subresources; 54 @end 55 56 @interface WebResource (WebResourceInternal) 57 - (WebCore::ArchiveResource*)_coreResource; 58 @end 59 60 namespace WebKit { 61 62 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event) 63 { 64 if (m_page->handleEditingKeyboardEvent(event, false)) 65 event->setDefaultHandled(); 66 } 67 68 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event) 69 { 70 if (m_page->handleEditingKeyboardEvent(event, true)) 71 event->setDefaultHandled(); 72 } 73 74 NSString *WebEditorClient::userVisibleString(NSURL *url) 75 { 76 return [url _web_userVisibleString]; 77 } 78 79 NSURL *WebEditorClient::canonicalizeURL(NSURL *url) 80 { 81 return [url _webkit_canonicalize]; 82 } 83 84 NSURL *WebEditorClient::canonicalizeURLString(NSString *URLString) 85 { 86 NSURL *URL = nil; 87 if ([URLString _webkit_looksLikeAbsoluteURL]) 88 URL = [[NSURL _web_URLWithUserTypedString:URLString] _webkit_canonicalize]; 89 return URL; 90 } 91 92 static NSArray *createExcludedElementsForAttributedStringConversion() 93 { 94 NSArray *elements = [[NSArray alloc] initWithObjects: 95 // Omit style since we want style to be inline so the fragment can be easily inserted. 96 @"style", 97 // Omit xml so the result is not XHTML. 98 @"xml", 99 // Omit tags that will get stripped when converted to a fragment anyway. 100 @"doctype", @"html", @"head", @"body", 101 // Omit deprecated tags. 102 @"applet", @"basefont", @"center", @"dir", @"font", @"isindex", @"menu", @"s", @"strike", @"u", 103 // Omit object so no file attachments are part of the fragment. 104 @"object", nil]; 105 CFRetain(elements); 106 return elements; 107 } 108 109 DocumentFragment* WebEditorClient::documentFragmentFromAttributedString(NSAttributedString *string, Vector<RefPtr<ArchiveResource> >& resources) 110 { 111 static NSArray *excludedElements = createExcludedElementsForAttributedStringConversion(); 112 113 NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys: excludedElements, 114 NSExcludedElementsDocumentAttribute, nil, @"WebResourceHandler", nil]; 115 116 NSArray *subResources; 117 DOMDocumentFragment* fragment = [string _documentFromRange:NSMakeRange(0, [string length]) 118 document:kit(m_page->mainFrame()->coreFrame()->document()) 119 documentAttributes:dictionary 120 subresources:&subResources]; 121 for (WebResource* resource in subResources) 122 resources.append([resource _coreResource]); 123 124 [dictionary release]; 125 return core(fragment); 126 } 127 128 void WebEditorClient::setInsertionPasteboard(NSPasteboard *) 129 { 130 // This is used only by Mail, no need to implement it now. 131 notImplemented(); 132 } 133 134 #ifdef BUILDING_ON_TIGER 135 NSArray *WebEditorClient::pasteboardTypesForSelection(Frame*) 136 { 137 notImplemented(); 138 return nil; 139 } 140 #endif 141 142 static void changeWordCase(WebPage* page, SEL selector) 143 { 144 Frame* frame = page->corePage()->focusController()->focusedOrMainFrame(); 145 if (!frame->editor()->canEdit()) 146 return; 147 148 frame->editor()->command("selectWord").execute(); 149 150 NSString *selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText()); 151 page->replaceSelectionWithText(frame, [selectedString performSelector:selector]); 152 } 153 154 void WebEditorClient::uppercaseWord() 155 { 156 changeWordCase(m_page, @selector(uppercaseString)); 157 } 158 159 void WebEditorClient::lowercaseWord() 160 { 161 changeWordCase(m_page, @selector(lowercaseString)); 162 } 163 164 void WebEditorClient::capitalizeWord() 165 { 166 changeWordCase(m_page, @selector(capitalizedString)); 167 } 168 169 void WebEditorClient::showSubstitutionsPanel(bool) 170 { 171 notImplemented(); 172 } 173 174 bool WebEditorClient::substitutionsPanelIsShowing() 175 { 176 bool isShowing; 177 m_page->sendSync(Messages::WebPageProxy::SubstitutionsPanelIsShowing(), Messages::WebPageProxy::SubstitutionsPanelIsShowing::Reply(isShowing)); 178 return isShowing; 179 } 180 181 void WebEditorClient::toggleSmartInsertDelete() 182 { 183 // This is handled in the UI process. 184 ASSERT_NOT_REACHED(); 185 } 186 187 bool WebEditorClient::isAutomaticQuoteSubstitutionEnabled() 188 { 189 return WebProcess::shared().textCheckerState().isAutomaticQuoteSubstitutionEnabled; 190 } 191 192 void WebEditorClient::toggleAutomaticQuoteSubstitution() 193 { 194 // This is handled in the UI process. 195 ASSERT_NOT_REACHED(); 196 } 197 198 bool WebEditorClient::isAutomaticLinkDetectionEnabled() 199 { 200 return WebProcess::shared().textCheckerState().isAutomaticLinkDetectionEnabled; 201 } 202 203 void WebEditorClient::toggleAutomaticLinkDetection() 204 { 205 // This is handled in the UI process. 206 ASSERT_NOT_REACHED(); 207 } 208 209 bool WebEditorClient::isAutomaticDashSubstitutionEnabled() 210 { 211 return WebProcess::shared().textCheckerState().isAutomaticDashSubstitutionEnabled; 212 } 213 214 void WebEditorClient::toggleAutomaticDashSubstitution() 215 { 216 // This is handled in the UI process. 217 ASSERT_NOT_REACHED(); 218 } 219 220 bool WebEditorClient::isAutomaticTextReplacementEnabled() 221 { 222 return WebProcess::shared().textCheckerState().isAutomaticTextReplacementEnabled; 223 } 224 225 void WebEditorClient::toggleAutomaticTextReplacement() 226 { 227 // This is handled in the UI process. 228 ASSERT_NOT_REACHED(); 229 } 230 231 bool WebEditorClient::isAutomaticSpellingCorrectionEnabled() 232 { 233 return WebProcess::shared().textCheckerState().isAutomaticSpellingCorrectionEnabled; 234 } 235 236 void WebEditorClient::toggleAutomaticSpellingCorrection() 237 { 238 notImplemented(); 239 } 240 241 void WebEditorClient::checkTextOfParagraph(const UChar* text, int length, WebCore::TextCheckingTypeMask checkingTypes, Vector<TextCheckingResult>& results) 242 { 243 // FIXME: It would be nice if we wouldn't have to copy the text here. 244 m_page->sendSync(Messages::WebPageProxy::CheckTextOfParagraph(String(text, length), checkingTypes), Messages::WebPageProxy::CheckTextOfParagraph::Reply(results)); 245 } 246 247 #if !defined(BUILDING_ON_SNOW_LEOPARD) 248 void WebEditorClient::showCorrectionPanel(WebCore::CorrectionPanelInfo::PanelType type, const WebCore::FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings) 249 { 250 m_page->send(Messages::WebPageProxy::ShowCorrectionPanel(type, boundingBoxOfReplacedString, replacedString, replacementString, alternativeReplacementStrings)); 251 } 252 253 void WebEditorClient::dismissCorrectionPanel(WebCore::ReasonForDismissingCorrectionPanel reason) 254 { 255 m_page->send(Messages::WebPageProxy::DismissCorrectionPanel(reason)); 256 } 257 258 String WebEditorClient::dismissCorrectionPanelSoon(WebCore::ReasonForDismissingCorrectionPanel reason) 259 { 260 String result; 261 m_page->sendSync(Messages::WebPageProxy::DismissCorrectionPanelSoon(reason), Messages::WebPageProxy::DismissCorrectionPanelSoon::Reply(result)); 262 return result; 263 } 264 265 void WebEditorClient::recordAutocorrectionResponse(EditorClient::AutocorrectionResponseType responseType, const String& replacedString, const String& replacementString) 266 { 267 m_page->send(Messages::WebPageProxy::RecordAutocorrectionResponse(responseType, replacedString, replacementString)); 268 } 269 #endif 270 271 } // namespace WebKit 272