https://bugs.webkit.org/show_bug.cgi?id=53330
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / win / WebPageWin.cpp
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 "config.h"
27 #include "WebPage.h"
28
29 #include "FontSmoothingLevel.h"
30 #include "WebEvent.h"
31 #include "WebPreferencesStore.h"
32 #include <WebCore/FocusController.h>
33 #include <WebCore/FontRenderingMode.h>
34 #include <WebCore/Frame.h>
35 #include <WebCore/FrameView.h>
36 #include <WebCore/KeyboardEvent.h>
37 #include <WebCore/Page.h>
38 #include <WebCore/PlatformKeyboardEvent.h>
39 #include <WebCore/Settings.h>
40 #if PLATFORM(CG)
41 #include <WebKitSystemInterface/WebKitSystemInterface.h>
42 #endif
43 #include <WinUser.h>
44
45 #if USE(CFNETWORK)
46 #include <CFNetwork/CFURLCachePriv.h>
47 #include <CFNetwork/CFURLProtocolPriv.h>
48 #include <CFNetwork/CFURLRequestPriv.h>
49 #endif
50
51 using namespace WebCore;
52
53 namespace WebKit {
54
55 void WebPage::platformInitialize()
56 {
57     m_page->settings()->setFontRenderingMode(AlternateRenderingMode);
58 }
59
60 void WebPage::platformPreferencesDidChange(const WebPreferencesStore& store)
61 {
62     FontSmoothingLevel fontSmoothingLevel = static_cast<FontSmoothingLevel>(store.getUInt32ValueForKey(WebPreferencesKey::fontSmoothingLevelKey()));
63
64 #if PLATFORM(CG)
65     FontSmoothingLevel adjustedLevel = fontSmoothingLevel;
66     if (adjustedLevel == FontSmoothingLevelWindows)
67         adjustedLevel = FontSmoothingLevelMedium;
68     wkSetFontSmoothingLevel(adjustedLevel);
69 #endif
70
71     m_page->settings()->setFontRenderingMode(fontSmoothingLevel == FontSmoothingLevelWindows ? AlternateRenderingMode : NormalRenderingMode);
72 }
73
74 static const unsigned CtrlKey = 1 << 0;
75 static const unsigned AltKey = 1 << 1;
76 static const unsigned ShiftKey = 1 << 2;
77
78 struct KeyDownEntry {
79     unsigned virtualKey;
80     unsigned modifiers;
81     const char* name;
82 };
83
84 struct KeyPressEntry {
85     unsigned charCode;
86     unsigned modifiers;
87     const char* name;
88 };
89
90 static const KeyDownEntry keyDownEntries[] = {
91     { VK_LEFT,   0,                  "MoveLeft"                                    },
92     { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
93     { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
94     { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
95     { VK_RIGHT,  0,                  "MoveRight"                                   },
96     { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
97     { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
98     { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
99     { VK_UP,     0,                  "MoveUp"                                      },
100     { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
101     { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
102     { VK_DOWN,   0,                  "MoveDown"                                    },
103     { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
104     { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
105     { VK_PRIOR,  0,                  "MovePageUp"                                  },
106     { VK_NEXT,   0,                  "MovePageDown"                                },
107     { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
108     { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
109     { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
110     { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
111
112     { VK_END,    0,                  "MoveToEndOfLine"                             },
113     { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
114     { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
115     { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
116
117     { VK_BACK,   0,                  "DeleteBackward"                              },
118     { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
119     { VK_DELETE, 0,                  "DeleteForward"                               },
120     { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
121     { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
122     
123     { 'B',       CtrlKey,            "ToggleBold"                                  },
124     { 'I',       CtrlKey,            "ToggleItalic"                                },
125
126     { VK_ESCAPE, 0,                  "Cancel"                                      },
127     { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
128     { VK_TAB,    0,                  "InsertTab"                                   },
129     { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
130     { VK_RETURN, 0,                  "InsertNewline"                               },
131     { VK_RETURN, CtrlKey,            "InsertNewline"                               },
132     { VK_RETURN, AltKey,             "InsertNewline"                               },
133     { VK_RETURN, ShiftKey,           "InsertNewline"                               },
134     { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
135
136     // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
137     // in the application or in WebKit. We chose WebKit.
138     { 'C',       CtrlKey,            "Copy"                                        },
139     { 'V',       CtrlKey,            "Paste"                                       },
140     { 'X',       CtrlKey,            "Cut"                                         },
141     { 'A',       CtrlKey,            "SelectAll"                                   },
142     { VK_INSERT, CtrlKey,            "Copy"                                        },
143     { VK_DELETE, ShiftKey,           "Cut"                                         },
144     { VK_INSERT, ShiftKey,           "Paste"                                       },
145     { 'Z',       CtrlKey,            "Undo"                                        },
146     { 'Z',       CtrlKey | ShiftKey, "Redo"                                        },
147 };
148
149 static const KeyPressEntry keyPressEntries[] = {
150     { '\t',   0,                  "InsertTab"                                   },
151     { '\t',   ShiftKey,           "InsertBacktab"                               },
152     { '\r',   0,                  "InsertNewline"                               },
153     { '\r',   CtrlKey,            "InsertNewline"                               },
154     { '\r',   AltKey,             "InsertNewline"                               },
155     { '\r',   ShiftKey,           "InsertNewline"                               },
156     { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
157 };
158
159 const char* WebPage::interpretKeyEvent(const KeyboardEvent* evt)
160 {
161     ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
162
163     static HashMap<int, const char*>* keyDownCommandsMap = 0;
164     static HashMap<int, const char*>* keyPressCommandsMap = 0;
165
166     if (!keyDownCommandsMap) {
167         keyDownCommandsMap = new HashMap<int, const char*>;
168         keyPressCommandsMap = new HashMap<int, const char*>;
169
170         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
171             keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
172
173         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
174             keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
175     }
176
177     unsigned modifiers = 0;
178     if (evt->shiftKey())
179         modifiers |= ShiftKey;
180     if (evt->altKey())
181         modifiers |= AltKey;
182     if (evt->ctrlKey())
183         modifiers |= CtrlKey;
184
185     if (evt->type() == eventNames().keydownEvent) {
186         int mapKey = modifiers << 16 | evt->keyCode();
187         return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
188     }
189
190     int mapKey = modifiers << 16 | evt->charCode();
191     return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
192 }
193
194 static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
195 {
196     page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
197 }
198
199 static inline void logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
200 {
201     page->focusController()->focusedOrMainFrame()->eventHandler()->logicalScrollRecursively(direction, granularity);
202 }
203
204 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
205 {
206     if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown)
207         return false;
208
209     switch (keyboardEvent.windowsVirtualKeyCode()) {
210     case VK_BACK:
211         if (keyboardEvent.shiftKey())
212             m_page->goForward();
213         else
214             m_page->goBack();
215         break;
216     case VK_LEFT:
217         scroll(m_page.get(), ScrollLeft, ScrollByLine);
218         break;
219     case VK_RIGHT:
220         scroll(m_page.get(), ScrollRight, ScrollByLine);
221         break;
222     case VK_UP:
223         scroll(m_page.get(), ScrollUp, ScrollByLine);
224         break;
225     case VK_DOWN:
226         scroll(m_page.get(), ScrollDown, ScrollByLine);
227         break;
228     case VK_HOME:
229         logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
230         break;
231     case VK_END:
232         logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
233         break;
234     case VK_PRIOR:
235         logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
236         break;
237     case VK_NEXT:
238         logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
239         break;
240     default:
241         return false;
242     }
243
244     return true;
245 }
246
247 bool WebPage::platformHasLocalDataForURL(const WebCore::KURL& url)
248 {
249 #if USE(CFNETWORK)
250     RetainPtr<CFURLRef> cfURL(AdoptCF, url.createCFURL());
251     RetainPtr<CFMutableURLRequestRef> request(AdoptCF, CFURLRequestCreateMutable(0, cfURL.get(), kCFURLRequestCachePolicyReloadIgnoringCache, 60, 0));
252     
253     RetainPtr<CFStringRef> userAgent(AdoptCF, userAgent().createCFString());
254     CFURLRequestSetHTTPHeaderFieldValue(request.get(), CFSTR("User-Agent"), userAgent.get());
255
256     RetainPtr<CFURLCacheRef> cache(AdoptCF, CFURLCacheCopySharedURLCache());
257
258     RetainPtr<CFCachedURLResponseRef> response(AdoptCF, CFURLCacheCopyResponseForRequest(cache.get(), request.get()));    
259     return response;
260 #else
261     return false;
262 #endif
263 }
264
265 String WebPage::cachedResponseMIMETypeForURL(const WebCore::KURL& url)
266 {
267 #if USE(CFNETWORK)
268     RetainPtr<CFURLRef> cfURL(AdoptCF, url.createCFURL());
269     RetainPtr<CFMutableURLRequestRef> request(AdoptCF, CFURLRequestCreateMutable(0, cfURL.get(), kCFURLRequestCachePolicyReloadIgnoringCache, 60, 0));
270     
271     RetainPtr<CFStringRef> userAgent(AdoptCF, userAgent().createCFString());
272     CFURLRequestSetHTTPHeaderFieldValue(request.get(), CFSTR("User-Agent"), userAgent.get());
273
274     RetainPtr<CFURLCacheRef> cache(AdoptCF, CFURLCacheCopySharedURLCache());
275
276     RetainPtr<CFCachedURLResponseRef> cachedResponse(AdoptCF, CFURLCacheCopyResponseForRequest(cache.get(), request.get()));
277     
278     CFURLResponseRef response = CFCachedURLResponseGetWrappedResponse(cachedResponse.get());
279     
280     return response ? CFURLResponseGetMIMEType(response) : String();
281 #else
282     return String();
283 #endif
284 }
285
286 bool WebPage::canHandleRequest(const WebCore::ResourceRequest& request)
287 {
288 #if USE(CFNETWORK)
289      // FIXME: Are there other requests we need to be able to handle? WebKit1's WebView.cpp has a FIXME here as well.
290     return CFURLProtocolCanHandleRequest(request.cfURLRequest());
291 #else
292     return true;
293 #endif
294 }
295
296 void WebPage::confirmComposition(const String& compositionString)
297 {
298     Frame* frame = m_page->focusController()->focusedOrMainFrame();
299     if (!frame || !frame->editor()->canEdit())
300         return;
301     frame->editor()->confirmComposition(compositionString);
302 }
303
304 void WebPage::setComposition(const String& compositionString, const Vector<WebCore::CompositionUnderline>& underlines, uint64_t cursorPosition)
305 {
306     Frame* frame = m_page->focusController()->focusedOrMainFrame();
307     if (!frame || !frame->editor()->canEdit())
308         return;
309     frame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
310 }
311
312 void WebPage::firstRectForCharacterInSelectedRange(const uint64_t characterPosition, WebCore::IntRect& resultRect)
313 {
314     Frame* frame = m_page->focusController()->focusedOrMainFrame();
315     IntRect rect;
316     if (RefPtr<Range> range = frame->editor()->hasComposition() ? frame->editor()->compositionRange() : frame->selection()->selection().toNormalizedRange()) {
317         ExceptionCode ec = 0;
318         RefPtr<Range> tempRange = range->cloneRange(ec);
319         tempRange->setStart(tempRange->startContainer(ec), tempRange->startOffset(ec) + characterPosition, ec);
320         rect = frame->editor()->firstRectForRange(tempRange.get());
321     }
322     resultRect = frame->view()->contentsToWindow(rect);
323 }
324
325 void WebPage::getSelectedText(String& text)
326 {
327     Frame* frame = m_page->focusController()->focusedOrMainFrame();
328     RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
329     text = selectedRange->text();
330 }
331
332 } // namespace WebKit