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 "WebPageProxyMessages.h"
32 #include "WebPreferencesStore.h"
33 #include <WebCore/FocusController.h>
34 #include <WebCore/FontRenderingMode.h>
35 #include <WebCore/Frame.h>
36 #include <WebCore/FrameView.h>
37 #include <WebCore/HitTestRequest.h>
38 #include <WebCore/HitTestResult.h>
39 #include <WebCore/KeyboardEvent.h>
40 #include <WebCore/Page.h>
41 #include <WebCore/PlatformKeyboardEvent.h>
42 #include <WebCore/RenderLayer.h>
43 #include <WebCore/RenderView.h>
44 #include <WebCore/ResourceHandle.h>
45 #include <WebCore/Settings.h>
46 #if USE(CG)
47 #include <WebKitSystemInterface/WebKitSystemInterface.h>
48 #endif
49 #include <WinUser.h>
50
51 #if USE(CFNETWORK)
52 #include <CFNetwork/CFURLCachePriv.h>
53 #include <CFNetwork/CFURLProtocolPriv.h>
54 #include <CFNetwork/CFURLRequestPriv.h>
55 #endif
56
57 using namespace WebCore;
58
59 namespace WebKit {
60
platformInitialize()61 void WebPage::platformInitialize()
62 {
63 m_page->settings()->setFontRenderingMode(AlternateRenderingMode);
64 }
65
platformPreferencesDidChange(const WebPreferencesStore & store)66 void WebPage::platformPreferencesDidChange(const WebPreferencesStore& store)
67 {
68 FontSmoothingLevel fontSmoothingLevel = static_cast<FontSmoothingLevel>(store.getUInt32ValueForKey(WebPreferencesKey::fontSmoothingLevelKey()));
69
70 #if USE(CG)
71 FontSmoothingLevel adjustedLevel = fontSmoothingLevel;
72 if (adjustedLevel == FontSmoothingLevelWindows)
73 adjustedLevel = FontSmoothingLevelMedium;
74 wkSetFontSmoothingLevel(adjustedLevel);
75 #endif
76
77 m_page->settings()->setFontRenderingMode(fontSmoothingLevel == FontSmoothingLevelWindows ? AlternateRenderingMode : NormalRenderingMode);
78 }
79
80 static const unsigned CtrlKey = 1 << 0;
81 static const unsigned AltKey = 1 << 1;
82 static const unsigned ShiftKey = 1 << 2;
83
84 struct KeyDownEntry {
85 unsigned virtualKey;
86 unsigned modifiers;
87 const char* name;
88 };
89
90 struct KeyPressEntry {
91 unsigned charCode;
92 unsigned modifiers;
93 const char* name;
94 };
95
96 static const KeyDownEntry keyDownEntries[] = {
97 { VK_LEFT, 0, "MoveLeft" },
98 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
99 { VK_LEFT, CtrlKey, "MoveWordLeft" },
100 { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" },
101 { VK_RIGHT, 0, "MoveRight" },
102 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
103 { VK_RIGHT, CtrlKey, "MoveWordRight" },
104 { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" },
105 { VK_UP, 0, "MoveUp" },
106 { VK_UP, ShiftKey, "MoveUpAndModifySelection" },
107 { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" },
108 { VK_DOWN, 0, "MoveDown" },
109 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" },
110 { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" },
111 { VK_PRIOR, 0, "MovePageUp" },
112 { VK_NEXT, 0, "MovePageDown" },
113 { VK_HOME, 0, "MoveToBeginningOfLine" },
114 { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" },
115 { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" },
116 { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
117
118 { VK_END, 0, "MoveToEndOfLine" },
119 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" },
120 { VK_END, CtrlKey, "MoveToEndOfDocument" },
121 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" },
122
123 { VK_BACK, 0, "DeleteBackward" },
124 { VK_BACK, ShiftKey, "DeleteBackward" },
125 { VK_DELETE, 0, "DeleteForward" },
126 { VK_BACK, CtrlKey, "DeleteWordBackward" },
127 { VK_DELETE, CtrlKey, "DeleteWordForward" },
128
129 { 'B', CtrlKey, "ToggleBold" },
130 { 'I', CtrlKey, "ToggleItalic" },
131
132 { VK_ESCAPE, 0, "Cancel" },
133 { VK_OEM_PERIOD, CtrlKey, "Cancel" },
134 { VK_TAB, 0, "InsertTab" },
135 { VK_TAB, ShiftKey, "InsertBacktab" },
136 { VK_RETURN, 0, "InsertNewline" },
137 { VK_RETURN, CtrlKey, "InsertNewline" },
138 { VK_RETURN, AltKey, "InsertNewline" },
139 { VK_RETURN, ShiftKey, "InsertNewline" },
140 { VK_RETURN, AltKey | ShiftKey, "InsertNewline" },
141
142 // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
143 // in the application or in WebKit. We chose WebKit.
144 { 'C', CtrlKey, "Copy" },
145 { 'V', CtrlKey, "Paste" },
146 { 'X', CtrlKey, "Cut" },
147 { 'A', CtrlKey, "SelectAll" },
148 { VK_INSERT, CtrlKey, "Copy" },
149 { VK_DELETE, ShiftKey, "Cut" },
150 { VK_INSERT, ShiftKey, "Paste" },
151 { 'Z', CtrlKey, "Undo" },
152 { 'Z', CtrlKey | ShiftKey, "Redo" },
153 };
154
155 static const KeyPressEntry keyPressEntries[] = {
156 { '\t', 0, "InsertTab" },
157 { '\t', ShiftKey, "InsertBacktab" },
158 { '\r', 0, "InsertNewline" },
159 { '\r', CtrlKey, "InsertNewline" },
160 { '\r', AltKey, "InsertNewline" },
161 { '\r', ShiftKey, "InsertNewline" },
162 { '\r', AltKey | ShiftKey, "InsertNewline" },
163 };
164
interpretKeyEvent(const KeyboardEvent * evt)165 const char* WebPage::interpretKeyEvent(const KeyboardEvent* evt)
166 {
167 ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
168
169 static HashMap<int, const char*>* keyDownCommandsMap = 0;
170 static HashMap<int, const char*>* keyPressCommandsMap = 0;
171
172 if (!keyDownCommandsMap) {
173 keyDownCommandsMap = new HashMap<int, const char*>;
174 keyPressCommandsMap = new HashMap<int, const char*>;
175
176 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
177 keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
178
179 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
180 keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
181 }
182
183 unsigned modifiers = 0;
184 if (evt->shiftKey())
185 modifiers |= ShiftKey;
186 if (evt->altKey())
187 modifiers |= AltKey;
188 if (evt->ctrlKey())
189 modifiers |= CtrlKey;
190
191 if (evt->type() == eventNames().keydownEvent) {
192 int mapKey = modifiers << 16 | evt->keyCode();
193 return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
194 }
195
196 int mapKey = modifiers << 16 | evt->charCode();
197 return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
198 }
199
performDefaultBehaviorForKeyEvent(const WebKeyboardEvent & keyboardEvent)200 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
201 {
202 if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown)
203 return false;
204
205 switch (keyboardEvent.windowsVirtualKeyCode()) {
206 case VK_BACK:
207 if (keyboardEvent.isSystemKey())
208 return false;
209 if (keyboardEvent.shiftKey())
210 m_page->goForward();
211 else
212 m_page->goBack();
213 break;
214 case VK_LEFT:
215 if (keyboardEvent.isSystemKey())
216 m_page->goBack();
217 else
218 scroll(m_page.get(), ScrollLeft, ScrollByLine);
219 break;
220 case VK_RIGHT:
221 if (keyboardEvent.isSystemKey())
222 m_page->goForward();
223 else
224 scroll(m_page.get(), ScrollRight, ScrollByLine);
225 break;
226 case VK_UP:
227 if (keyboardEvent.isSystemKey())
228 return false;
229 scroll(m_page.get(), ScrollUp, ScrollByLine);
230 break;
231 case VK_DOWN:
232 if (keyboardEvent.isSystemKey())
233 return false;
234 scroll(m_page.get(), ScrollDown, ScrollByLine);
235 break;
236 case VK_HOME:
237 if (keyboardEvent.isSystemKey())
238 return false;
239 logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
240 break;
241 case VK_END:
242 if (keyboardEvent.isSystemKey())
243 return false;
244 logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
245 break;
246 case VK_PRIOR:
247 if (keyboardEvent.isSystemKey())
248 return false;
249 logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
250 break;
251 case VK_NEXT:
252 if (keyboardEvent.isSystemKey())
253 return false;
254 logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
255 break;
256 default:
257 return false;
258 }
259
260 return true;
261 }
262
platformHasLocalDataForURL(const WebCore::KURL & url)263 bool WebPage::platformHasLocalDataForURL(const WebCore::KURL& url)
264 {
265 #if USE(CFNETWORK)
266 RetainPtr<CFURLRef> cfURL(AdoptCF, url.createCFURL());
267 RetainPtr<CFMutableURLRequestRef> request(AdoptCF, CFURLRequestCreateMutable(0, cfURL.get(), kCFURLRequestCachePolicyReloadIgnoringCache, 60, 0));
268
269 RetainPtr<CFStringRef> userAgent(AdoptCF, userAgent().createCFString());
270 CFURLRequestSetHTTPHeaderFieldValue(request.get(), CFSTR("User-Agent"), userAgent.get());
271
272 RetainPtr<CFURLCacheRef> cache;
273 #if USE(CFURLSTORAGESESSIONS)
274 if (CFURLStorageSessionRef storageSession = ResourceHandle::privateBrowsingStorageSession())
275 cache.adoptCF(wkCopyURLCache(storageSession));
276 else
277 #endif
278 cache.adoptCF(CFURLCacheCopySharedURLCache());
279
280 RetainPtr<CFCachedURLResponseRef> response(AdoptCF, CFURLCacheCopyResponseForRequest(cache.get(), request.get()));
281 return response;
282 #else
283 return false;
284 #endif
285 }
286
cachedResponseMIMETypeForURL(const WebCore::KURL & url)287 String WebPage::cachedResponseMIMETypeForURL(const WebCore::KURL& url)
288 {
289 #if USE(CFNETWORK)
290 RetainPtr<CFURLRef> cfURL(AdoptCF, url.createCFURL());
291 RetainPtr<CFMutableURLRequestRef> request(AdoptCF, CFURLRequestCreateMutable(0, cfURL.get(), kCFURLRequestCachePolicyReloadIgnoringCache, 60, 0));
292
293 RetainPtr<CFStringRef> userAgent(AdoptCF, userAgent().createCFString());
294 CFURLRequestSetHTTPHeaderFieldValue(request.get(), CFSTR("User-Agent"), userAgent.get());
295
296 RetainPtr<CFURLCacheRef> cache;
297 #if USE(CFURLSTORAGESESSIONS)
298 if (CFURLStorageSessionRef storageSession = ResourceHandle::privateBrowsingStorageSession())
299 cache.adoptCF(wkCopyURLCache(storageSession));
300 else
301 #endif
302 cache.adoptCF(CFURLCacheCopySharedURLCache());
303
304 RetainPtr<CFCachedURLResponseRef> cachedResponse(AdoptCF, CFURLCacheCopyResponseForRequest(cache.get(), request.get()));
305
306 CFURLResponseRef response = CFCachedURLResponseGetWrappedResponse(cachedResponse.get());
307
308 return response ? CFURLResponseGetMIMEType(response) : String();
309 #else
310 return String();
311 #endif
312 }
313
platformCanHandleRequest(const WebCore::ResourceRequest & request)314 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest& request)
315 {
316 #if USE(CFNETWORK)
317 return CFURLProtocolCanHandleRequest(request.cfURLRequest());
318 #else
319 return true;
320 #endif
321 }
322
confirmComposition(const String & compositionString)323 void WebPage::confirmComposition(const String& compositionString)
324 {
325 Frame* frame = m_page->focusController()->focusedOrMainFrame();
326 if (!frame || !frame->editor()->canEdit())
327 return;
328 frame->editor()->confirmComposition(compositionString);
329 }
330
setComposition(const String & compositionString,const Vector<WebCore::CompositionUnderline> & underlines,uint64_t cursorPosition)331 void WebPage::setComposition(const String& compositionString, const Vector<WebCore::CompositionUnderline>& underlines, uint64_t cursorPosition)
332 {
333 Frame* frame = m_page->focusController()->focusedOrMainFrame();
334 if (!frame || !frame->editor()->canEdit())
335 return;
336 frame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
337 }
338
firstRectForCharacterInSelectedRange(const uint64_t characterPosition,WebCore::IntRect & resultRect)339 void WebPage::firstRectForCharacterInSelectedRange(const uint64_t characterPosition, WebCore::IntRect& resultRect)
340 {
341 Frame* frame = m_page->focusController()->focusedOrMainFrame();
342 IntRect rect;
343 if (RefPtr<Range> range = frame->editor()->hasComposition() ? frame->editor()->compositionRange() : frame->selection()->selection().toNormalizedRange()) {
344 ExceptionCode ec = 0;
345 RefPtr<Range> tempRange = range->cloneRange(ec);
346 tempRange->setStart(tempRange->startContainer(ec), tempRange->startOffset(ec) + characterPosition, ec);
347 rect = frame->editor()->firstRectForRange(tempRange.get());
348 }
349 resultRect = frame->view()->contentsToWindow(rect);
350 }
351
getSelectedText(String & text)352 void WebPage::getSelectedText(String& text)
353 {
354 Frame* frame = m_page->focusController()->focusedOrMainFrame();
355 RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
356 text = selectedRange->text();
357 }
358
gestureWillBegin(const WebCore::IntPoint & point,bool & canBeginPanning)359 void WebPage::gestureWillBegin(const WebCore::IntPoint& point, bool& canBeginPanning)
360 {
361 m_gestureReachedScrollingLimit = false;
362
363 bool hitScrollbar = false;
364
365 HitTestRequest request(HitTestRequest::ReadOnly);
366 for (Frame* childFrame = m_page->mainFrame(); childFrame; childFrame = EventHandler::subframeForTargetNode(m_gestureTargetNode.get())) {
367 ScrollView* scollView = childFrame->view();
368 if (!scollView)
369 break;
370
371 RenderView* renderView = childFrame->document()->renderView();
372 if (!renderView)
373 break;
374
375 RenderLayer* layer = renderView->layer();
376 if (!layer)
377 break;
378
379 HitTestResult result = scollView->windowToContents(point);
380 layer->hitTest(request, result);
381 m_gestureTargetNode = result.innerNode();
382
383 if (!hitScrollbar)
384 hitScrollbar = result.scrollbar();
385 }
386
387 if (hitScrollbar) {
388 canBeginPanning = false;
389 return;
390 }
391
392 if (!m_gestureTargetNode) {
393 canBeginPanning = false;
394 return;
395 }
396
397 for (RenderObject* renderer = m_gestureTargetNode->renderer(); renderer; renderer = renderer->parent()) {
398 if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) {
399 canBeginPanning = true;
400 return;
401 }
402 }
403
404 canBeginPanning = false;
405 }
406
scrollbarAtTopOrBottomOfDocument(Scrollbar * scrollbar)407 static bool scrollbarAtTopOrBottomOfDocument(Scrollbar* scrollbar)
408 {
409 ASSERT_ARG(scrollbar, scrollbar);
410 return !scrollbar->currentPos() || scrollbar->currentPos() >= scrollbar->maximum();
411 }
412
gestureDidScroll(const IntSize & size)413 void WebPage::gestureDidScroll(const IntSize& size)
414 {
415 ASSERT_ARG(size, !size.isZero());
416
417 if (!m_gestureTargetNode || !m_gestureTargetNode->renderer() || !m_gestureTargetNode->renderer()->enclosingLayer())
418 return;
419
420 Scrollbar* verticalScrollbar = 0;
421 if (Frame* frame = m_page->mainFrame()) {
422 if (ScrollView* view = frame->view())
423 verticalScrollbar = view->verticalScrollbar();
424 }
425
426 m_gestureTargetNode->renderer()->enclosingLayer()->scrollByRecursively(size.width(), size.height());
427 bool gestureReachedScrollingLimit = verticalScrollbar && scrollbarAtTopOrBottomOfDocument(verticalScrollbar);
428
429 // FIXME: We really only want to update this state if the state was updated via scrolling the main frame,
430 // not scrolling something in a main frame when the main frame had already reached its scrolling limit.
431
432 if (gestureReachedScrollingLimit == m_gestureReachedScrollingLimit)
433 return;
434
435 send(Messages::WebPageProxy::SetGestureReachedScrollingLimit(gestureReachedScrollingLimit));
436 m_gestureReachedScrollingLimit = gestureReachedScrollingLimit;
437 }
438
gestureDidEnd()439 void WebPage::gestureDidEnd()
440 {
441 m_gestureTargetNode = nullptr;
442 }
443
444 } // namespace WebKit
445