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