08b5021f04442316f26e664cf053da39d99c5cc1
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / qt / WebPageQt.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "WebPage.h"
29
30 #include "NotImplemented.h"
31 #include "PopupMenuClient.h"
32 #include "WebEditorClient.h"
33 #include "WebEvent.h"
34 #include "WebPageProxyMessages.h"
35 #include "WebPopupMenu.h"
36 #include "WebProcess.h"
37 #include <QClipboard>
38 #include <QGuiApplication>
39 #include <WebCore/DOMWrapperWorld.h>
40 #include <WebCore/FocusController.h>
41 #include <WebCore/Frame.h>
42 #include <WebCore/KeyboardEvent.h>
43 #include <WebCore/Page.h>
44 #include <WebCore/PageGroup.h>
45 #include <WebCore/PlatformKeyboardEvent.h>
46 #include <WebCore/Range.h>
47 #include <WebCore/Settings.h>
48 #include <WebCore/Text.h>
49 #include <WebCore/TextIterator.h>
50
51 #ifndef VK_UNKNOWN
52 #define VK_UNKNOWN 0
53 #define VK_BACK 0x08
54 #define VK_TAB 0x09
55 #define VK_CLEAR 0x0C
56 #define VK_RETURN 0x0D
57 #define VK_SHIFT 0x10
58 #define VK_CONTROL 0x11 // CTRL key
59 #define VK_MENU 0x12 // ALT key
60 #define VK_PAUSE 0x13 // PAUSE key
61 #define VK_CAPITAL 0x14 // CAPS LOCK key
62 #define VK_KANA 0x15 // Input Method Editor (IME) Kana mode
63 #define VK_HANGUL 0x15 // IME Hangul mode
64 #define VK_JUNJA 0x17 // IME Junja mode
65 #define VK_FINAL 0x18 // IME final mode
66 #define VK_HANJA 0x19 // IME Hanja mode 
67 #define VK_KANJI 0x19 // IME Kanji mode
68 #define VK_ESCAPE 0x1B // ESC key
69 #define VK_CONVERT 0x1C // IME convert
70 #define VK_NONCONVERT 0x1D // IME nonconvert
71 #define VK_ACCEPT 0x1E // IME accept
72 #define VK_MODECHANGE 0x1F // IME mode change request
73 #define VK_SPACE 0x20 // SPACE key
74 #define VK_PRIOR 0x21 // PAGE UP key
75 #define VK_NEXT 0x22 // PAGE DOWN key
76 #define VK_END 0x23 // END key
77 #define VK_HOME 0x24 // HOME key
78 #define VK_LEFT 0x25 // LEFT ARROW key
79 #define VK_UP 0x26 // UP ARROW key
80 #define VK_RIGHT 0x27 // RIGHT ARROW key
81 #define VK_DOWN 0x28 // DOWN ARROW key
82 #define VK_SELECT 0x29 // SELECT key
83 #define VK_PRINT 0x2A // PRINT key
84 #define VK_EXECUTE 0x2B // EXECUTE key
85 #define VK_SNAPSHOT 0x2C // PRINT SCREEN key
86 #define VK_INSERT 0x2D // INS key
87 #define VK_DELETE 0x2E // DEL key
88 #define VK_HELP 0x2F // HELP key
89 // Windows 2000/XP: For any country/region, the '.' key
90 #define VK_OEM_PERIOD 0xBE
91 #endif
92
93 using namespace WebCore;
94
95 namespace WebKit {
96     
97 void WebPage::platformInitialize()
98 {
99 }
100
101 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
102 {
103 }
104
105 static const unsigned CtrlKey = 1 << 0;
106 static const unsigned AltKey = 1 << 1;
107 static const unsigned ShiftKey = 1 << 2;
108
109 struct KeyDownEntry {
110     unsigned virtualKey;
111     unsigned modifiers;
112     const char* name;
113 };
114
115 struct KeyPressEntry {
116     unsigned charCode;
117     unsigned modifiers;
118     const char* name;
119 };
120
121 static const KeyDownEntry keyDownEntries[] = {
122     { VK_LEFT,   0,                  "MoveLeft"                                    },
123     { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
124     { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
125     { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
126     { VK_RIGHT,  0,                  "MoveRight"                                   },
127     { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
128     { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
129     { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
130     { VK_UP,     0,                  "MoveUp"                                      },
131     { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
132     { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
133     { VK_DOWN,   0,                  "MoveDown"                                    },
134     { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
135     { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
136     { VK_PRIOR,  0,                  "MovePageUp"                                  },
137     { VK_NEXT,   0,                  "MovePageDown"                                },
138     { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
139     { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
140     { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
141     { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
142     
143     { VK_END,    0,                  "MoveToEndOfLine"                             },
144     { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
145     { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
146     { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
147     
148     { VK_BACK,   0,                  "DeleteBackward"                              },
149     { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
150     { VK_DELETE, 0,                  "DeleteForward"                               },
151     { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
152     { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
153     
154     { 'B',       CtrlKey,            "ToggleBold"                                  },
155     { 'I',       CtrlKey,            "ToggleItalic"                                },
156     
157     { VK_ESCAPE, 0,                  "Cancel"                                      },
158     { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
159     { VK_TAB,    0,                  "InsertTab"                                   },
160     { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
161     { VK_RETURN, 0,                  "InsertNewline"                               },
162     { VK_RETURN, CtrlKey,            "InsertNewline"                               },
163     { VK_RETURN, AltKey,             "InsertNewline"                               },
164     { VK_RETURN, ShiftKey,           "InsertNewline"                               },
165     { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
166     
167     // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
168     // in the application or in WebKit. We chose WebKit.
169     { 'C',       CtrlKey,            "Copy"                                        },
170     { 'V',       CtrlKey,            "Paste"                                       },
171     { 'X',       CtrlKey,            "Cut"                                         },
172     { 'A',       CtrlKey,            "SelectAll"                                   },
173     { VK_INSERT, CtrlKey,            "Copy"                                        },
174     { VK_DELETE, ShiftKey,           "Cut"                                         },
175     { VK_INSERT, ShiftKey,           "Paste"                                       },
176     { 'Z',       CtrlKey,            "Undo"                                        },
177     { 'Z',       CtrlKey | ShiftKey, "Redo"                                        },
178 };
179
180 static const KeyPressEntry keyPressEntries[] = {
181     { '\t',   0,                  "InsertTab"                                   },
182     { '\t',   ShiftKey,           "InsertBacktab"                               },
183     { '\r',   0,                  "InsertNewline"                               },
184     { '\r',   CtrlKey,            "InsertNewline"                               },
185     { '\r',   AltKey,             "InsertNewline"                               },
186     { '\r',   ShiftKey,           "InsertNewline"                               },
187     { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
188 };
189
190 const char* WebPage::interpretKeyEvent(const KeyboardEvent* evt)
191 {
192     ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
193     
194     static HashMap<int, const char*>* keyDownCommandsMap = 0;
195     static HashMap<int, const char*>* keyPressCommandsMap = 0;
196     
197     if (!keyDownCommandsMap) {
198         keyDownCommandsMap = new HashMap<int, const char*>;
199         keyPressCommandsMap = new HashMap<int, const char*>;
200         
201         for (unsigned i = 0; i < (sizeof(keyDownEntries) / sizeof(keyDownEntries[0])); i++)
202             keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
203         
204         for (unsigned i = 0; i < (sizeof(keyPressEntries) / sizeof(keyPressEntries[0])); i++)
205             keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
206     }
207     
208     unsigned modifiers = 0;
209     if (evt->shiftKey())
210         modifiers |= ShiftKey;
211     if (evt->altKey())
212         modifiers |= AltKey;
213     if (evt->ctrlKey())
214         modifiers |= CtrlKey;
215     
216     if (evt->type() == eventNames().keydownEvent) {
217         int mapKey = modifiers << 16 | evt->keyEvent()->windowsVirtualKeyCode();
218         return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
219     }
220     
221     int mapKey = modifiers << 16 | evt->charCode();
222     return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
223 }
224
225 static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
226 {
227     page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
228 }
229
230 static inline void logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
231 {
232     page->focusController()->focusedOrMainFrame()->eventHandler()->logicalScrollRecursively(direction, granularity);
233 }
234
235 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
236 {
237     if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown)
238         return false;
239
240     switch (keyboardEvent.windowsVirtualKeyCode()) {
241     case VK_BACK:
242         if (keyboardEvent.shiftKey())
243             m_page->goForward();
244         else
245             m_page->goBack();
246         break;
247     case VK_SPACE:
248         logicalScroll(m_page.get(), keyboardEvent.shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward, ScrollByPage);
249         break;
250     case VK_LEFT:
251         scroll(m_page.get(), ScrollLeft, ScrollByLine);
252         break;
253     case VK_RIGHT:
254         scroll(m_page.get(), ScrollRight, ScrollByLine);
255         break;
256     case VK_UP:
257         scroll(m_page.get(), ScrollUp, ScrollByLine);
258         break;
259     case VK_DOWN:
260         scroll(m_page.get(), ScrollDown, ScrollByLine);
261         break;
262     case VK_HOME:
263         logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
264         break;
265     case VK_END:
266         logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
267         break;
268     case VK_PRIOR:
269         logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
270         break;
271     case VK_NEXT:
272         logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
273         break;
274     default:
275         return false;
276     }
277
278     return true;
279 }
280
281 bool WebPage::platformHasLocalDataForURL(const KURL&)
282 {
283     notImplemented();
284     return false;
285 }
286
287 String WebPage::cachedResponseMIMETypeForURL(const KURL&)
288 {
289     notImplemented();
290     return String();
291 }
292
293 bool WebPage::platformCanHandleRequest(const ResourceRequest&)
294 {
295     notImplemented();
296     return true;
297 }
298
299 String WebPage::cachedSuggestedFilenameForURL(const KURL&)
300 {
301     notImplemented();
302     return String();
303 }
304
305 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const KURL&)
306 {
307     notImplemented();
308     return 0;
309 }
310
311 void WebPage::commitPageTransitionViewport()
312 {
313     m_drawingArea->setLayerTreeStateIsFrozen(false);
314 }
315
316 static Frame* targetFrameForEditing(WebPage* page)
317 {
318     Frame* targetFrame = page->corePage()->focusController()->focusedOrMainFrame();
319
320     if (!targetFrame || !targetFrame->editor())
321         return 0;
322
323     Editor* editor = targetFrame->editor();
324     if (!editor->canEdit())
325         return 0;
326
327     if (editor->hasComposition()) {
328         // We should verify the parent node of this IME composition node are
329         // editable because JavaScript may delete a parent node of the composition
330         // node. In this case, WebKit crashes while deleting texts from the parent
331         // node, which doesn't exist any longer.
332         if (PassRefPtr<Range> range = editor->compositionRange()) {
333             Node* node = range->startContainer();
334             if (!node || !node->isContentEditable())
335                 return 0;
336         }
337     }
338     return targetFrame;
339 }
340
341 void WebPage::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength)
342 {
343     Frame* targetFrame = targetFrameForEditing(this);
344     if (!targetFrame)
345         return;
346
347     Editor* editor = targetFrame->editor();
348     editor->confirmComposition(compositionString);
349
350     if (selectionStart == -1)
351         return;
352
353     Element* scope = targetFrame->selection()->rootEditableElement();
354     RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(scope, selectionStart, selectionLength);
355     ASSERT_WITH_MESSAGE(selectionRange, "Invalid selection: [%lld:%lld] in text of length %d", static_cast<long long>(selectionStart), static_cast<long long>(selectionLength), scope->innerText().length());
356
357     if (selectionRange) {
358         VisibleSelection selection(selectionRange.get(), SEL_DEFAULT_AFFINITY);
359         targetFrame->selection()->setSelection(selection);
360     }
361
362     // FIXME: static_cast<WebEditorClient*>(editor->client())->sendSelectionChangedMessage();
363 }
364
365 void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementStart, uint64_t replacementLength)
366 {
367     Frame* targetFrame = targetFrameForEditing(this);
368     if (!targetFrame)
369         return;
370
371     Element* scope = targetFrame->selection()->rootEditableElement();
372
373     if (targetFrame->selection()->isContentEditable()) {
374         if (replacementLength > 0) {
375             // The layout needs to be uptodate before setting a selection
376             targetFrame->document()->updateLayout();
377
378             RefPtr<Range> replacementRange = TextIterator::rangeFromLocationAndLength(scope, replacementStart, replacementLength);
379
380             targetFrame->editor()->setIgnoreCompositionSelectionChange(true);
381             targetFrame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
382             targetFrame->editor()->setIgnoreCompositionSelectionChange(false);
383         }
384
385         targetFrame->editor()->setComposition(text, underlines, selectionStart, selectionEnd);
386
387         // FIXME: static_cast<WebEditorClient*>(targetFrame->editor()->client())->sendSelectionChangedMessage();
388     }
389 }
390
391 void WebPage::cancelComposition()
392 {
393     Frame* frame = targetFrameForEditing(this);
394
395     frame->editor()->cancelComposition();
396
397     // FIXME: static_cast<WebEditorClient*>(targetFrame->editor()->client())->sendSelectionChangedMessage();
398 }
399
400 void WebPage::registerApplicationScheme(const String& scheme)
401 {
402     QtNetworkAccessManager* qnam = qobject_cast<QtNetworkAccessManager*>(WebProcess::shared().networkAccessManager());
403     if (!qnam)
404         return;
405     qnam->registerApplicationScheme(this, QString(scheme));
406 }
407
408 void WebPage::receivedApplicationSchemeRequest(const QNetworkRequest& request, QtNetworkReply* reply)
409 {
410     QtNetworkRequestData requestData(request, reply);
411     m_applicationSchemeReplies.add(requestData.m_replyUuid, reply);
412     send(Messages::WebPageProxy::ResolveApplicationSchemeRequest(requestData));
413 }
414
415 void WebPage::applicationSchemeReply(const QtNetworkReplyData& replyData)
416 {
417     if (!m_applicationSchemeReplies.contains(replyData.m_replyUuid))
418         return;
419
420     QtNetworkReply* networkReply = m_applicationSchemeReplies.take(replyData.m_replyUuid);
421     networkReply->setReplyData(replyData);
422     networkReply->finalize();
423 }
424
425 void WebPage::setUserScripts(const Vector<String>& scripts)
426 {
427     // This works because we keep an unique page group for each Page.
428     PageGroup* pageGroup = PageGroup::pageGroup(this->pageGroup()->identifier());
429     pageGroup->removeUserScriptsFromWorld(mainThreadNormalWorld());
430     for (unsigned i = 0; i < scripts.size(); ++i)
431         pageGroup->addUserScriptToWorld(mainThreadNormalWorld(), scripts.at(i), KURL(), nullptr, nullptr, InjectAtDocumentEnd, InjectInTopFrameOnly);
432 }
433
434 void WebPage::selectedIndex(int32_t newIndex)
435 {
436     changeSelectedIndex(newIndex);
437 }
438
439 void WebPage::hidePopupMenu()
440 {
441     if (!m_activePopupMenu)
442         return;
443
444     m_activePopupMenu->client()->popupDidHide();
445     m_activePopupMenu = 0;
446 }
447
448 } // namespace WebKit