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 61 void WebPage::platformInitialize() 62 { 63 m_page->settings()->setFontRenderingMode(AlternateRenderingMode); 64 } 65 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 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 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 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 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 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 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 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 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 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 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 407 static bool scrollbarAtTopOrBottomOfDocument(Scrollbar* scrollbar) 408 { 409 ASSERT_ARG(scrollbar, scrollbar); 410 return !scrollbar->currentPos() || scrollbar->currentPos() >= scrollbar->maximum(); 411 } 412 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 439 void WebPage::gestureDidEnd() 440 { 441 m_gestureTargetNode = nullptr; 442 } 443 444 } // namespace WebKit 445