1/*
2 * Copyright (C) 2006, 2010, 2011 Apple 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 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#if PLATFORM(MAC)
34
35#import "WebCoreArgumentCoders.h"
36#import "WebPage.h"
37#import "WebFrame.h"
38#import "WebPageProxyMessages.h"
39#import "WebProcess.h"
40#import <WebCore/ArchiveResource.h>
41#import <WebCore/DocumentFragment.h>
42#import <WebCore/DOMDocumentFragmentInternal.h>
43#import <WebCore/DOMDocumentInternal.h>
44#import <WebCore/FocusController.h>
45#import <WebCore/Frame.h>
46#import <WebCore/KeyboardEvent.h>
47#import <WebCore/NotImplemented.h>
48#import <WebCore/Page.h>
49#import <WebCore/WebCoreNSURLExtras.h>
50
51using namespace WebCore;
52
53@interface NSAttributedString (WebNSAttributedStringDetails)
54- (DOMDocumentFragment*)_documentFromRange:(NSRange)range document:(DOMDocument*)document documentAttributes:(NSDictionary *)dict subresources:(NSArray **)subresources;
55@end
56
57@interface NSObject (WebResourceInternal)
58- (WebCore::ArchiveResource*)_coreResource;
59@end
60
61namespace WebKit {
62
63void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
64{
65    if (m_page->handleEditingKeyboardEvent(event))
66        event->setDefaultHandled();
67}
68
69void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event)
70{
71    if (event->handledByInputMethod())
72        event->setDefaultHandled();
73}
74
75NSString *WebEditorClient::userVisibleString(NSURL *url)
76{
77    return WebCore::userVisibleString(url);
78}
79
80NSURL *WebEditorClient::canonicalizeURL(NSURL *url)
81{
82    return URLByCanonicalizingURL(url);
83}
84
85NSURL *WebEditorClient::canonicalizeURLString(NSString *URLString)
86{
87    NSURL *URL = nil;
88    if (looksLikeAbsoluteURL(URLString))
89        URL = URLByCanonicalizingURL(URLWithUserTypedString(URLString, nil));
90    return URL;
91}
92
93static NSArray *createExcludedElementsForAttributedStringConversion()
94{
95    NSArray *elements = [[NSArray alloc] initWithObjects:
96        // Omit style since we want style to be inline so the fragment can be easily inserted.
97        @"style",
98        // Omit xml so the result is not XHTML.
99        @"xml",
100        // Omit tags that will get stripped when converted to a fragment anyway.
101        @"doctype", @"html", @"head", @"body",
102        // Omit deprecated tags.
103        @"applet", @"basefont", @"center", @"dir", @"font", @"isindex", @"menu", @"s", @"strike", @"u",
104        // Omit object so no file attachments are part of the fragment.
105        @"object", nil];
106    CFRetain(elements);
107    return elements;
108}
109
110DocumentFragment* WebEditorClient::documentFragmentFromAttributedString(NSAttributedString *string, Vector<RefPtr<ArchiveResource>>& resources)
111{
112    static NSArray *excludedElements = createExcludedElementsForAttributedStringConversion();
113
114    NSDictionary *dictionary = [NSDictionary dictionaryWithObject:excludedElements forKey:NSExcludedElementsDocumentAttribute];
115
116    NSArray *subResources;
117    Document* document = m_page->mainFrame()->document();
118
119    // FIXME: Isntead of calling this WebKit1 method, the code should be factored out and moved into WebCore.
120    DOMDocumentFragment* fragment = [string _documentFromRange:NSMakeRange(0, [string length])
121                                                      document:kit(document)
122                                            documentAttributes:dictionary
123                                                  subresources:&subResources];
124    for (id resource in subResources)
125        resources.append([resource _coreResource]);
126
127    return core(fragment);
128}
129
130void WebEditorClient::setInsertionPasteboard(const String&)
131{
132    // This is used only by Mail, no need to implement it now.
133    notImplemented();
134}
135
136
137static void changeWordCase(WebPage* page, SEL selector)
138{
139    Frame& frame = page->corePage()->focusController().focusedOrMainFrame();
140    if (!frame.editor().canEdit())
141        return;
142
143    frame.editor().command("selectWord").execute();
144
145    NSString *selectedString = frame.displayStringModifiedByEncoding(frame.editor().selectedText());
146    page->replaceSelectionWithText(&frame, [selectedString performSelector:selector]);
147}
148
149#if USE(APPKIT)
150void WebEditorClient::uppercaseWord()
151{
152    changeWordCase(m_page, @selector(uppercaseString));
153}
154
155void WebEditorClient::lowercaseWord()
156{
157    changeWordCase(m_page, @selector(lowercaseString));
158}
159
160void WebEditorClient::capitalizeWord()
161{
162    changeWordCase(m_page, @selector(capitalizedString));
163}
164#endif
165
166#if USE(AUTOMATIC_TEXT_REPLACEMENT)
167void WebEditorClient::showSubstitutionsPanel(bool)
168{
169    notImplemented();
170}
171
172bool WebEditorClient::substitutionsPanelIsShowing()
173{
174    bool isShowing;
175    m_page->sendSync(Messages::WebPageProxy::SubstitutionsPanelIsShowing(), Messages::WebPageProxy::SubstitutionsPanelIsShowing::Reply(isShowing));
176    return isShowing;
177}
178
179void WebEditorClient::toggleSmartInsertDelete()
180{
181    // This is handled in the UI process.
182    ASSERT_NOT_REACHED();
183}
184
185bool WebEditorClient::isAutomaticQuoteSubstitutionEnabled()
186{
187    return WebProcess::shared().textCheckerState().isAutomaticQuoteSubstitutionEnabled;
188}
189
190void WebEditorClient::toggleAutomaticQuoteSubstitution()
191{
192    // This is handled in the UI process.
193    ASSERT_NOT_REACHED();
194}
195
196bool WebEditorClient::isAutomaticLinkDetectionEnabled()
197{
198    return WebProcess::shared().textCheckerState().isAutomaticLinkDetectionEnabled;
199}
200
201void WebEditorClient::toggleAutomaticLinkDetection()
202{
203    // This is handled in the UI process.
204    ASSERT_NOT_REACHED();
205}
206
207bool WebEditorClient::isAutomaticDashSubstitutionEnabled()
208{
209    return WebProcess::shared().textCheckerState().isAutomaticDashSubstitutionEnabled;
210}
211
212void WebEditorClient::toggleAutomaticDashSubstitution()
213{
214    // This is handled in the UI process.
215    ASSERT_NOT_REACHED();
216}
217
218bool WebEditorClient::isAutomaticTextReplacementEnabled()
219{
220    return WebProcess::shared().textCheckerState().isAutomaticTextReplacementEnabled;
221}
222
223void WebEditorClient::toggleAutomaticTextReplacement()
224{
225    // This is handled in the UI process.
226    ASSERT_NOT_REACHED();
227}
228
229bool WebEditorClient::isAutomaticSpellingCorrectionEnabled()
230{
231    return WebProcess::shared().textCheckerState().isAutomaticSpellingCorrectionEnabled;
232}
233
234void WebEditorClient::toggleAutomaticSpellingCorrection()
235{
236    notImplemented();
237}
238#endif // USE(AUTOMATIC_TEXT_REPLACEMENT)
239
240} // namespace WebKit
241
242#endif // PLATFORM(MAC)
243