<rdar://problem/8613727> and https://bugs.webkit.org/show_bug.cgi?id=49836
[WebKit-https.git] / WebKit2 / WebProcess / WebPage / mac / WebPageMac.mm
1 /*
2  * Copyright (C) 2010 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 #include "WebPage.h"
27
28 #include "WebCoreArgumentCoders.h"
29 #include "WebEvent.h"
30 #include "WebPageProxyMessages.h"
31 #include "WebProcess.h"
32 #include <WebCore/ArchiveResource.h>
33 #include <WebCore/DocumentLoader.h>
34 #include <WebCore/FocusController.h>
35 #include <WebCore/Frame.h>
36 #include <WebCore/KeyboardEvent.h>
37 #include <WebCore/Page.h>
38 #include <WebCore/PlatformKeyboardEvent.h>
39 #include <WebCore/WindowsKeyboardCodes.h>
40
41 using namespace WebCore;
42
43 namespace WebKit {
44
45 void WebPage::platformInitialize()
46 {
47     m_page->addSchedulePair(SchedulePair::create([NSRunLoop currentRunLoop], kCFRunLoopCommonModes));
48 }
49
50 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
51 {
52 }
53
54 // FIXME: need to add support for input methods
55     
56 bool WebPage::interceptEditingKeyboardEvent(KeyboardEvent* evt, bool shouldSaveCommand)
57 {
58     Node* node = evt->target()->toNode();
59     ASSERT(node);
60     Frame* frame = node->document()->frame();
61     ASSERT(frame);
62     
63     const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
64     if (!keyEvent)
65         return false;
66     const Vector<KeypressCommand>& commands = evt->keypressCommands();
67     bool hasKeypressCommand = !commands.isEmpty();
68     
69     bool eventWasHandled = false;
70     
71     if (shouldSaveCommand && !hasKeypressCommand) {
72         Vector<KeypressCommand> commandsList;        
73         if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(keyEvent->type()), Messages::WebPageProxy::InterpretKeyEvent::Reply(commandsList), m_pageID))
74             return false;
75         for (size_t i = 0; i < commandsList.size(); i++)
76             evt->keypressCommands().append(commandsList[i]);
77     } else {
78         size_t size = commands.size();
79         // Are there commands that would just cause text insertion if executed via Editor?
80         // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
81         // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
82         // (e.g. Tab that inserts a Tab character, or Enter).
83         bool haveTextInsertionCommands = false;
84         for (size_t i = 0; i < size; ++i) {
85             if (frame->editor()->command(commands[i].commandName).isTextInsertion())
86                 haveTextInsertionCommands = true;
87         }
88         if (!haveTextInsertionCommands || keyEvent->type() == PlatformKeyboardEvent::Char) {
89             for (size_t i = 0; i < size; ++i) {
90                 if (commands[i].commandName == "insertText") {
91                     // Don't insert null or control characters as they can result in unexpected behaviour
92                     if (evt->charCode() < ' ')
93                         return false;
94                     eventWasHandled = frame->editor()->insertText(commands[i].text, evt);
95                 } else
96                     if (frame->editor()->command(commands[i].commandName).isSupported())
97                         eventWasHandled = frame->editor()->command(commands[i].commandName).execute(evt);
98             }
99         }
100     }
101     return eventWasHandled;
102 }
103
104 static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
105 {
106     page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
107 }
108
109 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
110 {
111     if (keyboardEvent.type() != WebEvent::KeyDown)
112         return false;
113
114     // FIXME: This should be in WebCore.
115
116     switch (keyboardEvent.windowsVirtualKeyCode()) {
117     case VK_BACK:
118         if (keyboardEvent.shiftKey())
119             m_page->goForward();
120         else
121             m_page->goBack();
122         break;
123     case VK_SPACE:
124         if (keyboardEvent.shiftKey())
125             scroll(m_page.get(), ScrollUp, ScrollByPage);
126         else
127             scroll(m_page.get(), ScrollDown, ScrollByPage);
128         break;
129     case VK_PRIOR:
130         scroll(m_page.get(), ScrollUp, ScrollByPage);
131         break;
132     case VK_NEXT:
133         scroll(m_page.get(), ScrollDown, ScrollByPage);
134         break;
135     case VK_HOME:
136         scroll(m_page.get(), ScrollUp, ScrollByDocument);
137         scroll(m_page.get(), ScrollLeft, ScrollByDocument);
138         break;
139     case VK_END:
140         scroll(m_page.get(), ScrollDown, ScrollByDocument);
141         scroll(m_page.get(), ScrollLeft, ScrollByDocument);
142         break;
143     case VK_UP:
144         if (keyboardEvent.shiftKey())
145             return false;
146         if (keyboardEvent.metaKey()) {
147             scroll(m_page.get(), ScrollUp, ScrollByDocument);
148             scroll(m_page.get(), ScrollLeft, ScrollByDocument);
149         } else if (keyboardEvent.altKey() || keyboardEvent.controlKey())
150             scroll(m_page.get(), ScrollUp, ScrollByPage);
151         else
152             scroll(m_page.get(), ScrollUp, ScrollByLine);
153         break;
154     case VK_DOWN:
155         if (keyboardEvent.shiftKey())
156             return false;
157         if (keyboardEvent.metaKey()) {
158             scroll(m_page.get(), ScrollDown, ScrollByDocument);
159             scroll(m_page.get(), ScrollLeft, ScrollByDocument);
160         } else if (keyboardEvent.altKey() || keyboardEvent.controlKey())
161             scroll(m_page.get(), ScrollDown, ScrollByPage);
162         else
163             scroll(m_page.get(), ScrollDown, ScrollByLine);
164         break;
165     case VK_LEFT:
166         if (keyboardEvent.shiftKey())
167             return false;
168         if (keyboardEvent.metaKey())
169             m_page->goBack();
170         else {
171             if (keyboardEvent.altKey()  | keyboardEvent.controlKey())
172                 scroll(m_page.get(), ScrollLeft, ScrollByPage);
173             else
174                 scroll(m_page.get(), ScrollLeft, ScrollByLine);
175         }
176         break;
177     case VK_RIGHT:
178         if (keyboardEvent.shiftKey())
179             return false;
180         if (keyboardEvent.metaKey())
181             m_page->goForward();
182         else {
183             if (keyboardEvent.altKey() || keyboardEvent.controlKey())
184                 scroll(m_page.get(), ScrollRight, ScrollByPage);
185             else
186                 scroll(m_page.get(), ScrollRight, ScrollByLine);
187         }
188         break;
189     default:
190         return false;
191     }
192
193     return true;
194 }
195
196 bool WebPage::hasLocalDataForURL(const WebCore::KURL& url)
197 {
198     if (url.isLocalFile())
199         return true;
200     
201     FrameLoader* frameLoader = m_page->mainFrame()->loader();
202     DocumentLoader* documentLoader = frameLoader ? frameLoader->documentLoader() : 0;
203     if (documentLoader && documentLoader->subresource(url))
204         return true;
205
206     NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
207     [request setValue:(NSString*)userAgent() forHTTPHeaderField:@"User-Agent"];
208     NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
209     [request release];
210     
211     return cachedResponse;
212 }
213
214 bool WebPage::canHandleRequest(const WebCore::ResourceRequest& request)
215 {
216     if ([NSURLConnection canHandleRequest:request.nsURLRequest()])
217         return YES;
218
219     // FIXME: Return true if this scheme is any one WebKit2 knows how to handle.
220     return request.url().protocolIs("applewebdata");
221 }
222
223 } // namespace WebKit