WebPageWin.cpp revision 2fc2651226baac27029e38c9d6ef883fa32084db
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
51using namespace WebCore;
52
53namespace WebKit {
54
55void WebPage::platformInitialize()
56{
57    m_page->settings()->setFontRenderingMode(AlternateRenderingMode);
58}
59
60void 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
74static const unsigned CtrlKey = 1 << 0;
75static const unsigned AltKey = 1 << 1;
76static const unsigned ShiftKey = 1 << 2;
77
78struct KeyDownEntry {
79    unsigned virtualKey;
80    unsigned modifiers;
81    const char* name;
82};
83
84struct KeyPressEntry {
85    unsigned charCode;
86    unsigned modifiers;
87    const char* name;
88};
89
90static 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
149static 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
159const 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
194static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
195{
196    page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
197}
198
199static inline void logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
200{
201    page->focusController()->focusedOrMainFrame()->eventHandler()->logicalScrollRecursively(direction, granularity);
202}
203
204bool 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
247bool 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
265String 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
286bool 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
296void 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
304void 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
312void 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
325void 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
333