2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "FontSmoothingLevel.h"
30 #include "WebCoreArgumentCoders.h"
32 #include "WebPageProxyMessages.h"
33 #include "WebPreferencesStore.h"
34 #include "WebProcess.h"
35 #include <WebCore/FocusController.h>
36 #include <WebCore/FontRenderingMode.h>
37 #include <WebCore/Frame.h>
38 #include <WebCore/FrameView.h>
39 #include <WebCore/HitTestRequest.h>
40 #include <WebCore/HitTestResult.h>
41 #include <WebCore/KeyboardEvent.h>
42 #include <WebCore/Page.h>
43 #include <WebCore/PlatformKeyboardEvent.h>
44 #include <WebCore/RenderLayer.h>
45 #include <WebCore/RenderView.h>
46 #include <WebCore/ResourceHandle.h>
47 #include <WebCore/Settings.h>
49 #include <WebKitSystemInterface/WebKitSystemInterface.h>
54 #include <CFNetwork/CFURLCachePriv.h>
55 #include <CFNetwork/CFURLProtocolPriv.h>
56 #include <CFNetwork/CFURLRequestPriv.h>
59 using namespace WebCore;
63 void WebPage::platformInitialize()
67 void WebPage::platformPreferencesDidChange(const WebPreferencesStore& store)
69 FontSmoothingLevel fontSmoothingLevel = static_cast<FontSmoothingLevel>(store.getUInt32ValueForKey(WebPreferencesKey::fontSmoothingLevelKey()));
72 FontSmoothingLevel adjustedLevel = fontSmoothingLevel;
73 if (adjustedLevel == FontSmoothingLevelWindows)
74 adjustedLevel = FontSmoothingLevelMedium;
75 wkSetFontSmoothingLevel(adjustedLevel);
78 m_page->settings()->setFontRenderingMode(fontSmoothingLevel == FontSmoothingLevelWindows ? AlternateRenderingMode : NormalRenderingMode);
81 static const unsigned CtrlKey = 1 << 0;
82 static const unsigned AltKey = 1 << 1;
83 static const unsigned ShiftKey = 1 << 2;
91 struct KeyPressEntry {
97 static const KeyDownEntry keyDownEntries[] = {
98 { VK_LEFT, 0, "MoveLeft" },
99 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
100 { VK_LEFT, CtrlKey, "MoveWordLeft" },
101 { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" },
102 { VK_RIGHT, 0, "MoveRight" },
103 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
104 { VK_RIGHT, CtrlKey, "MoveWordRight" },
105 { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" },
106 { VK_UP, 0, "MoveUp" },
107 { VK_UP, ShiftKey, "MoveUpAndModifySelection" },
108 { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" },
109 { VK_DOWN, 0, "MoveDown" },
110 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" },
111 { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" },
112 { VK_PRIOR, 0, "MovePageUp" },
113 { VK_NEXT, 0, "MovePageDown" },
114 { VK_HOME, 0, "MoveToBeginningOfLine" },
115 { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" },
116 { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" },
117 { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
119 { VK_END, 0, "MoveToEndOfLine" },
120 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" },
121 { VK_END, CtrlKey, "MoveToEndOfDocument" },
122 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" },
124 { VK_BACK, 0, "DeleteBackward" },
125 { VK_BACK, ShiftKey, "DeleteBackward" },
126 { VK_DELETE, 0, "DeleteForward" },
127 { VK_BACK, CtrlKey, "DeleteWordBackward" },
128 { VK_DELETE, CtrlKey, "DeleteWordForward" },
130 { 'B', CtrlKey, "ToggleBold" },
131 { 'I', CtrlKey, "ToggleItalic" },
133 { VK_ESCAPE, 0, "Cancel" },
134 { VK_OEM_PERIOD, CtrlKey, "Cancel" },
135 { VK_TAB, 0, "InsertTab" },
136 { VK_TAB, ShiftKey, "InsertBacktab" },
137 { VK_RETURN, 0, "InsertNewline" },
138 { VK_RETURN, CtrlKey, "InsertNewline" },
139 { VK_RETURN, AltKey, "InsertNewline" },
140 { VK_RETURN, ShiftKey, "InsertNewline" },
141 { VK_RETURN, AltKey | ShiftKey, "InsertNewline" },
143 // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
144 // in the application or in WebKit. We chose WebKit.
145 { 'C', CtrlKey, "Copy" },
146 { 'V', CtrlKey, "Paste" },
147 { 'X', CtrlKey, "Cut" },
148 { 'A', CtrlKey, "SelectAll" },
149 { VK_INSERT, CtrlKey, "Copy" },
150 { VK_DELETE, ShiftKey, "Cut" },
151 { VK_INSERT, ShiftKey, "Paste" },
152 { 'Z', CtrlKey, "Undo" },
153 { 'Z', CtrlKey | ShiftKey, "Redo" },
156 static const KeyPressEntry keyPressEntries[] = {
157 { '\t', 0, "InsertTab" },
158 { '\t', ShiftKey, "InsertBacktab" },
159 { '\r', 0, "InsertNewline" },
160 { '\r', CtrlKey, "InsertNewline" },
161 { '\r', AltKey, "InsertNewline" },
162 { '\r', ShiftKey, "InsertNewline" },
163 { '\r', AltKey | ShiftKey, "InsertNewline" },
166 const char* WebPage::interpretKeyEvent(const KeyboardEvent* evt)
168 ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
170 static HashMap<int, const char*>* keyDownCommandsMap = 0;
171 static HashMap<int, const char*>* keyPressCommandsMap = 0;
173 if (!keyDownCommandsMap) {
174 keyDownCommandsMap = new HashMap<int, const char*>;
175 keyPressCommandsMap = new HashMap<int, const char*>;
177 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
178 keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
180 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
181 keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
184 unsigned modifiers = 0;
186 modifiers |= ShiftKey;
190 modifiers |= CtrlKey;
192 if (evt->type() == eventNames().keydownEvent) {
193 int mapKey = modifiers << 16 | evt->keyCode();
194 return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
197 int mapKey = modifiers << 16 | evt->charCode();
198 return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
201 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
203 if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown)
206 switch (keyboardEvent.windowsVirtualKeyCode()) {
208 if (keyboardEvent.isSystemKey())
210 if (keyboardEvent.shiftKey())
216 if (keyboardEvent.isSystemKey())
219 scroll(m_page.get(), ScrollLeft, ScrollByLine);
222 if (keyboardEvent.isSystemKey())
225 scroll(m_page.get(), ScrollRight, ScrollByLine);
228 if (keyboardEvent.isSystemKey())
230 scroll(m_page.get(), ScrollUp, ScrollByLine);
233 if (keyboardEvent.isSystemKey())
235 scroll(m_page.get(), ScrollDown, ScrollByLine);
238 if (keyboardEvent.isSystemKey())
240 logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
243 if (keyboardEvent.isSystemKey())
245 logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
248 if (keyboardEvent.isSystemKey())
250 logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
253 if (keyboardEvent.isSystemKey())
255 logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
265 static RetainPtr<CFCachedURLResponseRef> cachedResponseForURL(WebPage* webPage, const KURL& url)
267 RetainPtr<CFURLRef> cfURL(AdoptCF, url.createCFURL());
268 RetainPtr<CFMutableURLRequestRef> request(AdoptCF, CFURLRequestCreateMutable(0, cfURL.get(), kCFURLRequestCachePolicyReloadIgnoringCache, 60, 0));
269 #if USE(CFURLSTORAGESESSIONS)
270 wkSetRequestStorageSession(ResourceHandle::currentStorageSession(), request.get());
273 RetainPtr<CFStringRef> userAgent(AdoptCF, webPage->userAgent().createCFString());
274 CFURLRequestSetHTTPHeaderFieldValue(request.get(), CFSTR("User-Agent"), userAgent.get());
276 RetainPtr<CFURLCacheRef> cache;
277 #if USE(CFURLSTORAGESESSIONS)
278 if (CFURLStorageSessionRef currentStorageSession = ResourceHandle::currentStorageSession())
279 cache.adoptCF(wkCopyURLCache(currentStorageSession));
282 cache.adoptCF(CFURLCacheCopySharedURLCache());
284 RetainPtr<CFCachedURLResponseRef> response(AdoptCF, CFURLCacheCopyResponseForRequest(cache.get(), request.get()));
289 bool WebPage::platformHasLocalDataForURL(const KURL& url)
292 return cachedResponseForURL(this, url);
298 String WebPage::cachedResponseMIMETypeForURL(const KURL& url)
301 RetainPtr<CFCachedURLResponseRef> cachedResponse = cachedResponseForURL(this, url);
302 CFURLResponseRef response = CFCachedURLResponseGetWrappedResponse(cachedResponse.get());
303 return response ? CFURLResponseGetMIMEType(response) : String();
309 String WebPage::cachedSuggestedFilenameForURL(const KURL& url)
312 RetainPtr<CFCachedURLResponseRef> cachedResponse = cachedResponseForURL(this, url);
313 CFURLResponseRef response = CFCachedURLResponseGetWrappedResponse(cachedResponse.get());
316 RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(response));
318 return suggestedFilename.get();
324 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const KURL& url)
327 RetainPtr<CFCachedURLResponseRef> cachedResponse = cachedResponseForURL(this, url);
328 CFDataRef data = CFCachedURLResponseGetReceiverData(cachedResponse.get());
332 return SharedBuffer::wrapCFData(data);
338 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest& request)
341 return CFURLProtocolCanHandleRequest(request.cfURLRequest());
347 void WebPage::confirmComposition(const String& compositionString)
349 Frame* frame = m_page->focusController()->focusedOrMainFrame();
350 if (!frame || !frame->editor()->canEdit())
352 frame->editor()->confirmComposition(compositionString);
355 void WebPage::setComposition(const String& compositionString, const Vector<WebCore::CompositionUnderline>& underlines, uint64_t cursorPosition)
357 Frame* frame = m_page->focusController()->focusedOrMainFrame();
358 if (!frame || !frame->editor()->canEdit())
360 frame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
363 void WebPage::firstRectForCharacterInSelectedRange(const uint64_t characterPosition, WebCore::IntRect& resultRect)
365 Frame* frame = m_page->focusController()->focusedOrMainFrame();
367 if (RefPtr<Range> range = frame->editor()->hasComposition() ? frame->editor()->compositionRange() : frame->selection()->selection().toNormalizedRange()) {
368 ExceptionCode ec = 0;
369 RefPtr<Range> tempRange = range->cloneRange(ec);
370 tempRange->setStart(tempRange->startContainer(ec), tempRange->startOffset(ec) + characterPosition, ec);
371 rect = frame->editor()->firstRectForRange(tempRange.get());
373 resultRect = frame->view()->contentsToWindow(rect);
376 void WebPage::getSelectedText(String& text)
378 Frame* frame = m_page->focusController()->focusedOrMainFrame();
379 RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
380 text = selectedRange->text();
383 void WebPage::gestureWillBegin(const WebCore::IntPoint& point, bool& canBeginPanning)
385 m_gestureReachedScrollingLimit = false;
387 bool hitScrollbar = false;
389 HitTestRequest request(HitTestRequest::ReadOnly);
390 for (Frame* childFrame = m_page->mainFrame(); childFrame; childFrame = EventHandler::subframeForTargetNode(m_gestureTargetNode.get())) {
391 ScrollView* scollView = childFrame->view();
395 RenderView* renderView = childFrame->document()->renderView();
399 RenderLayer* layer = renderView->layer();
403 HitTestResult result = scollView->windowToContents(point);
404 layer->hitTest(request, result);
405 m_gestureTargetNode = result.innerNode();
408 hitScrollbar = result.scrollbar();
412 canBeginPanning = false;
416 if (!m_gestureTargetNode) {
417 canBeginPanning = false;
421 for (RenderObject* renderer = m_gestureTargetNode->renderer(); renderer; renderer = renderer->parent()) {
422 if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) {
423 canBeginPanning = true;
428 canBeginPanning = false;
431 static bool scrollbarAtTopOrBottomOfDocument(Scrollbar* scrollbar)
433 ASSERT_ARG(scrollbar, scrollbar);
434 return !scrollbar->currentPos() || scrollbar->currentPos() >= scrollbar->maximum();
437 void WebPage::gestureDidScroll(const IntSize& size)
439 ASSERT_ARG(size, !size.isZero());
441 if (!m_gestureTargetNode || !m_gestureTargetNode->renderer() || !m_gestureTargetNode->renderer()->enclosingLayer())
444 Scrollbar* verticalScrollbar = 0;
445 if (Frame* frame = m_page->mainFrame()) {
446 if (ScrollView* view = frame->view())
447 verticalScrollbar = view->verticalScrollbar();
450 m_gestureTargetNode->renderer()->enclosingLayer()->scrollByRecursively(size.width(), size.height());
451 bool gestureReachedScrollingLimit = verticalScrollbar && scrollbarAtTopOrBottomOfDocument(verticalScrollbar);
453 // FIXME: We really only want to update this state if the state was updated via scrolling the main frame,
454 // not scrolling something in a main frame when the main frame had already reached its scrolling limit.
456 if (gestureReachedScrollingLimit == m_gestureReachedScrollingLimit)
459 send(Messages::WebPageProxy::SetGestureReachedScrollingLimit(gestureReachedScrollingLimit));
460 m_gestureReachedScrollingLimit = gestureReachedScrollingLimit;
463 void WebPage::gestureDidEnd()
465 m_gestureTargetNode = nullptr;
468 } // namespace WebKit