Home | History | Annotate | Download | only in win
      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