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 "WindowGeometry.h"
36 #include <WebCore/FocusController.h>
37 #include <WebCore/FontRenderingMode.h>
38 #include <WebCore/Frame.h>
39 #include <WebCore/FrameView.h>
40 #include <WebCore/HitTestRequest.h>
41 #include <WebCore/HitTestResult.h>
42 #include <WebCore/KeyboardEvent.h>
43 #include <WebCore/Page.h>
44 #include <WebCore/PlatformKeyboardEvent.h>
45 #include <WebCore/RenderLayer.h>
46 #include <WebCore/RenderView.h>
47 #include <WebCore/ResourceHandle.h>
48 #include <WebCore/Settings.h>
50 #include <WebKitSystemInterface/WebKitSystemInterface.h>
55 #include <CFNetwork/CFURLCachePriv.h>
56 #include <CFNetwork/CFURLProtocolPriv.h>
57 #include <CFNetwork/CFURLRequestPriv.h>
60 using namespace WebCore;
64 void WebPage::platformInitialize()
68 void WebPage::platformPreferencesDidChange(const WebPreferencesStore& store)
70 FontSmoothingLevel fontSmoothingLevel = static_cast<FontSmoothingLevel>(store.getUInt32ValueForKey(WebPreferencesKey::fontSmoothingLevelKey()));
73 FontSmoothingLevel adjustedLevel = fontSmoothingLevel;
74 if (adjustedLevel == FontSmoothingLevelWindows)
75 adjustedLevel = FontSmoothingLevelMedium;
76 wkSetFontSmoothingLevel(adjustedLevel);
79 m_page->settings()->setFontRenderingMode(fontSmoothingLevel == FontSmoothingLevelWindows ? AlternateRenderingMode : NormalRenderingMode);
82 static const unsigned CtrlKey = 1 << 0;
83 static const unsigned AltKey = 1 << 1;
84 static const unsigned ShiftKey = 1 << 2;
92 struct KeyPressEntry {
98 static const KeyDownEntry keyDownEntries[] = {
99 { VK_LEFT, 0, "MoveLeft" },
100 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
101 { VK_LEFT, CtrlKey, "MoveWordLeft" },
102 { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" },
103 { VK_RIGHT, 0, "MoveRight" },
104 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
105 { VK_RIGHT, CtrlKey, "MoveWordRight" },
106 { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" },
107 { VK_UP, 0, "MoveUp" },
108 { VK_UP, ShiftKey, "MoveUpAndModifySelection" },
109 { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" },
110 { VK_DOWN, 0, "MoveDown" },
111 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" },
112 { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" },
113 { VK_PRIOR, 0, "MovePageUp" },
114 { VK_NEXT, 0, "MovePageDown" },
115 { VK_HOME, 0, "MoveToBeginningOfLine" },
116 { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" },
117 { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" },
118 { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
120 { VK_END, 0, "MoveToEndOfLine" },
121 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" },
122 { VK_END, CtrlKey, "MoveToEndOfDocument" },
123 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" },
125 { VK_BACK, 0, "DeleteBackward" },
126 { VK_BACK, ShiftKey, "DeleteBackward" },
127 { VK_DELETE, 0, "DeleteForward" },
128 { VK_BACK, CtrlKey, "DeleteWordBackward" },
129 { VK_DELETE, CtrlKey, "DeleteWordForward" },
131 { 'B', CtrlKey, "ToggleBold" },
132 { 'I', CtrlKey, "ToggleItalic" },
134 { VK_ESCAPE, 0, "Cancel" },
135 { VK_OEM_PERIOD, CtrlKey, "Cancel" },
136 { VK_TAB, 0, "InsertTab" },
137 { VK_TAB, ShiftKey, "InsertBacktab" },
138 { VK_RETURN, 0, "InsertNewline" },
139 { VK_RETURN, CtrlKey, "InsertNewline" },
140 { VK_RETURN, AltKey, "InsertNewline" },
141 { VK_RETURN, ShiftKey, "InsertNewline" },
142 { VK_RETURN, AltKey | ShiftKey, "InsertNewline" },
144 // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
145 // in the application or in WebKit. We chose WebKit.
146 { 'C', CtrlKey, "Copy" },
147 { 'V', CtrlKey, "Paste" },
148 { 'X', CtrlKey, "Cut" },
149 { 'A', CtrlKey, "SelectAll" },
150 { VK_INSERT, CtrlKey, "Copy" },
151 { VK_DELETE, ShiftKey, "Cut" },
152 { VK_INSERT, ShiftKey, "Paste" },
153 { 'Z', CtrlKey, "Undo" },
154 { 'Z', CtrlKey | ShiftKey, "Redo" },
157 static const KeyPressEntry keyPressEntries[] = {
158 { '\t', 0, "InsertTab" },
159 { '\t', ShiftKey, "InsertBacktab" },
160 { '\r', 0, "InsertNewline" },
161 { '\r', CtrlKey, "InsertNewline" },
162 { '\r', AltKey, "InsertNewline" },
163 { '\r', ShiftKey, "InsertNewline" },
164 { '\r', AltKey | ShiftKey, "InsertNewline" },
167 const char* WebPage::interpretKeyEvent(const KeyboardEvent* evt)
169 ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
171 static HashMap<int, const char*>* keyDownCommandsMap = 0;
172 static HashMap<int, const char*>* keyPressCommandsMap = 0;
174 if (!keyDownCommandsMap) {
175 keyDownCommandsMap = new HashMap<int, const char*>;
176 keyPressCommandsMap = new HashMap<int, const char*>;
178 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
179 keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
181 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
182 keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
185 unsigned modifiers = 0;
187 modifiers |= ShiftKey;
191 modifiers |= CtrlKey;
193 if (evt->type() == eventNames().keydownEvent) {
194 int mapKey = modifiers << 16 | evt->keyCode();
195 return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
198 int mapKey = modifiers << 16 | evt->charCode();
199 return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
202 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
204 if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown)
207 switch (keyboardEvent.windowsVirtualKeyCode()) {
209 if (keyboardEvent.isSystemKey())
211 if (keyboardEvent.shiftKey())
217 if (keyboardEvent.isSystemKey())
220 scroll(m_page.get(), ScrollLeft, ScrollByLine);
223 if (keyboardEvent.isSystemKey())
226 scroll(m_page.get(), ScrollRight, ScrollByLine);
229 if (keyboardEvent.isSystemKey())
231 scroll(m_page.get(), ScrollUp, ScrollByLine);
234 if (keyboardEvent.isSystemKey())
236 scroll(m_page.get(), ScrollDown, ScrollByLine);
239 if (keyboardEvent.isSystemKey())
241 logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
244 if (keyboardEvent.isSystemKey())
246 logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
249 if (keyboardEvent.isSystemKey())
251 logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
254 if (keyboardEvent.isSystemKey())
256 logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
266 static RetainPtr<CFCachedURLResponseRef> cachedResponseForURL(WebPage* webPage, const KURL& url)
268 RetainPtr<CFURLRef> cfURL(AdoptCF, url.createCFURL());
269 RetainPtr<CFMutableURLRequestRef> request(AdoptCF, CFURLRequestCreateMutable(0, cfURL.get(), kCFURLRequestCachePolicyReloadIgnoringCache, 60, 0));
270 #if USE(CFURLSTORAGESESSIONS)
271 wkSetRequestStorageSession(ResourceHandle::currentStorageSession(), request.get());
274 RetainPtr<CFStringRef> userAgent(AdoptCF, webPage->userAgent().createCFString());
275 CFURLRequestSetHTTPHeaderFieldValue(request.get(), CFSTR("User-Agent"), userAgent.get());
277 RetainPtr<CFURLCacheRef> cache;
278 #if USE(CFURLSTORAGESESSIONS)
279 if (CFURLStorageSessionRef currentStorageSession = ResourceHandle::currentStorageSession())
280 cache.adoptCF(wkCopyURLCache(currentStorageSession));
283 cache.adoptCF(CFURLCacheCopySharedURLCache());
285 RetainPtr<CFCachedURLResponseRef> response(AdoptCF, CFURLCacheCopyResponseForRequest(cache.get(), request.get()));
290 bool WebPage::platformHasLocalDataForURL(const KURL& url)
293 return cachedResponseForURL(this, url);
299 String WebPage::cachedResponseMIMETypeForURL(const KURL& url)
302 RetainPtr<CFCachedURLResponseRef> cachedResponse = cachedResponseForURL(this, url);
303 CFURLResponseRef response = CFCachedURLResponseGetWrappedResponse(cachedResponse.get());
304 return response ? CFURLResponseGetMIMEType(response) : String();
310 String WebPage::cachedSuggestedFilenameForURL(const KURL& url)
313 RetainPtr<CFCachedURLResponseRef> cachedResponse = cachedResponseForURL(this, url);
314 CFURLResponseRef response = CFCachedURLResponseGetWrappedResponse(cachedResponse.get());
317 RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(response));
319 return suggestedFilename.get();
325 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const KURL& url)
328 RetainPtr<CFCachedURLResponseRef> cachedResponse = cachedResponseForURL(this, url);
329 CFDataRef data = CFCachedURLResponseGetReceiverData(cachedResponse.get());
333 return SharedBuffer::wrapCFData(data);
339 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest& request)
342 return CFURLProtocolCanHandleRequest(request.cfURLRequest());
348 void WebPage::confirmComposition(const String& compositionString)
350 Frame* frame = m_page->focusController()->focusedOrMainFrame();
351 if (!frame || !frame->editor()->canEdit())
353 frame->editor()->confirmComposition(compositionString);
356 void WebPage::setComposition(const String& compositionString, const Vector<WebCore::CompositionUnderline>& underlines, uint64_t cursorPosition)
358 Frame* frame = m_page->focusController()->focusedOrMainFrame();
359 if (!frame || !frame->editor()->canEdit())
361 frame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
364 void WebPage::firstRectForCharacterInSelectedRange(const uint64_t characterPosition, WebCore::IntRect& resultRect)
366 Frame* frame = m_page->focusController()->focusedOrMainFrame();
368 if (RefPtr<Range> range = frame->editor()->hasComposition() ? frame->editor()->compositionRange() : frame->selection()->selection().toNormalizedRange()) {
369 ExceptionCode ec = 0;
370 RefPtr<Range> tempRange = range->cloneRange(ec);
371 tempRange->setStart(tempRange->startContainer(ec), tempRange->startOffset(ec) + characterPosition, ec);
372 rect = frame->editor()->firstRectForRange(tempRange.get());
374 resultRect = frame->view()->contentsToWindow(rect);
377 void WebPage::getSelectedText(String& text)
379 Frame* frame = m_page->focusController()->focusedOrMainFrame();
380 RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
381 text = selectedRange->text();
384 void WebPage::gestureWillBegin(const WebCore::IntPoint& point, bool& canBeginPanning)
386 m_gestureReachedScrollingLimit = false;
388 bool hitScrollbar = false;
390 HitTestRequest request(HitTestRequest::ReadOnly);
391 for (Frame* childFrame = m_page->mainFrame(); childFrame; childFrame = EventHandler::subframeForTargetNode(m_gestureTargetNode.get())) {
392 ScrollView* scollView = childFrame->view();
396 RenderView* renderView = childFrame->document()->renderView();
400 RenderLayer* layer = renderView->layer();
404 HitTestResult result = scollView->windowToContents(point);
405 layer->hitTest(request, result);
406 m_gestureTargetNode = result.innerNode();
409 hitScrollbar = result.scrollbar();
413 canBeginPanning = false;
417 if (!m_gestureTargetNode) {
418 canBeginPanning = false;
422 for (RenderObject* renderer = m_gestureTargetNode->renderer(); renderer; renderer = renderer->parent()) {
423 if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) {
424 canBeginPanning = true;
429 canBeginPanning = false;
432 static bool scrollbarAtTopOrBottomOfDocument(Scrollbar* scrollbar)
434 ASSERT_ARG(scrollbar, scrollbar);
435 return !scrollbar->currentPos() || scrollbar->currentPos() >= scrollbar->maximum();
438 void WebPage::gestureDidScroll(const IntSize& size)
440 ASSERT_ARG(size, !size.isZero());
442 if (!m_gestureTargetNode || !m_gestureTargetNode->renderer() || !m_gestureTargetNode->renderer()->enclosingLayer())
445 Scrollbar* verticalScrollbar = 0;
446 if (Frame* frame = m_page->mainFrame()) {
447 if (ScrollView* view = frame->view())
448 verticalScrollbar = view->verticalScrollbar();
451 m_gestureTargetNode->renderer()->enclosingLayer()->scrollByRecursively(size.width(), size.height());
452 bool gestureReachedScrollingLimit = verticalScrollbar && scrollbarAtTopOrBottomOfDocument(verticalScrollbar);
454 // FIXME: We really only want to update this state if the state was updated via scrolling the main frame,
455 // not scrolling something in a main frame when the main frame had already reached its scrolling limit.
457 if (gestureReachedScrollingLimit == m_gestureReachedScrollingLimit)
460 send(Messages::WebPageProxy::SetGestureReachedScrollingLimit(gestureReachedScrollingLimit));
461 m_gestureReachedScrollingLimit = gestureReachedScrollingLimit;
464 void WebPage::gestureDidEnd()
466 m_gestureTargetNode = nullptr;
469 void WebPage::scheduleChildWindowGeometryUpdate(const WindowGeometry& geometry)
471 WebProcess::shared().connection()->send(Messages::WebPageProxy::ScheduleChildWindowGeometryUpdate(geometry), m_pageID);
474 } // namespace WebKit